/* * OpenClonk, http://www.openclonk.org * * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/ * Copyright (c) 2009-2016, The OpenClonk Team and contributors * * Distributed under the terms of the ISC license; see accompanying file * "COPYING" for details. * * "Clonk" is a registered trademark of Matthes Bender, used with permission. * See accompanying file "TRADEMARK" for details. * * To redistribute this file separately, substitute the full license texts * for the above references. */ #ifndef STDADAPTORS_H #define STDADAPTORS_H #include "lib/StdCompiler.h" // * Wrappers for C4Compiler-types // Whole-line string, automatic size deduction (C4Compiler-String) #define toC4CStr(szString) mkStringAdaptMA(szString) #define toC4CStrBuf(rBuf) mkParAdapt(rBuf, StdCompiler::RCT_All) // Integer-array with default 0, automatic size deduction #define toC4CArr(rArr) mkArrayAdaptDM(rArr, 0) #define toC4CArrU(rArr) mkArrayAdaptDM(rArr, 0u) // * Null Adaptor // Doesn't compile anything struct StdNullAdapt { inline void CompileFunc(StdCompiler *pComp) const { } }; // * Defaulting Adaptor // Sets default if CompileFunc fails with a Exception of type NotFoundException template struct StdDefaultAdapt { T &rValue; const D &rDefault; StdDefaultAdapt(T &rValue, const D &rDefault) : rValue(rValue), rDefault(rDefault) { } inline void CompileFunc(StdCompiler *pComp) const { try { #ifdef STDCOMPILER_EXCEPTION_WORKAROUND if (!pComp->ValueSafe(rValue)) rValue = rDefault; #else pComp->Value(rValue); #endif } catch (StdCompiler::NotFoundException *pEx) { rValue = rDefault; delete pEx; } } }; template inline StdDefaultAdapt mkDefaultAdapt(T &&rValue, const D &rDefault) { return StdDefaultAdapt(rValue, rDefault); } // * Naming Adaptor // Embeds a value into a named section, failsafe // (use for values that do defaulting themselves - e.g. objects using naming) template struct StdNamingAdapt { T &rValue; const char *szName; StdNamingAdapt(T &rValue, const char *szName) : rValue(rValue), szName(szName) { } inline void CompileFunc(StdCompiler *pComp) const { pComp->Name(szName); try { pComp->Value(rValue); } catch (StdCompiler::Exception *) { pComp->NameEnd(true); throw; } pComp->NameEnd(); } template inline bool operator == (const D &nValue) const { return rValue == nValue; } template inline StdNamingAdapt &operator = (const D &nValue) { rValue = nValue; return *this; } }; template inline StdNamingAdapt mkNamingAdapt(T &&rValue, const char *szName) { return StdNamingAdapt(rValue, szName); } // * Naming Adaptor (defaulting) // Embeds a value into a named section, sets default on fail template struct StdNamingDefaultAdapt { T &rValue; const char *szName; const D &rDefault; bool fPrefillDefault; bool fStoreDefault; StdNamingDefaultAdapt(T &rValue, const char *szName, const D &rDefault, bool fPrefillDefault, bool fStoreDefault) : rValue(rValue), szName(szName), rDefault(rDefault), fPrefillDefault(fPrefillDefault), fStoreDefault(fStoreDefault) { } inline void CompileFunc(StdCompiler *pComp) const { // Default check if (pComp->hasNaming() && pComp->isSerializer() && rValue == rDefault && !fStoreDefault) { if (pComp->Default(szName)) return; } try { // Search named section, set default if not found if (pComp->Name(szName)) { if (fPrefillDefault && pComp->isDeserializer()) rValue = rDefault; // default prefill if desired pComp->Value(mkDefaultAdapt(rValue, rDefault)); } else rValue = rDefault; } catch (StdCompiler::Exception *) { pComp->NameEnd(true); throw; } // End section pComp->NameEnd(); } }; template inline StdNamingDefaultAdapt mkNamingAdapt(T &&rValue, const char *szName, const D &rDefault, bool fPrefillDefault=false, bool fStoreDefault=false) { return StdNamingDefaultAdapt(rValue, szName, rDefault, fPrefillDefault, fStoreDefault); } // * Decompiling Adaptor // Allows to use const objects if the compiler won't change the targets template struct StdDecompileAdapt { const T &rValue; explicit StdDecompileAdapt(const T &rValue) : rValue(rValue) { } inline void CompileFunc(StdCompiler *pComp) const { assert(pComp->isSerializer()); pComp->Value(const_cast(rValue)); } // make this work with in combination with StdParameterAdapt template inline void CompileFunc(StdCompiler* pComp, P && ... pars) const { assert(pComp->isSerializer()); pComp->Value(mkParAdapt(const_cast(rValue), std::forward

