diff options
Diffstat (limited to 'RenderScript/include/LuaBindings.h')
| -rw-r--r-- | RenderScript/include/LuaBindings.h | 662 |
1 files changed, 662 insertions, 0 deletions
diff --git a/RenderScript/include/LuaBindings.h b/RenderScript/include/LuaBindings.h new file mode 100644 index 0000000..b9dcace --- /dev/null +++ b/RenderScript/include/LuaBindings.h @@ -0,0 +1,662 @@ +/* Copyright 2015 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#pragma once + +#include "lua.h" +#include "lualib.h" +#include "lauxlib.h" +#include "EnumMappings.h" + +namespace Diligent +{ + template< typename ValueType> + ValueType ReadValueFromLua( lua_State *L, int Index ) + { + UNSUPPORTED( "Type is not supported" ); + return static_cast<ValueType>(0); + } + template<>int ReadValueFromLua<int>( lua_State *L, int Index ); + template<>double ReadValueFromLua<double>( lua_State *L, int Index ); + template<>float ReadValueFromLua<float>( lua_State *L, int Index ); + template<>String ReadValueFromLua<String>( lua_State *L, int Index ); + template<>const Char* ReadValueFromLua<const Char*>( lua_State *L, int Index ); + template<>Bool ReadValueFromLua<Bool>( lua_State *L, int Index ); + template<>Uint32 ReadValueFromLua<Uint32>( lua_State *L, int Index ); + template<>Uint8 ReadValueFromLua<Uint8>( lua_State *L, int Index ); + + + inline void CheckType( lua_State *L, int Index, int ExpectedType ) + { + auto Type = lua_type( L, Index ); + if( Type != ExpectedType ) + { + auto TypeName = lua_typename( L, Type ); + auto ExpectedTypeName = lua_typename( L, ExpectedType ); + auto Param = lua_tostring( L, Index ); + SCRIPT_PARSING_ERROR( L, "Incorrect argument: \"", Param ? Param : "<Unknown>", "\". \"", ExpectedTypeName, "\" is expected, while \"", TypeName, "\" is provided." ); + } + } + + // Special version of luaL_testudata() which takes an array of allowed metatables + void *luaL_testudata( lua_State *L, int ud, const std::vector<String> &MetatableNames ); + + template<typename DataType, typename MetatableNameType> + DataType GetUserData( lua_State *L, int Index, MetatableNameType MetatableName ) + { + CheckType( L, Index, LUA_TUSERDATA ); + auto pUserData = luaL_testudata( L, Index, MetatableName ); + if( pUserData == nullptr ) + { + auto Type = lua_type( L, Index ); + auto TypeName = lua_typename( L, Type ); + SCRIPT_PARSING_ERROR( L, "Bad argument #", Index, ". User data with metatable \"", MetatableName, "\" is expected. \"", TypeName, "\" is provided." ); + } + return reinterpret_cast<DataType>(pUserData); + } + + template<typename DataType> + DataType GetGlobalObject( lua_State *L, const Char* ObjectName, const Char* MetatableName ) + { + INIT_LUA_STACK_TRACKING( L ); + // Pushes onto the stack the value of the given global name + lua_getglobal( L, ObjectName ); // -0 | +1 -> +1 + auto pData = GetUserData<DataType>( L, -1, MetatableName ); // -0 | +0 -> 0 + lua_pop( L, 1 ); // -1 | +0 -> -1 + CHECK_LUA_STACK_HEIGHT(); + return pData; + } + + + + template<typename Type> + void PushValue( lua_State *L, Type ) + { + UNSUPPORTED( "Type is not supported" ); + } + // Forward declarations of template specializations + template<> void PushValue<double>( lua_State *L, double Val ); + template<> void PushValue<const float&>( lua_State *L, const float& Val ); + template<> void PushValue<const Int32&>( lua_State *L, const Int32& Val ); + template<> void PushValue<const Uint32&>( lua_State *L, const Uint32& Val ); + template<> void PushValue<const Uint8&>( lua_State *L, const Uint8& Val ); + template<> void PushValue<const Char*>( lua_State *L, const Char* Val ); + template<> void PushValue<const Char* const&>( lua_State *L, const Char* const& Val ); + template<> void PushValue<const String&>( lua_State *L, const String& Val ); + template<> void PushValue<bool>( lua_State *L, bool Val ); + template<> void PushValue<const bool &>( lua_State *L, const bool &Val ); + + + class MemberBinderBase + { + public: + MemberBinderBase( size_t MemberOffset ) : + m_MemberOffset( MemberOffset ) + {} + virtual ~MemberBinderBase(){} + virtual void GetValue( lua_State *L, const void* pBasePointer ) = 0; + virtual void SetValue( lua_State *L, int Index, void* pBasePointer ) = 0; + + protected: + const size_t m_MemberOffset; + }; + typedef std::unordered_map<Diligent::HashMapStringKey, std::unique_ptr<MemberBinderBase> > BindingsMapType; + +#define DEFINE_BINDER(BindingsMap, Struct, Member, type, ValidationFunc) \ + {\ + auto *pNewBinder = new MemberBinder<type>( offsetof( Struct, Member ), ValidationFunc ); \ + /* No need to make a copy of #Member since it is constant string. */ \ + /* HashMapStringKey will simply keep pointer to it */ \ + BindingsMap.insert( std::make_pair( #Member, std::unique_ptr<MemberBinderBase>(pNewBinder) ) ); \ + } + + template<typename ValueType> + void SkipValidationFunc( const ValueType & ) + { + // Do nothing + } + + template<typename ValueType> + class Validator + { + public: + typedef void( *ValidationFuncType )(const ValueType &); + Validator( const char *pParameterName, ValueType MinValue, ValueType MaxValue ) : + m_pParameterName( pParameterName ), + m_MinValue( MinValue ), + m_MaxValue( MaxValue ), + m_ValidationFunc( nullptr ) + {} + + Validator( ValidationFuncType ValidationFunc = SkipValidationFunc<ValueType> ) : + m_pParameterName( nullptr ), + m_MinValue( ValueType() ), + m_MaxValue( ValueType() ), + m_ValidationFunc( ValidationFunc ) + {} + + void SetParameterName( const char *NewName ){ m_pParameterName = NewName; } + + void operator()( lua_State *L, const ValueType &Value )const + { + if( m_ValidationFunc ) + { + m_ValidationFunc( Value ); + } + else + { + if( Value < m_MinValue || Value > m_MaxValue ) + { + SCRIPT_PARSING_ERROR( L, "Parameter '", m_pParameterName, "' (", Value, ") is out of range [", m_MinValue, ",", m_MaxValue, "]\n" ); + } + } + } + + private: + const char *m_pParameterName; + ValueType m_MinValue, m_MaxValue; + ValidationFuncType m_ValidationFunc; + }; + + template<> + class Validator < Bool > + { + public: + void operator()( lua_State *L, const Bool & )const + { + // Do nothing + } + }; + + template<typename MemberType> + MemberType& GetMemberByOffest( void* pBasePointer, size_t Offset ) + { + return *(reinterpret_cast<MemberType*>(reinterpret_cast<char*>(pBasePointer)+Offset)); + } + + template<typename MemberType> + const MemberType& GetMemberByOffest( const void* pBasePointer, size_t Offset ) + { + return *(reinterpret_cast<const MemberType*>(reinterpret_cast<const char*>(pBasePointer)+Offset)); + } + + template<typename MemberType> + class MemberBinder : public MemberBinderBase + { + public: + MemberBinder( size_t MemberOffset, Validator<MemberType> Validator ) : + MemberBinderBase( MemberOffset ), + m_Validator( Validator ) + {} + + virtual void GetValue( lua_State *L, const void* pBasePointer ) + { + const auto &Value = GetMemberByOffest<MemberType>(pBasePointer, m_MemberOffset); + PushValue<const MemberType &>( L, Value ); + } + + virtual void SetValue( lua_State *L, int Index, void* pBasePointer ) + { + auto Value = ReadValueFromLua<MemberType>( L, Index ); + m_Validator( L, Value ); + GetMemberByOffest<MemberType>( pBasePointer, m_MemberOffset ) = Value; + } + protected: + Validator<MemberType> m_Validator; + }; + + + inline void ParseLuaTable( lua_State *L, int Index, void* pBasePointer, BindingsMapType &Bindings ) + { + CheckType( L, Index, LUA_TTABLE ); + + lua_pushnil( L ); // first key which will be popped out in the first call to lua_next() + // lua_next() pops a key from the stack, and pushes a key–value pair from the table at the given index + // (the "next" pair after the given key). If there are no more elements in the table, then lua_next returns + // 0 (and pushes nothing). + if( Index < 0 ) + --Index; + while( lua_next( L, Index ) != 0 ) + { + // Key is now at index -2 and Value is at index -1 + auto IsString = lua_isstring( L, -2 ); + if( !IsString ) + { + SCRIPT_PARSING_ERROR( L, "Table key value must be string") + } + // NOTE: the lua_tostring function returns a pointer to an internal copy of the string. + // The string is always zero-terminated and Lua ensures that this pointer is valid as long + // as the corresponding value is in the stack. + auto Key = lua_tostring( L, -2 ); + auto Binding = Bindings.find( Key ); + if( Binding != Bindings.end() ) + { + Binding->second->SetValue( L, -1, pBasePointer ); + } + else + { + SCRIPT_PARSING_ERROR( L, "Unknown Member ", Key ); + } + // Pop value from the stack, but KEEP Key for the next iteration + lua_pop( L, 1 ); + } + } + + template<class ArrayElemParser> + inline void ParseLuaArray( lua_State *L, int Index, void* pBasePointer, ArrayElemParser ElemParser ) + { + CheckType( L, Index, LUA_TTABLE ); + + lua_pushnil( L ); // first key which will be popped out in the first call to lua_next() + // lua_next() pops a key from the stack, and pushes a key–value pair from the table at the given index + // (the "next" pair after the given key). If there are no more elements in the table, then lua_next returns + // 0 (and pushes nothing). + if( Index < 0 ) + --Index; + while( lua_next( L, Index ) != 0 ) + { + // Key is now at index -2 and Value is at index -1 + CheckType( L, -2, LUA_TNUMBER ); + + auto NewArrayIndex = static_cast<int>( lua_tointeger( L, -2 ) ); + ElemParser( pBasePointer, -1, NewArrayIndex ); + + // Pop value from the stack, but KEEP Key for the next iteration + lua_pop( L, 1 ); + } + } + + inline void PushLuaTable( lua_State *L, const void* pBasePointer, BindingsMapType &Bindings ) + { + lua_newtable( L ); + for( auto it = Bindings.begin(); it != Bindings.end(); ++it ) + { + const auto &Field = it->first.GetStr(); + lua_pushstring( L, Field ); + it->second->GetValue( L, pBasePointer ); + lua_settable( L, -3 ); // Stack: 0 + } + } + + template<typename ItType, class ElemPushAlg> + void PushLuaArray( lua_State *L, ItType Begin, ItType End, ElemPushAlg PushAlg ) + { + lua_newtable( L ); + int ArrayInd = 1; // Lua arrays are 1-based + for( auto it = Begin; it != End; ++it, ++ArrayInd ) + { + lua_pushnumber( L, ArrayInd ); // -0 | +1 -> +1 + PushAlg( *it ); // -0 | +1 -> +1 + lua_settable( L, -3 ); // -2 | +0 -> -2 + } + } + + template<typename ArrayType, class ElemPushAlg> + void PushLuaArray( lua_State *L, const ArrayType& Arr, ElemPushAlg PushAlg ) + { + PushLuaArray( L, Arr.begin(), Arr.end(), PushAlg ); + } + + inline void PushField( lua_State *L, const void* pBasePointer, const Char *Field, BindingsMapType &Bindings ) + { + auto It = Bindings.find( Field ); + if( It != Bindings.end() ) + { + It->second->GetValue( L, pBasePointer ); + } + else + { + SCRIPT_PARSING_ERROR( L, "Unknown Member ", Field ); + } + } + + inline void UpdateField( lua_State *L, int Index, void* pBasePointer, const Char *Field, BindingsMapType &Bindings ) + { + auto It = Bindings.find( Field ); + if( It != Bindings.end() ) + { + It->second->SetValue( L, Index, pBasePointer ); + } + else + { + SCRIPT_PARSING_ERROR( L, "Unknown Member ", Field ); + } + } + + class RGBALoader; // Used only as a template switch + template<> + class MemberBinder<RGBALoader> : public MemberBinderBase + { + public: + MemberBinder( size_t MemberOffset, size_t Dummy ) : + MemberBinderBase( MemberOffset ) + { + const char* Members[] = { "r", "g", "b", "a" }; + for( int c = 0; c < 4; ++c ) + { + auto *pNewBinder = new MemberBinder<Float32>( MemberOffset + sizeof( Float32 )*c, Validator<float>() ); + // No need to make a copy of Members[c] since it is constant string. + // HashMapStringKey will simply keep pointer to it + Bindings.insert( std::make_pair( Members[c], std::unique_ptr<MemberBinderBase>( pNewBinder ) ) ); + } + } + virtual void GetValue( lua_State *L, const void* pBasePointer ) + { + PushLuaTable( L, pBasePointer, Bindings ); + } + + virtual void SetValue( lua_State *L, int Index, void* pBasePointer ) + { + ParseLuaTable( L, Index, pBasePointer, Bindings ); + } + private: + BindingsMapType Bindings; + }; + + + template< typename EnumType > + String GetEnumMappingsString( const EnumMapping<EnumType> &EnumMapping ) + { + String Values; + bool bFirst = true; + for( auto it = EnumMapping.m_Str2ValMap.begin(); it != EnumMapping.m_Str2ValMap.end(); ++it ) + { + if( !bFirst ) + Values += ", "; + Values += '\"'; + Values.append( it->first.GetStr() ); + Values += '\"'; + bFirst = false; + } + return Values; + } + + template<typename EnumType> + class EnumMemberBinder : public MemberBinderBase + { + public: + EnumMemberBinder( size_t MemberOffset, const Char* MemberName, const EnumMapping<EnumType> &EnumMapping ) : + MemberBinderBase( MemberOffset ), + m_MemberName( MemberName ), + m_EnumMapping( EnumMapping ) + { + } + + virtual void GetValue( lua_State *L, const void* pBasePointer ) + { + const auto &Val = GetMemberByOffest<EnumType>( pBasePointer, m_MemberOffset ); + auto It = m_EnumMapping.m_Val2StrMap.find( Val ); + if( It != m_EnumMapping.m_Val2StrMap.end() ) + { + const String& StrVal = It->second; + PushValue<const String&>( L, StrVal ); + } + else + { + UNEXPECTED( "Enum value not found in the map" ); + SCRIPT_PARSING_ERROR( L, "Enum value (", Val, ") not found in the map" ); + } + } + + virtual void SetValue( lua_State *L, int Index, void* pBasePointer ) + { + auto Str = ReadValueFromLua<String>( L, Index ); + auto It = m_EnumMapping.m_Str2ValMap.find( Str.c_str() ); + if( It != m_EnumMapping.m_Str2ValMap.end() ) + { + auto Val = It->second; + GetMemberByOffest<EnumType>(pBasePointer, m_MemberOffset) = Val; + } + else + { + String AllowableValues = GetEnumMappingsString<EnumType>( m_EnumMapping ); + SCRIPT_PARSING_ERROR( L, "Unknown value (\"", Str, "\") provided for parameter ", m_MemberName, ". Only the following values are allowed:\n", AllowableValues ); + } + } + + private: + const Char *m_MemberName; + const EnumMapping<EnumType> &m_EnumMapping; + }; + +#define DEFINE_ENUM_BINDER(BindingsMap, Struct, Member, type, EnumMapping ) \ + {\ + auto *pNewBinder = new EnumMemberBinder<type>( offsetof( Struct, Member ), #Member, EnumMapping ); \ + /* No need to make a copy of #Member since it is constant string. */ \ + /* HashMapStringKey will simply keep pointer to it */ \ + BindingsMap.insert( std::make_pair( #Member, std::unique_ptr<MemberBinderBase>(pNewBinder) ) ); \ + } + + template< typename EnumType, typename FlagsType = Uint32 > + class FlagsLoader : public MemberBinderBase + { + public: + FlagsLoader( size_t MemberOffset, const Char* MemberName, const EnumMapping<EnumType> &EnumMapping ) : + MemberBinderBase( MemberOffset ), + m_MemberName( MemberName ), + m_EnumMapping( EnumMapping ) + { + } + virtual void GetValue( lua_State *L, const void* pBasePointer ) + { + auto Flags = GetMemberByOffest<FlagsType>( pBasePointer, m_MemberOffset ); + lua_newtable( L ); + int ArrayInd = 1; + for( auto it = m_EnumMapping.m_Val2StrMap.begin(); it != m_EnumMapping.m_Val2StrMap.end(); ++it ) + { + if( (Flags & it->first) == it->first ) + { + lua_pushnumber( L, ArrayInd ); // -0 | +1 -> +1 + PushValue<const String&>( L, it->second ); // -0 | +1 -> +1 + lua_settable( L, -3 ); // -2 | +0 -> -2 + ++ArrayInd; + } + } + } + + virtual void SetValue( lua_State *L, int Index, void* pBasePointer ) + { + FlagsType Flags = 0; + if( lua_isnumber( L, Index ) ) + { + Flags = static_cast<FlagsType>( ReadValueFromLua<Uint32>( L, Index ) ); + } + else if( lua_isstring( L, Index ) ) + { + Flags = ReadFlag( L, Index ); + } + else if( lua_istable( L, Index ) ) + { + ParseLuaArray( L, Index, pBasePointer, [ &]( void* _pBasePointer, int StackIndex, int NewArrayIndex ) + { + auto CurrFlag = ReadFlag( L, StackIndex ); + Flags |= CurrFlag; + } + ); + } + else + { + SCRIPT_PARSING_ERROR( L, m_MemberName, "must be specified as a single string or an array of strings." ); + } + GetMemberByOffest<FlagsType>( pBasePointer, m_MemberOffset ) = Flags; + } + + private: + FlagsType ReadFlag( lua_State *L, int StackIndex ) + { + auto CurrFlagName = ReadValueFromLua<const Char *>( L, StackIndex ); + auto It = m_EnumMapping.m_Str2ValMap.find( CurrFlagName ); + if( It != m_EnumMapping.m_Str2ValMap.end() ) + { + return It->second; + } + else + { + String AllowableValues = GetEnumMappingsString<EnumType>( m_EnumMapping ); + SCRIPT_PARSING_ERROR( L, "Unknown flag (\"", CurrFlagName, "\") provided for parameter ", m_MemberName, ". Only the following flags are allowed:\n", AllowableValues ); + return 0; + } + } + + const Char *m_MemberName; + const EnumMapping<EnumType> &m_EnumMapping; + }; +#define DEFINE_FLAGS_BINDER(BindingsMap, Struct, Member, type, EnumMapping ) \ + {\ + auto *pNewBinder = new FlagsLoader<type>( offsetof( Struct, Member ), #Member, EnumMapping ); \ + /* No need to make a copy of #Member since it is constant string. */ \ + /* HashMapStringKey will simply keep pointer to it */ \ + BindingsMap.insert( std::make_pair( #Member, std::unique_ptr<MemberBinderBase>(pNewBinder) ) ); \ + } + + + template<typename FieldType> + void SetTableField( lua_State *L, const char *FieldName, int TableStackIndex, FieldType Value ) + { + INIT_LUA_STACK_TRACKING( L ); + + lua_pushstring( L, FieldName ); // -0 | +1 -> +1 + PushValue<FieldType>( L, Value ); // -0 | +1 -> +1 + + // lua_settable() does the equivalent to t[k] = v, where t is the value at the given index, + // v is the value at the top of the stack (-1), and k is the value just below the top (-2) + // The function pops both the key and the value from the stack. As in Lua, this function may + // trigger a metamethod for the "newindex" event + lua_settable( L, TableStackIndex - 2 ); // -2 | +0 -> -2 + + CHECK_LUA_STACK_HEIGHT(); + } + + class NumericArrayLoader + { + public: + NumericArrayLoader(); + void LoadArray( lua_State *L, int StackIndex, std::vector< Uint8 >& RawData ); + private: + EnumMapping<VALUE_TYPE> m_ValueTypeEnumMapping; + EnumMemberBinder<VALUE_TYPE> m_ValueTypeBinder; + typedef void (*ParseNumericArrayFuncType)(lua_State *L, int StackIndex, std::vector< Uint8 >& RawData); + std::unordered_map< VALUE_TYPE, ParseNumericArrayFuncType > m_ParseFuncJumpTbl; + }; + + + template<typename EngineObjectType> + class EngineObjectPtrLoader + { + public: + typedef EngineObjectType ObjectType; + }; + + template<typename EngineObjectType> + class MemberBinder< EngineObjectPtrLoader<EngineObjectType> > : public MemberBinderBase + { + public: + typedef typename EngineObjectPtrLoader<EngineObjectType>::ObjectType ObjectType; + + MemberBinder( size_t MemberOffset, const std::vector<String> &_Metatables ) : + MemberBinderBase( MemberOffset ), + Metatables( _Metatables ) + { + } + + virtual void GetValue( lua_State *L, const void* pBasePointer ) + { + VERIFY( Metatables.size() == 1, "Ambiguous metatable" ); + const auto& MetatableName = *Metatables.begin(); + auto pObject = GetMemberByOffest<ObjectType*>( pBasePointer, m_MemberOffset ); + auto ppNewObject = reinterpret_cast<ObjectType**>(lua_newuserdata( L, sizeof( ObjectType* ) )); + *ppNewObject = pObject; + pObject->AddRef(); + // Push onto the stack the metatable associated with name given in the registry + luaL_getmetatable( L, MetatableName.c_str() ); // -0 | +1 -> +1 + // Pop a table from the top of the stack and set it as the new metatable + // for the value at the given index (which is where the new user datum is) + lua_setmetatable( L, -2 ); // -1 | +0 -> -1 + } + + virtual void SetValue( lua_State *L, int Index, void* pBasePointer ) + { + ObjectType *pObject = nullptr; + pObject = *GetUserData<ObjectType**>( L, -1, Metatables ); + GetMemberByOffest<ObjectType*>( pBasePointer, m_MemberOffset ) = pObject; + } + private: + BindingsMapType Bindings; + std::vector<String> Metatables; + }; + + // None of the graphics engine structures (such as BufferDesc or TextureDesc) + // provide storage for strings, but only contain const Char* pointers. + // The script wraps every such structure to provide the storage + // This binder handles such strings + class BufferedStringBinder : public MemberBinderBase + { + public: + BufferedStringBinder( + size_t StringPtrOffset, // This is the offset of the const Char* pointer + size_t StringBuffOffset // This is the offset of the buffer that contains string data + ) : + MemberBinderBase( StringBuffOffset ), + m_StringPtrOffset( StringPtrOffset ) + { + } + + virtual void GetValue( lua_State *L, const void* pBasePointer ) + { + // Always use const Char* pointer to push value to Lua as there + // might be no valid buffer + auto *StringPtr = GetMemberByOffest<const Char*>( pBasePointer, m_StringPtrOffset ); + PushValue<const Char*>( L, StringPtr ); + } + + virtual void SetValue( lua_State *L, int Index, void* pBasePointer ) + { + // When reading the string from Lua, we need to make + // sure that the string pointer contains the right data + auto SrcString = ReadValueFromLua<String>( L, Index ); + // Set the const Char* pointer + auto &DstStrBuff = GetMemberByOffest<String>( pBasePointer, m_MemberOffset ); + auto &DstStringPtr = GetMemberByOffest<const Char*>( pBasePointer, m_StringPtrOffset ); + DstStrBuff = SrcString; + DstStringPtr = DstStrBuff.data(); + } + protected: + size_t m_StringPtrOffset; + }; + +#define DEFINE_BUFFERED_STRING_BINDER(BindingsMap, Struct, StringPtr, StringBuffer) \ + {\ + auto *pNewBinder = new BufferedStringBinder( offsetof( Struct, StringPtr ), offsetof( Struct, StringBuffer ) ); \ + /* No need to make a copy of #Member since it is constant string. */ \ + /* HashMapStringKey will simply keep pointer to it */ \ + BindingsMap.insert( std::make_pair( #StringPtr, std::unique_ptr<MemberBinderBase>(pNewBinder) ) ); \ + } + + // Object description wrapper that provides storage for + // the Name field + template<typename ObjectDescType> + struct ObjectDescWrapper : ObjectDescType + { + String NameBuffer; + }; +} |
