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)

This commit is contained in:
ecker 2025-08-16 12:19:55 -05:00
parent 9858cf9800
commit 5f8a80c25f
10 changed files with 154 additions and 104 deletions

View File

@ -76,10 +76,10 @@
"shadows": true "shadows": true
}, },
"stream": { "stream": {
"tag": "", // worldspawn", "tag": "worldspawn",
"player": "info_player_spawn", "player": "info_player_spawn",
"enabled": true, // "auto", "enabled": "auto",
"radius": 16, "radius": 32,
"every": 1 "every": 1
} }
} }

View File

@ -28,10 +28,7 @@ size_t uf::Object::addHook( const uf::stl::string& name, T callback ) {
} }
template<typename T> template<typename T>
uf::Hooks::return_t uf::Object::callHook( const uf::stl::string& name, const T& p ) { uf::Hooks::return_t uf::Object::callHook( const uf::stl::string& name, const T& p ) {
pod::Hook::userdata_t payload; return uf::hooks.call( this->formatHookName( name ), p );
payload.create<T>(p);
return uf::hooks.call( this->formatHookName( name ), payload );
} }
template<typename T> template<typename T>

View File

@ -34,8 +34,15 @@ size_t uf::Hooks::addHook( const uf::Hooks::name_t& name, const Function& lambda
} }
template<typename T> template<typename T>
uf::Hooks::return_t uf::Hooks::call( const uf::Hooks::name_t& name, const T& p ) { 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<T>(const_cast<T&>(p));
return call( name, payload );
/*
pod::Hook::userdata_t payload; pod::Hook::userdata_t payload;
payload.create<T>(p); payload.create<T>(p);
auto results = call( name, payload );
return call( name, payload ); payload.destruct<T>();
return results;
*/
} }

View File