(pars)...)); } }; template inline StdDecompileAdapt mkDecompileAdapt(const T& rValue) { return StdDecompileAdapt(rValue); } // * Runtime value Adaptor // Allows the C4ValueSetCompiler to set the value template struct StdRuntimeValueAdapt { T &rValue; explicit StdRuntimeValueAdapt(T &rValue) : rValue(rValue) { } inline void CompileFunc(StdCompiler *pComp) const { pComp->setRuntimeWritesAllowed(+1); pComp->Value(rValue); pComp->setRuntimeWritesAllowed(-1); } template inline bool operator == (const D &nValue) const { return rValue == nValue; } template inline StdRuntimeValueAdapt &operator = (const D &nValue) { rValue = nValue; return *this; } }; template inline StdRuntimeValueAdapt mkRuntimeValueAdapt(T &&rValue) { return StdRuntimeValueAdapt(rValue); } // * String adaptor struct StdStringAdapt { char *szString; int iMaxLength; StdCompiler::RawCompileType eRawType; StdStringAdapt(char *szString, int iMaxLength, StdCompiler::RawCompileType eRawType = StdCompiler::RCT_Escaped) : szString(szString), iMaxLength(iMaxLength), eRawType(eRawType) { } inline void CompileFunc(StdCompiler *pComp) const { pComp->String(szString, iMaxLength, eRawType); } inline bool operator == (const char *szDefault) const { return SEqual(szString, szDefault); } inline StdStringAdapt &operator = (const char *szDefault) { SCopy(szDefault, szString, iMaxLength); return *this; } }; inline StdStringAdapt mkStringAdapt(char *szString, int iMaxLength, StdCompiler::RawCompileType eRawType = StdCompiler::RCT_Escaped) { return StdStringAdapt(szString, iMaxLength, eRawType); } template inline StdStringAdapt mkStringAdaptM(char (&szString)[size]) { return mkStringAdapt(szString, size); } template inline StdStringAdapt mkStringAdaptMA(char (&szString)[size]) { return mkStringAdapt(szString, size, StdCompiler::RCT_All); } template inline StdStringAdapt mkStringAdaptMI(char (&szString)[size]) { return mkStringAdapt(szString, size, StdCompiler::RCT_Idtf); } template inline StdStringAdapt mkStringAdaptMIE(char (&szString)[size]) { return mkStringAdapt(szString, size, StdCompiler::RCT_IdtfAllowEmpty); } // * std::string adaptor struct StdStdStringAdapt { std::string& string; StdCompiler::RawCompileType eRawType; StdStdStringAdapt(std::string& string, StdCompiler::RawCompileType eRawType = StdCompiler::RCT_Escaped) : string(string), eRawType(eRawType) { } inline void CompileFunc(StdCompiler *pComp) const { pComp->String(string, eRawType); } inline bool operator == (const char *szDefault) const { return string == szDefault; } inline StdStdStringAdapt &operator = (const char *szDefault) { string = szDefault; return *this; } }; inline StdStdStringAdapt mkStringAdapt(std::string& string, StdCompiler::RawCompileType eRawType = StdCompiler::RCT_Escaped) { return StdStdStringAdapt(string, eRawType); } inline StdStdStringAdapt mkStringAdaptA(std::string& string) { return StdStdStringAdapt(string, StdCompiler::RCT_All); } // * Raw adaptor struct StdRawAdapt { void *pData; size_t iSize; StdCompiler::RawCompileType eRawType; StdRawAdapt(void *pData, size_t iSize, StdCompiler::RawCompileType eRawType = StdCompiler::RCT_Escaped) : pData(pData), iSize(iSize), eRawType(eRawType) { } inline void CompileFunc(StdCompiler *pComp) const { pComp->Raw(pData, iSize, eRawType); } inline bool operator == (const void *pDefault) const { return !memcmp(pDefault, pData, iSize); } inline StdRawAdapt &operator = (const void *pDefault) { memcpy(pData, pDefault, iSize); return *this; } }; inline StdRawAdapt mkRawAdapt(void *pData, size_t iSize, StdCompiler::RawCompileType eRawType = StdCompiler::RCT_Escaped) { return StdRawAdapt(pData, iSize, eRawType); } template inline StdRawAdapt mkRawAdaptM(T &val) { // GCC 4.x doesn't support std::is_trivially_copyable #if !defined(__GNUC__) || __GNUC__ > 4 static_assert(std::is_trivially_copyable::value, "StdRawAdapt: type must be trivially copyable"); #endif return mkRawAdapt(&val, sizeof(val)); } // * Integer Adaptor // Stores Integer-like datatypes (Enumerations) template struct StdIntAdapt { T &rValue; explicit StdIntAdapt(T &rValue) : rValue(rValue) { } inline void CompileFunc(StdCompiler *pComp) const { // Cast int_t iVal = int_t(rValue); pComp->Value(iVal); rValue = T(iVal); } // Operators for default checking/setting template inline bool operator == (const D &nValue) const { return rValue == nValue; } template inline StdIntAdapt &operator = (const D &nValue) { rValue = nValue; return *this; } }; template inline StdIntAdapt mkIntAdapt(T &rValue) { return StdIntAdapt(rValue); } template StdIntAdapt mkIntAdaptT(T &rValue) { return StdIntAdapt(rValue); } // * Casting Adaptor // Does a reinterprete_cast template struct StdCastAdapt { T &rValue; explicit StdCastAdapt(T &rValue) : rValue(rValue) { } inline void CompileFunc(StdCompiler *pComp) const { // Cast static_assert(sizeof(to_t) == sizeof(T), "CastAdapt sanity: sizes match"); static_assert(std::is_pod::value, "CastAdapt sanity: to-type is POD"); static_assert(std::is_pod::value, "CastAdapt sanity: from-type is POD"); to_t vVal; std::memcpy(&vVal, &rValue, sizeof(to_t)); pComp->Value(vVal); std::memcpy(&rValue, &vVal, sizeof(T)); } // Operators for default checking/setting template inline bool operator == (const D &nValue) const { return rValue == nValue; } template inline StdCastAdapt &operator = (const D &nValue) { rValue = nValue; return *this; } }; template StdCastAdapt mkCastAdapt(T &rValue) { return StdCastAdapt(rValue); } template StdCastAdapt mkCastIntAdapt(T &rValue) { return StdCastAdapt(rValue); } // Helper: Identity function class template struct _IdFuncClass { T &operator ()(T &rValue) const { return rValue; } }; // * Array Adaptor // Stores a separated list template > struct StdArrayAdapt { StdArrayAdapt(T *pArray, int iSize, M && map = M()) : pArray(pArray), iSize(iSize), map(std::forward(map)) { } T *pArray; int iSize; M && map; inline void CompileFunc(StdCompiler *pComp) const { for (int i = 0; i < iSize; i++) { if (i) pComp->Separator(StdCompiler::SEP_SEP); pComp->Value(map(pArray[i])); } } // Operators for default checking/setting inline bool operator == (const T &rDefault) const { for (int i = 0; i < iSize; i++) if (pArray[i] != rDefault) return false; return true; } inline StdArrayAdapt &operator = (const T &rDefault) { for (int i = 0; i < iSize; i++) pArray[i] = rDefault; return *this; } inline bool operator == (const T *pDefaults) const { for (int i = 0; i < iSize; i++) if (pArray[i] != pDefaults[i]) return false; return true; } inline StdArrayAdapt &operator = (const T *pDefaults) { for (int i = 0; i < iSize; i++) pArray[i] = pDefaults[i]; return *this; } }; template inline StdArrayAdapt mkArrayAdapt(T *pArray, int iSize) { return StdArrayAdapt(pArray, iSize); } template inline StdArrayAdapt mkArrayAdaptM(T (&array)[size]) { return StdArrayAdapt(array, size); } template inline StdArrayAdapt mkArrayAdaptMap(T *pArray, int iSize, M && map) { return StdArrayAdapt(pArray, iSize, std::forward(map)); } template inline StdArrayAdapt mkArrayAdaptMapM(T (&array)[size], M && map) { return StdArrayAdapt(array, size, std::forward(map)); } // * Array Adaptor (defaulting) // Stores a separated list, sets defaults if a value or separator is missing. template > struct StdArrayDefaultAdapt { StdArrayDefaultAdapt(T *pArray, size_t iSize, const D &rDefault, const M &map = M()) : pArray(pArray), iSize(iSize), rDefault(rDefault), map(map) { } T *pArray; size_t iSize; const D &rDefault; const M map; inline void CompileFunc(StdCompiler *pComp) const { size_t i, iWrite = iSize; bool deserializing = pComp->isDeserializer(); // Decompiling: Omit defaults if (!deserializing && pComp->hasNaming()) while (iWrite > 0 && pArray[iWrite - 1] == rDefault) iWrite--; // Read/write values for (i = 0; i < iWrite; i++) { // Separator? if (i) if (!pComp->Separator(StdCompiler::SEP_SEP)) break; // Expect a value. Default if not found. pComp->Value(mkDefaultAdapt(map(pArray[i]), rDefault)); } // Fill rest of array if (deserializing) for (; i < iSize; i++) pArray[i] = rDefault; } // Additional defaulting (whole array) inline bool operator == (const T *pDefaults) const { for (size_t i = 0; i < iSize; i++) if (pArray[i] != pDefaults[i]) return false; return true; } inline StdArrayDefaultAdapt &operator = (const T *pDefaults) { for (size_t i = 0; i < iSize; i++) pArray[i] = pDefaults[i]; return *this; } }; template inline StdArrayDefaultAdapt mkArrayAdapt(T *pArray, size_t iSize, const D &rDefault) { return StdArrayDefaultAdapt(pArray, iSize, rDefault); } template inline StdArrayDefaultAdapt mkArrayAdaptDM(T (&array)[size], const D &rDefault) { return StdArrayDefaultAdapt(array, size, rDefault); } template inline StdArrayDefaultAdapt mkArrayAdaptMap(T *pArray, size_t iSize, const D &rDefault, M map) { return StdArrayDefaultAdapt(pArray, iSize, rDefault, map); } template inline StdArrayDefaultAdapt mkArrayAdaptMapDM(T (&array)[size], const D &rDefault, M map) { return StdArrayDefaultAdapt(array, size, rDefault, map); } // * Array Adaptor (defaulting to another array) // Stores a separated list, sets defaults if a value or separator is missing. template > struct StdArrayDefaultArrayAdapt { StdArrayDefaultArrayAdapt(T *pArray, size_t iSize, const D &rDefault, const M &map = M()) : pArray(pArray), iSize(iSize), rDefault(rDefault), map(map) { } T *pArray; size_t iSize; const D &rDefault; const M map; inline void CompileFunc(StdCompiler *pComp) const { size_t i, iWrite = iSize; bool deserializing = pComp->isDeserializer(); // Decompiling: Omit defaults if (!deserializing && pComp->hasNaming()) while (iWrite > 0 && pArray[iWrite - 1] == rDefault[iWrite - 1]) iWrite--; // Read/write values for (i = 0; i < iWrite; i++) { // Separator? if (i) if (!pComp->Separator(StdCompiler::SEP_SEP)) break; // Expect a value. Default if not found. pComp->Value(mkDefaultAdapt(map(pArray[i]), rDefault[i])); } // Fill rest of array if (deserializing) for (; i < iSize; i++) pArray[i] = rDefault[i]; } // Additional defaulting (whole array) inline bool operator == (const T *pDefaults) const { for (size_t i = 0; i < iSize; i++) if (pArray[i] != pDefaults[i]) return false; return true; } inline StdArrayDefaultArrayAdapt &operator = (const T *pDefaults) { for (size_t i = 0; i < iSize; i++) pArray[i] = pDefaults[i]; return *this; } }; template inline StdArrayDefaultArrayAdapt mkArrayAdaptDefArr(T *pArray, size_t iSize, const D &rDefault) { return StdArrayDefaultArrayAdapt(pArray, iSize, rDefault); } template inline StdArrayDefaultArrayAdapt mkArrayAdaptDMA(T (&array)[size], const D &rDefault) { return StdArrayDefaultArrayAdapt(array, size, rDefault); } template inline StdArrayDefaultArrayAdapt mkArrayAdaptDefArrMap(T *pArray, size_t iSize, const D &rDefault, const M &map) { return StdArrayDefaultArrayAdapt(pArray, iSize, rDefault, map); } template inline StdArrayDefaultArrayAdapt mkArrayAdaptDMAM(T (&array)[size], const D &rDefault, const M &map) { return StdArrayDefaultArrayAdapt(array, size, rDefault, map); } // * Insertion Adaptor // Compile a value before / after another template struct StdInsertAdapt { StdInsertAdapt(T &rObj, I &rIns, bool fBefore = true) : rObj(rObj), rIns(rIns), fBefore(fBefore) { } T &rObj; I &rIns; bool fBefore; void CompileFunc(StdCompiler *pComp) const { if (fBefore) pComp->Value(rIns); pComp->Value(rObj); if (!fBefore) pComp->Value(rIns); } }; template inline StdInsertAdapt mkInsertAdapt(T &&rObj, I &&rIns, bool fBefore = true) { return StdInsertAdapt(rObj, rIns, fBefore); } // * Parameter Adaptor // Specify a second parameter for the CompileFunc template struct StdParameterAdapt { StdParameterAdapt(T && rObj, P && rPar) : rObj(std::forward(rObj)), Par(std::forward

