Skip to content

Commit 2c4a2f6

Browse files
committed
Added unit tests for Deallocation function
1 parent 9bf6559 commit 2c4a2f6

File tree

1 file changed

+158
-13
lines changed

1 file changed

+158
-13
lines changed

tests/src/resources/test_ResourceSystem.cpp

Lines changed: 158 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -631,7 +631,7 @@ class Allocator
631631
public:
632632
Allocator() {};
633633
Allocator(const size_t capacity)
634-
: capacity {capacity}
634+
: capacity {capacity}, bytesRemaining {capacity}
635635
{
636636
data = TO_BYTES(calloc(1, sizeof(BlockHeader) + sizeof(BlockFooter) + capacity));
637637

@@ -672,7 +672,9 @@ class Allocator
672672
void* Allocate(size_t size)
673673
{
674674
size_t requiredSize = sizeof(BlockHeader) + size + sizeof(BlockFooter);
675-
if (!data || capacity == 0 ||size == 0 || requiredSize < size) return nullptr;
675+
if (!data || capacity == 0 ||size == 0
676+
|| requiredSize < size || requiredSize > bytesRemaining) return nullptr;
677+
676678
if (requiredSize < MIN_ALLOC_SIZE) return nullptr;
677679

678680
size_t freeListIdx = 0, fl = 0, sl = 0;
@@ -694,13 +696,16 @@ class Allocator
694696
BlockFooter* footer = TO_FBLOCK((ptr+size));
695697
footer->totalBlockSize = requiredSize;
696698

699+
bytesRemaining -= requiredSize;
700+
697701
return ptr;
698702
}
699703

700704
template<typename T>
701705
void Deallocate(T*& ptr)
702706
{
703707
if (!ptr) return;
708+
if ((TO_BYTES(ptr) < data || TO_BYTES(ptr) >= (data + capacity))) return;
704709

705710
BlockHeader* header = TO_HBLOCK((TO_BYTES(ptr) - sizeof(BlockHeader)));
706711
size_t blockSize = GetHeaderSize(header);
@@ -716,6 +721,9 @@ class Allocator
716721
if (nextHeader) nextHeader->sizeAndFlags |= IS_PREV_FREE_FLAG;
717722

718723
CreateNewBlock(TO_BYTES(targetHeader), totalBlockSize);
724+
725+
bytesRemaining += blockSize;
726+
719727
ptr = nullptr;
720728
}
721729

@@ -755,7 +763,7 @@ class Allocator
755763
BlockHeader* TryCoalesce(BlockHeader* header, OUT size_t& size)
756764
{
757765
BlockHeader* start = header;
758-
BlockHeader* prev = GetPreviousHeader(header);
766+
BlockHeader* prev = GetPreviousHeader(start);
759767

760768
if (prev && BlockIsFree(prev))
761769
{
@@ -775,11 +783,11 @@ class Allocator
775783
return start;
776784
}
777785

778-
BlockHeader* GetPreviousHeader(void* currentHeader)
786+
BlockHeader* GetPreviousHeader(BlockHeader* currentHeader)
779787
{
780788
if (IsHead(currentHeader)) return nullptr;
781-
BlockFooter* prev = TO_FBLOCK(TO_BYTES(currentHeader) - sizeof(BlockFooter));
782-
BlockHeader* prevHeader = TO_HBLOCK(TO_BYTES(currentHeader) - prev->totalBlockSize);
789+
BlockFooter* prev = TO_FBLOCK((TO_BYTES(currentHeader) - sizeof(BlockFooter)));
790+
BlockHeader* prevHeader = TO_HBLOCK((TO_BYTES(currentHeader) - prev->totalBlockSize));
783791
return prevHeader;
784792
}
785793

@@ -791,7 +799,7 @@ class Allocator
791799
return TO_HBLOCK(next);
792800
}
793801

794-
void TrySetPreviousHeaderFlag(void* currentHeader, size_t& flags)
802+
void TrySetPreviousHeaderFlag(BlockHeader* currentHeader, size_t& flags)
795803
{
796804
BlockHeader* prevHeader = GetPreviousHeader(currentHeader);
797805
if (prevHeader &&
@@ -842,6 +850,8 @@ class Allocator
842850

843851
size_t sizeFlag = (size << FLAG_BITS);
844852

853+
// 0000 0000 0000 0000
854+
845855
BlockHeader* header = TO_HBLOCK(ptr);
846856
header->sizeAndFlags = (sizeFlag | IS_FREE_FLAG);
847857

@@ -886,9 +896,11 @@ class Allocator
886896
const uint64_t& FlBitmask() { return flBitmask; }
887897
uint16_t*& SlBitmask() { return slBitmasks; }
888898
FreeBlockNode** FreeList() { return freeList; }
899+
const size_t BytesRemaining() { return bytesRemaining; }
889900

890901
private:
891902
size_t capacity {0};
903+
size_t bytesRemaining {0};
892904
unsigned char* data {nullptr};
893905
FreeBlockNode** freeList {nullptr};
894906

@@ -909,6 +921,7 @@ UTEST(test_ResourceSystem, TestAllocatorCreationWithSize)
909921
Allocator a(64);
910922
ASSERT_NE(a.Data(), nullptr);
911923
ASSERT_EQ(a.Capacity(), 64);
924+
ASSERT_EQ(64, a.BytesRemaining());
912925

913926
// 0001 0000
914927
ASSERT_EQ(a.FlBitmask(), 4);
@@ -934,6 +947,7 @@ UTEST(test_ResourceSystem, TestAllocateFunction)
934947
Allocator a(64);
935948
ASSERT_NE(a.Data(), nullptr);
936949
ASSERT_EQ(a.Capacity(), 64);
950+
ASSERT_EQ(64, a.BytesRemaining());
937951

938952
TestStruct* p = (TestStruct*) a.Allocate(sizeof(TestStruct));
939953

@@ -957,6 +971,7 @@ UTEST(test_ResourceSystem, TestAllocateFunction)
957971
ASSERT_EQ(192, header->sizeAndFlags);
958972
ASSERT_EQ(data, p);
959973
ASSERT_EQ(sizeof(BlockHeader) + sizeof(TestStruct) + sizeof(BlockFooter), footer->totalBlockSize);
974+
ASSERT_EQ(40, a.BytesRemaining());
960975

961976
Siege::String* str = (Siege::String*) a.Allocate(sizeof(Siege::String));
962977

@@ -974,9 +989,10 @@ UTEST(test_ResourceSystem, TestAllocateFunction)
974989
auto newData = (Siege::String*) (((unsigned char*)newHeader) + sizeof(BlockHeader));
975990
auto newFooter = (BlockFooter*) (((unsigned char*)newData) + sizeof(TestStruct));
976991

977-
ASSERT_EQ(194, newHeader->sizeAndFlags);
992+
ASSERT_EQ(192, newHeader->sizeAndFlags);
978993
ASSERT_EQ(newData, str);
979994
ASSERT_EQ(sizeof(BlockHeader) + sizeof(Siege::String) + sizeof(BlockFooter), newFooter->totalBlockSize);
995+
ASSERT_EQ(16, a.BytesRemaining());
980996

981997
// Edge cases
982998

@@ -994,13 +1010,21 @@ UTEST(test_ResourceSystem, TestAllocateFunction)
9941010
Allocator overflowAlloc(SIZE_T_MAX);
9951011
void* overflowPtr = overflowAlloc.Allocate(SIZE_T_MAX);
9961012
ASSERT_FALSE(overflowPtr);
1013+
1014+
void* tooLargeCase = a.Allocate(100);
1015+
ASSERT_FALSE(tooLargeCase);
1016+
1017+
Allocator tooSmallAlloc(64);
1018+
void* tooLargeAlloc = a.Allocate(100);
1019+
ASSERT_FALSE(tooLargeCase);
9971020
}
9981021

9991022
UTEST(test_ResourceSystem, TestDeallocateFunction)
10001023
{
10011024
Allocator a(64);
10021025
ASSERT_NE(a.Data(), nullptr);
10031026
ASSERT_EQ(a.Capacity(), 64);
1027+
ASSERT_EQ(64, a.BytesRemaining());
10041028

10051029
TestStruct* p = (TestStruct*) a.Allocate(sizeof(TestStruct));
10061030

@@ -1016,6 +1040,7 @@ UTEST(test_ResourceSystem, TestDeallocateFunction)
10161040
FreeBlockNode* block = a.FreeList()[(1 * 16) + 4];
10171041
ASSERT_EQ(block->next, nullptr);
10181042
ASSERT_EQ(block->prev, nullptr);
1043+
ASSERT_EQ(40, a.BytesRemaining());
10191044

10201045
auto header = (BlockHeader*)a.Data();
10211046
auto data = (TestStruct*) (((unsigned char*)header) + sizeof(BlockHeader));
@@ -1033,6 +1058,7 @@ UTEST(test_ResourceSystem, TestDeallocateFunction)
10331058
ASSERT_FALSE(p);
10341059
ASSERT_EQ(a.FlBitmask(), 4);
10351060
ASSERT_EQ(a.SlBitmask()[2], 1);
1061+
ASSERT_EQ(64, a.BytesRemaining());
10361062

10371063
p = (TestStruct*) a.Allocate(sizeof(TestStruct));
10381064
p->inta = 10;
@@ -1047,6 +1073,7 @@ UTEST(test_ResourceSystem, TestDeallocateFunction)
10471073
block = a.FreeList()[(1 * 16) + 4];
10481074
ASSERT_EQ(block->next, nullptr);
10491075
ASSERT_EQ(block->prev, nullptr);
1076+
ASSERT_EQ(40, a.BytesRemaining());
10501077

10511078
header = (BlockHeader*)a.Data();
10521079
data = (TestStruct*) (((unsigned char*)header) + sizeof(BlockHeader));
@@ -1067,12 +1094,13 @@ UTEST(test_ResourceSystem, TestDeallocateFunction)
10671094
FreeBlockNode* NewBlock = a.FreeList()[0];
10681095
ASSERT_EQ(NewBlock->next, nullptr);
10691096
ASSERT_EQ(NewBlock->prev, nullptr);
1097+
ASSERT_EQ(16, a.BytesRemaining());
10701098

10711099
auto newHeader = (BlockHeader*)(TO_BYTES(footer) + sizeof(BlockFooter));
10721100
auto newData = (Siege::String*) (((unsigned char*)newHeader) + sizeof(BlockHeader));
10731101
auto newFooter = (BlockFooter*) (((unsigned char*)newData) + sizeof(TestStruct));
10741102

1075-
ASSERT_EQ(194, newHeader->sizeAndFlags);
1103+
ASSERT_EQ(192, newHeader->sizeAndFlags);
10761104
ASSERT_EQ(newData, str);
10771105
ASSERT_EQ(sizeof(BlockHeader) + sizeof(Siege::String) + sizeof(BlockFooter), newFooter->totalBlockSize);
10781106

@@ -1084,10 +1112,127 @@ UTEST(test_ResourceSystem, TestDeallocateFunction)
10841112
FreeBlockNode* newFreeBlock = TO_FREEBLOCK((TO_BYTES(header)+sizeof(BlockHeader)));
10851113
ASSERT_EQ(newFreeBlock->next, nullptr);
10861114
ASSERT_EQ(newFreeBlock->prev, nullptr);
1115+
ASSERT_EQ(40, a.BytesRemaining());
10871116

10881117
a.Deallocate(str);
1089-
// ASSERT_FALSE(str);
1090-
// ASSERT_EQ(513, header->sizeAndFlags);
1091-
// ASSERT_EQ(a.FlBitmask(), 4);
1092-
// ASSERT_EQ(a.SlBitmask()[2], 1);
1118+
ASSERT_FALSE(str);
1119+
ASSERT_EQ(513, header->sizeAndFlags);
1120+
ASSERT_EQ(4, a.FlBitmask());
1121+
ASSERT_EQ(1, a.SlBitmask()[2]);
1122+
ASSERT_EQ(64, a.BytesRemaining());
1123+
}
1124+
1125+
UTEST(test_ResourceSystem, TestBlockCoalescing)
1126+
{
1127+
Allocator a(128);
1128+
ASSERT_NE(a.Data(), nullptr);
1129+
ASSERT_EQ(a.Capacity(), 128);
1130+
ASSERT_EQ(128, a.BytesRemaining());
1131+
1132+
TestStruct* p = (TestStruct*) a.Allocate(sizeof(TestStruct));
1133+
1134+
p->inta = 10;
1135+
p->intb = 20;
1136+
1137+
ASSERT_EQ(10, p->inta);
1138+
ASSERT_EQ(20, p->intb);
1139+
1140+
ASSERT_EQ(4, a.FlBitmask());
1141+
ASSERT_EQ(0, a.SlBitmask()[1]);
1142+
1143+
FreeBlockNode* block = a.FreeList()[42];
1144+
ASSERT_EQ(block->next, nullptr);
1145+
ASSERT_EQ(block->prev, nullptr);
1146+
ASSERT_EQ(104, a.BytesRemaining());
1147+
1148+
auto header = (BlockHeader*)a.Data();
1149+
auto data = (TestStruct*) (((unsigned char*)header) + sizeof(BlockHeader));
1150+
auto footer = (BlockFooter*) (((unsigned char*)data) + sizeof(TestStruct));
1151+
1152+
ASSERT_EQ(192, header->sizeAndFlags);
1153+
ASSERT_EQ(data, p);
1154+
ASSERT_EQ(sizeof(BlockHeader) + sizeof(TestStruct) + sizeof(BlockFooter), footer->totalBlockSize);
1155+
1156+
Siege::String* str = (Siege::String*) a.Allocate(sizeof(Siege::String));
1157+
1158+
*str = "Hello There!";
1159+
ASSERT_STREQ(str->Str(),"Hello There!");
1160+
1161+
ASSERT_EQ(4, a.FlBitmask());
1162+
ASSERT_EQ(0, a.SlBitmask()[1]);
1163+
1164+
FreeBlockNode* NewBlock = a.FreeList()[36];
1165+
ASSERT_EQ(NewBlock->next, nullptr);
1166+
ASSERT_EQ(NewBlock->prev, nullptr);
1167+
ASSERT_EQ(80, a.BytesRemaining());
1168+
1169+
auto newHeader = (BlockHeader*)(TO_BYTES(footer) + sizeof(BlockFooter));
1170+
auto newData = (Siege::String*) (((unsigned char*)newHeader) + sizeof(BlockHeader));
1171+
auto newFooter = (BlockFooter*) (((unsigned char*)newData) + sizeof(TestStruct));
1172+
1173+
ASSERT_EQ(192, newHeader->sizeAndFlags);
1174+
ASSERT_EQ(newData, str);
1175+
ASSERT_EQ(sizeof(BlockHeader) + sizeof(Siege::String) + sizeof(BlockFooter), newFooter->totalBlockSize);
1176+
1177+
TestStruct* p2 = (TestStruct*) a.Allocate(sizeof(TestStruct));
1178+
1179+
p2->inta = 10;
1180+
p2->intb = 20;
1181+
1182+
ASSERT_EQ(10, p2->inta);
1183+
ASSERT_EQ(20, p2->intb);
1184+
1185+
ASSERT_EQ(a.FlBitmask(), 2);
1186+
ASSERT_EQ(4096, a.SlBitmask()[1]);
1187+
1188+
FreeBlockNode* newFreeBlock = a.FreeList()[28];
1189+
ASSERT_EQ(newFreeBlock->next, nullptr);
1190+
ASSERT_EQ(newFreeBlock->prev, nullptr);
1191+
ASSERT_EQ(56, a.BytesRemaining());
1192+
1193+
auto newHeader2 = (BlockHeader*)(TO_BYTES(newFooter) + sizeof(BlockFooter));
1194+
auto newData2 = (TestStruct*) (((unsigned char*)newHeader2) + sizeof(BlockHeader));
1195+
auto newFooter2 = (BlockFooter*) (((unsigned char*)newData2) + sizeof(TestStruct));
1196+
1197+
ASSERT_EQ(192, header->sizeAndFlags);
1198+
ASSERT_EQ(data, p);
1199+
ASSERT_EQ(sizeof(BlockHeader) + sizeof(TestStruct) + sizeof(BlockFooter), footer->totalBlockSize);
1200+
1201+
a.Deallocate(p);
1202+
1203+
FreeBlockNode* firstFree = a.FreeList()[8];
1204+
ASSERT_EQ(firstFree->next, nullptr);
1205+
ASSERT_EQ(firstFree->prev, nullptr);
1206+
ASSERT_EQ(80, a.BytesRemaining());
1207+
1208+
BlockHeader* firstFreeHeader = TO_HBLOCK((TO_BYTES(firstFree) - sizeof(BlockHeader)));
1209+
ASSERT_TRUE(firstFreeHeader->sizeAndFlags & IS_FREE_FLAG);
1210+
ASSERT_FALSE(firstFreeHeader->sizeAndFlags & IS_PREV_FREE_FLAG);
1211+
ASSERT_FALSE(p);
1212+
ASSERT_EQ(a.FlBitmask(), 3);
1213+
ASSERT_EQ(256, a.SlBitmask()[0]);
1214+
1215+
a.Deallocate(p2);
1216+
ASSERT_FALSE(p2);
1217+
ASSERT_EQ(104, a.BytesRemaining());
1218+
ASSERT_EQ(a.FlBitmask(), 5);
1219+
ASSERT_EQ(256, a.SlBitmask()[0]);
1220+
ASSERT_EQ(16, a.SlBitmask()[2]);
1221+
1222+
a.Deallocate(str);
1223+
ASSERT_FALSE(str);
1224+
ASSERT_EQ(128, a.BytesRemaining());
1225+
ASSERT_EQ(a.FlBitmask(), 8);
1226+
ASSERT_EQ(a.SlBitmask()[3], 1);
1227+
1228+
// Edge Cases
1229+
1230+
void* badPointer = nullptr;
1231+
a.Deallocate(badPointer);
1232+
ASSERT_FALSE(badPointer);
1233+
1234+
// try to deallocate pointer not in allocator;
1235+
uint64_t* val = new uint64_t;
1236+
1237+
a.Deallocate(val);
10931238
}

0 commit comments

Comments
 (0)