@ -8,7 +8,7 @@ namespace pod {
namespace uf { namespace uf {
namespace pointeredUserdata { 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 ); void UF_API destroy( pod::PointeredUserdata& userdata );
pod::PointeredUserdata UF_API copy( const pod::PointeredUserdata& userdata ); pod::PointeredUserdata UF_API copy( const pod::PointeredUserdata& userdata );
@ -17,15 +17,19 @@ namespace uf {
template<typename T> const T& get(const pod::PointeredUserdata& userdata, bool validate = uf::userdata::autoValidate ); template<typename T> const T& get(const pod::PointeredUserdata& userdata, bool validate = uf::userdata::autoValidate );
template<typename T> bool is(const pod::PointeredUserdata& userdata); template<typename T> bool is(const pod::PointeredUserdata& userdata);
uf::stl::string UF_API toBase64( pod::PointeredUserdata& userdata ); uf::stl::string UF_API toBase64( pod::PointeredUserdata& userdata );
pod::PointeredUserdata UF_API fromBase64( const uf::stl::string& base64 ); pod::PointeredUserdata UF_API fromBase64( const uf::stl::string& base64 );
// usage with MemoryPool // 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<typename T> pod::PointeredUserdata create( uf::MemoryPool&, const T& data = T() ); template<typename T> pod::PointeredUserdata create( uf::MemoryPool&, const T& data = T() );
void UF_API destroy( uf::MemoryPool&, pod::PointeredUserdata& userdata ); void UF_API destroy( uf::MemoryPool&, pod::PointeredUserdata& userdata );
pod::PointeredUserdata UF_API copy( uf::MemoryPool&, const 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<typename T> const pod::UserdataTraits& registerTrait();
size_t UF_API size( size_t size, size_t padding = 0 ); size_t UF_API size( size_t size, size_t padding = 0 );
} }
} }
@ -43,12 +47,12 @@ namespace uf {
public: public:
// C-tor // 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( const pod::PointeredUserdata& ); // initializes from POD
PointeredUserdata( PointeredUserdata&& move ) noexcept; // Move c-tor PointeredUserdata( PointeredUserdata&& move ) noexcept; // Move c-tor
PointeredUserdata( const PointeredUserdata& copy ); // Copy 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 move( PointeredUserdata&& move ); void move( PointeredUserdata&& move );
void copy( const PointeredUserdata& copy ); void copy( const PointeredUserdata& copy );
@ -70,13 +74,15 @@ namespace uf {
template<typename T> bool is() const; template<typename T> bool is() const;
template<typename T> inline T& as() { return get<T>(); } template<typename T> inline T& as() { return get<T>(); }
template<typename T> inline const T& as() const { return get<T>(); } template<typename T> inline const T& as() const { return get<T>(); }
template<typename T> void alias( T& );
// Overloaded ops // Overloaded ops
operator void*(); operator void*();
operator void*() const; operator void*() const;
operator bool() const; operator bool() const;
PointeredUserdata& operator=( pod::PointeredUserdata pointer ); PointeredUserdata& operator=( const pod::PointeredUserdata& pointer );
PointeredUserdata& operator=( PointeredUserdata&& move ); PointeredUserdata& operator=( PointeredUserdata&& move );
PointeredUserdata& operator=( const PointeredUserdata& copy ); PointeredUserdata& operator=( const PointeredUserdata& copy );
}; };
@ -90,15 +96,8 @@ pod::PointeredUserdata uf::pointeredUserdata::create( const T& data ) {
template<typename T> template<typename T>
pod::PointeredUserdata uf::pointeredUserdata::create( uf::MemoryPool& requestedMemoryPool, const T& data ) { pod::PointeredUserdata uf::pointeredUserdata::create( uf::MemoryPool& requestedMemoryPool, const T& data ) {
// if ( std::is_reference<T>() ) return uf::pointeredUserdata::create<typename std::remove_reference<T>::type>( requestedMemoryPool, data ); // if ( std::is_reference<T>() ) return uf::pointeredUserdata::create<typename std::remove_reference<T>::type>( requestedMemoryPool, data );
pod::PointeredUserdata userdata = uf::pointeredUserdata::create( requestedMemoryPool, sizeof(data), nullptr ); uf::pointeredUserdata::registerTrait<T>();
userdata.type = UF_USERDATA_CTTI(T); return uf::pointeredUserdata::create( requestedMemoryPool, sizeof(data), (const void*) &data, UF_USERDATA_CTTI(T) );
union {
void* from;
T* to;
} kludge;
kludge.from = userdata.data;
::new (kludge.to) T(data);
return userdata;
} }
// Easy way to get the userdata as a reference // Easy way to get the userdata as a reference
#include <stdexcept> #include <stdexcept>
@ -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); if ( userdata.type != UF_USERDATA_CTTI(void) ) return userdata.type == UF_USERDATA_CTTI(T) && userdata.len == sizeof(T);
return userdata.len == sizeof(T); return userdata.len == sizeof(T);
} }
template<typename T> 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<T>;
trait.destructor = &uf::userdata::destruct<T>;
return trait;}
//
// No need to cast data to a pointer AND get the data's size! // No need to cast data to a pointer AND get the data's size!
template<typename T> template<typename T>
pod::PointeredUserdata& uf::PointeredUserdata::create( const T& data ) { pod::PointeredUserdata& uf::PointeredUserdata::create( const T& data ) {
this->destroy();
return this->m_pod = uf::pointeredUserdata::create<T>(data); return this->m_pod = uf::pointeredUserdata::create<T>(data);
} }
// Easy way to get the userdata as a reference // Easy way to get the userdata as a reference
@ -155,4 +159,13 @@ const T& uf::PointeredUserdata::get(bool validate) const {
template<typename T> template<typename T>
bool uf::PointeredUserdata::is() const { bool uf::PointeredUserdata::is() const {
return uf::pointeredUserdata::is<T>( this->m_pod ); return uf::pointeredUserdata::is<T>( this->m_pod );
}
// I am not proud of having to do this
template<typename T>
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);
} }

View File