(rPar)) { } T && rObj; P && Par; void CompileFunc(StdCompiler *pComp) const { std::forward(rObj).CompileFunc(pComp, std::forward

(Par)); } // Operators for default checking/setting template inline bool operator == (const D &nValue) const { return rObj == nValue; } template inline StdParameterAdapt &operator = (const D &nValue) { rObj = nValue; return *this; } // getting value inline T && GetObj() { return std::forward(rObj); } }; template inline StdParameterAdapt mkParAdapt(T && rObj, P && rPar) { return StdParameterAdapt(std::forward(rObj), std::forward

(rPar)); } // for mkArrayAdaptMap template struct StdParameterAdaptMaker { P && Par; StdParameterAdaptMaker(P && rPar) : Par(std::forward

(rPar)) { } template StdParameterAdapt operator ()(T && rObj) const { return StdParameterAdapt(std::forward(rObj), std::forward

(Par)); } }; template inline StdParameterAdaptMaker

mkParAdaptMaker(P && rPar) { return StdParameterAdaptMaker

(std::forward

(rPar)); } // * Parameter Adaptor 2 // Specify a second and a third parameter for the CompileFunc template struct StdParameter2Adapt { StdParameter2Adapt(T && rObj, P1 && rPar1, P2 && rPar2) : rObj(std::forward(rObj)), rPar1(std::forward(rPar1)), rPar2(std::forward(rPar2)) { } T && rObj; P1 && rPar1; P2 && rPar2; void CompileFunc(StdCompiler *pComp) const { std::forward(rObj).CompileFunc(pComp, std::forward(rPar1), std::forward(rPar2)); } // Operators for default checking/setting template inline bool operator == (const D &nValue) const { return rObj == nValue; } template inline StdParameter2Adapt &operator = (const D &nValue) { rObj = nValue; return *this; } }; template inline StdParameter2Adapt mkParAdapt(T && rObj, P1 && rPar1, P2 && rPar2) { return StdParameter2Adapt(std::forward(rObj), std::forward(rPar1), std::forward(rPar2)); } template struct StdBasicPtrAdapt { StdBasicPtrAdapt(T *&rpObj, bool fAllowNull = true, const char *szNaming = "Data") : rpObj(rpObj), fAllowNull(fAllowNull), szNaming(szNaming) {} T *&rpObj; bool fAllowNull; const char *szNaming; // Operators for default checking/setting inline bool operator == (const T &nValue) const { return rpObj && *rpObj == nValue; } inline StdBasicPtrAdapt &operator = (const T &nValue) { delete rpObj; rpObj = new T(nValue); return *this; } inline bool operator == (const T *pValue) const { return rpObj == pValue; } inline StdBasicPtrAdapt &operator = (const T *pValue) { delete rpObj; rpObj = pValue; return *this; } }; // * Store pointer (contents) // Defaults to null template struct StdPtrAdapt: StdBasicPtrAdapt { StdPtrAdapt(T *&rpObj, bool fAllowNull = true, const char *szNaming = "Data") : StdBasicPtrAdapt(rpObj, fAllowNull, szNaming) { } void CompileFunc(StdCompiler *pComp) const { StdPtrAdaptCompileFunc(pComp, *this); } // For use with StdParAdapt template void CompileFunc(StdCompiler *pComp, P && ...pars) { StdPtrAdaptCompileFunc(pComp, *this, std::forward

