From 5f8a80c25ff47671b04a2bf0e24eb2acabe6db0a Mon Sep 17 00:00:00 2001 From: ecker Date: Sat, 16 Aug 2025 12:19:55 -0500 Subject: [PATCH] resolved an oversight past me never realized where you still need to call destructors on placement new'd memory (and other things to resolve a memory leak that was very noticeable with 16MB of RAM) --- bin/data/entities/model.json | 6 +- engine/inc/uf/engine/object/object.inl | 5 +- engine/inc/uf/utils/hook/hook.inl | 11 +++- engine/inc/uf/utils/userdata/pointered.inl | 45 +++++++++----- engine/inc/uf/utils/userdata/userdata.h | 23 +++++-- engine/inc/uf/utils/userdata/userdata.inl | 28 ++++++--- engine/src/engine/object/behavior.cpp | 5 +- engine/src/ext/lua/usertypes/object.cpp | 7 --- engine/src/utils/userdata/pointered.cpp | 72 ++++++++++++---------- engine/src/utils/userdata/userdata.cpp | 56 +++++++++-------- 10 files changed, 154 insertions(+), 104 deletions(-) diff --git a/bin/data/entities/model.json b/bin/data/entities/model.json index 9d820db7..a7fa9332 100644 --- a/bin/data/entities/model.json +++ b/bin/data/entities/model.json @@ -76,10 +76,10 @@ "shadows": true }, "stream": { - "tag": "", // worldspawn", + "tag": "worldspawn", "player": "info_player_spawn", - "enabled": true, // "auto", - "radius": 16, + "enabled": "auto", + "radius": 32, "every": 1 } } diff --git a/engine/inc/uf/engine/object/object.inl b/engine/inc/uf/engine/object/object.inl index 53785490..00a53bf9 100644 --- a/engine/inc/uf/engine/object/object.inl +++ b/engine/inc/uf/engine/object/object.inl @@ -28,10 +28,7 @@ size_t uf::Object::addHook( const uf::stl::string& name, T callback ) { } template uf::Hooks::return_t uf::Object::callHook( const uf::stl::string& name, const T& p ) { - pod::Hook::userdata_t payload; - payload.create(p); - - return uf::hooks.call( this->formatHookName( name ), payload ); + return uf::hooks.call( this->formatHookName( name ), p ); } template diff --git a/engine/inc/uf/utils/hook/hook.inl b/engine/inc/uf/utils/hook/hook.inl index 49458015..b1bcf63c 100644 --- a/engine/inc/uf/utils/hook/hook.inl +++ b/engine/inc/uf/utils/hook/hook.inl @@ -34,8 +34,15 @@ size_t uf::Hooks::addHook( const uf::Hooks::name_t& name, const Function& lambda } template uf::Hooks::return_t uf::Hooks::call( const uf::Hooks::name_t& name, const T& p ) { + // alias directly to save an allocation + pod::Hook::userdata_t payload; + payload.alias(const_cast(p)); + return call( name, payload ); + /* pod::Hook::userdata_t payload; payload.create(p); - - return call( name, payload ); + auto results = call( name, payload ); + payload.destruct(); + return results; + */ } \ No newline at end of file diff --git a/engine/inc/uf/utils/userdata/pointered.inl b/engine/inc/uf/utils/userdata/pointered.inl index 522aa007..eff3c9ca 100644 --- a/engine/inc/uf/utils/userdata/pointered.inl +++ b/engine/inc/uf/utils/userdata/pointered.inl @@ -8,7 +8,7 @@ namespace pod { namespace uf { namespace pointeredUserdata { - pod::PointeredUserdata UF_API create( size_t len, void* data = NULL ); + pod::PointeredUserdata UF_API create( size_t len, const void* data = NULL, UF_USERDATA_CTTI_TYPE = UF_USERDATA_CTTI(void) ); void UF_API destroy( pod::PointeredUserdata& userdata ); pod::PointeredUserdata UF_API copy( const pod::PointeredUserdata& userdata ); @@ -17,15 +17,19 @@ namespace uf { template const T& get(const pod::PointeredUserdata& userdata, bool validate = uf::userdata::autoValidate ); template bool is(const pod::PointeredUserdata& userdata); + uf::stl::string UF_API toBase64( pod::PointeredUserdata& userdata ); pod::PointeredUserdata UF_API fromBase64( const uf::stl::string& base64 ); // usage with MemoryPool - pod::PointeredUserdata UF_API create( uf::MemoryPool&, size_t len, void* data = NULL ); + pod::PointeredUserdata UF_API create( uf::MemoryPool&, size_t len, const void* data = NULL, UF_USERDATA_CTTI_TYPE = UF_USERDATA_CTTI(void) ); template pod::PointeredUserdata create( uf::MemoryPool&, const T& data = T() ); void UF_API destroy( uf::MemoryPool&, pod::PointeredUserdata& userdata ); pod::PointeredUserdata UF_API copy( uf::MemoryPool&, const pod::PointeredUserdata& userdata ); + const pod::UserdataTraits& UF_API getTrait( UF_USERDATA_CTTI_TYPE type ); + template const pod::UserdataTraits& registerTrait(); + size_t UF_API size( size_t size, size_t padding = 0 ); } } @@ -43,12 +47,12 @@ namespace uf { public: // C-tor - PointeredUserdata( size_t len = 0, void* data = NULL); // initializes POD to default + PointeredUserdata( size_t len = 0, const void* data = NULL, UF_USERDATA_CTTI_TYPE = UF_USERDATA_CTTI(void)); // initializes POD to default PointeredUserdata( const pod::PointeredUserdata& ); // initializes from POD PointeredUserdata( PointeredUserdata&& move ) noexcept; // Move c-tor PointeredUserdata( const PointeredUserdata& copy ); // Copy c-tor - pod::PointeredUserdata& create( size_t len, void* data = NULL ); + pod::PointeredUserdata& create( size_t len, const void* data = NULL, UF_USERDATA_CTTI_TYPE = UF_USERDATA_CTTI(void) ); void move( PointeredUserdata& move ); void move( PointeredUserdata&& move ); void copy( const PointeredUserdata& copy ); @@ -70,13 +74,15 @@ namespace uf { template bool is() const; template inline T& as() { return get(); } template inline const T& as() const { return get(); } + + template void alias( T& ); // Overloaded ops operator void*(); operator void*() const; operator bool() const; - PointeredUserdata& operator=( pod::PointeredUserdata pointer ); + PointeredUserdata& operator=( const pod::PointeredUserdata& pointer ); PointeredUserdata& operator=( PointeredUserdata&& move ); PointeredUserdata& operator=( const PointeredUserdata& copy ); }; @@ -90,15 +96,8 @@ pod::PointeredUserdata uf::pointeredUserdata::create( const T& data ) { template pod::PointeredUserdata uf::pointeredUserdata::create( uf::MemoryPool& requestedMemoryPool, const T& data ) { // if ( std::is_reference() ) return uf::pointeredUserdata::create::type>( requestedMemoryPool, data ); - pod::PointeredUserdata userdata = uf::pointeredUserdata::create( requestedMemoryPool, sizeof(data), nullptr ); - userdata.type = UF_USERDATA_CTTI(T); - union { - void* from; - T* to; - } kludge; - kludge.from = userdata.data; - ::new (kludge.to) T(data); - return userdata; + uf::pointeredUserdata::registerTrait(); + return uf::pointeredUserdata::create( requestedMemoryPool, sizeof(data), (const void*) &data, UF_USERDATA_CTTI(T) ); } // Easy way to get the userdata as a reference #include @@ -134,11 +133,16 @@ bool uf::pointeredUserdata::is( const pod::PointeredUserdata& userdata ) { if ( userdata.type != UF_USERDATA_CTTI(void) ) return userdata.type == UF_USERDATA_CTTI(T) && userdata.len == sizeof(T); return userdata.len == sizeof(T); } - +template const pod::UserdataTraits& uf::pointeredUserdata::registerTrait() { + auto& trait = uf::userdata::traits[UF_USERDATA_CTTI(T)]; + trait.name = TYPE_NAME(T); + trait.constructor = &uf::userdata::construct; + trait.destructor = &uf::userdata::destruct; + return trait;} +// // No need to cast data to a pointer AND get the data's size! template pod::PointeredUserdata& uf::PointeredUserdata::create( const T& data ) { - this->destroy(); return this->m_pod = uf::pointeredUserdata::create(data); } // Easy way to get the userdata as a reference @@ -155,4 +159,13 @@ const T& uf::PointeredUserdata::get(bool validate) const { template bool uf::PointeredUserdata::is() const { return uf::pointeredUserdata::is( this->m_pod ); +} + +// I am not proud of having to do this +template +void uf::PointeredUserdata::alias( T& data ) { + autoDestruct = false; + m_pod.len = sizeof(T); + m_pod.data = (void*) &data; + m_pod.type = UF_USERDATA_CTTI(T); } \ No newline at end of file diff --git a/engine/inc/uf/utils/userdata/userdata.h b/engine/inc/uf/utils/userdata/userdata.h index d9a4d9c1..3c479386 100644 --- a/engine/inc/uf/utils/userdata/userdata.h +++ b/engine/inc/uf/utils/userdata/userdata.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -22,15 +23,23 @@ namespace pod { UF_USERDATA_CTTI_TYPE type = UF_USERDATA_CTTI(void); uint8_t data[1]; }; + + struct UF_API UserdataTraits { + uf::stl::string name = ""; + void (*constructor)(void*, const void*) = NULL; + void (*destructor)(void*) = NULL; + }; } namespace uf { namespace userdata { + extern UF_API uf::stl::unordered_map traits; + extern UF_API uf::MemoryPool memoryPool; extern UF_API bool autoDestruct; extern UF_API bool autoValidate; - pod::Userdata* UF_API create( size_t len, void* data = NULL ); + pod::Userdata* UF_API create( size_t len, const void* data = NULL, UF_USERDATA_CTTI_TYPE = UF_USERDATA_CTTI(void) ); void UF_API destroy( pod::Userdata* userdata ); pod::Userdata* UF_API copy( const pod::Userdata* userdata ); @@ -46,12 +55,18 @@ namespace uf { // void copy( pod::Userdata& to, const pod::Userdata& from ); // usage with MemoryPool - pod::Userdata* UF_API create( uf::MemoryPool&, size_t len, void* data = NULL ); + pod::Userdata* UF_API create( uf::MemoryPool&, size_t len, const void* data = NULL, UF_USERDATA_CTTI_TYPE = UF_USERDATA_CTTI(void) ); template pod::Userdata* create( uf::MemoryPool&, const T& data = T() ); void UF_API destroy( uf::MemoryPool&, pod::Userdata* userdata ); pod::Userdata* UF_API copy( uf::MemoryPool&, const pod::Userdata* userdata ); size_t UF_API size( size_t size, size_t padding = 0 ); + + template void construct( void* dst, const void* src ); + template void destruct( void* p ); + + const pod::UserdataTraits& UF_API getTrait( UF_USERDATA_CTTI_TYPE type ); + template const pod::UserdataTraits& registerTrait(); } } @@ -68,12 +83,12 @@ namespace uf { public: // C-tor - Userdata( size_t len = 0, void* data = NULL ); // initializes POD to default + Userdata( size_t len = 0, const void* data = NULL, UF_USERDATA_CTTI_TYPE = UF_USERDATA_CTTI(void) ); // initializes POD to default Userdata( pod::Userdata* ); // initializes from POD Userdata( Userdata&& move ) noexcept ; // Move c-tor Userdata( const Userdata& copy ); // Copy c-tor - pod::Userdata* create( size_t len, void* data = NULL ); + pod::Userdata* create( size_t len, const void* data = NULL, UF_USERDATA_CTTI_TYPE = UF_USERDATA_CTTI(void) ); void move( Userdata& move ); void move( Userdata&& move ); void copy( const Userdata& copy ); diff --git a/engine/inc/uf/utils/userdata/userdata.inl b/engine/inc/uf/utils/userdata/userdata.inl index f12b7197..2e4d4450 100644 --- a/engine/inc/uf/utils/userdata/userdata.inl +++ b/engine/inc/uf/utils/userdata/userdata.inl @@ -9,16 +9,9 @@ template pod::Userdata* uf::userdata::create( uf::MemoryPool& requestedMemoryPool, const T& data ) { // CTTI information of a T& != T // if ( std::is_reference() ) return uf::userdata::create::type>( requestedMemoryPool, data ); - - pod::Userdata* userdata = uf::userdata::create( requestedMemoryPool, sizeof(data), nullptr ); - userdata->type = UF_USERDATA_CTTI(T); - union { - void* from; - T* to; - } kludge; - kludge.from = userdata->data; - ::new (kludge.to) T(data); - return userdata; + // Register trait + uf::userdata::registerTrait(); + return uf::userdata::create( requestedMemoryPool, sizeof(data), (const void*) &data, UF_USERDATA_CTTI(T) ); } // Easy way to get the userdata as a reference #include @@ -55,6 +48,21 @@ bool uf::userdata::is( const pod::Userdata* userdata ) { return userdata && userdata->len == sizeof(T); } +template void uf::userdata::construct( void* dst, const void* src ) { + ::new (dst) T(*static_cast(src)); +} +template void uf::userdata::destruct( void* p ) { + static_cast(p)->~T(); +} +template const pod::UserdataTraits& uf::userdata::registerTrait() { + auto& trait = uf::userdata::traits[UF_USERDATA_CTTI(T)]; + trait.name = TYPE_NAME(T); + trait.constructor = &uf::userdata::construct; + trait.destructor = &uf::userdata::destruct; + return trait; +} + +// // No need to cast data to a pointer AND get the data's size! template pod::Userdata* uf::Userdata::create( const T& data ) { diff --git a/engine/src/engine/object/behavior.cpp b/engine/src/engine/object/behavior.cpp index e73d1169..8a6ec5bf 100644 --- a/engine/src/engine/object/behavior.cpp +++ b/engine/src/engine/object/behavior.cpp @@ -288,7 +288,10 @@ void uf::ObjectBehavior::tick( uf::Object& self ) { else unprocessed.emplace_back(q); } for ( auto& q : executeQueue ) { - if ( q.type == 1 ) this->callHook( q.name, q.userdata ); + if ( q.type == 1 ) { + this->callHook( q.name, q.userdata ); + q.userdata.destroy(); + } else if ( q.type == -1 ) this->callHook( q.name, q.json ); else this->callHook( q.name ); } diff --git a/engine/src/ext/lua/usertypes/object.cpp b/engine/src/ext/lua/usertypes/object.cpp index d43e0d90..ca11ba8f 100644 --- a/engine/src/ext/lua/usertypes/object.cpp +++ b/engine/src/ext/lua/usertypes/object.cpp @@ -95,13 +95,6 @@ namespace binds { if ( type == "Metadata" ) { auto encoded = ext::lua::encode( value.as() ); if ( encoded ) { - /* - self.callHook( "object:Serialize.%UID%" ); - auto& metadata = self.getComponent(); - uf::stl::string str = encoded.value(); - metadata.merge( str, false ); - self.callHook( "object:Deserialize.%UID%" ); - */ uf::stl::string str = encoded.value(); ext::json::Value json; ext::json::decode( json, str ); diff --git a/engine/src/utils/userdata/pointered.cpp b/engine/src/utils/userdata/pointered.cpp index 720aeafd..bda1fab0 100644 --- a/engine/src/utils/userdata/pointered.cpp +++ b/engine/src/utils/userdata/pointered.cpp @@ -5,8 +5,8 @@ #include // Constructs a pod::PointeredUserdata struct -pod::PointeredUserdata uf::pointeredUserdata::create( size_t len, void* data ) { - return uf::pointeredUserdata::create( uf::userdata::memoryPool, len, data ); +pod::PointeredUserdata uf::pointeredUserdata::create( size_t len, const void* data, UF_USERDATA_CTTI_TYPE type ) { + return uf::pointeredUserdata::create( uf::userdata::memoryPool, len, data, type ); } void uf::pointeredUserdata::destroy( pod::PointeredUserdata& userdata ) { return uf::pointeredUserdata::destroy( uf::userdata::memoryPool, userdata ); @@ -20,31 +20,38 @@ size_t uf::pointeredUserdata::size( size_t len, size_t padding ) { } // -pod::PointeredUserdata uf::pointeredUserdata::create( uf::MemoryPool& requestedMemoryPool, size_t len, void* data ) { +pod::PointeredUserdata uf::pointeredUserdata::create( uf::MemoryPool& requestedMemoryPool, size_t len, const void* data, UF_USERDATA_CTTI_TYPE type ) { if ( len <= 0 ) return {}; size_t requestedLen = size( len ); #if UF_MEMORYPOOL_INVALID_MALLOC uf::MemoryPool& memoryPool = requestedMemoryPool.size() > 0 ? requestedMemoryPool : uf::memoryPool::global; pod::PointeredUserdata userdata = { .len = requestedLen, + .type = type, .data = memoryPool.alloc( requestedLen ), }; #else - uf::MemoryPool* memoryPool = {}; + uf::MemoryPool* memoryPool = NULL; if ( requestedMemoryPool.size() > 0 ) memoryPool = &requestedMemoryPool; else if ( uf::memoryPool::global.size() > 0 ) memoryPool = &uf::memoryPool::global; pod::PointeredUserdata userdata = {}; if ( memoryPool ) userdata.data = memoryPool->alloc( requestedLen ); else userdata.data = uf::allocator::malloc_m( requestedLen ); // allocate data for the userdata struct, and then some + userdata.len = requestedLen; + userdata.type = type; #endif - if ( data ) memcpy( userdata.data, data, len ); - else memset( userdata.data, 0, len ); - userdata.len = len; - userdata.type = UF_USERDATA_CTTI(void); + auto& trait = uf::pointeredUserdata::getTrait( userdata.type ); + if ( data && userdata.type != UF_USERDATA_CTTI(void) ) trait.constructor( userdata.data, data ); + else if ( data ) memcpy( userdata.data, data, requestedLen ); + else memset( userdata.data, 0, requestedLen ); + //UF_MSG_DEBUG("Calling create: {}: {}", trait.name, (void*) userdata.data); return userdata; } void uf::pointeredUserdata::destroy( uf::MemoryPool& requestedMemoryPool, pod::PointeredUserdata& userdata ) { if ( !userdata.data ) return; + auto& trait = uf::pointeredUserdata::getTrait( userdata.type ); + if ( userdata.type != UF_USERDATA_CTTI(void) ) trait.destructor( userdata.data ); + //UF_MSG_DEBUG("Calling destroy: {}: {}", trait.name, (void*) userdata.data); #if UF_MEMORYPOOL_INVALID_FREE uf::MemoryPool& memoryPool = requestedMemoryPool.size() > 0 ? requestedMemoryPool : uf::memoryPool::global; memoryPool.free( userdata.data, size(userdata.len) ); @@ -58,6 +65,7 @@ void uf::pointeredUserdata::destroy( uf::MemoryPool& requestedMemoryPool, pod::P #endif userdata.len = 0; userdata.data = NULL; + userdata.type = UF_USERDATA_CTTI(void); } pod::PointeredUserdata uf::pointeredUserdata::copy( uf::MemoryPool& requestedMemoryPool, const pod::PointeredUserdata& userdata ) { if ( !userdata.data || userdata.len <= 0 ) return {}; @@ -66,6 +74,10 @@ pod::PointeredUserdata uf::pointeredUserdata::copy( uf::MemoryPool& requestedMem return copied; } +const pod::UserdataTraits& uf::pointeredUserdata::getTrait( UF_USERDATA_CTTI_TYPE type ) { + return uf::userdata::traits[type]; +} + uf::stl::string uf::pointeredUserdata::toBase64( pod::PointeredUserdata& userdata ) { return uf::base64::encode( static_cast(userdata.data), userdata.len ); } @@ -76,19 +88,18 @@ pod::PointeredUserdata uf::pointeredUserdata::fromBase64( const uf::stl::string& // C-tor // Initializes POD -uf::PointeredUserdata::PointeredUserdata(size_t len, void* data) : m_pod({}), autoDestruct(uf::userdata::autoDestruct) { - if ( len && data ) this->create(len, data); +uf::PointeredUserdata::PointeredUserdata(size_t len, const void* data, UF_USERDATA_CTTI_TYPE type) : m_pod({}), autoDestruct(uf::userdata::autoDestruct) { + if ( len && data ) this->create(len, data, type); } // Initializes from POD -uf::PointeredUserdata::PointeredUserdata( const pod::PointeredUserdata& pointer ) : m_pod(pointer), autoDestruct(uf::userdata::autoDestruct) { - +uf::PointeredUserdata::PointeredUserdata( const pod::PointeredUserdata& userdata ) : m_pod({}), autoDestruct(uf::userdata::autoDestruct) { + this->create( userdata.len, userdata.data, userdata.type ); } // Move c-tor -uf::PointeredUserdata::PointeredUserdata( PointeredUserdata&& move ) noexcept : - m_pod(std::move(move.m_pod)), - autoDestruct(move.autoDestruct) { +uf::PointeredUserdata::PointeredUserdata( PointeredUserdata&& move ) noexcept : m_pod(move.m_pod), autoDestruct(move.autoDestruct) { + move.m_pod = {}; } // Copy c-tor uf::PointeredUserdata::PointeredUserdata( const PointeredUserdata& userdata ) { @@ -97,37 +108,27 @@ uf::PointeredUserdata::PointeredUserdata( const PointeredUserdata& userdata ) { } // Creates the POD -pod::PointeredUserdata& uf::PointeredUserdata::create( size_t len, void* data ) { +pod::PointeredUserdata& uf::PointeredUserdata::create( size_t len, const void* data, UF_USERDATA_CTTI_TYPE type ) { if ( len <= 0 ) return this->m_pod; this->destroy(); - return this->m_pod = uf::pointeredUserdata::create( len, data ); + return this->m_pod = uf::pointeredUserdata::create( len, data, type ); } void uf::PointeredUserdata::move( PointeredUserdata& moved ) { // if ( this->m_pod && move.m_pod ) uf::pointeredUserdata::move( *this->m_pod, *move.m_pod ); this->destroy(); this->m_pod = moved.m_pod; - moved.m_pod.len = 0; - moved.m_pod.data = NULL; + moved.m_pod = {}; } void uf::PointeredUserdata::move( PointeredUserdata&& moved ) { // if ( this->m_pod && move.m_pod ) uf::pointeredUserdata::move( *this->m_pod, *move.m_pod ); this->destroy(); this->m_pod = moved.m_pod; - moved.m_pod.len = 0; - moved.m_pod.data = NULL; + moved.m_pod = {}; } void uf::PointeredUserdata::copy( const PointeredUserdata& userdata ) { if ( !userdata.m_pod.data || !userdata.m_pod.len ) return; this->destroy(); -// this->m_pod = uf::pointeredUserdata::copy( userdata.m_pod ); - this->create( userdata.m_pod.len, userdata.m_pod.data ); -// this->m_pod.type = userdata.m_pod.type; -/* -// if ( this->m_pod && copy.m_pod ) uf::pointeredUserdata::copy( *this->m_pod, *copy.m_pod ); - if ( !userdata ) return; - this->destroy(); -// this->m_pod = uf::pointeredUserdata::copy( userdata.m_pod ); -*/ + this->create( userdata.m_pod.len, userdata.m_pod.data, userdata.m_pod.type ); } // D-tor uf::PointeredUserdata::~PointeredUserdata() noexcept { @@ -136,6 +137,7 @@ uf::PointeredUserdata::~PointeredUserdata() noexcept { // Destroys the POD void uf::PointeredUserdata::destroy() { uf::pointeredUserdata::destroy( this->m_pod ); + this->m_pod = {}; } // POD access // Returns a reference of POD @@ -166,14 +168,18 @@ uf::PointeredUserdata::operator bool() const { return this->initialized(); } -uf::PointeredUserdata& uf::PointeredUserdata::operator=( pod::PointeredUserdata pointer ) { - this->m_pod = pointer; +uf::PointeredUserdata& uf::PointeredUserdata::operator=( const pod::PointeredUserdata& userdata ) { + this->create( userdata.len, userdata.data, userdata.type ); return *this; } uf::PointeredUserdata& uf::PointeredUserdata::operator=( PointeredUserdata&& move ) { - if ( this->initialized() && move.initialized() ) { + if ( this->m_pod.data != move.m_pod.data ) { + this->destroy(); this->m_pod = move.m_pod; + this->autoDestruct = move.autoDestruct; + move.m_pod = {}; + move.autoDestruct = false; } return *this; } diff --git a/engine/src/utils/userdata/userdata.cpp b/engine/src/utils/userdata/userdata.cpp index f203e900..abb1333a 100644 --- a/engine/src/utils/userdata/userdata.cpp +++ b/engine/src/utils/userdata/userdata.cpp @@ -7,9 +7,12 @@ uf::MemoryPool uf::userdata::memoryPool; bool uf::userdata::autoDestruct = true; bool uf::userdata::autoValidate = true; + +uf::stl::unordered_map uf::userdata::traits; + // Constructs a pod::Userdata struct -pod::Userdata* uf::userdata::create( std::size_t len, void* data ) { - return uf::userdata::create( uf::userdata::memoryPool, len, data ); +pod::Userdata* uf::userdata::create( std::size_t len, const void* data, UF_USERDATA_CTTI_TYPE type ) { + return uf::userdata::create( uf::userdata::memoryPool, len, data, type ); } void uf::userdata::destroy( pod::Userdata* userdata ) { return uf::userdata::destroy( uf::userdata::memoryPool, userdata ); @@ -23,7 +26,7 @@ size_t uf::userdata::size( size_t len, size_t padding ) { } // -pod::Userdata* uf::userdata::create( uf::MemoryPool& requestedMemoryPool, size_t len, void* data ) { +pod::Userdata* uf::userdata::create( uf::MemoryPool& requestedMemoryPool, size_t len, const void* data, UF_USERDATA_CTTI_TYPE type ) { if ( len <= 0 ) return NULL; size_t requestedLen = size( len ); #if UF_MEMORYPOOL_INVALID_MALLOC @@ -40,13 +43,19 @@ pod::Userdata* uf::userdata::create( uf::MemoryPool& requestedMemoryPool, size_t userdata = (pod::Userdata*) uf::allocator::malloc_m( requestedLen ); // allocate data for the userdata struct, and then some } #endif - if ( data ) memcpy( userdata->data, data, len ); - else memset( userdata->data, 0, len ); - userdata->len = len; - userdata->type = UF_USERDATA_CTTI(void); + userdata->len = requestedLen; + userdata->type = type; + auto& trait = uf::userdata::getTrait( userdata->type ); + if ( data && userdata->type != UF_USERDATA_CTTI(void) ) trait.constructor( userdata->data, data ); + else if ( data ) memcpy( userdata->data, data, requestedLen ); + else memset( userdata->data, 0, requestedLen ); + //UF_MSG_DEBUG("Calling create: {}: {}", trait.name, (void*) userdata->data); return userdata; } void uf::userdata::destroy( uf::MemoryPool& requestedMemoryPool, pod::Userdata* userdata ) { + auto& trait = uf::userdata::getTrait( userdata->type ); + if ( userdata->type != UF_USERDATA_CTTI(void) ) trait.destructor( userdata->data ); + //UF_MSG_DEBUG("Calling destroy: {}: {}", trait.name, (void*) userdata->data); #if UF_MEMORYPOOL_INVALID_FREE uf::MemoryPool& memoryPool = requestedMemoryPool.size() > 0 ? requestedMemoryPool : uf::memoryPool::global; memoryPool.free( userdata, size(userdata->len) ); @@ -61,11 +70,14 @@ void uf::userdata::destroy( uf::MemoryPool& requestedMemoryPool, pod::Userdata* } pod::Userdata* uf::userdata::copy( uf::MemoryPool& requestedMemoryPool, const pod::Userdata* userdata ) { if ( !userdata || userdata->len <= 0 ) return NULL; - auto* copied = uf::userdata::create( userdata->len, const_cast((const void*) &userdata->data[0]) ); - copied->type = userdata->type; + auto* copied = uf::userdata::create( userdata->len, const_cast((const void*) &userdata->data[0]), userdata->type ); return copied; } +const pod::UserdataTraits& uf::userdata::getTrait( UF_USERDATA_CTTI_TYPE type ) { + return uf::userdata::traits[type]; +} + uf::stl::string uf::userdata::toBase64( pod::Userdata* userdata ) { return uf::base64::encode( userdata->data, userdata->len ); } @@ -76,8 +88,8 @@ pod::Userdata* uf::userdata::fromBase64( const uf::stl::string& base64 ) { // C-tor // Initializes POD -uf::Userdata::Userdata(std::size_t len, void* data) : m_pod(NULL), autoDestruct(uf::userdata::autoDestruct) { - if ( len && data ) this->create(len, data); +uf::Userdata::Userdata(std::size_t len, const void* data, UF_USERDATA_CTTI_TYPE type) : m_pod(NULL), autoDestruct(uf::userdata::autoDestruct) { + if ( len && data ) this->create(len, data, type); } // Initializes from POD @@ -87,8 +99,9 @@ uf::Userdata::Userdata( pod::Userdata* pointer ) : m_pod(pointer), autoDestruct( // Move c-tor uf::Userdata::Userdata( Userdata&& move ) noexcept : - m_pod(std::move(move.m_pod)), + m_pod(move.m_pod), autoDestruct(move.autoDestruct) { + move.m_pod = {}; } // Copy c-tor uf::Userdata::Userdata( const Userdata& userdata ) { @@ -97,10 +110,10 @@ uf::Userdata::Userdata( const Userdata& userdata ) { } // Creates the POD -pod::Userdata* uf::Userdata::create( std::size_t len, void* data ) { +pod::Userdata* uf::Userdata::create( std::size_t len, const void* data, UF_USERDATA_CTTI_TYPE type ) { if ( len <= 0 ) return NULL; this->destroy(); - return this->m_pod = uf::userdata::create( len, data ); + return this->m_pod = uf::userdata::create( len, data, type ); } void uf::Userdata::move( Userdata& moved ) { // if ( this->m_pod && move.m_pod ) uf::userdata::move( *this->m_pod, *move.m_pod ); @@ -117,15 +130,7 @@ void uf::Userdata::move( Userdata&& moved ) { void uf::Userdata::copy( const Userdata& userdata ) { if ( !userdata.m_pod || !userdata.m_pod->len ) return; this->destroy(); -// this->m_pod = uf::userdata::copy( userdata.m_pod ); - this->create( userdata.m_pod->len, userdata.m_pod->data ); -// this->m_pod->type = userdata.m_pod->type; -/* -// if ( this->m_pod && copy.m_pod ) uf::userdata::copy( *this->m_pod, *copy.m_pod ); - if ( !userdata ) return; - this->destroy(); -// this->m_pod = uf::userdata::copy( userdata.m_pod ); -*/ + this->create( userdata.m_pod->len, userdata.m_pod->data, userdata.m_pod->type ); } // D-tor uf::Userdata::~Userdata() noexcept { @@ -173,7 +178,10 @@ uf::Userdata& uf::Userdata::operator=( pod::Userdata* pointer ) { return *this; } uf::Userdata& uf::Userdata::operator=( Userdata&& move ) { - if ( this->m_pod && move.m_pod ) this->m_pod = move.m_pod, move.m_pod = NULL; + if ( this->m_pod && move.m_pod ) { + this->m_pod = move.m_pod; + move.m_pod = NULL; + } return *this; } uf::Userdata& uf::Userdata::operator=( const Userdata& copy ) {