• R/O
  • SSH
  • HTTPS

eirrepo: Commit


Commit MetaInfo

Revision126 (tree)
Time2018-09-12 21:10:11
Authorquiret

Log Message

- added object allocator concept to Eir SDK
- added object allocator support for eir::String and eir::Vector

it is pretty ugly because C++ does not support static_if. I am not pleased with the future idea of "Plugin Error: Load Denied: no_unique_address" because that fucking thing is an optional attribute, NOT an enforcement!

Change Summary

Incremental Difference

--- common/sdk/DynamicTypeSystem.h (revision 125)
+++ common/sdk/DynamicTypeSystem.h (revision 126)
@@ -17,6 +17,7 @@
1717 #include "MemoryUtils.h"
1818
1919 #include "String.h"
20+#include "MetaHelpers.h"
2021
2122 // Memory allocation for boot-strapping.
2223 template <typename structType, typename allocatorType, typename... Args>
--- common/sdk/Map.h (revision 125)
+++ common/sdk/Map.h (revision 126)
@@ -20,8 +20,12 @@
2020
2121 #include "eirutils.h"
2222 #include "MacroUtils.h"
23+#include "MetaHelpers.h"
24+
2325 #include "AVLTree.h"
2426
27+// TODO: add object allocator support for eir::Map.
28+
2529 namespace eir
2630 {
2731
@@ -28,6 +32,9 @@
2832 template <typename keyType, typename valueType, typename allocatorType>
2933 struct Map
3034 {
35+ // Make templates friends of each-other.
36+ template <typename, typename, typename> friend struct Map;
37+
3138 // Node inside this Map.
3239 struct Node
3340 {
--- common/sdk/MetaHelpers.h (revision 125)
+++ common/sdk/MetaHelpers.h (revision 126)
@@ -42,4 +42,50 @@
4242
4343 #define INSTANCE_METHCHECK( methName ) INSTANCE_METHCHECKEX( methName, methName )
4444
45+// Check if a class has a specific field.
46+#define INSTANCE_FIELDCHECK( fieldName ) \
47+ template <typename T, typename = int> \
48+ struct hasField_##fieldName : std::false_type { }; \
49+ template <typename T> \
50+ struct hasField_##fieldName <T, decltype((void) T::fieldName, 0)> : std::true_type { };
51+
52+#define PERFORM_FIELDCHECK( className, fieldName ) ( hasField_##fieldName <className>::value )
53+
54+#define INSTANCE_SUBSTRUCTCHECK( subStructName ) \
55+ template <typename T, typename = int> \
56+ struct hasSubStruct_##subStructName : std::false_type { }; \
57+ template <typename T> \
58+ struct hasSubStruct_##subStructName <T, decltype(T::subStructName(), 0)> : std::true_type { };
59+
60+#define PERFORM_SUBSTRUCTCHECK( className, subStructName ) ( hasSubStruct_##subStructName <className>::value )
61+
62+// Providing the everything-purpose standard allocator pattern in the Eir SDK!
63+// We want a common setup where the link to the DynamicTypeSystem (DTS) is fixed to the position of the DTS.
64+#define DEFINE_HEAP_REDIR_ALLOC( allocTypeName ) \
65+ struct allocTypeName \
66+ { \
67+ static inline void* Allocate( void *refMem, size_t memSize, size_t alignment ); \
68+ static inline bool Resize( void *refMem, void *objMem, size_t reqNewSize ); \
69+ static inline void Free( void *refMem, void *memPtr ); \
70+ };
71+
72+// This thing assumes that the object pointed at by allocNode is of type "NativeHeapAllocator",
73+// but you may of course implement your own thing that has the same semantics.
74+#define IMPL_HEAP_REDIR_ALLOC( allocTypeName, hostStructTypeName, redirNode, allocNode ) \
75+ void* allocTypeName::Allocate( void *refMem, size_t memSize, size_t alignment ) \
76+ { \
77+ hostStructTypeName *hostStruct = LIST_GETITEM( hostStructTypeName, refMem, redirNode ); \
78+ return hostStruct->allocNode.Allocate( memSize, alignment ); \
79+ } \
80+ bool allocTypeName::Resize( void *refMem, void *objMem, size_t reqNewSize ) \
81+ { \
82+ hostStructTypeName *hostStruct = LIST_GETITEM( hostStructTypeName, refMem, redirNode ); \
83+ return hostStruct->allocNode.SetAllocationSize( objMem, reqNewSize ); \
84+ } \
85+ void allocTypeName::Free( void *refMem, void *memPtr ) \
86+ { \
87+ hostStructTypeName *hostStruct = LIST_GETITEM( hostStructTypeName, refMem, redirNode ); \
88+ hostStruct->allocNode.Free( memPtr ); \
89+ }
90+
4591 #endif //_COMMON_META_PROGRAMMING_HELPERS_
\ No newline at end of file
--- common/sdk/String.h (revision 125)
+++ common/sdk/String.h (revision 126)
@@ -21,6 +21,7 @@
2121 #include "eirutils.h"
2222 #include "MacroUtils.h"
2323 #include "DataUtil.h"
24+#include "MetaHelpers.h"
2425
2526 #include <type_traits>
2627
@@ -30,18 +31,29 @@
3031 template <typename charType, typename allocatorType>
3132 struct String
3233 {
34+ // TODO: think about copying the allocator aswell, when a copy-assignment is being done.
35+
36+ // Make sure that templates are friends of each-other.
37+ template <typename, typename> friend struct String;
38+
3339 // When we talk about characters in this object we actually mean code-points that historically
3440 // were single characters but became redundant as single characters after the invention of
3541 // UTF-8 and other multi-codepoint encodings for internationalization.
3642
3743 // Characters should be a trivial type, meaning that it does not throw exceptions and stuff when
38- // copying or assigning.
44+ // copying or assigning. It also does use the default constructor.
3945 static_assert( std::is_trivial <charType>::value == true, "eir::String charType has to be of trivial type" );
4046
47+private:
48+ INSTANCE_SUBSTRUCTCHECK( is_object );
49+
50+ static constexpr bool hasObjectAllocator = PERFORM_SUBSTRUCTCHECK( allocatorType, is_object );
51+
52+public:
4153 inline String( void )
4254 {
43- this->char_data = "";
44- this->num_chars = 0;
55+ this->data.char_data = "";
56+ this->data.num_chars = 0;
4557 }
4658
4759 private:
@@ -49,14 +61,14 @@
4961 {
5062 if ( initCharCount == 0 )
5163 {
52- this->char_data = "";
53- this->num_chars = 0;
64+ this->data.char_data = "";
65+ this->data.num_chars = 0;
5466 }
5567 else
5668 {
5769 size_t copyCharSize = sizeof(charType) * ( initCharCount + 1 );
5870
59- charType *charBuf = (charType*)allocatorType::Allocate( this, copyCharSize, alignof(charType) );
71+ charType *charBuf = (charType*)this->data.allocData.Allocate( this, copyCharSize, alignof(charType) );
6072
6173 if ( charBuf == nullptr )
6274 {
@@ -72,23 +84,24 @@
7284 *( charBuf + initCharCount ) = charType();
7385
7486 // We take the data.
75- this->char_data = charBuf;
76- this->num_chars = initCharCount;
87+ this->data.char_data = charBuf;
88+ this->data.num_chars = initCharCount;
7789 }
7890 }
7991 }
8092
8193 // Helper logic.
82- static AINLINE void free_old_buffer( void *objMem, charType *oldChars, size_t oldCharCount, bool isNewBuf )
94+ static AINLINE void free_old_buffer( String *refMem, charType *oldChars, size_t oldCharCount, bool isNewBuf )
8395 {
8496 if ( isNewBuf && oldCharCount > 0 )
8597 {
86- allocatorType::Free( objMem, oldChars );
98+ refMem->data.allocData.Free( refMem, oldChars );
8799 }
88100 }
89101
90102 public:
91- inline String( const charType *initChars, size_t initCharCount )
103+ template <typename... Args>
104+ inline String( const charType *initChars, size_t initCharCount, Args... allocArgs ) : data( 0, std::forward <Args> ( allocArgs )... )
92105 {
93106 initialize_with( initChars, initCharCount );
94107 }
@@ -100,31 +113,38 @@
100113 initialize_with( initChars, initCharCount );
101114 }
102115
103- inline String( const String& right )
116+ inline String( const String& right ) : data( right.data )
104117 {
105118 // Simply create a copy.
106- size_t copyCharCount = right.num_chars;
107- const charType *src_data = right.char_data;
119+ size_t copyCharCount = right.data.num_chars;
120+ const charType *src_data = right.data.char_data;
108121
109122 initialize_with( src_data, copyCharCount );
110123 }
111124
112- inline String( String&& right )
125+ template <typename otherAllocatorType>
126+ inline String( const String <charType, otherAllocatorType>& right )
113127 {
114- this->char_data = right.char_data;
115- this->num_chars = right.num_chars;
128+ // Simply create a copy.
129+ size_t copyCharCount = right.data.num_chars;
130+ const charType *src_data = right.data.char_data;
116131
117- right.char_data = "";
118- right.num_chars = 0;
132+ initialize_with( src_data, copyCharCount );
119133 }
120134
135+ inline String( String&& right ) : data( std::move( right.data ) )
136+ {
137+ this->data.char_data = right.data.char_data;
138+ this->data.num_chars = right.data.num_chars;
139+
140+ right.data.char_data = "";
141+ right.data.num_chars = 0;
142+ }
143+
121144 private:
122145 AINLINE void release_data( void )
123146 {
124- if ( this->num_chars > 0 )
125- {
126- allocatorType::Free( this, this->char_data );
127- }
147+ free_old_buffer( this, this->data.char_data, this->data.num_chars, true );
128148 }
129149
130150 public:
@@ -134,7 +154,7 @@
134154 }
135155
136156 private:
137- AINLINE static void expand_buffer( void *objMem, charType *oldCharBuf, size_t oldCharCount, size_t oldCharCopyCount, size_t newCharCount, charType*& useBufOut, bool& isBufNewOut )
157+ AINLINE static void expand_buffer( String *refMem, charType *oldCharBuf, size_t oldCharCount, size_t oldCharCopyCount, size_t newCharCount, charType*& useBufOut, bool& isBufNewOut )
138158 {
139159 size_t newRequiredCharsSize = sizeof(charType) * ( newCharCount + 1 );
140160
@@ -143,7 +163,7 @@
143163
144164 if ( oldCharBuf && oldCharCount > 0 )
145165 {
146- bool couldResize = allocatorType::Resize( objMem, oldCharBuf, newRequiredCharsSize );
166+ bool couldResize = refMem->data.allocData.Resize( refMem, oldCharBuf, newRequiredCharsSize );
147167
148168 if ( couldResize )
149169 {
@@ -154,7 +174,7 @@
154174
155175 if ( useBuf == nullptr )
156176 {
157- useBuf = (charType*)allocatorType::Allocate( objMem, newRequiredCharsSize, alignof(charType) );
177+ useBuf = (charType*)refMem->data.allocData.Allocate( refMem, newRequiredCharsSize, alignof(charType) );
158178
159179 if ( useBuf == nullptr )
160180 {
@@ -185,7 +205,7 @@
185205 {
186206 this->release_data();
187207
188- this->char_data = "";
208+ this->data.char_data = "";
189209 }
190210 else
191211 {
@@ -195,8 +215,8 @@
195215 charType *useBuf = nullptr;
196216 bool isBufNew;
197217
198- charType *oldCharBuf = this->char_data;
199- size_t oldCharCount = this->num_chars;
218+ charType *oldCharBuf = this->data.char_data;
219+ size_t oldCharCount = this->data.num_chars;
200220
201221 expand_buffer( this, oldCharBuf, oldCharCount, 0, copyCharCount, useBuf, isBufNew );
202222
@@ -210,20 +230,28 @@
210230 // Take over the buff.
211231 free_old_buffer( this, oldCharBuf, oldCharCount, isBufNew );
212232
213- this->char_data = useBuf;
233+ this->data.char_data = useBuf;
214234 }
215235 }
216236
217- this->num_chars = copyCharCount;
237+ this->data.num_chars = copyCharCount;
218238 }
219239
220240 inline String& operator = ( const String& right )
221241 {
222- this->Assign( right.char_data, right.num_chars );
242+ this->Assign( right.data.char_data, right.data.num_chars );
223243
224244 return *this;
225245 }
226246
247+ template <typename otherAllocatorType>
248+ inline String& operator = ( const String <charType, otherAllocatorType>& right )
249+ {
250+ this->Assign( right.data.char_data, right.data.num_chars );
251+
252+ return *this;
253+ }
254+
227255 inline String& operator = ( const charType *rightChars )
228256 {
229257 this->Assign( rightChars, cplen_tozero( rightChars ) );
@@ -231,14 +259,21 @@
231259 return *this;
232260 }
233261
262+ // WARNING: only move if allocator stays the same!
234263 inline String& operator = ( String&& right )
235264 {
236- this->char_data = right.char_data;
237- this->num_chars = right.num_chars;
265+ // Delete previous string.
266+ free_old_buffer( this, this->data.char_data, this->data.num_chars, true );
238267
239- right.char_data = "";
240- right.num_chars = 0;
268+ // Move over allocator if needed.
269+ this->data = std::move( right.data );
241270
271+ this->data.char_data = right.data.char_data;
272+ this->data.num_chars = right.data.num_chars;
273+
274+ right.data.char_data = "";
275+ right.data.num_chars = 0;
276+
242277 return *this;
243278 }
244279
@@ -249,13 +284,13 @@
249284 if ( charsToAppendCount == 0 )
250285 return;
251286
252- size_t num_chars = this->num_chars;
287+ size_t num_chars = this->data.num_chars;
253288
254289 // Calculate how long the new string has to be.
255290 size_t newCharCount = ( num_chars + charsToAppendCount );
256291
257292 // Allocate the new buffer.
258- charType *oldCharBuf = this->char_data;
293+ charType *oldCharBuf = this->data.char_data;
259294
260295 charType *useBuf;
261296 bool isBufNew;
@@ -274,8 +309,8 @@
274309 // Take over the new buffer.
275310 free_old_buffer( this, oldCharBuf, num_chars, isBufNew );
276311
277- this->char_data = useBuf;
278- this->num_chars = newCharCount;
312+ this->data.char_data = useBuf;
313+ this->data.num_chars = newCharCount;
279314 }
280315 }
281316
@@ -286,8 +321,8 @@
286321 return;
287322
288323 // Expand the memory as required.
289- size_t oldCharCount = this->num_chars;
290- charType *oldCharBuf = this->char_data;
324+ size_t oldCharCount = this->data.num_chars;
325+ charType *oldCharBuf = this->data.char_data;
291326
292327 // If the insertion position is after the string size, then we clamp the insertion
293328 // position to the size.
@@ -324,8 +359,8 @@
324359 // Take over the new stuff.
325360 free_old_buffer( this, oldCharBuf, oldCharCount, isBufNew );
326361
327- this->char_data = useBuf;
328- this->num_chars = newCharCount;
362+ this->data.char_data = useBuf;
363+ this->data.num_chars = newCharCount;
329364 }
330365 }
331366
@@ -334,13 +369,13 @@
334369 // Use other algorithms if you need an case-insensitive comparison because it is complicated (UniChar.h).
335370 inline bool equals( const charType *compareWith, size_t compareWithCount ) const
336371 {
337- size_t num_chars = this->num_chars;
372+ size_t num_chars = this->data.num_chars;
338373
339374 if ( num_chars != compareWithCount )
340375 return false;
341376
342377 // Do we find any codepoint that does not match?
343- const charType *leftChars = this->char_data;
378+ const charType *leftChars = this->data.char_data;
344379
345380 for ( size_t n = 0; n < num_chars; n++ )
346381 {
@@ -364,12 +399,12 @@
364399
365400 inline size_t GetLength( void ) const
366401 {
367- return this->num_chars;
402+ return this->data.num_chars;
368403 }
369404
370405 inline const charType* GetConstString( void ) const
371406 {
372- return this->char_data;
407+ return this->data.char_data;
373408 }
374409
375410 // Helpful operator overrides.
@@ -390,9 +425,10 @@
390425 return *this;
391426 }
392427
393- inline String& operator += ( const String& right )
428+ template <typename otherAllocatorType>
429+ inline String& operator += ( const String <charType, otherAllocatorType>& right )
394430 {
395- this->Append( right.char_data, right.num_chars );
431+ this->Append( right.data.char_data, right.data.num_chars );
396432
397433 return *this;
398434 }
@@ -415,7 +451,8 @@
415451 return newString;
416452 }
417453
418- inline String operator + ( const String& right )
454+ template <typename otherAllocatorType>
455+ inline String operator + ( const String <charType, otherAllocatorType>& right )
419456 {
420457 String newString( *this );
421458
@@ -429,9 +466,10 @@
429466 return this->equals( someChars, cplen_tozero( someChars ) );
430467 }
431468
432- inline bool operator == ( const String& right ) const
469+ template <typename otherAllocatorType>
470+ inline bool operator == ( const String <charType, otherAllocatorType>& right ) const
433471 {
434- return this->equals( right.char_data, right.num_chars );
472+ return this->equals( right.data.char_data, right.data.num_chars );
435473 }
436474
437475 inline bool operator != ( const charType *someChars ) const
@@ -439,7 +477,8 @@
439477 return !( operator == ( someChars ) );
440478 }
441479
442- inline bool operator != ( const String& right ) const
480+ template <typename otherAllocatorType>
481+ inline bool operator != ( const String <charType, otherAllocatorType>& right ) const
443482 {
444483 return !( operator == ( right ) );
445484 }
@@ -448,8 +487,15 @@
448487 // sense with case-insensitive functionality added.
449488
450489 private:
451- charType *char_data;
452- size_t num_chars;
490+ // The actual members of the String object.
491+ // Only time will tell if they'll include static_if.
492+ struct fields
493+ {
494+ charType *char_data;
495+ size_t num_chars;
496+ };
497+
498+ size_opt <hasObjectAllocator, allocatorType, fields> data;
453499 };
454500
455501 }
--- common/sdk/Vector.h (revision 125)
+++ common/sdk/Vector.h (revision 126)
@@ -20,6 +20,7 @@
2020
2121 #include "eirutils.h"
2222 #include "MacroUtils.h"
23+#include "MetaHelpers.h"
2324
2425 #include <algorithm>
2526 #include <assert.h>
@@ -30,33 +31,48 @@
3031 template <typename structType, typename allocatorType>
3132 struct Vector
3233 {
34+ // Make sure that templates are friends of each-other.
35+ template <typename, typename> friend struct Vector;
36+
3337 inline Vector( void )
3438 {
35- this->data_entries = nullptr;
36- this->data_count = 0;
39+ this->data.data_entries = nullptr;
40+ this->data.data_count = 0;
3741 }
3842
3943 private:
40- static AINLINE structType* make_data_copy( void *objPtr, const structType *right_data, size_t right_count )
44+ static AINLINE structType* make_data_copy( Vector *refPtr, const structType *right_data, size_t right_count )
4145 {
42- structType *data_entries = (structType*)allocatorType::Allocate( objPtr, right_count * sizeof(structType), alignof(structType) );
46+ structType *data_entries = (structType*)refPtr->data.allocData.Allocate( refPtr, right_count * sizeof(structType), alignof(structType) );
4347
4448 if ( data_entries == nullptr )
4549 {
4650 throw eir_exception();
4751 }
48-
52+
53+ size_t cur_idx = 0;
54+
4955 try
5056 {
51- for ( size_t n = 0; n < right_count; n++ )
57+ while ( cur_idx < right_count )
5258 {
53- new ( data_entries + n ) structType( right_data[n] );
59+ new ( data_entries + cur_idx ) structType( right_data[cur_idx] );
60+
61+ cur_idx++;
5462 }
5563 }
5664 catch( ... )
5765 {
58- allocatorType::Free( objPtr, data_entries );
66+ // Destroy all constructed items again.
67+ while ( cur_idx > 0 )
68+ {
69+ cur_idx--;
5970
71+ ( data_entries + cur_idx )->~structType();
72+ }
73+
74+ refPtr->data.allocData.Free( refPtr, data_entries );
75+
6076 throw;
6177 }
6278
@@ -63,35 +79,59 @@
6379 return data_entries;
6480 }
6581
66-public:
67- inline Vector( const Vector& right )
82+ AINLINE void initialize_with( const structType *data, size_t data_count )
6883 {
69- size_t right_count = right.data_count;
70- structType *data_entries = nullptr;
84+ structType *our_data_entries = nullptr;
7185
72- if ( right_count > 0 )
86+ if ( data_count > 0 )
7387 {
74- structType *right_data = right.data_entries;
75-
76- data_entries = make_data_copy( this, right_data, right_count );
88+ our_data_entries = make_data_copy( this, data, data_count );
7789 }
7890
79- this->data_entries = data_entries;
80- this->data_count = right_count;
91+ this->data.data_entries = our_data_entries;
92+ this->data.data_count = data_count;
8193 }
8294
95+ INSTANCE_SUBSTRUCTCHECK( is_object );
96+
97+ static constexpr bool hasObjectAllocator = PERFORM_SUBSTRUCTCHECK( allocatorType, is_object );
98+
99+public:
100+ template <typename... Args>
101+ inline Vector( const structType *data, size_t data_count, Args... allocArgs ) : data( 0, std::forward <Args> ( allocArgs )... )
102+ {
103+ initialize_with( data, data_count );
104+ }
105+
106+ inline Vector( const Vector& right ) : data( right.data )
107+ {
108+ size_t right_count = right.data.data_count;
109+ structType *right_data = right.data.data_entries;
110+
111+ initialize_with( right_data, right_count );
112+ }
113+
114+ template <typename otherAllocatorType>
115+ inline Vector( const Vector <structType, otherAllocatorType>& right )
116+ {
117+ size_t right_count = right.data.data_count;
118+ structType *right_data = right.data.data_entries;
119+
120+ initialize_with( right_data, right_count );
121+ }
122+
83123 // WARNING: only move if allocator stays the same.
84- inline Vector( Vector&& right )
124+ inline Vector( Vector&& right ) : data( std::move( right.data ) )
85125 {
86- this->data_entries = right.data_entries;
87- this->data_count = right.data_count;
126+ this->data.data_entries = right.data.data_entries;
127+ this->data.data_count = right.data.data_count;
88128
89- right.data_entries = nullptr;
90- right.data_count = 0;
129+ right.data.data_entries = nullptr;
130+ right.data.data_count = 0;
91131 }
92132
93133 private:
94- static AINLINE void release_data( void *objPtr, structType *data_entries, size_t data_count )
134+ static AINLINE void release_data( Vector *refPtr, structType *data_entries, size_t data_count )
95135 {
96136 if ( data_entries )
97137 {
@@ -100,7 +140,7 @@
100140 data_entries[n].~structType();
101141 }
102142
103- allocatorType::Free( objPtr, data_entries );
143+ refPtr->data.allocData.Free( refPtr, data_entries );
104144 }
105145 }
106146
@@ -107,40 +147,63 @@
107147 public:
108148 inline ~Vector( void )
109149 {
110- release_data( this, this->data_entries, this->data_count );
150+ release_data( this, this->data.data_entries, this->data.data_count );
111151 }
112152
113153 inline Vector& operator = ( const Vector& right )
114154 {
115- size_t right_count = right.data_count;
155+ size_t right_count = right.data.data_count;
116156 structType *new_data_entries = nullptr;
117157
118158 if ( right_count > 0 )
119159 {
120- new_data_entries = make_data_copy( this, right.data_entries, right_count );
160+ new_data_entries = make_data_copy( this, right.data.data_entries, right_count );
121161 }
122162
123163 // Swap old with new.
124- release_data( this, this->data_entries, this->data_count );
164+ release_data( this, this->data.data_entries, this->data.data_count );
125165
126- this->data_entries = new_data_entries;
127- this->data_count = right_count;
166+ this->data.data_entries = new_data_entries;
167+ this->data.data_count = right_count;
128168
129169 return *this;
130170 }
131171
172+ template <typename otherAllocatorType>
173+ inline Vector& operator = ( const Vector <structType, otherAllocatorType>& right )
174+ {
175+ size_t right_count = right.data.data_count;
176+ structType *new_data_entries = nullptr;
177+
178+ if ( right_count > 0 )
179+ {
180+ new_data_entries = make_data_copy( this, right.data.data_entries, right_count );
181+ }
182+
183+ // Swap old with new.
184+ release_data( this, this->data.data_entries, this->data.data_count );
185+
186+ this->data.data_entries = new_data_entries;
187+ this->data.data_count = right_count;
188+
189+ return *this;
190+ }
191+
132192 // WARNING: only move if allocator stays the same.
133193 inline Vector& operator = ( Vector&& right )
134194 {
135195 // Release our previous data.
136- release_data( this, this->data_entries, this->data_count );
196+ release_data( this, this->data.data_entries, this->data.data_count );
137197
138- this->data_entries = right.data_entries;
139- this->data_count = right.data_count;
198+ // Move over allocator, if needed.
199+ this->data = std::move( right.data );
140200
141- right.data_entries = nullptr;
142- right.data_count = 0;
201+ this->data.data_entries = right.data.data_entries;
202+ this->data.data_count = right.data.data_count;
143203
204+ right.data.data_entries = nullptr;
205+ right.data.data_count = 0;
206+
144207 return *this;
145208 }
146209
@@ -149,7 +212,7 @@
149212 AINLINE void recast_memory( size_t new_item_count, size_t newRequiredSize, const callbackType& cb )
150213 {
151214 // Try to fetch new memory.
152- void *new_data_ptr = allocatorType::Allocate( this, newRequiredSize, alignof(structType) );
215+ void *new_data_ptr = this->data.allocData.Allocate( this, newRequiredSize, alignof(structType) );
153216
154217 if ( new_data_ptr == nullptr )
155218 {
@@ -157,8 +220,8 @@
157220 }
158221
159222 // Construct the memory.
160- size_t old_count = this->data_count;
161- structType *old_data = this->data_entries;
223+ size_t old_count = this->data.data_count;
224+ structType *old_data = this->data.data_entries;
162225
163226 size_t moved_idx = 0;
164227
@@ -186,11 +249,18 @@
186249 {
187250 moved_idx--;
188251
189-
252+ if ( moved_idx < old_count )
253+ {
254+ *( old_data + moved_idx ) = std::move( *( (structType*)new_data_ptr + moved_idx ) );
255+ }
256+ else
257+ {
258+ ( old_data + moved_idx )->~structType();
259+ }
190260 }
191261
192262 // We do not add the item to our array, so clean-up.
193- allocatorType::Free( this, new_data_ptr );
263+ this->data.allocData.Free( this, new_data_ptr );
194264
195265 throw;
196266 }
@@ -201,8 +271,8 @@
201271 release_data( this, old_data, old_count );
202272 }
203273
204- this->data_entries = (structType*)new_data_ptr;
205- this->data_count = new_item_count;
274+ this->data.data_entries = (structType*)new_data_ptr;
275+ this->data.data_count = new_item_count;
206276 }
207277
208278 public:
@@ -209,13 +279,13 @@
209279 // Simple modification methods.
210280 inline void AddToBack( const structType& item )
211281 {
212- size_t oldCount = ( this->data_count );
282+ size_t oldCount = ( this->data.data_count );
213283 size_t newCount = ( oldCount + 1 );
214284 size_t newRequiredSize = newCount * sizeof(structType);
215285
216- if ( structType *use_data = this->data_entries )
286+ if ( structType *use_data = this->data.data_entries )
217287 {
218- bool gotToResize = allocatorType::Resize( this, use_data, newRequiredSize );
288+ bool gotToResize = this->data.allocData.Resize( this, use_data, newRequiredSize );
219289
220290 if ( gotToResize )
221291 {
@@ -222,7 +292,7 @@
222292 // We just have to add at back.
223293 new ( use_data + oldCount ) structType( item );
224294
225- this->data_count = newCount;
295+ this->data.data_count = newCount;
226296
227297 return;
228298 }
@@ -244,7 +314,7 @@
244314
245315 inline void RemoveFromBack( void )
246316 {
247- size_t oldCount = this->data_count;
317+ size_t oldCount = this->data.data_count;
248318
249319 if ( oldCount == 0 )
250320 return;
@@ -252,39 +322,39 @@
252322 size_t newCount = ( oldCount - 1 );
253323
254324 // We can always shrink memory, so go for it.
255- structType *use_data = this->data_entries;
325+ structType *use_data = this->data.data_entries;
256326
257327 use_data[ newCount ].~structType();
258328
259329 if ( newCount == 0 )
260330 {
261- allocatorType::Free( this, use_data );
331+ this->data.allocData.Free( this, use_data );
262332
263333 // Gotta do this.
264- this->data_entries = nullptr;
334+ this->data.data_entries = nullptr;
265335 }
266336 else
267337 {
268- bool resizeSuccess = allocatorType::Resize( this, use_data, sizeof(structType) * newCount );
338+ bool resizeSuccess = this->data.allocData.Resize( this, use_data, sizeof(structType) * newCount );
269339
270340 assert( resizeSuccess == true );
271341 }
272342
273- this->data_count = newCount;
343+ this->data.data_count = newCount;
274344 }
275345
276346 // Removes all items from this array by release the back-end memory.
277347 inline void Clear( void )
278348 {
279- release_data( this, this->data_entries, this->data_count );
349+ release_data( this, this->data.data_entries, this->data.data_count );
280350
281- this->data_entries = nullptr;
282- this->data_count = 0;
351+ this->data.data_entries = nullptr;
352+ this->data.data_count = 0;
283353 }
284354
285355 inline size_t GetCount( void ) const
286356 {
287- return this->data_count;
357+ return this->data.data_count;
288358 }
289359
290360 // Walks all items of this object.
@@ -291,8 +361,8 @@
291361 template <typename callbackType>
292362 AINLINE void Walk( const callbackType& cb )
293363 {
294- structType *data = this->data_entries;
295- size_t num_data = this->data_count;
364+ structType *data = this->data.data_entries;
365+ size_t num_data = this->data.data_count;
296366
297367 for ( size_t n = 0; n < num_data; n++ )
298368 {
@@ -304,8 +374,8 @@
304374 template <typename callbackType>
305375 AINLINE void Walk( const callbackType& cb ) const
306376 {
307- const structType *data = this->data_entries;
308- size_t num_data = this->data_count;
377+ const structType *data = this->data.data_entries;
378+ size_t num_data = this->data.data_count;
309379
310380 for ( size_t n = 0; n < num_data; n++ )
311381 {
@@ -316,27 +386,27 @@
316386 // Indexing operators.
317387 inline structType& operator [] ( size_t idx )
318388 {
319- if ( idx >= this->data_count )
389+ if ( idx >= this->data.data_count )
320390 {
321391 throw eir_exception();
322392 }
323393
324- return this->data_entries[ idx ];
394+ return this->data.data_entries[ idx ];
325395 }
326396
327397 inline const structType& operator [] ( size_t idx ) const
328398 {
329- if ( idx >= this->data_count )
399+ if ( idx >= this->data.data_count )
330400 {
331401 throw eir_exception();
332402 }
333403
334- return this->data_entries[ idx ];
404+ return this->data.data_entries[ idx ];
335405 }
336406
337407 inline structType& GetBack( void )
338408 {
339- size_t curCount = this->data_count;
409+ size_t curCount = this->data.data_count;
340410
341411 if ( curCount == 0 )
342412 {
@@ -343,12 +413,12 @@
343413 throw eir_exception();
344414 }
345415
346- return this->data_entries[ curCount - 1 ];
416+ return this->data.data_entries[ curCount - 1 ];
347417 }
348418
349419 inline structType& GetBack( void ) const
350420 {
351- size_t curCount = this->data_count;
421+ size_t curCount = this->data.data_count;
352422
353423 if ( curCount == 0 )
354424 {
@@ -355,25 +425,29 @@
355425 throw eir_exception();
356426 }
357427
358- return this->data_entries[ curCount - 1 ];
428+ return this->data.data_entries[ curCount - 1 ];
359429 }
360430
361431 // Implement some comparison operators.
362- inline bool operator == ( const Vector& right ) const
432+ template <typename otherAllocatorType>
433+ inline bool operator == ( const Vector <structType, otherAllocatorType>& right ) const
363434 {
364- size_t leftCount = this->data_count;
365- size_t rightCount = right.data_count;
435+ size_t leftCount = this->data.data_count;
436+ size_t rightCount = right.data.data_count;
366437
367438 if ( leftCount != rightCount )
368439 return false;
369440
441+ const structType *leftData = this->data.data_entries;
442+ const structType *rightData = right.data.data_entries;
443+
370444 for ( size_t n = 0; n < leftCount; n++ )
371445 {
372- const structType& leftData = this->data_entries[ n ];
373- const structType& rightData = right.data_entries[ n ];
446+ const structType& leftDataItem = leftData[ n ];
447+ const structType& rightDataItem = rightData[ n ];
374448
375449 // Actually use the item comparator.
376- if ( leftData != rightData )
450+ if ( leftDataItem != rightDataItem )
377451 {
378452 return false;
379453 }
@@ -382,14 +456,21 @@
382456 return true;
383457 }
384458
385- inline bool operator != ( const Vector& right ) const
459+ template <typename otherAllocatorType>
460+ inline bool operator != ( const Vector <structType, otherAllocatorType>& right ) const
386461 {
387462 return !( operator == ( right ) );
388463 }
389464
390465 private:
391- structType *data_entries;
392- size_t data_count;
466+ // Need this thing as long as there is no static_if.
467+ struct fields
468+ {
469+ structType *data_entries;
470+ size_t data_count;
471+ };
472+
473+ size_opt <hasObjectAllocator, allocatorType, fields> data;
393474 };
394475
395476 }
--- common/sdk/eirutils.h (revision 125)
+++ common/sdk/eirutils.h (revision 126)
@@ -13,6 +13,10 @@
1313 #ifndef _EIR_COMMON_SDK_UTILITIES_
1414 #define _EIR_COMMON_SDK_UTILITIES_
1515
16+#include <type_traits>
17+
18+#include "MacroUtils.h"
19+
1620 // TODO: flesh out this exception stuff.
1721 struct eir_exception
1822 {
@@ -33,33 +37,81 @@
3337 return len;
3438 }
3539
36-// Providing the everything-purpose standard allocator pattern in the Eir SDK!
37-// We want a common setup where the link to the DynamicTypeSystem (DTS) is fixed to the position of the DTS.
38-#define DEFINE_HEAP_REDIR_ALLOC( allocTypeName ) \
39- struct allocTypeName \
40- { \
41- static inline void* Allocate( void *refMem, size_t memSize, size_t alignment ); \
42- static inline bool Resize( void *refMem, void *objMem, size_t reqNewSize ); \
43- static inline void Free( void *refMem, void *memPtr ); \
44- };
40+// Conditionally make an object static inline or a real member.
41+// This is there to solve the problem of zero-size structs, because static methods can be invoked same as
42+// object methods.
43+template <bool trueRealMemberFalseStaticInline, typename structType, typename fieldsStruct>
44+struct size_opt : public fieldsStruct
45+{
46+};
4547
46-// This thing assumes that the object pointed at by allocNode is of type "NativeHeapAllocator",
47-// but you may of course implemnet your own thing that has the same semantics.
48-#define IMPL_HEAP_REDIR_ALLOC( allocTypeName, hostStructTypeName, redirNode, allocNode ) \
49- void* allocTypeName::Allocate( void *refMem, size_t memSize, size_t alignment ) \
50- { \
51- hostStructTypeName *hostStruct = LIST_GETITEM( hostStructTypeName, refMem, redirNode ); \
52- return hostStruct->allocNode.Allocate( memSize, alignment ); \
53- } \
54- bool allocTypeName::Resize( void *refMem, void *objMem, size_t reqNewSize ) \
55- { \
56- hostStructTypeName *hostStruct = LIST_GETITEM( hostStructTypeName, refMem, redirNode ); \
57- return hostStruct->allocNode.SetAllocationSize( objMem, reqNewSize ); \
58- } \
59- void allocTypeName::Free( void *refMem, void *memPtr ) \
60- { \
61- hostStructTypeName *hostStruct = LIST_GETITEM( hostStructTypeName, refMem, redirNode ); \
62- hostStruct->allocNode.Free( memPtr ); \
48+template <typename structType, typename fieldsStruct>
49+struct size_opt <false, structType, fieldsStruct> : public fieldsStruct
50+{
51+ AINLINE size_opt( int )
52+ {
53+ return;
6354 }
55+ AINLINE size_opt( void )
56+ {
57+ return;
58+ }
59+ AINLINE size_opt( const size_opt& right )
60+ {
61+ return;
62+ }
63+ AINLINE size_opt( size_opt&& right )
64+ {
65+ return;
66+ }
6467
68+ AINLINE size_opt& operator = ( const size_opt& right )
69+ {
70+ return *this;
71+ }
72+ AINLINE size_opt& operator = ( size_opt&& right )
73+ {
74+ return *this;
75+ }
76+
77+ inline static structType allocData;
78+};
79+
80+template <typename structType, typename fieldsStruct>
81+struct size_opt <true, structType, fieldsStruct> : public fieldsStruct
82+{
83+ template <typename... Args>
84+ AINLINE size_opt( int _, Args... allocArgs ) : allocData( std::forward <Args> ( allocArgs )... )
85+ {
86+ return;
87+ }
88+ AINLINE size_opt( void ) : allocData()
89+ {
90+ return;
91+ }
92+ AINLINE size_opt( const size_opt& right ) : allocData( right.allocData )
93+ {
94+ return;
95+ }
96+ AINLINE size_opt( size_opt&& right ) : allocData( std::move( right.allocData ) )
97+ {
98+ return;
99+ }
100+
101+ AINLINE size_opt& operator = ( const size_opt& right )
102+ {
103+ this->allocData = right.allocData;
104+
105+ return *this;
106+ }
107+ AINLINE size_opt& operator = ( size_opt&& right )
108+ {
109+ this->allocData = std::move( right.allocData );
110+
111+ return *this;
112+ }
113+
114+ structType allocData;
115+};
116+
65117 #endif //_EIR_COMMON_SDK_UTILITIES_
\ No newline at end of file
--- unittests/src/alloc_helper.hxx (revision 125)
+++ unittests/src/alloc_helper.hxx (revision 126)
@@ -24,4 +24,36 @@
2424 }
2525 };
2626
27+struct EirHeapLinkAllocator
28+{
29+ inline EirHeapLinkAllocator( NativeHeapAllocator *heapLink ) : heapLink( heapLink )
30+ {
31+ return;
32+ }
33+
34+ inline EirHeapLinkAllocator( const EirHeapLinkAllocator& right ) : heapLink( right.heapLink )
35+ {
36+ return;
37+ }
38+
39+ inline void* Allocate( void *refMem, size_t memSize, size_t alignment )
40+ {
41+ return this->heapLink->Allocate( memSize, alignment );
42+ }
43+
44+ inline bool Resize( void *refMem, void *memPtr, size_t reqSize )
45+ {
46+ return this->heapLink->SetAllocationSize( memPtr, reqSize );
47+ }
48+
49+ inline void Free( void *refMem, void *memPtr )
50+ {
51+ this->heapLink->Free( memPtr );
52+ }
53+
54+ NativeHeapAllocator *heapLink;
55+
56+ struct is_object {};
57+};
58+
2759 #endif //_ALLOC_HELPERS_
\ No newline at end of file
--- unittests/src/impltests.cpp (revision 125)
+++ unittests/src/impltests.cpp (revision 126)
@@ -3,7 +3,10 @@
33 #include <assert.h>
44
55 #include <type_traits>
6+#include <functional>
67
8+#include <sdk/MetaHelpers.h>
9+
710 struct class_a
811 {
912 int value = -1;
@@ -28,6 +31,48 @@
2831 return a;
2932 }
3033
34+struct empty {};
35+
36+template <bool has_e>
37+struct my_test
38+{
39+ struct with_e
40+ {
41+ empty e;
42+ int a;
43+ };
44+
45+ struct without_e
46+ {
47+ int a;
48+ };
49+
50+ typename std::conditional <has_e, with_e, without_e>::type data;
51+};
52+
53+INSTANCE_FIELDCHECK( meow );
54+INSTANCE_SUBSTRUCTCHECK( meow );
55+
56+struct cheapAllocator
57+{
58+ static void Test( void )
59+ {
60+ return;
61+ }
62+};
63+
64+struct one_allocTest
65+{
66+ int a;
67+
68+ inline static cheapAllocator alloc;
69+};
70+
71+struct two_allocTest
72+{
73+ cheapAllocator alloc;
74+};
75+
3176 void IMPLEMENTATION_TESTS( void )
3277 {
3378 // TODO.
@@ -89,4 +134,46 @@
89134
90135 static_assert( std::is_trivial <woofy>::value == true );
91136 }
137+
138+ // Check that empty structs do not increase the size of things as members, meow.
139+ {
140+ static_assert( sizeof(my_test <false>) == sizeof(int) );
141+ static_assert( sizeof(my_test <true>) == sizeof(int) * 2 );
142+ }
143+
144+ // Check that this fieldcheck stuff even works.
145+ {
146+ struct a
147+ {
148+ int miau;
149+ };
150+
151+ struct b
152+ {
153+ int meow;
154+ };
155+
156+ static_assert( PERFORM_FIELDCHECK( a, meow ) == false );
157+ static_assert( PERFORM_FIELDCHECK( b, meow ) == true );
158+
159+ struct c
160+ {
161+ struct meow
162+ {};
163+ };
164+
165+ static_assert( PERFORM_SUBSTRUCTCHECK( c, meow ) == true );
166+ static_assert( PERFORM_SUBSTRUCTCHECK( b, meow ) == false );
167+ }
168+
169+ // Testing if access through a inline static field can be same as through data member (success).
170+ {
171+ one_allocTest one;
172+ two_allocTest two;
173+
174+ one.alloc.Test();
175+ two.alloc.Test();
176+
177+ static_assert( sizeof( one_allocTest ) == sizeof(int) );
178+ }
92179 }
--- unittests/src/string.cpp (revision 125)
+++ unittests/src/string.cpp (revision 126)
@@ -144,4 +144,30 @@
144144 assert( string2 == "" );
145145 }
146146 printf( "ok.\n" );
147+
148+ printf( "testing string with custom allocator link..." );
149+ {
150+ eir::String <char, EirHeapLinkAllocator> string( nullptr, 0, &globalHeapAlloc );
151+
152+ string += "meow";
153+
154+ assert( string == "meow" );
155+
156+ StringWithHeap stringHeap( string );
157+
158+ assert( stringHeap == "meow" );
159+ assert( string == stringHeap );
160+ assert( !( string != stringHeap ) );
161+
162+ eir::String <char, EirHeapLinkAllocator> string2( string );
163+
164+ assert( string2 == string );
165+ assert( string2 == stringHeap );
166+
167+ // Need to keep size guarrantees.
168+ static_assert( sizeof(string) == sizeof(void*) + sizeof(size_t) + sizeof(void*) );
169+ static_assert( sizeof(string2) == sizeof(void*) + sizeof(size_t) + sizeof(void*) );
170+ static_assert( sizeof(stringHeap) == sizeof(void*) + sizeof(size_t) );
171+ }
172+ printf( "ok.\n" );
147173 }
\ No newline at end of file
--- unittests/src/vector.cpp (revision 125)
+++ unittests/src/vector.cpp (revision 126)
@@ -186,4 +186,31 @@
186186 });
187187 }
188188 printf( "ok.\n" );
189+
190+ printf( "testing vector with custom allocator link..." );
191+ {
192+ eir::Vector <long long, EirHeapLinkAllocator> customVec( nullptr, 0, &globalHeapAlloc );
193+
194+ customVec.AddToBack( 1 );
195+
196+ assert( customVec.GetCount() == 1 );
197+
198+ customVec.RemoveFromBack();
199+
200+ assert( customVec.GetCount() == 0 );
201+
202+ VectorWithHeap vec;
203+ vec.AddToBack( 42 );
204+
205+ customVec = vec;
206+ vec = customVec;
207+
208+ assert( vec == customVec );
209+ assert( customVec == vec );
210+
211+ eir::Vector <long long, EirHeapLinkAllocator> customVec2( customVec );
212+
213+ assert( customVec == customVec2 );
214+ }
215+ printf( "ok.\n" );
189216 }
\ No newline at end of file
Show on old repository browser