(pars)...); } }; template struct StdContextPtrAdapt: StdBasicPtrAdapt { StdContextPtrAdapt(T *&rpObj, const ContextT& rCtx, bool fAllowNull = true, const char *szNaming = "Data") : StdBasicPtrAdapt(rpObj, fAllowNull, szNaming), pCtx(&rCtx) { } const ContextT* pCtx; void CompileFunc(StdCompiler *pComp) const { StdPtrAdaptCompileFunc(pComp, *this); } // For use with StdParAdapt template void CompileFunc(StdCompiler *pComp, const P& p) { StdPtrAdaptCompileFunc(pComp, *this, p); } }; template void StdPtrAdaptCompileFunc(StdCompiler* pComp, const T& adapt, P && ...pars) { bool deserializing = pComp->isDeserializer(), fNaming = pComp->hasNaming(); // Compiling? Clear object before if(deserializing) { delete adapt.rpObj; adapt.rpObj = nullptr; } // Null checks - different with naming support. if(adapt.fAllowNull) if(fNaming) { // Null check: just omit when writing if(!deserializing && !adapt.rpObj) return; // Set up naming if(!pComp->Name(adapt.szNaming)) { assert(deserializing); pComp->NameEnd(); return; } } else { bool fNull = !! adapt.rpObj; pComp->Value(fNull); // Null? Nothing further to do if(fNull) return; } else if(!deserializing) assert(adapt.rpObj); // Compile value if(deserializing) StdPtrAdaptCompileNewFunc(adapt, pComp, std::forward

(pars)...); else StdPtrAdaptDecompileNewFunc(adapt, pComp, std::forward

(pars)...); // Close naming if(adapt.fAllowNull && fNaming) pComp->NameEnd(); } template void StdPtrAdaptCompileNewFunc(const StdPtrAdapt& adapt, StdCompiler* pComp, P && ...pars) { CompileNewFunc(adapt.rpObj, pComp, std::forward

