summaryrefslogtreecommitdiff
path: root/src/util
diff options
context:
space:
mode:
authoraura <nw@moneybot.cc>2026-03-16 10:15:01 +0100
committeraura <nw@moneybot.cc>2026-03-16 10:15:01 +0100
commitfdc5e8760fb7ac0af8e7ebb98a2076db15e31082 (patch)
treec94991e1e594c7703295aa413caf40786f343c1f /src/util
parente2829336cfedb39d23263f75b61ed969c8193534 (diff)
giga refactor, fix ALL the leaks
Diffstat (limited to 'src/util')
-rw-r--r--src/util/allocator.h11
-rw-r--r--src/util/callback.h88
-rw-r--r--src/util/config.h25
-rw-r--r--src/util/config/config.cpp13
-rw-r--r--src/util/config/serializers.cpp115
-rw-r--r--src/util/file.h4
-rw-r--r--src/util/input.h3
-rw-r--r--src/util/str_tokenizer.h114
-rw-r--r--src/util/string.h23
9 files changed, 299 insertions, 97 deletions
diff --git a/src/util/allocator.h b/src/util/allocator.h
index 327dfc1..623d227 100644
--- a/src/util/allocator.h
+++ b/src/util/allocator.h
@@ -2,8 +2,7 @@
#include <stdlib.h>
#include <string.h>
-#include <functional>
-#include "typedef.h"
+#include "callback.h"
template <typename T>
struct LIST_ITERATOR {
@@ -19,7 +18,7 @@ struct LIST_ITERATOR {
};
template <typename T>
-using QSORT_FN = std::function< U8( T*, T* ) >;
+using QSORT_FN = FN< U8( T*, T* ) >;
template <typename T>
static U8 qsort_basic_sort( T* t1, T* t2 ) {
@@ -58,8 +57,8 @@ struct LIST {
U32 capacity;
U32 size;
- using ON_EACH_FN = std::function< void(T*) >;
- using ON_SEARCH_FN = std::function< bool(T*) >;
+ using ON_EACH_FN = FN< void(T*) >;
+ using ON_SEARCH_FN = FN< U8(T*) >;
LIST() {
data = (T*)malloc( sizeof( T ) );
@@ -265,6 +264,8 @@ struct LIST {
}
T ret = data[--size];
+ if constexpr( !__is_trivially_destructible(T) )
+ data[size].~T();
if( size < capacity / 4 )
shrink();
diff --git a/src/util/callback.h b/src/util/callback.h
new file mode 100644
index 0000000..df93b59
--- /dev/null
+++ b/src/util/callback.h
@@ -0,0 +1,88 @@
+#pragma once
+#include "typedef.h"
+
+template <typename T>
+struct FN;
+
+template <typename RET, typename... ARGS>
+struct FN<RET(ARGS...)> {
+ // voodoo
+ template <typename T> struct __strip_ref { using type = T; };
+ template <typename T> struct __strip_ref<T&> { using type = T; };
+ template <typename T> struct __strip_ref<T&&> { using type = T; };
+ template <typename R, typename... A> struct __strip_ref<R(A...)> { using type = R(*)(A...); };
+ template <typename R, typename... A> struct __strip_ref<R(&)(A...)> { using type = R(*)(A...); };
+
+ void* data;
+ U32 size;
+ RET( *invoke )( void*, ARGS... );
+ void( *destroy )( void* );
+ void*( *clone )( void* );
+
+ template <typename F>
+ FN( F&& f ) {
+ using __stripped = typename __strip_ref<F>::type;
+ data = new __stripped( static_cast<F&&>(f) );
+ size = sizeof( __stripped );
+ invoke = pfn( void* d, ARGS... args ) -> RET {
+ return ( *(__stripped*)d )( args... );
+ };
+ destroy = pfn( void* d ) {
+ delete (__stripped*)d;
+ };
+ clone = pfn( void* data ) {
+ return (void*)new __stripped( *(__stripped*)data );
+ };
+ }
+
+ template <>
+ FN( int&& ) : data( 0 ), invoke( 0 ), destroy( 0 ) {}
+ FN() : data( 0 ), invoke( 0 ), destroy( 0 ) {}
+
+ FN( FN&& other ) : data( other.data ), invoke( other.invoke ), destroy( other.destroy ) {
+ other.data = 0;
+ other.invoke = 0;
+ other.destroy = 0;
+ }
+
+ FN& operator=( FN&& other ) {
+ if( this == &other ) return *this;
+ if( destroy ) destroy( data );
+ data = other.data;
+ invoke = other.invoke;
+ destroy = other.destroy;
+ other.data = 0;
+ other.invoke = 0;
+ other.destroy = 0;
+ return *this;
+ }
+
+ FN( const FN& other ) {
+ *this = other;
+ };
+
+ FN& operator=( const FN& other ) {
+ if( !other.data ) {
+ data = 0;
+ invoke = 0;
+ destroy = 0;
+ size = 0;
+ return *this;
+ }
+
+ size = other.size;
+ data = other.clone( other.data );
+ invoke = other.invoke;
+ destroy = other.destroy;
+ clone = other.clone;
+ return *this;
+ }
+
+ ~FN() { if( destroy ) destroy( data ); }
+ operator bool() const { return !!invoke; }
+
+ RET operator()( ARGS... args ) const {
+ return invoke( data, args... );
+ }
+
+};
diff --git a/src/util/config.h b/src/util/config.h
index 7973db0..d8c1c2e 100644
--- a/src/util/config.h
+++ b/src/util/config.h
@@ -1,7 +1,7 @@
#pragma once
#include <stdio.h>
-#include "allocator.h"
+#include "string.h"
#include "vector.h"
#include "color.h"
@@ -26,8 +26,8 @@ enum CfgNodeType_t {
// ===================================== [ definitions ] ===========================================
-using CFG_PARSEFN = std::function<void( CFG_PARSER*, CFG_SECTION*, char* )>;
-using CFG_SERIALIZEFN = std::function<void( CFG_SERIALIZER*, CFG_NODE*, char* )>;
+using CFG_PARSEFN = FN<STAT( CFG_PARSER*, CFG_SECTION*, char* )>;
+using CFG_SERIALIZEFN = FN<STR( CFG_SERIALIZER*, CFG_NODE*)>;
struct CFG_TYPE {
U8 type;
@@ -37,7 +37,7 @@ struct CFG_TYPE {
};
struct CFG_NODE {
- char name[64];
+ STR name;
CFG_NODE* parent;
U8 type;
};
@@ -66,14 +66,14 @@ extern STAT cfg_parser_clr( CFG_PARSER* parser, CFG_SECTION* section, char* name
// ====================================== [ serializers ] ==========================================
-extern void cfg_serialize_section( CFG_SERIALIZER* serializer, CFG_NODE* section, char* buf );
-extern void cfg_serialize_bytes( CFG_SERIALIZER* serializer, CFG_NODE* node, char* buf );
-extern void cfg_serialize_str( CFG_SERIALIZER* serializer, CFG_NODE* node, char* buf );
-extern void cfg_serialize_float( CFG_SERIALIZER* serializer, CFG_NODE* node, char* buf );
-extern void cfg_serialize_int( CFG_SERIALIZER* serializer, CFG_NODE* node, char* buf );
-extern void cfg_serialize_vec2( CFG_SERIALIZER* serializer, CFG_NODE* node, char* buf );
-extern void cfg_serialize_vec3( CFG_SERIALIZER* serializer, CFG_NODE* node, char* buf );
-extern void cfg_serialize_clr( CFG_SERIALIZER* serializer, CFG_NODE* node, char* buf );
+extern STR cfg_serialize_section( CFG_SERIALIZER* serializer, CFG_NODE* section );
+extern STR cfg_serialize_bytes( CFG_SERIALIZER* serializer, CFG_NODE* node );
+extern STR cfg_serialize_str( CFG_SERIALIZER* serializer, CFG_NODE* node );
+extern STR cfg_serialize_float( CFG_SERIALIZER* serializer, CFG_NODE* node );
+extern STR cfg_serialize_int( CFG_SERIALIZER* serializer, CFG_NODE* node );
+extern STR cfg_serialize_vec2( CFG_SERIALIZER* serializer, CFG_NODE* node );
+extern STR cfg_serialize_vec3( CFG_SERIALIZER* serializer, CFG_NODE* node );
+extern STR cfg_serialize_clr( CFG_SERIALIZER* serializer, CFG_NODE* node );
// ========================================= [ config ] ============================================
@@ -158,6 +158,7 @@ static void cfg_free( CFG_NODE* n ) {
else if( n->type == CFGT_SECTION ) {
CFG_SECTION* s = (CFG_SECTION*)n;
s->children.each( fn( CFG_NODE** child ) { cfg_free( *child ); } );
+ return delete s;
}
delete n;
diff --git a/src/util/config/config.cpp b/src/util/config/config.cpp
index a41e455..00a2512 100644
--- a/src/util/config/config.cpp
+++ b/src/util/config/config.cpp
@@ -30,9 +30,7 @@ inline void trim_whitespace( char* buf ) {
}
inline void init_cfg_node( CFG_NODE* node, const char* name, CFG_NODE* parent, U8 type ) {
- memset( node->name, 0, sizeof(node->name) );
- strcpy( node->name, name );
- node->name[sizeof(node->name) - 1] = '\0';
+ node->name = name;
node->parent = parent;
if( parent )
( (CFG_SECTION*)parent )->children.push( node );
@@ -290,17 +288,12 @@ STAT cfg_save( CFG_SECTION* root, const char* path ) {
if( !f )
return STAT_ERR;
- char* buf = (char*)malloc( 999999 );
- buf[0] = 0;
CFG_SERIALIZER s;
s.tabc = 0;
s.f = f;
- cfg_serialize_section( &s, (CFG_NODE*)root, buf );
- U32 len = strlen( buf );
-
- fwrite( buf, 1, len, f );
- free( buf );
+ STR buf = cfg_serialize_section( &s, (CFG_NODE*)root );
+ fwrite( buf, 1, buf.size, f );
fclose( f );
return STAT_OK;
diff --git a/src/util/config/serializers.cpp b/src/util/config/serializers.cpp
index 01f416c..15ddae0 100644
--- a/src/util/config/serializers.cpp
+++ b/src/util/config/serializers.cpp
@@ -1,109 +1,122 @@
-#include <cstdarg>
-#include <cstdio>
-
#include "../config.h"
-void serialize_node( CFG_SERIALIZER* s, CFG_NODE* n, char* buf ) {
- U32 len = strlen( buf );
- for( U32 i = 0; i < s->tabc * 2; ++i ) buf[i + len] = ' ';
- buf[len + s->tabc * 2] = 0;
- sprintf( buf, "%s%s %s", buf, cfg_types[n->type].def, n->name );
+STR serialize_node( CFG_SERIALIZER* s, CFG_NODE* n ) {
+ STR ret{};
+ for( U32 i = 0; i < s->tabc * 2; ++i ) ret.append( " " );
+ ret.fmt( "%s %s", cfg_types[n->type].def, n->name.data );
+
+ return ret;
}
-void cfg_serialize_section( CFG_SERIALIZER* s, CFG_NODE *n, char *buf ) {
+STR cfg_serialize_section( CFG_SERIALIZER* s, CFG_NODE *n ) {
CFG_SECTION* sec = (CFG_SECTION*)n;
+ STR buf;
if( sec->parent ) {
- serialize_node( s, n, buf );
- strcat( buf, " {\n" );
+ buf += serialize_node( s, n );
+ buf += " {\n";
s->tabc++;
}
- char line[8192];
for( U32 i = 0; i < sec->children.size; ++i ) {
- line[0] = 0;
CFG_NODE* c = sec->children[i];
if( c->type == CFGT_SECTION ) {
- cfg_serialize_section( s, c, buf );
+ buf += cfg_serialize_section( s, c );
continue;
}
- cfg_types[c->type].serializer( s, c, line );
- strcat( buf, line );
- strcat( buf, "\n" );
+ buf += cfg_types[c->type].serializer( s, c );
+ buf += "\n";
}
if( sec->parent ) {
s->tabc--;
- char tabbuf[512] = { 0 };
- for( U32 i = 0 ; i < s->tabc * 2; ++i )
- tabbuf[i] = ' ';
- tabbuf[s->tabc * 2] = 0;
- strcat( buf, tabbuf );
- strcat( buf, "}" );
+ for( U32 i = 0 ; i < s->tabc * 2; ++i ) buf += ' ';
+ buf += "}";
if( sec->parent )
- strcat( buf, "\n" );
+ buf += "\n";
}
+
+ return buf;
}
-void cfg_serialize_bytes( CFG_SERIALIZER* s, CFG_NODE* n, char* buf ) {
+STR cfg_serialize_bytes( CFG_SERIALIZER* s, CFG_NODE* n ) {
CFG_BYTES* b = (CFG_BYTES*)n;
U32 size = b->size;
U8* bytes = b->bytes;
- serialize_node( s, n, buf );
- sprintf( buf, "%s[%d] = \"", buf, size );
- U32 len = strlen( buf );
+ STR buf{};
+
+ buf += serialize_node( s, n );
+ buf.fmt( "[%d] = \"", size );
for( U32 i = 0; i < size; ++i ) {
- sprintf( buf + len + i * 2, "%02X", bytes[i] );
+ buf.fmt( "%02X", bytes[i] );
}
-
- sprintf( buf, "%s%s", buf, "\";" );
+ buf += "\";";
+ return buf;
}
-void cfg_serialize_str( CFG_SERIALIZER* s, CFG_NODE* n, char *buf ) {
+STR cfg_serialize_str( CFG_SERIALIZER* s, CFG_NODE* n ) {
CFG_STR* sn = (CFG_STR*)n;
char* str = sn->str;
- serialize_node( s, n, buf );
- sprintf( buf, "%s[%d] = \"%s\";", buf, sn->len, str );
+ STR buf{};
+
+ buf += serialize_node( s, n );
+ buf.fmt( "[%d] = \"%s\";", sn->len, str );
+ return buf;
}
-void cfg_serialize_int( CFG_SERIALIZER* s, CFG_NODE* n, char *buf ) {
- CFG_INT* i = (CFG_INT*)n;
- I32 ival = i->value;
+STR cfg_serialize_int( CFG_SERIALIZER* s, CFG_NODE* n ) {
+ CFG_INT* i = (CFG_INT*)n;
+ I32 ival = i->value;
- serialize_node( s, n, buf );
- sprintf( buf, "%s = %d;", buf, ival );
+ STR buf{};
+
+ buf += serialize_node( s, n );
+ buf.fmt( " = %d;", ival );
+ return buf;
}
-void cfg_serialize_float( CFG_SERIALIZER* s, CFG_NODE* n, char *buf ) {
+STR cfg_serialize_float( CFG_SERIALIZER* s, CFG_NODE* n ) {
CFG_FLOAT* f = (CFG_FLOAT*)n;
F32 fval = f->value;
- serialize_node( s, n, buf );
- sprintf( buf, "%s = %g;", buf, fval );
+ STR buf{};
+
+ buf += serialize_node( s, n );
+ buf.fmt( " = %g;", fval );
+ return buf;
}
-void cfg_serialize_vec2( CFG_SERIALIZER* s, CFG_NODE* n, char *buf ) {
+STR cfg_serialize_vec2( CFG_SERIALIZER* s, CFG_NODE* n ) {
CFG_VEC2* v = (CFG_VEC2*)n;
VEC2 val = v->value;
- serialize_node( s, n, buf );
- sprintf( buf, "%s = { %g, %g };", buf, val.x, val.y );
+ STR buf{};
+
+ buf += serialize_node( s, n );
+ buf.fmt( " = { %g, %g };", val.x, val.y );
+ return buf;
}
-void cfg_serialize_vec3( CFG_SERIALIZER* s, CFG_NODE* n, char *buf ) {
+STR cfg_serialize_vec3( CFG_SERIALIZER* s, CFG_NODE* n ) {
CFG_VEC3* v = (CFG_VEC3*)n;
VEC3 val = v->value;
- serialize_node( s, n, buf );
- sprintf( buf, "%s = { %g, %g, %g };", buf, val.x, val.y, val.z );
+ STR buf{};
+
+ buf += serialize_node( s, n );
+ buf.fmt( " = { %g, %g, %g };", val.x, val.y, val.z );
+ return buf;
}
-void cfg_serialize_clr( CFG_SERIALIZER* s, CFG_NODE* n, char *buf ) {
+STR cfg_serialize_clr( CFG_SERIALIZER* s, CFG_NODE* n ) {
CFG_CLR* v = (CFG_CLR*)n;
CLR val = v->value;
- serialize_node( s, n, buf );
- sprintf( buf, "%s = { %g, %g, %g, %g };", buf, val.r, val.g, val.b, val.a );
+ STR buf{};
+
+ buf += serialize_node( s, n );
+ buf.fmt( " = { %g, %g, %g, %g };", val.r, val.g, val.b, val.a );
+ return buf;
}
diff --git a/src/util/file.h b/src/util/file.h
index e19a390..769d8b7 100644
--- a/src/util/file.h
+++ b/src/util/file.h
@@ -1,7 +1,7 @@
#pragma once
-#include <cstdlib>
-#include <cstring>
+#include <stdlib.h>
+#include <string.h>
#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
diff --git a/src/util/input.h b/src/util/input.h
index 1317f94..af5e258 100644
--- a/src/util/input.h
+++ b/src/util/input.h
@@ -1,7 +1,6 @@
#pragma once
#include <SDL_events.h>
-#include <functional>
#include "vector.h"
#include "allocator.h"
@@ -33,7 +32,7 @@ struct INPUT_KEYBINDS {
U8 crouch = SDL_SCANCODE_LCTRL;
};
-using ON_INPUT_FN = std::function<void( SDL_Event* )>;
+using ON_INPUT_FN = FN<void( SDL_Event* )>;
struct INPUT_DATA {
MOUSE_DATA mouse;
diff --git a/src/util/str_tokenizer.h b/src/util/str_tokenizer.h
new file mode 100644
index 0000000..f316104
--- /dev/null
+++ b/src/util/str_tokenizer.h
@@ -0,0 +1,114 @@
+#pragma once
+
+#include "string.h"
+
+using TOKENIZER_COMPARE_FN = FN<U8( char )>;
+
+struct STR_TOKENIZER {
+ STR str;
+ STR ignored;
+
+ I32 cur;
+ I32 last;
+};
+
+inline STR_TOKENIZER tok_init( STR str, STR whitespace_chars = " \t\n\r" ) {
+ return {
+ .str = str,
+ .ignored = { whitespace_chars },
+ .cur = 0,
+ .last = 0,
+ };
+}
+
+inline STR tok_next( STR_TOKENIZER* t ) {
+ if( t->cur >= t->str.size )
+ return "";
+
+ U8 start = 0;
+ for( I32 i = t->cur; i < t->str.size; i++ ) {
+ U8 c = t->str.data[i];
+ if( i == t->str.size - 1 ) {
+ if( !start )
+ return "";
+
+ STR ret = { (U32)i - t->cur + 1, t->str.data + t->cur };
+ t->last = t->cur;
+ t->cur = i + 1;
+ return ret;
+ }
+
+ for( auto& it : t->ignored ) {
+ if( c == it ) {
+ if( !start ) {
+ t->cur = i + 1;
+ continue;
+ } else {
+ STR ret = { (U32)i - t->cur, t->str.data + t->cur };
+ t->last = t->cur;
+ t->cur = i + 1;
+ return ret;
+ }
+ }
+ }
+
+ start = 1;
+ }
+
+ return "";
+}
+
+inline STR tok_peek( STR_TOKENIZER *t ) {
+ if( t->cur >= t->str.size )
+ return "";
+
+ U8 start = 0;
+ I32 cur = t->cur;
+ for( I32 i = cur; i < t->str.size; i++ ) {
+ U8 c = t->str.data[i];
+ if( i == t->str.size - 1 ) {
+ if( !start )
+ return "";
+
+ STR ret = { (U32)i - cur + 1, t->str.data + cur };
+ return ret;
+ }
+
+ for( auto& it : t->ignored ) {
+ if( c == it ) {
+ if( !start ) {
+ cur = i + 1;
+ continue;
+ } else {
+ STR ret = { (U32)i - cur, t->str.data + cur };
+ return ret;
+ }
+ }
+ }
+
+ start = 1;
+ }
+
+ return "";
+}
+
+
+inline STR tok_next( STR_TOKENIZER *t, STR what ) {
+ if( t->cur >= t->str.size )
+ return "";
+
+ if( !what.size )
+ return "";
+
+ for( I32 i = t->cur; i <= t->str.size - what.size; i++ ) {
+ STR slice = { what.size, t->str.data + i };
+ if( slice == what ) {
+ STR ret = { (U32)i - t->cur, t->str.data + i + what.size };
+ t->last = t->cur;
+ t->cur = i + what.size;
+ return ret;
+ }
+ }
+
+ return "";
+}
diff --git a/src/util/string.h b/src/util/string.h
index 6d44b53..7dfab69 100644
--- a/src/util/string.h
+++ b/src/util/string.h
@@ -54,23 +54,19 @@ struct ARRSTR {
template <typename CT>
struct __str : public LIST<CT> {
__str() : LIST<CT>() {}
- __str( U32 count, const CT* str ) {
- this->data = 0;
- this->capacity = this->size = 0;
+ __str( U32 count, const CT* str ) : LIST<CT>() {
this->reserve( count * 2 );
memcpy( this->data, str, count );
this->size = count;
this->data[this->size] = 0;
}
- __str( const CT* fmt, ... ) {
+ __str( const CT* fmt, ... ) : LIST<CT>() {
va_list args;
va_start( args, fmt );
va_list args2;
va_copy( args2, args );
U32 c = vsnprintf( 0, 0, fmt, args );
va_end( args );
- this->data = 0;
- this->capacity = this->size = 0;
this->reserve( c * 2 );
vsnprintf( this->data, c + 1, fmt, args2 );
this->data[c] = 0;
@@ -89,8 +85,6 @@ struct __str : public LIST<CT> {
if( this->data && this->data != other.data )
free( this->data );
- this->data = 0;
-
if( !other.capacity || !other.size ) {
this->capacity = 1;
this->size = 0;
@@ -116,8 +110,9 @@ struct __str : public LIST<CT> {
__str<CT> operator+( const CT rhs ) { __str<CT> ret = *this; ret.push( rhs ); return ret; }
__str<CT>& operator+=( const __str<CT>& rhs ) { return this->append( rhs ); }
__str<CT>& operator+=( const CT* rhs ) { return this->append( rhs ); }
- __str<CT>& operator+=( const CT rhs ) { this->push( rhs ); return this; }
+ __str<CT>& operator+=( const CT rhs ) { this->push( rhs ); return *this; }
+ operator const CT*() { return this->data; }
operator CT*() { return this->data; }
CT operator[]( U32 i ) {
@@ -128,10 +123,8 @@ struct __str : public LIST<CT> {
if( rhs.size != this->size )
return 0;
- for( U32 i = 0; i < this->size; ++i ) {
- if( this->data[i] != rhs.data[i] )
- return 0;
- }
+ if( !!memcmp( this->data, rhs.data, this->size ) )
+ return 0;
return 1;
}
@@ -165,7 +158,7 @@ struct __str : public LIST<CT> {
__str<CT>& append( const CT* str ) {
U32 len;
for( len = 0; !!str[len]; ++len );
- if( this->size + len + 1 > this->capacity )
+ if( this->size + len + 1 >= this->capacity )
this->reserve( this->size + len + 1 );
memcpy( this->data + this->size, str, len * sizeof(CT) );
@@ -179,7 +172,7 @@ struct __str : public LIST<CT> {
if( this->size + len + 1 >= this->capacity )
this->reserve( this->size + len + 1 );
- memcpy( this->data + this->size, str, len * sizeof(CT) );
+ memcpy( this->data + this->size, str.data, len * sizeof(CT) );
this->size += len;
this->data[this->size] = 0;
return *this;