Files
secondo/StorageManager/smiKey.cpp
2026-01-23 17:03:45 +08:00

709 lines
13 KiB
C++

/*
----
This file is part of SECONDO.
Copyright (C) 2004, University in Hagen, Department of Computer Science,
Database Systems for New Applications.
SECONDO is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
SECONDO is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with SECONDO; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
----
1 Implementation of Class SmiKey
May 2002 Ulrich Telle
*/
#include <string.h>
#include <string>
#include <algorithm>
#include <cctype>
#include <cstring>
#include "SecondoSMI.h"
#include "SmiCodes.h"
#include "IndexableAttribute.h"
using namespace std;
SmiKey::SmiKey()
{
keyType = SmiKey::Unknown;
keyLength = 0;
integerKey = 0;
}
SmiKey::SmiKey( const int32_t key )
{
keyType = SmiKey::Unknown;
SetKey( key );
}
SmiKey::SmiKey( const int64_t key )
{
keyType = SmiKey::Unknown;
SetKey( key );
}
SmiKey::SmiKey( const uint32_t key )
{
keyType = SmiKey::Unknown;
SetKey( key );
}
SmiKey::SmiKey( const uint64_t key )
{
keyType = SmiKey::Unknown;
SetKey( key );
}
SmiKey::SmiKey( const double key )
{
keyType = SmiKey::Unknown;
SetKey( key );
}
SmiKey::SmiKey( const string& key )
{
keyType = SmiKey::Unknown;
SetKey( key );
}
SmiKey::SmiKey( const IndexableAttribute* key )
{
keyType = SmiKey::Unknown;
SetKey( key );
}
SmiKey::SmiKey( const SmiKey& other )
{
keyType = SmiKey::Unknown;
SetKey( other.keyType, other.GetAddr(), other.keyLength );
}
SmiKey::~SmiKey()
{
FreeData();
}
SmiKey&
SmiKey::operator=( const SmiKey& other )
{
// Check for self-assignment (smiKey = smiKey)
//
// Otherwise we would release "our" memory first (e.g.,
// calling FreeData() in SetKey()) and try to access
// the "other" memory in the copy operation later, which
// causes a 'use after free' bug.
if (this == &other) {
return *this;
}
SetKey( other.keyType, other.GetAddr(), other.keyLength );
return *this;
}
bool
SmiKey::operator==( const SmiKey& other ) const
{
if( keyType != other.GetType() )
return false;
bool ok = false;
switch (keyType)
{
case SmiKey::Integer:
ok = (integerKey == other.integerKey);
break;
case SmiKey::Longint:
ok = (longintKey == other.longintKey);
break;
case SmiKey::Float:
ok = (floatKey == other.floatKey);
break;
case SmiKey::String:
case SmiKey::Composite:
{
const void* key1 = ( keyLength > SMI_MAX_KEYLEN_LOCAL ) ?
longKeyData : shortKeyData;
const void* key2 = ( other.keyLength > SMI_MAX_KEYLEN_LOCAL ) ?
other.longKeyData : other.shortKeyData;
if ( keyLength == other.keyLength )
{
ok = (memcmp( key1, key2, other.keyLength ) == 0);
}
}
break;
default:
break;
}
return (ok);
}
bool
SmiKey::operator>( const SmiKey& other ) const
{
assert( keyType == other.GetType() );
bool ok;
switch (keyType)
{
case SmiKey::Integer:
ok = (integerKey > other.integerKey);
break;
case SmiKey::Longint:
ok = (longintKey > other.longintKey);
break;
case SmiKey::Float:
ok = (floatKey > other.floatKey);
break;
case SmiKey::String:
case SmiKey::Composite:
{
const void* key1 = ( keyLength > SMI_MAX_KEYLEN_LOCAL ) ?
longKeyData : shortKeyData;
const void* key2 = ( other.keyLength > SMI_MAX_KEYLEN_LOCAL ) ?
other.longKeyData : other.shortKeyData;
if ( keyLength > other.keyLength )
{
ok = (memcmp( key1, key2, other.keyLength ) >= 0);
}
else
{
ok = (memcmp( key1, key2, keyLength ) > 0);
}
}
break;
case SmiKey::Unknown:
default:
ok = false;
break;
}
return (ok);
}
SmiKey::KeyDataType
SmiKey::GetType() const
{
return keyType;
}
void
SmiKey::FreeData()
{
if ( keyType != SmiKey::Unknown &&
keyLength > SMI_MAX_KEYLEN_LOCAL
)
{
delete []longKeyData;
}
}
const void*
SmiKey::GetAddr() const
{
const void* addr;
switch ( keyType )
{
case SmiKey::Integer: addr = &integerKey; break;
case SmiKey::Longint: addr = &longintKey; break;
case SmiKey::Float: addr = &floatKey; break;
case SmiKey::String:
case SmiKey::Composite: addr = (keyLength > SMI_MAX_KEYLEN_LOCAL) ?
longKeyData : shortKeyData; break;
case SmiKey::Unknown:
default: addr = 0; break;
}
return addr;
}
void
SmiKey::SetKey( const int32_t key )
{
FreeData();
keyType = SmiKey::Integer;
keyLength = sizeof( key );
integerKey = key;
}
void
SmiKey::SetKey( const int64_t key )
{
FreeData();
keyType = SmiKey::Longint;
keyLength = sizeof( key );
integerKey = key;
}
void
SmiKey::SetKey( const uint32_t key )
{
FreeData();
keyType = SmiKey::Integer;
keyLength = sizeof( key );
integerKey = key;
}
void
SmiKey::SetKey( const uint64_t key )
{
FreeData();
keyType = SmiKey::Longint;
keyLength = sizeof( key );
integerKey = key;
}
void
SmiKey::SetKey( const double key )
{
FreeData();
keyType = SmiKey::Float;
keyLength = sizeof( key );
floatKey = key;
}
void
SmiKey::SetKey( const string& key )
{
FreeData();
keyType = SmiKey::String;
keyLength = (key.length() <= SMI_MAX_KEYLEN) ? key.length() : SMI_MAX_KEYLEN;
if ( keyLength > SMI_MAX_KEYLEN_LOCAL )
{
longKeyData = new char[keyLength+1];
key.copy( (char*) longKeyData, keyLength );
longKeyData[keyLength] = 0;
}
else
{
key.copy( shortKeyData, keyLength );
shortKeyData[keyLength] = 0;
}
}
void
SmiKey::SetKey( const IndexableAttribute* key )
{
static char mapdata[SMI_MAX_KEYLEN];
char* data;
FreeData();
keyType = SmiKey::Composite;
keyLength = key->SizeOfChars();
assert( keyLength < SMI_MAX_KEYLEN );
key->WriteTo( mapdata );
if ( keyLength > SMI_MAX_KEYLEN_LOCAL )
{
longKeyData = new char[keyLength+1];
data = longKeyData;
}
else
{
data = shortKeyData;
}
memcpy( data, mapdata, keyLength );
data[keyLength] = 0;
}
void
SmiKey::SetKey( const KeyDataType kdt,
const void* key, const SmiSize keyLen )
{
switch (kdt)
{
case SmiKey::Integer:
SetKey( *((int32_t*) key) );
break;
case SmiKey::Longint:
SetKey( *((int64_t*) key) );
break;
case SmiKey::Float:
SetKey( *((double*) key) );
break;
case SmiKey::String:
case SmiKey::Composite:
FreeData();
keyType = kdt;
keyLength = keyLen;
if ( keyLength > SMI_MAX_KEYLEN_LOCAL )
{
longKeyData = new char[keyLength+1];
memcpy( longKeyData, key, keyLength );
longKeyData[keyLength] = 0;
}
else
{
memcpy( shortKeyData, key, keyLength );
shortKeyData[keyLength] = 0;
}
break;
case SmiKey::Unknown:
default:
FreeData();
keyType = kdt;
break;
}
}
bool
SmiKey::GetKey( int32_t& key ) const
{
bool ok = false;
if ( keyType == SmiKey::Integer )
{
ok = true;
key = integerKey;
}
return ok;
}
bool
SmiKey::GetKey( int64_t& key ) const
{
bool ok = false;
if ( keyType == SmiKey::Longint )
{
ok = true;
key = longintKey;
}
return ok;
}
bool
SmiKey::GetKey( uint32_t& key ) const
{
bool ok = false;
if ( keyType == SmiKey::Integer )
{
ok = true;
key = integerKey;
}
return ok;
}
bool
SmiKey::GetKey( uint64_t& key ) const
{
bool ok = false;
if ( keyType == SmiKey::Longint )
{
ok = true;
key = longintKey;
}
return ok;
}
bool
SmiKey::GetKey( double& key ) const
{
bool ok = false;
if ( keyType == SmiKey::Float )
{
ok = true;
key = floatKey;
}
return ok;
}
bool
SmiKey::GetKey( string& key ) const
{
bool ok = false;
if ( keyType == SmiKey::String )
{
ok = true;
if ( keyLength > SMI_MAX_KEYLEN_LOCAL )
{
key.assign( (char*) longKeyData, keyLength );
}
else
{
key.assign( shortKeyData, keyLength );
}
}
return ok;
}
bool
SmiKey::GetKey( IndexableAttribute* key ) const
{
bool ok = false;
const char* data;
if ( keyType == SmiKey::Composite )
{
if ( keyLength > SMI_MAX_KEYLEN_LOCAL )
{
data = (const char*) longKeyData;
}
else
{
data = shortKeyData;
}
key->ReadFrom( data );
ok = true;
}
return ok;
}
SmiSize SmiKey::GetLength() const {
if(keyType == SmiKey::Composite)
return keyLength;
return -1;
}
void
SmiKey::Map( const int32_t inData, void* outData )
{
const unsigned char* s = (unsigned char*) &inData;
unsigned char* t = (unsigned char*) outData;
#ifdef SECONDO_LITTLE_ENDIAN
for ( unsigned int j = 0; j < sizeof( inData ); j++ )
{
t[j] = s[sizeof( inData )-j-1];
}
#else
for ( unsigned int j = 0; j < sizeof( inData ); j++ )
{
t[j] = s[j];
}
#endif
t[0] ^= 0x80;
}
void
SmiKey::Map( const int64_t inData, void* outData )
{
const unsigned char* s = (unsigned char*) &inData;
unsigned char* t = (unsigned char*) outData;
#ifdef SECONDO_LITTLE_ENDIAN
for ( unsigned int j = 0; j < sizeof( inData ); j++ )
{
t[j] = s[sizeof( inData )-j-1];
}
#else
for ( unsigned int j = 0; j < sizeof( inData ); j++ )
{
t[j] = s[j];
}
#endif
t[0] ^= 0x80;
}
void
SmiKey::Map( const uint32_t inData, void* outData )
{
const unsigned char* s = (unsigned char*) &inData;
unsigned char* t = (unsigned char*) outData;
#ifdef SECONDO_LITTLE_ENDIAN
for ( unsigned int j = 0; j < sizeof( inData ); j++ )
{
t[j] = s[sizeof( inData )-j-1];
}
#else
for ( unsigned int j = 0; j < sizeof( inData ); j++ )
{
t[j] = s[j];
}
#endif
t[0] ^= 0x80;
}
void
SmiKey::Map( const uint64_t inData, void* outData )
{
const unsigned char* s = (unsigned char*) &inData;
unsigned char* t = (unsigned char*) outData;
#ifdef SECONDO_LITTLE_ENDIAN
for ( unsigned int j = 0; j < sizeof( inData ); j++ )
{
t[j] = s[sizeof( inData )-j-1];
}
#else
for ( unsigned int j = 0; j < sizeof( inData ); j++ )
{
t[j] = s[j];
}
#endif
t[0] ^= 0x80;
}
void
SmiKey::Map( const double inData, void* outData )
{
const unsigned char* s = (unsigned char*) &inData;
unsigned char* t = (unsigned char*) outData;
#ifdef SECONDO_LITTLE_ENDIAN
for ( unsigned int j = 0; j < sizeof( inData ); j++ )
{
t[j] = s[sizeof( inData )-j-1];
if ( inData < 0.0 )
{
t[j] ^= 0xff;
}
}
#else
for ( int j = 0; j < sizeof( inData ); j++ )
{
t[j] = s[j];
}
#endif
if ( inData >= 0.0 )
{
t[0] ^= 0x80;
}
}
void
SmiKey::Unmap( const void* inData, int32_t& outData )
{
const unsigned char* s = (unsigned char*) inData;
unsigned char* t = (unsigned char*) &outData;
#ifdef SECONDO_LITTLE_ENDIAN
for ( unsigned int j = 0; j < sizeof( outData ); j++ )
{
t[j] = s[sizeof( outData )-j-1];
}
t[sizeof( outData )-1] ^= 0x80;
#else
for ( unsigned int j = 0; j < sizeof( inData ); j++ )
{
t[j] = s[j];
}
t[0] ^= 0x80;
#endif
}
void
SmiKey::Unmap( const void* inData, int64_t& outData )
{
const unsigned char* s = (unsigned char*) inData;
unsigned char* t = (unsigned char*) &outData;
#ifdef SECONDO_LITTLE_ENDIAN
for ( unsigned int j = 0; j < sizeof( outData ); j++ )
{
t[j] = s[sizeof( outData )-j-1];
}
t[sizeof( outData )-1] ^= 0x80;
#else
for ( unsigned int j = 0; j < sizeof( inData ); j++ )
{
t[j] = s[j];
}
t[0] ^= 0x80;
#endif
}
void
SmiKey::Unmap( const void* inData, uint32_t& outData )
{
const unsigned char* s = (unsigned char*) inData;
unsigned char* t = (unsigned char*) &outData;
#ifdef SECONDO_LITTLE_ENDIAN
for ( unsigned int j = 0; j < sizeof( outData ); j++ )
{
t[j] = s[sizeof( outData )-j-1];
}
t[sizeof( outData )-1] ^= 0x80;
#else
for ( unsigned int j = 0; j < sizeof( inData ); j++ )
{
t[j] = s[j];
}
t[0] ^= 0x80;
#endif
}
void
SmiKey::Unmap( const void* inData, uint64_t& outData )
{
const unsigned char* s = (unsigned char*) inData;
unsigned char* t = (unsigned char*) &outData;
#ifdef SECONDO_LITTLE_ENDIAN
for ( unsigned int j = 0; j < sizeof( outData ); j++ )
{
t[j] = s[sizeof( outData )-j-1];
}
t[sizeof( outData )-1] ^= 0x80;
#else
for ( unsigned int j = 0; j < sizeof( inData ); j++ )
{
t[j] = s[j];
}
t[0] ^= 0x80;
#endif
}
void
SmiKey::Unmap( const void* inData, double& outData )
{
const unsigned char* s = (unsigned char*) inData;
unsigned char* t = (unsigned char*) &outData;
#ifdef SECONDO_LITTLE_ENDIAN
for ( unsigned int j = 0; j < sizeof( outData ); j++ )
{
t[j] = s[sizeof( outData )-j-1];
if ( !(s[0] & 0x80) )
{
t[j] ^= 0xff;
}
}
if ( s[0] & 0x80 )
{
t[sizeof( outData )-1] ^= 0x80;
}
#else
for ( int j = 0; j < sizeof( inData ); j++ )
{
t[j] = s[j];
if ( !(s[0] & 0x80) )
{
t[j] ^= 0xff;
}
}
if ( s[0] & 0x80 )
{
t[0] ^= 0x80;
}
#endif
}
/* --- smiKey.cpp --- */