(pars)...); } template void StdPtrAdaptCompileNewFunc(const StdContextPtrAdapt& adapt, StdCompiler* pComp, P && ...pars) { CompileNewFuncCtx(adapt.rpObj, pComp, *adapt.pCtx, std::forward

(pars)...); } template void StdPtrAdaptDecompileNewFunc(const StdPtrAdapt& adapt, StdCompiler* pComp) { pComp->Value(mkDecompileAdapt(*adapt.rpObj)); } template void StdPtrAdaptDecompileNewFunc(const StdContextPtrAdapt& adapt, StdCompiler* pComp) { pComp->Value(mkDecompileAdapt(*adapt.rpObj)); } template void StdPtrAdaptDecompileNewFunc(const StdPtrAdapt& adapt, StdCompiler* pComp, P && ...pars) { pComp->Value(mkParAdapt(mkDecompileAdapt(*adapt.rpObj), std::forward

(pars)...)); } template void StdPtrAdaptDecompileNewFunc(const StdContextPtrAdapt& adapt, StdCompiler* pComp, P && ...pars) { pComp->Value(mkParAdapt(mkDecompileAdapt(*adapt.rpObj), std::forward

(pars)...)); } template inline StdPtrAdapt mkPtrAdapt(T *&rpObj, bool fAllowNull = true) { return StdPtrAdapt(rpObj, fAllowNull); } template inline StdPtrAdapt mkNamingPtrAdapt(T *&rpObj, const char *szNaming) { return StdPtrAdapt(rpObj, true, szNaming); } template inline StdPtrAdapt mkPtrAdaptNoNull(T *&rpObj) { return mkPtrAdapt(rpObj, false); } template inline StdContextPtrAdapt mkContextPtrAdapt(T *&rpObj, const ContextT& ctx, bool fAllowNull = true) { return StdContextPtrAdapt(rpObj, ctx, fAllowNull); } template inline StdContextPtrAdapt mkNamingContextPtrAdapt(T *&rpObj, const ContextT& ctx, const char* szNaming) { return StdContextPtrAdapt(rpObj, ctx, true, szNaming); } template inline StdContextPtrAdapt mkContextPtrAdaptNoNull(T *&rpObj, const ContextT& ctx) { return mkContextPtrAdapt(rpObj, ctx, false); } // * Adaptor for STL containers // Writes a comma-separated list for compilers that support it. Otherwise, the size is calculated and safed. // The defaulting uses the standard STL operators (full match) template struct StdSTLContainerAdapt { StdSTLContainerAdapt(C &rStruct, StdCompiler::Sep eSep = StdCompiler::SEP_SEP) : rStruct(rStruct), eSep(eSep) { } C &rStruct; const StdCompiler::Sep eSep; inline void CompileFunc(StdCompiler *pComp) const { typedef typename C::value_type T; // Get compiler specs bool deserializing = pComp->isDeserializer(); bool fNaming = pComp->hasNaming(); // Decompiling? if (!deserializing) { // Write size (binary only) if (!fNaming) { int32_t iSize = rStruct.size(); pComp->Value(iSize); } // Write all entries for (typename C::const_iterator i = rStruct.begin(); i != rStruct.end(); ++i) { if (i != rStruct.begin() && eSep) pComp->Separator(eSep); pComp->Value(const_cast(*i)); } } else { // Compiling: Empty previous rStruct.clear(); // Read size (binary only) uint32_t iSize; if (!fNaming) pComp->Value(iSize); // Read new do { // No entries left to read? if (!fNaming && !iSize--) break; // Read entries try { T val; pComp->Value(val); rStruct.push_back(val); } catch (StdCompiler::NotFoundException *pEx) { // No value found: Stop reading loop delete pEx; break; } } while (!eSep || pComp->Separator(eSep)); } } // Operators for default checking/setting inline bool operator == (const C &nValue) const { return rStruct == nValue; } inline StdSTLContainerAdapt &operator = (const C &nValue) { rStruct = nValue; return *this; } }; template inline StdSTLContainerAdapt mkSTLContainerAdapt(C &rTarget, StdCompiler::Sep eSep = StdCompiler::SEP_SEP) { return StdSTLContainerAdapt(rTarget, eSep); } // Write an integer that is supposed to be small most of the time. The adaptor writes it in // 7-bit-pieces, bit 8 being a continuation marker: If it's set, more data is following, if not, // all following bits are 0. // Code lengths for uint32_t: // 0x00000000 (0) - 0x0000007F (127) : 1 byte // 0x00000080 (128) - 0x00003FFF (16383) : 2 byte // 0x00004000 (16384) - 0x001FFFFF (2097151) : 3 byte // 0x00200000 (2097152) - 0x0FFFFFFF (268435456) : 4 byte // 0x10000000 (268435456) - 0xFFFFFFFF (4294967295) : 5 byte // So this sort of packing is always useful when the integer in question is almost impossible to // grow bigger than 2,097,151. template struct StdIntPackAdapt { StdIntPackAdapt(T &rVal) : rVal(rVal) { } T &rVal; inline T clearUpper(T x) const { const int CLEARBITS = 8 * sizeof(T) - 7; return (x << CLEARBITS) >> CLEARBITS; } void CompileFunc(StdCompiler *pComp) const { // simply write for textual compilers if (pComp->hasNaming()) { pComp->Value(rVal); return; } T val; uint8_t tmp; // writing? if (!pComp->isDeserializer()) { val = rVal; for (;;) { tmp = uint8_t(clearUpper(val)); // last byte? if (clearUpper(val) == val) break; // write byte tmp ^= 0x80; pComp->Value(tmp); // advance val >>= 7; } // write last byte pComp->Value(tmp); } // reading? else { // read first byte pComp->Value(tmp); val = clearUpper(T(tmp)); // read remaining bytes int i = 7; T data = val; while ( uint8_t(data) != tmp ) { // read byte pComp->Value(tmp); // add to value data = clearUpper(T(tmp)); val = (data << i) | (val & ((1 << i) - 1)); // next byte i+=7; } // write rVal = val; } } template inline bool operator == (const D &nValue) const { return rVal == nValue; } template inline StdIntPackAdapt &operator = (const D &nValue) { rVal = nValue; return *this; } }; template StdIntPackAdapt mkIntPackAdapt(T &rVal) { return StdIntPackAdapt(rVal); } template struct StdEnumEntry { const char *Name; T Val; }; // Enumeration: For text compilers, write a given name for a value. // For everything else, just write an integer of given type. template struct StdEnumAdapt { typedef StdEnumEntry Entry; StdEnumAdapt(T &rVal, const Entry *pNames) : rVal(rVal), pNames(pNames) { assert(pNames); } T &rVal; const Entry *pNames; void CompileFunc(StdCompiler *pComp) const { // Write as int if (!pComp->isVerbose()) { pComp->Value(mkIntAdaptT(rVal)); return; } // writing? if (!pComp->isDeserializer()) { // Find value const Entry *pName = pNames; for (; pName->Name; pName++) if (pName->Val == rVal) { // Put name pComp->String(const_cast(&pName->Name), StdCompiler::RCT_Idtf); break; } // No name found? if (!pName->Name) // Put value as integer pComp->Value(mkIntAdaptT(rVal)); } // reading? else { int_t val = 0; #ifdef STDCOMPILER_EXCEPTION_WORKAROUND // Try to read as number if (!pComp->ValueSafe(val)) { rVal = T(val); #else // Try to read as number try { pComp->Value(val); rVal = T(val); } catch (StdCompiler::NotFoundException *pEx) { delete pEx; #endif // Try to read as string StdStrBuf Name; pComp->Value(mkParAdapt(Name, StdCompiler::RCT_Idtf)); // Search in name list const Entry *pName = pNames; for (; pName->Name; pName++) if (Name == pName->Name) { rVal = pName->Val; break; } // Not found? Warn if (!pName->Name) pComp->Warn("Unknown bit name: %s", Name.getData()); } } } template inline bool operator == (const D &nValue) const { return rVal == nValue; } template inline StdEnumAdapt &operator = (const D &nValue) { rVal = nValue; return *this; } }; template StdEnumAdapt mkEnumAdapt(T &rVal, const StdEnumEntry *pNames) { return StdEnumAdapt(rVal, pNames); } template StdEnumAdapt mkEnumAdaptT(T &rVal, const StdEnumEntry *pNames) { return StdEnumAdapt(rVal, pNames); } template struct StdBitfieldEntry { const char *Name; T Val; }; // Convert a bitfield into/from something like "foo | bar | baz", where "foo", "bar" and "baz" are given constants. template struct StdBitfieldAdapt { typedef StdBitfieldEntry Entry; StdBitfieldAdapt(T &rVal, const Entry *pNames) : rVal(rVal), pNames(pNames) { assert(pNames); } T &rVal; const Entry *pNames; void CompileFunc(StdCompiler *pComp) const { // simply write for non-verbose compilers if (!pComp->isVerbose()) { pComp->Value(rVal); return; } // writing? if (!pComp->isDeserializer()) { T val = rVal, orig_val = rVal; // Write until value is comsumed bool fFirst = true; for (const Entry *pName = pNames; pName->Name; pName++) if ((pName->Val & val) == pName->Val) { // Avoid writing meaningless none-values (e.g. Category=C4D_None|C4D_Object) if (orig_val && !pName->Val) continue; // Put "|" if (!fFirst) pComp->Separator(StdCompiler::SEP_VLINE); // Put name pComp->String(const_cast(&pName->Name), StdCompiler::RCT_Idtf); fFirst = false; // Remove bits val &= ~pName->Val; } // Anything left is written as number, or a simple 0 in case no default was used if (val || fFirst) { // Put "|" if (!fFirst) pComp->Separator(StdCompiler::SEP_VLINE); // Put value pComp->Value(val); } } // reading? else { T val = 0; // Read do { #ifdef STDCOMPILER_EXCEPTION_WORKAROUND T tmp; // Try to read as number if (pComp->ValueSafe(tmp)) val |= tmp; else { #else // Try to read as number try { T tmp; pComp->Value(tmp); val |= tmp; } catch (StdCompiler::NotFoundException *pEx) { delete pEx; #endif // Try to read as string StdStrBuf Name; pComp->Value(mkParAdapt(Name, StdCompiler::RCT_Idtf)); // Search in name list const Entry *pName = pNames; for (; pName->Name; pName++) if (Name == pName->Name) { val |= pName->Val; break; } // Not found? Warn if (!pName->Name) pComp->Warn("Unknown bit name: %s", Name.getData()); } // Expect separation } while (pComp->Separator(StdCompiler::SEP_VLINE)); // Write value back rVal = val; } } template inline bool operator == (const D &nValue) const { return rVal == nValue; } template inline StdBitfieldAdapt &operator = (const D &nValue) { rVal = nValue; return *this; } }; template StdBitfieldAdapt mkBitfieldAdapt(T &rVal, const StdBitfieldEntry *pNames) { return StdBitfieldAdapt(rVal, pNames); } // * Name count adapter // For compilers without name support, this just compiles the given value. Otherwise, the count // of given namings is returned on compiling, and nothing is done for decompiling (The caller // has to make sure that an appropriate number of namings will be created) template struct StdNamingCountAdapt { int_t &iCount; const char *szName; StdNamingCountAdapt(int_t &iCount, const char *szName) : iCount(iCount), szName(szName) { } inline void CompileFunc(StdCompiler *pComp) const { if (pComp->hasNaming()) { if (pComp->isDeserializer()) iCount = pComp->NameCount(szName); } else pComp->Value(mkIntPackAdapt(iCount)); } }; template inline StdNamingCountAdapt mkNamingCountAdapt(int_t &iCount, const char *szName) { return StdNamingCountAdapt(iCount, szName); } // * Hex adapter // Writes raw binary data in hexadecimal class StdHexAdapt { void *pData; size_t iSize; public: StdHexAdapt(void *pData, size_t iSize) : pData(pData), iSize(iSize) { } inline void CompileFunc(StdCompiler *pComp) const { if (!pComp->isVerbose()) pComp->Raw(pData, iSize); char szData[2+1]; bool deserializing = pComp->isDeserializer(); for (size_t i = 0; i < iSize; i++) { uint8_t *pByte = reinterpret_cast(pData) + i; if (!deserializing) sprintf(szData, "%02x", *pByte); pComp->String(szData, 2, StdCompiler::RCT_Idtf); if (deserializing) { unsigned int b; if (sscanf(szData, "%02x", &b) != 1) pComp->excNotFound(i ? "hexadecimal data: bytes missing!" : "hexadecimal data missing!"); *pByte = b; } } } }; inline StdHexAdapt mkHexAdapt(void *pData, size_t iSize) { return StdHexAdapt(pData, iSize); } template inline StdHexAdapt mkHexAdapt(T &rData) { return StdHexAdapt(&rData, sizeof(rData)); } #endif //STDADAPTORS_H