@ -7,6 +7,7 @@
#include <stdint.h> #include <stdint.h>
#include <cstddef> #include <cstddef>
#include <uf/utils/memory/string.h> #include <uf/utils/memory/string.h>
#include <uf/utils/memory/unordered_map.h>
#include <algorithm> #include <algorithm>
#include <typeindex> #include <typeindex>
@ -22,15 +23,23 @@ namespace pod {
UF_USERDATA_CTTI_TYPE type = UF_USERDATA_CTTI(void); UF_USERDATA_CTTI_TYPE type = UF_USERDATA_CTTI(void);
uint8_t data[1]; 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 uf {
namespace userdata { namespace userdata {
extern UF_API uf::stl::unordered_map<UF_USERDATA_CTTI_TYPE, pod::UserdataTraits> traits;
extern UF_API uf::MemoryPool memoryPool; extern UF_API uf::MemoryPool memoryPool;
extern UF_API bool autoDestruct; extern UF_API bool autoDestruct;
extern UF_API bool autoValidate; 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 ); void UF_API destroy( pod::Userdata* userdata );
pod::Userdata* UF_API copy( const 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 ); // void copy( pod::Userdata& to, const pod::Userdata& from );
// usage with MemoryPool // 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<typename T> pod::Userdata* create( uf::MemoryPool&, const T& data = T() ); template<typename T> pod::Userdata* create( uf::MemoryPool&, const T& data = T() );
void UF_API destroy( uf::MemoryPool&, pod::Userdata* userdata ); void UF_API destroy( uf::MemoryPool&, pod::Userdata* userdata );
pod::Userdata* UF_API copy( uf::MemoryPool&, const 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 ); size_t UF_API size( size_t size, size_t padding = 0 );
template<typename T> void construct( void* dst, const void* src );
template<typename T> void destruct( void* p );
const pod::UserdataTraits& UF_API getTrait( UF_USERDATA_CTTI_TYPE type );
template<typename T> const pod::UserdataTraits& registerTrait();
} }
} }
@ -68,12 +83,12 @@ namespace uf {
public: public:
// C-tor // 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( pod::Userdata* ); // initializes from POD
Userdata( Userdata&& move ) noexcept ; // Move c-tor Userdata( Userdata&& move ) noexcept ; // Move c-tor
Userdata( const Userdata& copy ); // Copy 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 move( Userdata&& move ); void move( Userdata&& move );
void copy( const Userdata& copy ); void copy( const Userdata& copy );

View File

@ -9,16 +9,9 @@ template<typename T>
pod::Userdata* uf::userdata::create( uf::MemoryPool& requestedMemoryPool, const T& data ) { pod::Userdata* uf::userdata::create( uf::MemoryPool& requestedMemoryPool, const T& data ) {
// CTTI information of a T& != T // CTTI information of a T& != T
// if ( std::is_reference<T>() ) return uf::userdata::create<typename std::remove_reference<T>::type>( requestedMemoryPool, data ); // if ( std::is_reference<T>() ) return uf::userdata::create<typename std::remove_reference<T>::type>( requestedMemoryPool, data );
// Register trait
pod::Userdata* userdata = uf::userdata::create( requestedMemoryPool, sizeof(data), nullptr ); uf::userdata::registerTrait<T>();
userdata->type = UF_USERDATA_CTTI(T); return uf::userdata::create( requestedMemoryPool, sizeof(data), (const void*) &data, UF_USERDATA_CTTI(T) );
union {
void* from;
T* to;
} kludge;
kludge.from = userdata->data;
::new (kludge.to) T(data);
return userdata;
} }
// Easy way to get the userdata as a reference // Easy way to get the userdata as a reference
#include <stdexcept> #include <stdexcept>
@ -55,6 +48,21 @@ bool uf::userdata::is( const pod::Userdata* userdata ) {
return userdata && userdata->len == sizeof(T); return userdata && userdata->len == sizeof(T);
} }
template<typename T> void uf::userdata::construct( void* dst, const void* src ) {
::new (dst) T(*static_cast<const T*>(src));
}
template<typename T> void uf::userdata::destruct( void* p ) {
static_cast<T*>(p)->~T();
}
template<typename T> 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<T>;
trait.destructor = &uf::userdata::destruct<T>;
return trait;
}
//
// No need to cast data to a pointer AND get the data's size! // No need to cast data to a pointer AND get the data's size!
template<typename T> template<typename T>
pod::Userdata* uf::Userdata::create( const T& data ) { pod::Userdata* uf::Userdata::create( const T& data ) {

View File

@ -288,7 +288,10 @@ void uf::ObjectBehavior::tick( uf::Object& self ) {
else unprocessed.emplace_back(q); else unprocessed.emplace_back(q);
} }
for ( auto& q : executeQueue ) { 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 if ( q.type == -1 ) this->callHook( q.name, q.json );
else this->callHook( q.name ); else this->callHook( q.name );
} }

