Files
Leviathan/Library/Internal/include/toolkit/XPropertySet.h
T
2026-06-01 12:46:52 +02:00

239 lines
9.5 KiB
C++

#pragma once
#include <map>
#include <string>
#include "safe_function.h"
struct property_tag
{
int type;
int offset;
size_t data_len;
};
template< typename KEY >
struct XPropertySetBase
{
private:
typedef std::map< KEY, property_tag > PROPERTY_MAP;
public:
typedef KEY key_type;
enum {
PROPERTY_TYPE_NIL = -1,
PROPERTY_TYPE_BOOL = 0,
PROPERTY_TYPE_UCHAR,
PROPERTY_TYPE_SHORT,
PROPERTY_TYPE_INT,
PROPERTY_TYPE_UNSIGNED_INT,
PROPERTY_TYPE_INT64,
PROPERTY_TYPE_SIZE,
PROPERTY_TYPE_FLOAT,
PROPERTY_TYPE_DOUBLE,
PROPERTY_TYPE_STRING,
PROPERTY_TYPE_CSTRING,
};
void BindCString( const KEY & key, const char* data, size_t data_len ) { _bind( key, PROPERTY_TYPE_CSTRING, (int)( reinterpret_cast< const char* >( data ) - reinterpret_cast< const char* >( this ) ), data_len ); }
void Bind( const KEY & key, bool * data ) { _bind( key, PROPERTY_TYPE_BOOL, (int)( reinterpret_cast< const char* >( data ) - reinterpret_cast< const char* >( this ) ), sizeof( bool ) ); }
void Bind( const KEY & key, unsigned char * data ) { _bind( key, PROPERTY_TYPE_UCHAR, (int)( reinterpret_cast< const char* >( data ) - reinterpret_cast< const char* >( this ) ), sizeof( unsigned char ) ); }
void Bind( const KEY & key, short * data ) { _bind( key, PROPERTY_TYPE_SHORT, (int)( reinterpret_cast< const char* >( data ) - reinterpret_cast< const char* >( this ) ), sizeof( short ) ); }
void Bind( const KEY & key, int * data ) { _bind( key, PROPERTY_TYPE_INT, (int)( reinterpret_cast< const char* >( data ) - reinterpret_cast< const char* >( this ) ), sizeof( int ) ); }
void Bind( const KEY & key, size_t * data ) { _bind( key, PROPERTY_TYPE_SIZE, (size_t)( reinterpret_cast< const char* >( data ) - reinterpret_cast< const char* >( this ) ), sizeof( size_t ) ); }
void Bind( const KEY & key, __int64 * data ) { _bind( key, PROPERTY_TYPE_INT64, (int)( reinterpret_cast< const char* >( data ) - reinterpret_cast< const char* >( this ) ), sizeof( __int64 ) ); }
void Bind( const KEY & key, std::string * data ) { _bind( key, PROPERTY_TYPE_STRING, (int)( reinterpret_cast< const char* >( data ) - reinterpret_cast< const char* >( this ) ), 0 ); }
void Bind( const KEY & key, float * data ) { _bind( key, PROPERTY_TYPE_FLOAT, (int)( reinterpret_cast< const char* >( data ) - reinterpret_cast< const char* >( this ) ), sizeof( float ) ); }
void Bind( const KEY & key, double * data ) { _bind( key, PROPERTY_TYPE_DOUBLE, (int)( reinterpret_cast< const char* >( data ) - reinterpret_cast< const char* >( this ) ), sizeof( double ) ); }
int GetPropertyType( const KEY & key )
{
PROPERTY_MAP * map = getPropertyMap();
if ( !map ) return PROPERTY_TYPE_NIL;
PROPERTY_MAP::iterator it = map->find( key );
if( it == map->end() ) return PROPERTY_TYPE_NIL;
return it->second.type;
}
float GetFloat( const KEY & key ) { return *reinterpret_cast< float * >( getOffset( key, PROPERTY_TYPE_FLOAT ) ); }
float GetDouble( const KEY & key ) { return *reinterpret_cast< float * >( getOffset( key, PROPERTY_TYPE_DOUBLE ) ); }
std::string GetString( const KEY & key ) { return *reinterpret_cast< std::string * >( getOffset( key, PROPERTY_TYPE_STRING ) ); }
int GetInt( const KEY & key ) { return *reinterpret_cast< int * >( getOffset( key, PROPERTY_TYPE_INT ) ); }
int GetSize( const KEY & key ) { return *reinterpret_cast< size_t * >( getOffset( key, PROPERTY_TYPE_INT ) ); }
short GetShort( const KEY & key ) { return *reinterpret_cast< short * >( getOffset( key, PROPERTY_TYPE_SHORT ) ); }
char GetChar( const KEY & key ) { return *reinterpret_cast< unsigned char * >( getOffset( key, PROPERTY_TYPE_UCHAR ) ); }
bool GetBool( const KEY & key ) { return *reinterpret_cast< bool * >( getOffset( key, PROPERTY_TYPE_BOOL ) ); }
__int64 GetInt64( const KEY & key ) { return *reinterpret_cast< __int64 * >( getOffset( key, PROPERTY_TYPE_INT64 ) ); }
const char* GetCString( const KEY & key ) { return reinterpret_cast< const char * >( getOffset( key, PROPERTY_TYPE_CSTRING ) ); }
std::string GetAsString( const KEY & key, const char *szDefault = "" )
{
PROPERTY_MAP * map = getPropertyMap();
if ( !map ) return szDefault;
PROPERTY_MAP::iterator it = map->find( key );
if ( it == map->end() ) return onGetEmptyKey( key, szDefault );
char *pData = reinterpret_cast< char * >( this );
pData += it->second.offset;
char temp[1024];
char *pOutput = temp;
switch( it->second.type )
{
case PROPERTY_TYPE_UCHAR: s_sprintf( temp, _countof( temp ), "%u", *reinterpret_cast< unsigned char* >( pData ) ); break;
case PROPERTY_TYPE_BOOL: s_sprintf( temp, _countof( temp ), "%d", *reinterpret_cast< bool* >( pData ) ); break;
case PROPERTY_TYPE_SHORT: s_sprintf( temp, _countof( temp ), "%d", *reinterpret_cast< short* >( pData ) ); break;
case PROPERTY_TYPE_INT: s_sprintf( temp, _countof( temp ), "%d", *reinterpret_cast< int* >( pData ) ); break;
case PROPERTY_TYPE_SIZE: s_sprintf( temp, _countof( temp ), "%u", *reinterpret_cast< size_t* >( pData ) ); break;
case PROPERTY_TYPE_INT64: s_sprintf( temp, _countof( temp ), "%I64d", *reinterpret_cast< __int64* >( pData ) ); break;
case PROPERTY_TYPE_FLOAT: s_sprintf( temp, _countof( temp ), "%f", *reinterpret_cast< float* >( pData ) ); break;
case PROPERTY_TYPE_DOUBLE: s_sprintf( temp, _countof( temp ), "%f", *reinterpret_cast< double* >( pData ) ); break;
case PROPERTY_TYPE_STRING: return *reinterpret_cast< std::string * >( pData );
case PROPERTY_TYPE_CSTRING: return pData;
default: return "<INVALID_TYPE>";
}
return pOutput;
}
bool SetAsString( const KEY & key, const char * data )
{
onBeforeChangeProperty( key, data );
PROPERTY_MAP * map = getPropertyMap();
if ( !map ) return false;
PROPERTY_MAP::iterator it = map->find( key );
bool bIsValidOperation = true;
bool bKeyExist = true;
if ( !isValidChange( key, data ) ) return false;
// 없다면 KIN
if ( it == map->end() )
{
bKeyExist = false;
bIsValidOperation = onSetEmptyKey( key, data );
}
if ( bKeyExist )
{
char *pData = reinterpret_cast< char * >( this );
pData += it->second.offset;
size_t dat_len = it->second.data_len;
switch( it->second.type )
{
case PROPERTY_TYPE_BOOL: *reinterpret_cast< bool* >( pData ) = !!atoi( data ); break;
case PROPERTY_TYPE_UCHAR: *reinterpret_cast< unsigned char* >( pData ) = atoi( data ); break;
case PROPERTY_TYPE_SHORT: *reinterpret_cast< short* >( pData ) = atoi( data ); break;
case PROPERTY_TYPE_INT: *reinterpret_cast< int* >( pData ) = atoi( data ); break;
case PROPERTY_TYPE_SIZE: *reinterpret_cast< size_t* >( pData ) = atoi( data ); break;
case PROPERTY_TYPE_INT64: *reinterpret_cast< __int64* >( pData ) = _atoi64( data ); break;
case PROPERTY_TYPE_FLOAT: *reinterpret_cast< float* >( pData ) = (float)atof( data ); break;
case PROPERTY_TYPE_DOUBLE: *reinterpret_cast< double* >( pData ) = (double)atof( data ); break;
case PROPERTY_TYPE_STRING: *reinterpret_cast< std::string * >( pData ) = data; break;
case PROPERTY_TYPE_CSTRING: s_strcpy( pData, dat_len, data ); break;
default: break;
}
}
onChangeProperty( key, data );
return bIsValidOperation;
}
std::string EnumAllProperty()
{
std::string strResult;
PROPERTY_MAP * map = getPropertyMap();
if ( !map ) return strResult;
for ( PROPERTY_MAP::iterator it = map->begin(); it != map->end(); ++it )
{
strResult += it->first;
strResult += " : ";
strResult += GetAsString( it->first.c_str() );
strResult += "\n";
}
return strResult;
}
protected:
// 만약 RTTI 를 사용한다면 이런식으로 구현하지 않아도 된다.
virtual const char* getClassName() = 0;
virtual std::string onGetEmptyKey( const KEY & key, const char *szDefault = "" ) { return szDefault; }
virtual bool onSetEmptyKey( const KEY & key, const char *data ) { return false; }
virtual bool isValidChange( const KEY & key, const char *data ) { return true; }
virtual void onBeforeChangeProperty( const KEY & key, const char *data ) { return; }
virtual void onChangeProperty( const KEY & key, const char *data ) {}
private:
static std::map< std::string, typename XPropertySetBase::PROPERTY_MAP > & XPropertySetBase::getTypeMap()
{
static std::map< std::string, XPropertySetBase< KEY >::PROPERTY_MAP > _inst;
return _inst;
}
PROPERTY_MAP * getPropertyMap()
{
// 해당 타입에 대한 맵을 얻는다
std::map< std::string, PROPERTY_MAP >::iterator it;
it = getTypeMap().find( getClassName() );
// 존재하지 않는 타입이면 KIN
if ( it == getTypeMap().end() ) return NULL;
return &it->second;
}
char* getOffset( const KEY & key, int type )
{
// property 가 없을 경우 돌려줄 것들
static std::string strTmp( "<NULL>" );
static char szTmp[32] = {0,};
PROPERTY_MAP * map = getPropertyMap();
PROPERTY_MAP::iterator it = map->find( key );
// 타입 불일치라면 KIN
if ( !map || it == map->end() || it->second.type != type )
{
if ( type == PROPERTY_TYPE_STRING ) return reinterpret_cast< char* >( &strTmp );
else if ( type == PROPERTY_TYPE_CSTRING ) return "<NULL>";
else return szTmp;
}
char *pData = reinterpret_cast< char * >( this );
pData += it->second.offset;
return pData;
}
inline void _bind( const KEY& key, int type, int offset, size_t data_len )
{
property_tag tag;
tag.type = type;
tag.offset = offset;
tag.data_len = data_len;
(getTypeMap()[ getClassName() ])[ key ] = tag;
}
};
struct XPropertySet : public XPropertySetBase< std::string >
{
};