• R/O
  • SSH
  • HTTPS

eirrepo: Commit


Commit MetaInfo

Revision121 (tree)
Time2018-09-10 05:26:17
Authorquiret

Log Message

- fixed a bug in the heap allocator where it shrank the virtual memory without shrinking the associated free-space of the last free space block, causing an invalid state that would lead to access errors
- implemented the eir::String object
- added unit tests for the eir::String object
- added functionality of the native heap allocator to return the amount of bytes that are actually taken by all allocations

Change Summary

Incremental Difference

--- common/sdk/DataUtil.h (revision 120)
+++ common/sdk/DataUtil.h (revision 121)
@@ -1,6 +1,8 @@
11 #ifndef _EIRREPO_DATA_UTILITIES_
22 #define _EIRREPO_DATA_UTILITIES_
33
4+#include <type_traits>
5+
46 // Some helpers.
57 namespace FSDataUtil
68 {
@@ -7,6 +9,8 @@
79 template <typename dataType>
810 static inline void copy_impl( const dataType *srcPtr, const dataType *srcPtrEnd, dataType *dstPtr ) noexcept
911 {
12+ static_assert( std::is_trivial <dataType>::value == true );
13+
1014 while ( srcPtr != srcPtrEnd )
1115 {
1216 *dstPtr++ = *srcPtr++;
@@ -16,6 +20,8 @@
1620 template <typename dataType>
1721 static inline void copy_backward_impl( const dataType *srcPtr, const dataType *srcPtrEnd, dataType *dstPtr ) noexcept
1822 {
23+ static_assert( std::is_trivial <dataType>::value == true );
24+
1925 while ( srcPtr != srcPtrEnd )
2026 {
2127 *(--dstPtr) = *(--srcPtrEnd);
--- common/sdk/Map.h (revision 120)
+++ common/sdk/Map.h (revision 121)
@@ -173,7 +173,7 @@
173173
174174 public:
175175 inline Map( const Map& right )
176- : avlKeyTree( clone_key_tree( right.avlKeyTree ) )
176+ : avlKeyTree( clone_key_tree( this, right.avlKeyTree ) )
177177 {
178178 return;
179179 }
--- common/sdk/OSUtils.memheap.h (revision 120)
+++ common/sdk/OSUtils.memheap.h (revision 121)
@@ -260,6 +260,7 @@
260260 // Returns statistics about this memory allocator.
261261 struct heapStats
262262 {
263+ size_t usedBytes = 0;
263264 size_t usedMetaBytes = 0;
264265 size_t freeBytes = 0;
265266 size_t countOfAllocations = 0;
@@ -274,6 +275,7 @@
274275
275276 VMemIsland::usageStats islandStats = item->GetUsageStatistics();
276277
278+ stats.usedBytes += islandStats.usedBytes;
277279 stats.usedMetaBytes += islandStats.usedMetaBytes;
278280 stats.freeBytes += islandStats.freeBytes;
279281 stats.countOfAllocations += islandStats.countOfAllocations;
@@ -640,7 +642,7 @@
640642 }
641643
642644 // Grow the available free space.
643- lastFreeBlock->freeRegion.SetSliceEndPoint( finalMemEndOffset );
645+ lastFreeBlock->freeRegion.SetSliceEndPoint( this->allocHandle->GetTargetSlice().GetSliceEndPoint() );
644646
645647 // Since we have grown we must have some space now.
646648 this->avlSortedBySize.Insert( &lastFreeBlock->sortedBySizeNode );
@@ -767,10 +769,11 @@
767769 size_t actualReqSize = minSizeByPage;
768770
769771 // Minimum size by span.
772+ VMemFreeBlock *lastFreeBlock = LIST_GETITEM( VMemFreeBlock, this->sortedByAddrFreeBlocks.root.prev, sortedByAddrNode );
770773 {
771774 size_t vmemOff = (size_t)this;
772775
773- size_t newReqSize_local = this->GetIslandUsedBytesSize();
776+ size_t newReqSize_local = ( lastFreeBlock->freeRegion.GetSliceStartPoint() - (size_t)this );
774777
775778 if ( newReqSize_local > actualReqSize )
776779 {
@@ -781,6 +784,9 @@
781784 bool gotToShrink = manager->nativeMemProv.SetHandleSize( this->allocHandle, actualReqSize );
782785
783786 assert( gotToShrink == true );
787+
788+ // Update the region of free space for the last block.
789+ lastFreeBlock->freeRegion.SetSliceEndPoint( this->allocHandle->GetTargetSlice().GetSliceEndPoint() );
784790 }
785791 }
786792
@@ -839,6 +845,7 @@
839845 // Returns statistics about usage of this memory island.
840846 struct usageStats
841847 {
848+ size_t usedBytes = 0;
842849 size_t usedMetaBytes = 0;
843850 size_t freeBytes = 0;
844851 size_t countOfAllocations = 0;
@@ -853,6 +860,14 @@
853860
854861 LIST_FOREACH_BEGIN( VMemFreeBlock, this->sortedByAddrFreeBlocks.root, sortedByAddrNode )
855862
863+ // If we have an allocation associated with this free block, add up the data bytes.
864+ if ( item != &this->firstFreeSpaceBlock )
865+ {
866+ VMemAllocation *allocObj = LIST_GETITEM( VMemAllocation, item, freeSpaceAfterThis );
867+
868+ stats.usedBytes += allocObj->dataSize;
869+ }
870+
856871 memBlockSlice_t freeRegion = item->freeRegion;
857872
858873 if ( hasStartOfUsedBytesPos )
--- common/sdk/String.h (revision 120)
+++ common/sdk/String.h (revision 121)
@@ -11,7 +11,8 @@
1111
1212 // We can also use optimized memory semantics for Strings, aswell.
1313 // After all appending to a String should not cast another malloc, just a resize of
14-// the underlying memory buffer.
14+// the underlying memory buffer. Why would STL rely on this weird double-the-backbuffer
15+// trick, anyway?
1516
1617 #ifndef _EIR_STRING_HEADER_
1718 #define _EIR_STRING_HEADER_
@@ -18,7 +19,10 @@
1819
1920 #include "eirutils.h"
2021 #include "MacroUtils.h"
22+#include "DataUtil.h"
2123
24+#include <type_traits>
25+
2226 namespace eir
2327 {
2428
@@ -25,7 +29,452 @@
2529 template <typename charType, typename allocatorType>
2630 struct String
2731 {
32+ // When we talk about characters in this object we actually mean code-points that historically
33+ // were single characters but became redundant as single characters after the invention of
34+ // UTF-8 and other multi-codepoint encodings for internationalization.
2835
36+ // Characters should be a trivial type, meaning that it does not throw exceptions and stuff when
37+ // copying or assigning.
38+ static_assert( std::is_trivial <charType>::value == true, "eir::String charType has to be of trivial type" );
39+
40+ inline String( void )
41+ {
42+ this->char_data = "";
43+ this->num_chars = 0;
44+ }
45+
46+private:
47+ AINLINE void initialize_with( const charType *initChars, size_t initCharCount )
48+ {
49+ if ( initCharCount == 0 )
50+ {
51+ this->char_data = "";
52+ this->num_chars = 0;
53+ }
54+ else
55+ {
56+ size_t copyCharSize = sizeof(charType) * ( initCharCount + 1 );
57+
58+ charType *charBuf = (charType*)allocatorType::Allocate( this, copyCharSize, alignof(charType) );
59+
60+ if ( charBuf == nullptr )
61+ {
62+ throw eir_exception();
63+ }
64+
65+ //noexcept
66+ {
67+ // Copy the stuff.
68+ FSDataUtil::copy_impl( initChars, initChars + initCharCount, charBuf );
69+
70+ // Put the zero terminator.
71+ *( charBuf + initCharCount ) = charType();
72+
73+ // We take the data.
74+ this->char_data = charBuf;
75+ this->num_chars = initCharCount;
76+ }
77+ }
78+ }
79+
80+ // Helper logic.
81+ static AINLINE void free_old_buffer( void *objMem, charType *oldChars, size_t oldCharCount, bool isNewBuf )
82+ {
83+ if ( isNewBuf && oldCharCount > 0 )
84+ {
85+ allocatorType::Free( objMem, oldChars );
86+ }
87+ }
88+
89+public:
90+ inline String( const charType *initChars, size_t initCharCount )
91+ {
92+ initialize_with( initChars, initCharCount );
93+ }
94+
95+ inline String( const charType *initChars )
96+ {
97+ size_t initCharCount = cplen_tozero( initChars );
98+
99+ initialize_with( initChars, initCharCount );
100+ }
101+
102+ inline String( const String& right )
103+ {
104+ // Simply create a copy.
105+ size_t copyCharCount = right.num_chars;
106+ const charType *src_data = right.char_data;
107+
108+ initialize_with( src_data, copyCharCount );
109+ }
110+
111+ inline String( String&& right )
112+ {
113+ this->char_data = right.char_data;
114+ this->num_chars = right.num_chars;
115+
116+ right.char_data = "";
117+ right.num_chars = 0;
118+ }
119+
120+private:
121+ AINLINE void release_data( void )
122+ {
123+ if ( this->num_chars > 0 )
124+ {
125+ allocatorType::Free( this, this->char_data );
126+ }
127+ }
128+
129+public:
130+ inline ~String( void )
131+ {
132+ this->release_data();
133+ }
134+
135+ // *** Modification functions.
136+
137+ inline void Assign( const charType *theChars, size_t copyCharCount )
138+ {
139+ if ( copyCharCount == 0 )
140+ {
141+ this->release_data();
142+
143+ this->char_data = "";
144+ }
145+ else
146+ {
147+ // We need a big enough buffer for the new string.
148+ // If we have a buffer already then try scaling it.
149+ // Otherwise we allocate a new one.
150+ charType *useBuf = nullptr;
151+ bool isBufNew;
152+
153+ size_t charDataSize = sizeof(charType) * ( copyCharCount + 1 );
154+
155+ charType *oldCharBuf = this->char_data;
156+ size_t oldCharCount = this->num_chars;
157+
158+ if ( oldCharBuf && oldCharCount > 0 )
159+ {
160+ bool resizeSuccess = allocatorType::Resize( this, oldCharBuf, charDataSize );
161+
162+ if ( resizeSuccess )
163+ {
164+ useBuf = oldCharBuf;
165+ isBufNew = false;
166+ }
167+ }
168+
169+ // If we failed to retake our old buffer then we just allocate a new one.
170+ if ( useBuf == nullptr )
171+ {
172+ // It is ok to cast to charType immediatly because charType is trivial.
173+ useBuf = (charType*)allocatorType::Allocate( this, charDataSize, alignof(charType) );
174+
175+ if ( !useBuf )
176+ {
177+ throw eir_exception();
178+ }
179+
180+ isBufNew = true;
181+ }
182+
183+ // Granted because charType is trivial.
184+ //noexcept
185+ {
186+ // Create a copy of the input strings.
187+ // We add 1 to include the null-terminator.
188+ FSDataUtil::copy_impl( theChars, theChars + copyCharCount + 1, useBuf );
189+
190+ // Take over the buff.
191+ free_old_buffer( this, oldCharBuf, oldCharCount, isBufNew );
192+
193+ this->char_data = useBuf;
194+ }
195+ }
196+
197+ this->num_chars = copyCharCount;
198+ }
199+
200+ inline String& operator = ( const String& right )
201+ {
202+ this->Assign( right.char_data, right.num_chars );
203+
204+ return *this;
205+ }
206+
207+ inline String& operator = ( const charType *rightChars )
208+ {
209+ this->Assign( rightChars, cplen_tozero( rightChars ) );
210+
211+ return *this;
212+ }
213+
214+ inline String& operator = ( String&& right )
215+ {
216+ this->char_data = right.char_data;
217+ this->num_chars = right.num_chars;
218+
219+ right.char_data = "";
220+ right.num_chars = 0;
221+
222+ return *this;
223+ }
224+
225+private:
226+ AINLINE static void expand_buffer( void *objMem, charType *oldCharBuf, size_t oldCharCount, size_t newCharCount, charType*& useBufOut, bool& isBufNewOut )
227+ {
228+ size_t newRequiredCharsSize = sizeof(charType) * ( newCharCount + 1 );
229+
230+ charType *useBuf = nullptr;
231+ bool isBufNew;
232+
233+ if ( oldCharBuf && oldCharCount > 0 )
234+ {
235+ bool couldResize = allocatorType::Resize( objMem, oldCharBuf, newRequiredCharsSize );
236+
237+ if ( couldResize )
238+ {
239+ useBuf = oldCharBuf;
240+ isBufNew = false;
241+ }
242+ }
243+
244+ if ( useBuf == nullptr )
245+ {
246+ useBuf = (charType*)allocatorType::Allocate( objMem, newRequiredCharsSize, alignof(charType) );
247+
248+ if ( useBuf == nullptr )
249+ {
250+ throw eir_exception();
251+ }
252+
253+ // Guarranteed due to the trivial charType.
254+ // But we like to make sure anyway.
255+ //noexcept
256+ {
257+ // Copy over the characters.
258+ FSDataUtil::copy_impl( oldCharBuf, oldCharBuf + oldCharCount, useBuf );
259+
260+ isBufNew = true;
261+ }
262+ }
263+
264+ // Return the data.
265+ isBufNewOut = isBufNew;
266+ useBufOut = useBuf;
267+ }
268+
269+public:
270+ // Append characters to the end of this string.
271+ inline void Append( const charType *charsToAppend, size_t charsToAppendCount )
272+ {
273+ // There is nothing to do.
274+ if ( charsToAppendCount == 0 )
275+ return;
276+
277+ size_t num_chars = this->num_chars;
278+
279+ // Calculate how long the new string has to be.
280+ size_t newCharCount = ( num_chars + charsToAppendCount );
281+
282+ // Allocate the new buffer.
283+ charType *oldCharBuf = this->char_data;
284+
285+ charType *useBuf;
286+ bool isBufNew;
287+
288+ expand_buffer( this, oldCharBuf, num_chars, newCharCount, useBuf, isBufNew );
289+
290+ // Guarranteed due to trivial charType.
291+ //noexcept
292+ {
293+ // Now copy in the appended bytes.
294+ FSDataUtil::copy_impl( charsToAppend, charsToAppend + charsToAppendCount, useBuf + num_chars );
295+
296+ // We must re-put the null-terminator.
297+ *( useBuf + newCharCount ) = charType();
298+
299+ // Take over the new buffer.
300+ free_old_buffer( this, oldCharBuf, num_chars, isBufNew );
301+
302+ this->char_data = useBuf;
303+ this->num_chars = newCharCount;
304+ }
305+ }
306+
307+ inline void Insert( size_t insertPos, const charType *charsToInsert, size_t charsToInsertCount )
308+ {
309+ // Nothing to do? Then just quit.
310+ if ( charsToInsertCount == 0 )
311+ return;
312+
313+ // Expand the memory as required.
314+ size_t oldCharCount = this->num_chars;
315+ charType *oldCharBuf = this->char_data;
316+
317+ // If the insertion position is after the string size, then we clamp the insertion
318+ // position to the size.
319+ if ( insertPos > oldCharCount )
320+ {
321+ insertPos = oldCharCount;
322+ }
323+
324+ size_t newCharCount = ( oldCharCount + charsToInsertCount );
325+
326+ charType *useBuf;
327+ bool isBufNew;
328+
329+ expand_buffer( this, oldCharBuf, oldCharCount, newCharCount, useBuf, isBufNew );
330+
331+ //noexcept
332+ {
333+ // We first put any after-bytes to the end of the string.
334+ size_t afterBytesCount = ( oldCharCount - insertPos );
335+
336+ if ( afterBytesCount > 0 )
337+ {
338+ const charType *move_start = ( oldCharBuf + insertPos );
339+
340+ FSDataUtil::copy_backward_impl( move_start, move_start + afterBytesCount, useBuf + newCharCount );
341+ }
342+
343+ // Now copy in the insertion chars.
344+ FSDataUtil::copy_impl( charsToInsert, charsToInsert + charsToInsertCount, useBuf + insertPos );
345+
346+ // Put the zero terminator at the end.
347+ *( useBuf + newCharCount ) = charType();
348+
349+ // Take over the new stuff.
350+ free_old_buffer( this, oldCharBuf, oldCharCount, isBufNew );
351+
352+ this->char_data = useBuf;
353+ this->num_chars = newCharCount;
354+ }
355+ }
356+
357+ // Returns true if the codepoints of compareWith match this string.
358+ // This check if of course case-sensitive.
359+ // Use other algorithms if you need an case-insensitive comparison because it is complicated (UniChar.h).
360+ inline bool equals( const charType *compareWith, size_t compareWithCount ) const
361+ {
362+ size_t num_chars = this->num_chars;
363+
364+ if ( num_chars != compareWithCount )
365+ return false;
366+
367+ // Do we find any codepoint that does not match?
368+ const charType *leftChars = this->char_data;
369+
370+ for ( size_t n = 0; n < num_chars; n++ )
371+ {
372+ charType leftChar = *( leftChars + n );
373+ charType rightChar = *( compareWith + n );
374+
375+ if ( leftChar != rightChar )
376+ {
377+ return false;
378+ }
379+ }
380+
381+ return true;
382+ }
383+
384+ inline bool equals( const charType *compareWith ) const
385+ {
386+ // TODO: maybe optimize this so that we loop only once.
387+ return equals( compareWith, cplen_tozero( compareWith ) );
388+ }
389+
390+ inline size_t GetLength( void ) const
391+ {
392+ return this->num_chars;
393+ }
394+
395+ inline const charType* GetConstString( void ) const
396+ {
397+ return this->char_data;
398+ }
399+
400+ // Helpful operator overrides.
401+
402+ inline String& operator += ( charType oneChar )
403+ {
404+ this->Append( &oneChar, 1 );
405+
406+ return *this;
407+ }
408+
409+ inline String& operator += ( const charType *someChars )
410+ {
411+ size_t appendCount = cplen_tozero( someChars );
412+
413+ this->Append( someChars, appendCount );
414+
415+ return *this;
416+ }
417+
418+ inline String& operator += ( const String& right )
419+ {
420+ this->Append( right.char_data, right.num_chars );
421+
422+ return *this;
423+ }
424+
425+ inline String operator + ( charType oneChar )
426+ {
427+ String newString( *this );
428+
429+ newString += oneChar;
430+
431+ return newString;
432+ }
433+
434+ inline String operator + ( const charType *someChars )
435+ {
436+ String newString( *this );
437+
438+ newString += someChars;
439+
440+ return newString;
441+ }
442+
443+ inline String operator + ( const String& right )
444+ {
445+ String newString( *this );
446+
447+ newString += right;
448+
449+ return newString;
450+ }
451+
452+ inline bool operator == ( const charType *someChars ) const
453+ {
454+ return this->equals( someChars, cplen_tozero( someChars ) );
455+ }
456+
457+ inline bool operator == ( const String& right ) const
458+ {
459+ return this->equals( right.char_data, right.num_chars );
460+ }
461+
462+ inline bool operator != ( const charType *someChars ) const
463+ {
464+ return !( operator == ( someChars ) );
465+ }
466+
467+ inline bool operator != ( const String& right ) const
468+ {
469+ return !( operator == ( right ) );
470+ }
471+
472+ // Reason why we do not provide less-than or greater-than operators is because it would only make
473+ // sense with case-insensitive functionality added.
474+
475+private:
476+ charType *char_data;
477+ size_t num_chars;
29478 };
30479
31480 }
--- common/sdk/UniChar.h (revision 120)
+++ common/sdk/UniChar.h (revision 121)
@@ -20,21 +20,8 @@
2020
2121 #include <limits>
2222
23-// Calculates the length of a string to the zero-terminator.
24-template <typename charType>
25-inline size_t cplen_tozero( const charType *chars )
26-{
27- size_t len = 0;
23+#include "eirutils.h"
2824
29- while ( *chars != (charType)0 )
30- {
31- len++;
32- chars++;
33- }
34-
35- return len;
36-}
37-
3825 // UNICODE CHARACTER LIBRARY TESTING.
3926 template <typename charType>
4027 struct character_env
@@ -386,28 +373,28 @@
386373 throw codepoint_exception( "UTF-16 encoding exception: invalid UTF-32 codepoint" );
387374 }
388375
389- // We encode to two code points, basically a surrogate pair.
390- union
391- {
392- wideCharType cp_zero;
393- code_point_hi_surrogate hi_surrogate;
394- };
395-
396- union
397- {
398- wideCharType cp_one;
399- code_point_lo_surrogate lo_surrogate;
400- };
376+ // We encode to two code points, basically a surrogate pair.
377+ union
378+ {
379+ wideCharType cp_zero;
380+ code_point_hi_surrogate hi_surrogate;
381+ };
401382
383+ union
384+ {
385+ wideCharType cp_one;
386+ code_point_lo_surrogate lo_surrogate;
387+ };
388+
402389 hi_surrogate.hiorder_cp = codepoint.hi_order;
403390 hi_surrogate.plane_id = ( codepoint.plane_id - 1 );
404391 hi_surrogate.checksum = 54;
405392
406393 lo_surrogate.loworder_cp = codepoint.lo_order;
407- lo_surrogate.checksum = 55;
408-
409- // Write the data back.
410- resOut.data[0] = cp_zero;
394+ lo_surrogate.checksum = 55;
395+
396+ // Write the data back.
397+ resOut.data[0] = cp_zero;
411398 resOut.data[1] = cp_one;
412399
413400 resOut.numData = 2;
@@ -1141,4 +1128,4 @@
11411128 }
11421129 };
11431130
1144-#endif //_EIRREPO_CHARACTER_RESOLUTION_
1131+#endif //_EIRREPO_CHARACTER_RESOLUTION_
--- common/sdk/Vector.h (revision 120)
+++ common/sdk/Vector.h (revision 121)
@@ -72,7 +72,7 @@
7272 {
7373 structType *right_data = right.data_entries;
7474
75- data_entries = make_data_copy( right_data, right_count );
75+ data_entries = make_data_copy( this, right_data, right_count );
7676 }
7777
7878 this->data_entries = data_entries;
@@ -131,6 +131,9 @@
131131 // WARNING: only move if allocator stays the same.
132132 inline Vector& operator = ( Vector&& right )
133133 {
134+ // Release our previous data.
135+ release_data( this, this->data_entries, this->data_count );
136+
134137 this->data_entries = right.data_entries;
135138 this->data_count = right.data_count;
136139
--- common/sdk/eirutils.h (revision 120)
+++ common/sdk/eirutils.h (revision 121)
@@ -17,4 +17,19 @@
1717 {
1818 };
1919
20+// Calculates the length of a string to the zero-terminator.
21+template <typename charType>
22+inline size_t cplen_tozero( const charType *chars )
23+{
24+ size_t len = 0;
25+
26+ while ( *chars != (charType)0 )
27+ {
28+ len++;
29+ chars++;
30+ }
31+
32+ return len;
33+}
34+
2035 #endif //_EIR_COMMON_SDK_UTILITIES_
\ No newline at end of file
--- unittests/src/heaptests.cpp (revision 120)
+++ unittests/src/heaptests.cpp (revision 121)
@@ -168,17 +168,17 @@
168168
169169 NativeHeapAllocator::heapStats statsOfHeap1 = heap1.GetStatistics();
170170
171- assert( statsOfHeap1.usedMetaBytes >= 579 );
171+ assert( statsOfHeap1.usedBytes == 579 );
172172
173173 heap2 = std::move( heap1 );
174174
175- assert( heap1.GetStatistics().usedMetaBytes == 0 );
176- assert( heap2.GetStatistics().usedMetaBytes == statsOfHeap1.usedMetaBytes );
175+ assert( heap1.GetStatistics().usedBytes == 0 );
176+ assert( heap2.GetStatistics().usedBytes == statsOfHeap1.usedBytes );
177177
178178 heap2.Free( oneMem );
179179 heap2.Free( twoMem );
180180
181- assert( heap2.GetStatistics().usedMetaBytes == 0 );
181+ assert( heap2.GetStatistics().usedBytes == 0 );
182182 }
183183 printf( "ok.\n" );
184184 }
\ No newline at end of file
--- unittests/src/impltests.cpp (revision 120)
+++ unittests/src/impltests.cpp (revision 121)
@@ -2,6 +2,8 @@
22
33 #include <assert.h>
44
5+#include <type_traits>
6+
57 struct class_a
68 {
79 int value = -1;
@@ -36,4 +38,55 @@
3638
3739 assert( implicit.value == 42 );
3840 }
41+
42+ // Check that enums and integers are POD.
43+ {
44+ enum class test : unsigned char
45+ {
46+ DEFAULT
47+ };
48+
49+ static_assert( std::is_trivial <test>::value == true );
50+
51+ struct meow
52+ {
53+ int value;
54+
55+ inline meow& operator = ( const meow& right )
56+ {
57+ throw 1;
58+ }
59+ };
60+
61+ static_assert( std::is_trivial <meow>::value == false );
62+
63+ struct woof
64+ {
65+ int value;
66+ };
67+
68+ static_assert( std::is_trivial <woof>::value == true );
69+
70+ struct meowy
71+ {
72+ int value;
73+
74+ inline meowy( void ) = default;
75+ inline meowy( const meowy& right )
76+ {
77+ throw 1;
78+ }
79+ };
80+
81+ static_assert( std::is_trivial <meowy>::value == false );
82+
83+ struct woofy
84+ {
85+ int value;
86+
87+ inline woofy( void ) = default;
88+ };
89+
90+ static_assert( std::is_trivial <woofy>::value == true );
91+ }
3992 }
--- unittests/src/main.cpp (revision 120)
+++ unittests/src/main.cpp (revision 121)
@@ -17,6 +17,7 @@
1717 extern void AVLTREE_TESTS( void );
1818 extern void VECTOR_TESTS( void );
1919 extern void MAP_TESTS( void );
20+extern void STRING_TESTS( void );
2021
2122 #ifdef _WIN32
2223 // Shell extension test.
@@ -34,6 +35,7 @@
3435 AVLTREE_TESTS();
3536 VECTOR_TESTS();
3637 MAP_TESTS();
38+ STRING_TESTS();
3739
3840 //Test_DTSConditionalStructing();
3941
--- unittests/src/map.cpp (revision 120)
+++ unittests/src/map.cpp (revision 121)
@@ -111,6 +111,11 @@
111111
112112 assert( map2[ 1 ] == 2 );
113113 assert( map2[ 73 ] == 32 );
114+
115+ MapWithHeap map3( map1 );
116+
117+ assert( map3[ 1 ] == 2 );
118+ assert( map3[ 73 ] == 32 );
114119 }
115120 printf( "ok.\n" );
116121
@@ -127,6 +132,12 @@
127132 assert( map1.Find( 59 ) == nullptr );
128133 assert( map2.Find( 59 ) != nullptr );
129134 assert( map2[ 59 ] == 44 );
135+
136+ MapWithHeap map3( std::move( map2 ) );
137+
138+ assert( map2.Find( 59 ) == nullptr );
139+ assert( map3.Find( 59 ) != nullptr );
140+ assert( map3[ 59 ] == 44 );
130141 }
131142 printf( "ok.\n" );
132143
--- unittests/src/string.cpp (nonexistent)
+++ unittests/src/string.cpp (revision 121)
@@ -0,0 +1,130 @@
1+// Unit tests for the eir::String object.
2+#include <sdk/String.h>
3+
4+#include "alloc_helper.hxx"
5+
6+#include <string.h>
7+
8+typedef eir::String <char, EirHeapAllocator> StringWithHeap;
9+
10+void STRING_TESTS( void )
11+{
12+ printf( "testing string constructor..." );
13+ {
14+ StringWithHeap string( "hello world" );
15+
16+ assert( string.GetLength() == 11 );
17+ assert( strcmp( string.GetConstString(), "hello world" ) == 0 );
18+
19+ StringWithHeap string2( "hi there!", 9 );
20+
21+ assert( string2.GetLength() == 9 );
22+ assert( strcmp( string2.GetConstString(), "hi there!" ) == 0 );
23+
24+ StringWithHeap string3 = "meow";
25+
26+ assert( strcmp( string3.GetConstString(), "meow" ) == 0 );
27+ }
28+ printf( "ok.\n" );
29+
30+ printf( "testing string comparator..." );
31+ {
32+ StringWithHeap str = "hello";
33+
34+ assert( str == "hello" );
35+ assert( str != "hallo" );
36+ assert( str != "Hello" );
37+
38+ str = "das ist ein laengerer String.";
39+
40+ assert( str == "das ist ein laengerer String." );
41+
42+ str = "test string";
43+
44+ assert( str.equals( "test string" ) == true );
45+ assert( str.equals( "meow" ) == false );
46+ }
47+ printf( "ok.\n" );
48+
49+ printf( "testing string clone..." );
50+ {
51+ StringWithHeap string1, string2;
52+
53+ string1 = "hello";
54+ string2 = string1;
55+
56+ assert( string2 == "hello" );
57+ assert( string1 == string2 );
58+ }
59+ printf( "ok.\n" );
60+
61+ printf( "testing string append..." );
62+ {
63+ StringWithHeap string;
64+
65+ string += 'h';
66+ string += 'e';
67+ string += 'l';
68+ string += 'l';
69+ string += 'o';
70+
71+ assert( string == "hello" );
72+
73+ string += " world";
74+
75+ assert( string == "hello world" );
76+
77+ string += StringWithHeap( "!" );
78+
79+ assert( string == "hello world!" );
80+ }
81+ printf( "ok.\n" );
82+
83+ printf( "testing string massive append..." );
84+ {
85+ StringWithHeap string;
86+
87+ // We choose a big enough number to actually trigger a copy...
88+ // Maybe it wont ever copy for you???
89+ static constexpr size_t APPEND_COUNT = 40000;
90+
91+ for ( size_t n = 0; n < APPEND_COUNT; n++ )
92+ {
93+ string += 'a';
94+ }
95+
96+ assert( string.GetLength() == APPEND_COUNT );
97+ }
98+ printf( "ok.\n" );
99+
100+ printf( "testing string insert..." );
101+ {
102+ StringWithHeap string = "hello world";
103+
104+ string.Insert( 5, " my", 3 );
105+
106+ assert( string == "hello my world" );
107+
108+ string.Insert( 9, "beautiful ", 10 );
109+
110+ assert( string == "hello my beautiful world" );
111+ }
112+ printf( "ok.\n" );
113+
114+ printf( "testing string move..." );
115+ {
116+ StringWithHeap string1, string2;
117+
118+ string1 = "good guy";
119+ string2 = std::move( string1 );
120+
121+ assert( string2 == "good guy" );
122+ assert( string1 == "" );
123+
124+ StringWithHeap string3( std::move( string2 ) );
125+
126+ assert( string3 == "good guy" );
127+ assert( string2 == "" );
128+ }
129+ printf( "ok.\n" );
130+}
\ No newline at end of file
--- unittests/src/vector.cpp (revision 120)
+++ unittests/src/vector.cpp (revision 121)
@@ -110,6 +110,14 @@
110110 assert( vh1[0] == 2 );
111111 assert( vh1[1] == 3 );
112112 assert( vh1 == vh2 );
113+
114+ VectorWithHeap vh3( vh1 );
115+
116+ assert( vh3.GetCount() == 2 );
117+ assert( vh3[0] == 2 );
118+ assert( vh3[1] == 3 );
119+ assert( vh1 == vh3 );
120+ assert( vh2 == vh3 );
113121 }
114122 printf( "ok.\n" );
115123
@@ -122,6 +130,8 @@
122130
123131 vh1 = std::move( vh2 );
124132
133+ assert( vh2.GetCount() == 0 );
134+
125135 // After moving addition should still work.
126136 vh1.AddToBack( 15 );
127137
@@ -130,6 +140,11 @@
130140 vh2.AddToBack( 1 );
131141
132142 assert( vh2.GetCount() == 1 );
143+
144+ VectorWithHeap vh3( std::move( vh2 ) );
145+
146+ assert( vh3.GetCount() == 1 );
147+ assert( vh2.GetCount() == 0 );
133148 }
134149 printf( "ok.\n" );
135150
Show on old repository browser