View File

@ -95,13 +95,6 @@ namespace binds {
if ( type == "Metadata" ) { if ( type == "Metadata" ) {
auto encoded = ext::lua::encode( value.as<sol::table>() ); auto encoded = ext::lua::encode( value.as<sol::table>() );
if ( encoded ) { if ( encoded ) {
/*
self.callHook( "object:Serialize.%UID%" );
auto& metadata = self.getComponent<uf::Serializer>();
uf::stl::string str = encoded.value();
metadata.merge( str, false );
self.callHook( "object:Deserialize.%UID%" );
*/
uf::stl::string str = encoded.value(); uf::stl::string str = encoded.value();
ext::json::Value json; ext::json::Value json;
ext::json::decode( json, str ); ext::json::decode( json, str );

View File

@ -5,8 +5,8 @@
#include <iostream> #include <iostream>
// Constructs a pod::PointeredUserdata struct // Constructs a pod::PointeredUserdata struct
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 ) {
return uf::pointeredUserdata::create( uf::userdata::memoryPool, len, data ); return uf::pointeredUserdata::create( uf::userdata::memoryPool, len, data, type );
} }
void uf::pointeredUserdata::destroy( pod::PointeredUserdata& userdata ) { void uf::pointeredUserdata::destroy( pod::PointeredUserdata& userdata ) {
return uf::pointeredUserdata::destroy( uf::userdata::memoryPool, 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 {}; if ( len <= 0 ) return {};
size_t requestedLen = size( len ); size_t requestedLen = size( len );
#if UF_MEMORYPOOL_INVALID_MALLOC #if UF_MEMORYPOOL_INVALID_MALLOC
uf::MemoryPool& memoryPool = requestedMemoryPool.size() > 0 ? requestedMemoryPool : uf::memoryPool::global; uf::MemoryPool& memoryPool = requestedMemoryPool.size() > 0 ? requestedMemoryPool : uf::memoryPool::global;
pod::PointeredUserdata userdata = { pod::PointeredUserdata userdata = {
.len = requestedLen, .len = requestedLen,
.type = type,
.data = memoryPool.alloc( requestedLen ), .data = memoryPool.alloc( requestedLen ),
}; };
#else #else
uf::MemoryPool* memoryPool = {}; uf::MemoryPool* memoryPool = NULL;
if ( requestedMemoryPool.size() > 0 ) memoryPool = &requestedMemoryPool; if ( requestedMemoryPool.size() > 0 ) memoryPool = &requestedMemoryPool;
else if ( uf::memoryPool::global.size() > 0 ) memoryPool = &uf::memoryPool::global; else if ( uf::memoryPool::global.size() > 0 ) memoryPool = &uf::memoryPool::global;
pod::PointeredUserdata userdata = {}; pod::PointeredUserdata userdata = {};
if ( memoryPool ) userdata.data = memoryPool->alloc( requestedLen ); if ( memoryPool ) userdata.data = memoryPool->alloc( requestedLen );
else userdata.data = uf::allocator::malloc_m( requestedLen ); // allocate data for the userdata struct, and then some else userdata.data = uf::allocator::malloc_m( requestedLen ); // allocate data for the userdata struct, and then some
userdata.len = requestedLen;
userdata.type = type;
#endif #endif
if ( data ) memcpy( userdata.data, data, len ); auto& trait = uf::pointeredUserdata::getTrait( userdata.type );
else memset( userdata.data, 0, len ); if ( data && userdata.type != UF_USERDATA_CTTI(void) ) trait.constructor( userdata.data, data );
userdata.len = len; else if ( data ) memcpy( userdata.data, data, requestedLen );
userdata.type = UF_USERDATA_CTTI(void); else memset( userdata.data, 0, requestedLen );
//UF_MSG_DEBUG("Calling create: {}: {}", trait.name, (void*) userdata.data);
return userdata; return userdata;
} }
void uf::pointeredUserdata::destroy( uf::MemoryPool& requestedMemoryPool, pod::PointeredUserdata& userdata ) { void uf::pointeredUserdata::destroy( uf::MemoryPool& requestedMemoryPool, pod::PointeredUserdata& userdata ) {
if ( !userdata.data ) return; 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 #if UF_MEMORYPOOL_INVALID_FREE
uf::MemoryPool& memoryPool = requestedMemoryPool.size() > 0 ? requestedMemoryPool : uf::memoryPool::global; uf::MemoryPool& memoryPool = requestedMemoryPool.size() > 0 ? requestedMemoryPool : uf::memoryPool::global;
memoryPool.free( userdata.data, size(userdata.len) ); memoryPool.free( userdata.data, size(userdata.len) );
@ -58,6 +65,7 @@ void uf::pointeredUserdata::destroy( uf::MemoryPool& requestedMemoryPool, pod::P
#endif #endif
userdata.len = 0; userdata.len = 0;
userdata.data = NULL; userdata.data = NULL;
userdata.type = UF_USERDATA_CTTI(void);
} }
pod::PointeredUserdata uf::pointeredUserdata::copy( uf::MemoryPool& requestedMemoryPool, const pod::PointeredUserdata& userdata ) { pod::PointeredUserdata uf::pointeredUserdata::copy( uf::MemoryPool& requestedMemoryPool, const pod::PointeredUserdata& userdata ) {
if ( !userdata.data || userdata.len <= 0 ) return {}; if ( !userdata.data || userdata.len <= 0 ) return {};
@ -66,6 +74,10 @@ pod::PointeredUserdata uf::pointeredUserdata::copy( uf::MemoryPool& requestedMem
return copied; 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 ) { uf::stl::string uf::pointeredUserdata::toBase64( pod::PointeredUserdata& userdata ) {
return uf::base64::encode( static_cast<uint8_t*>(userdata.data), userdata.len ); return uf::base64::encode( static_cast<uint8_t*>(userdata.data), userdata.len );
} }
@ -76,19 +88,18 @@ pod::PointeredUserdata uf::pointeredUserdata::fromBase64( const uf::stl::string&
// C-tor // C-tor
// Initializes POD // Initializes POD
uf::PointeredUserdata::PointeredUserdata(size_t len, void* data) : m_pod({}), autoDestruct(uf::userdata::autoDestruct) { 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); if ( len && data ) this->create(len, data, type);
} }
// Initializes from POD // 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 // Move c-tor
uf::PointeredUserdata::PointeredUserdata( PointeredUserdata&& move ) noexcept : uf::PointeredUserdata::PointeredUserdata( PointeredUserdata&& move ) noexcept : m_pod(move.m_pod), autoDestruct(move.autoDestruct) {
m_pod(std::move(move.m_pod)), move.m_pod = {};
autoDestruct(move.autoDestruct) {
} }
// Copy c-tor // Copy c-tor
uf::PointeredUserdata::PointeredUserdata( const PointeredUserdata& userdata ) { uf::PointeredUserdata::PointeredUserdata( const PointeredUserdata& userdata ) {
@ -97,37 +108,27 @@ uf::PointeredUserdata::PointeredUserdata( const PointeredUserdata& userdata ) {
} }
// Creates the POD // 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; if ( len <= 0 ) return this->m_pod;
this->destroy(); 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 ) { void uf::PointeredUserdata::move( PointeredUserdata& moved ) {
// if ( this->m_pod && move.m_pod ) uf::pointeredUserdata::move( *this->m_pod, *move.m_pod ); // if ( this->m_pod && move.m_pod ) uf::pointeredUserdata::move( *this->m_pod, *move.m_pod );
this->destroy(); this->destroy();
this->m_pod = moved.m_pod; this->m_pod = moved.m_pod;
moved.m_pod.len = 0; moved.m_pod = {};
moved.m_pod.data = NULL;
} }
void uf::PointeredUserdata::move( PointeredUserdata&& moved ) { void uf::PointeredUserdata::move( PointeredUserdata&& moved ) {
// if ( this->m_pod && move.m_pod ) uf::pointeredUserdata::move( *this->m_pod, *move.m_pod ); // if ( this->m_pod && move.m_pod ) uf::pointeredUserdata::move( *this->m_pod, *move.m_pod );
this->destroy(); this->destroy();
this->m_pod = moved.m_pod; this->m_pod = moved.m_pod;
moved.m_pod.len = 0; moved.m_pod = {};
moved.m_pod.data = NULL;
} }
void uf::PointeredUserdata::copy( const PointeredUserdata& userdata ) { void uf::PointeredUserdata::copy( const PointeredUserdata& userdata ) {
if ( !userdata.m_pod.data || !userdata.m_pod.len ) return; if ( !userdata.m_pod.data || !userdata.m_pod.len ) return;
this->destroy(); 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 );
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 );
*/
} }
// D-tor // D-tor
uf::PointeredUserdata::~PointeredUserdata() noexcept { uf::PointeredUserdata::~PointeredUserdata() noexcept {
@ -136,6 +137,7 @@ uf::PointeredUserdata::~PointeredUserdata() noexcept {
// Destroys the POD // Destroys the POD
void uf::PointeredUserdata::destroy() { void uf::PointeredUserdata::destroy() {
uf::pointeredUserdata::destroy( this->m_pod ); uf::pointeredUserdata::destroy( this->m_pod );
this->m_pod = {};
} }
// POD access // POD access
// Returns a reference of POD // Returns a reference of POD
@ -166,14 +168,18 @@ uf::PointeredUserdata::operator bool() const {
return this->initialized(); return this->initialized();
} }
uf::PointeredUserdata& uf::PointeredUserdata::operator=( pod::PointeredUserdata pointer ) { uf::PointeredUserdata& uf::PointeredUserdata::operator=( const pod::PointeredUserdata& userdata ) {
this->m_pod = pointer; this->create( userdata.len, userdata.data, userdata.type );
return *this; return *this;
} }
uf::PointeredUserdata& uf::PointeredUserdata::operator=( PointeredUserdata&& move ) { 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->m_pod = move.m_pod;
this->autoDestruct = move.autoDestruct;
move.m_pod = {}; move.m_pod = {};
move.autoDestruct = false;
} }
return *this; return *this;
} }

View File

@ -7,9 +7,12 @@
uf::MemoryPool uf::userdata::memoryPool; uf::MemoryPool uf::userdata::memoryPool;
bool uf::userdata::autoDestruct = true; bool uf::userdata::autoDestruct = true;
bool uf::userdata::autoValidate = true; bool uf::userdata::autoValidate = true;
uf::stl::unordered_map<UF_USERDATA_CTTI_TYPE, pod::UserdataTraits> uf::userdata::traits;
// Constructs a pod::Userdata struct // Constructs a pod::Userdata struct
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 ) {
return uf::userdata::create( uf::userdata::memoryPool, len, data ); return uf::userdata::create( uf::userdata::memoryPool, len, data, type );
} }
void uf::userdata::destroy( pod::Userdata* userdata ) { void uf::userdata::destroy( pod::Userdata* userdata ) {
return uf::userdata::destroy( uf::userdata::memoryPool, 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; if ( len <= 0 ) return NULL;
size_t requestedLen = size( len ); size_t requestedLen = size( len );
#if UF_MEMORYPOOL_INVALID_MALLOC #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 userdata = (pod::Userdata*) uf::allocator::malloc_m( requestedLen ); // allocate data for the userdata struct, and then some
} }
#endif #endif
if ( data ) memcpy( userdata->data, data, len ); userdata->len = requestedLen;
else memset( userdata->data, 0, len ); userdata->type = type;
userdata->len = len; auto& trait = uf::userdata::getTrait( userdata->type );
userdata->type = UF_USERDATA_CTTI(void); 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; return userdata;
} }
void uf::userdata::destroy( uf::MemoryPool& requestedMemoryPool, pod::Userdata* 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 #if UF_MEMORYPOOL_INVALID_FREE
uf::MemoryPool& memoryPool = requestedMemoryPool.size() > 0 ? requestedMemoryPool : uf::memoryPool::global; uf::MemoryPool& memoryPool = requestedMemoryPool.size() > 0 ? requestedMemoryPool : uf::memoryPool::global;
memoryPool.free( userdata, size(userdata->len) ); 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 ) { pod::Userdata* uf::userdata::copy( uf::MemoryPool& requestedMemoryPool, const pod::Userdata* userdata ) {
if ( !userdata || userdata->len <= 0 ) return NULL; if ( !userdata || userdata->len <= 0 ) return NULL;
auto* copied = uf::userdata::create( userdata->len, const_cast<void*>((const void*) &userdata->data[0]) ); auto* copied = uf::userdata::create( userdata->len, const_cast<void*>((const void*) &userdata->data[0]), userdata->type );
copied->type = userdata->type;
return copied; 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 ) { uf::stl::string uf::userdata::toBase64( pod::Userdata* userdata ) {
return uf::base64::encode( userdata->data, userdata->len ); return uf::base64::encode( userdata->data, userdata->len );
} }
@ -76,8 +88,8 @@ pod::Userdata* uf::userdata::fromBase64( const uf::stl::string& base64 ) {
// C-tor // C-tor
// Initializes POD // Initializes POD
uf::Userdata::Userdata(std::size_t len, void* data) : m_pod(NULL), autoDestruct(uf::userdata::autoDestruct) { 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); if ( len && data ) this->create(len, data, type);
} }
// Initializes from POD // Initializes from POD
@ -87,8 +99,9 @@ uf::Userdata::Userdata( pod::Userdata* pointer ) : m_pod(pointer), autoDestruct(
// Move c-tor // Move c-tor
uf::Userdata::Userdata( Userdata&& move ) noexcept : uf::Userdata::Userdata( Userdata&& move ) noexcept :
m_pod(std::move(move.m_pod)), m_pod(move.m_pod),
autoDestruct(move.autoDestruct) { autoDestruct(move.autoDestruct) {
move.m_pod = {};
} }
// Copy c-tor // Copy c-tor
uf::Userdata::Userdata( const Userdata& userdata ) { uf::Userdata::Userdata( const Userdata& userdata ) {
@ -97,10 +110,10 @@ uf::Userdata::Userdata( const Userdata& userdata ) {
} }
// Creates the POD // 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; if ( len <= 0 ) return NULL;
this->destroy(); 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 ) { void uf::Userdata::move( Userdata& moved ) {
// if ( this->m_pod && move.m_pod ) uf::userdata::move( *this->m_pod, *move.m_pod ); // 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 ) { void uf::Userdata::copy( const Userdata& userdata ) {
if ( !userdata.m_pod || !userdata.m_pod->len ) return; if ( !userdata.m_pod || !userdata.m_pod->len ) return;
this->destroy(); 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 );
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 );
*/
} }
// D-tor // D-tor
uf::Userdata::~Userdata() noexcept { uf::Userdata::~Userdata() noexcept {
@ -173,7 +178,10 @@ uf::Userdata& uf::Userdata::operator=( pod::Userdata* pointer ) {
return *this; return *this;
} }
uf::Userdata& uf::Userdata::operator=( Userdata&& move ) { 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; return *this;
} }
uf::Userdata& uf::Userdata::operator=( const Userdata& copy ) { uf::Userdata& uf::Userdata::operator=( const Userdata& copy ) {