Skip to content

Commit 647edbe

Browse files
committed
Checking allocation counts.
1 parent 743d9cf commit 647edbe

File tree

6 files changed

+101
-45
lines changed

6 files changed

+101
-45
lines changed

Source/DFPSR/api/stringAPI.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,9 @@ static char toAscii(DsrChar c) {
6767
ReadableString::ReadableString(const DsrChar *content)
6868
: view(content, strlen_utf32(content)) {}
6969

70-
ReadableString::ReadableString(const String& source)
71-
: characters(source.characters), view(source.view) {}
72-
7370
String::String() {}
7471
String::String(const char* source) { atomic_append_ascii(*this, source); }
7572
String::String(const DsrChar* source) { atomic_append_utf32(*this, source); }
76-
String::String(const ReadableString& source)
77-
: ReadableString(source.characters, source.view) {}
7873

7974
String& Printable::toStream(String& target) const {
8075
return this->toStreamIndented(target, U"");
@@ -733,7 +728,7 @@ static uintptr_t getStartOffset(const ReadableString &source) {
733728
static void serializeCharacterBuffer(PrintCharacter target, void const * const allocation, uintptr_t maxLength) {
734729
uintptr_t characterCount = heap_getUsedSize(allocation) / sizeof(DsrChar);
735730
target(U'\"');
736-
for (intptr_t c = 0; c < characterCount; c++) {
731+
for (uintptr_t c = 0; c < characterCount; c++) {
737732
if (c == maxLength) {
738733
target(U'\"');
739734
target(U'.');

Source/DFPSR/api/stringAPI.h

Lines changed: 56 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,6 @@ struct Impl_CharacterView {
9393
}
9494
};
9595

96-
// TODO: Explicitly define destructor, copy/move construct/assign operations.
97-
9896
// Replacing String with a ReadableString reference for input arguments can make passing of U"" literals faster,
9997
// because String is not allowed to assume anything about how long the literal will be available.
10098
// Unlike String, it cannot be constructed from a "" literal, because it is not allowed to heap allocate new memory
@@ -106,12 +104,7 @@ class ReadableString {
106104
Handle<DsrChar> characters;
107105
// Pointing to a subset of the buffer or memory that is not shared.
108106
Impl_CharacterView view;
109-
// TODO: Merge the pointer and length into a new View type for unified bound checks. Then remove the writer pointer.
110-
//SafePointer<const DsrChar> reader;
111-
//intptr_t length = 0;
112107
public:
113-
// TODO: Inline the [] operator for faster reading of characters.
114-
// Use the padded read internally, because the old version was hard-coded for buffers padded to default alignment.
115108
// Returning the character by value prevents writing to memory that might be a constant literal or shared with other strings
116109
inline DsrChar operator[] (intptr_t index) const {
117110
return this->view[index];
@@ -123,8 +116,35 @@ class ReadableString {
123116
ReadableString(const DsrChar *content);
124117
ReadableString(Handle<DsrChar> characters, Impl_CharacterView view)
125118
: characters(characters), view(view) {}
126-
// Create from String by sharing the buffer
127-
ReadableString(const String& source);
119+
// Destructor.
120+
~ReadableString() {}
121+
// Copy constructor.
122+
ReadableString(const ReadableString& source)
123+
: characters(source.characters), view(source.view) {}
124+
// Move constructor.
125+
ReadableString(ReadableString &&source) noexcept
126+
: characters(source.characters), view(source.view) {
127+
source.characters = Handle<DsrChar>();
128+
source.view = Impl_CharacterView();
129+
}
130+
// Copy assignment.
131+
ReadableString& operator = (const ReadableString& source) {
132+
if (this != &source) {
133+
this->characters = source.characters;
134+
this->view = source.view;
135+
}
136+
return *this;
137+
};
138+
// Move assignment.
139+
ReadableString& operator = (ReadableString &&source) {
140+
if (this != &source) {
141+
this->characters = source.characters;
142+
this->view = source.view;
143+
source.characters = Handle<DsrChar>();
144+
source.view = Impl_CharacterView();
145+
}
146+
return *this;
147+
}
128148
};
129149

130150
// A safe and simple string type
@@ -134,15 +154,37 @@ class ReadableString {
134154
// Endianness is native
135155
// No combined characters allowed, use precomposed instead, so that the strings can guarantee a fixed character size
136156
class String : public ReadableString {
137-
//IMPL_ACCESS:
138-
// TODO: Have a single pointer to the data in ReadableString and let the API be responsible for type safety.
139-
//SafePointer<DsrChar> writer;
140157
public:
141-
// Constructors
158+
// Constructors.
142159
String();
143160
String(const char* source);
144161
String(const DsrChar* source);
145-
String(const ReadableString& source);
162+
// Destructor.
163+
~String() {}
164+
// Copy constructor.
165+
String(const ReadableString& source) : ReadableString(source) {}
166+
String(const String& source) : ReadableString(source) {}
167+
// Move constructor.
168+
String(ReadableString &&source) noexcept : ReadableString(std::move(source)) {}
169+
String(String &&source) noexcept : ReadableString(std::move(source)) {}
170+
// Copy assignment.
171+
String& operator = (const String& source) {
172+
if (this != &source) {
173+
this->characters = source.characters;
174+
this->view = source.view;
175+
}
176+
return *this;
177+
};
178+
// Move assignment.
179+
String& operator = (String &&source) {
180+
if (this != &source) {
181+
this->characters = source.characters;
182+
this->view = source.view;
183+
source.characters = Handle<DsrChar>();
184+
source.view = Impl_CharacterView();
185+
}
186+
return *this;
187+
}
146188
};
147189

148190
// Used as format tags around numbers passed to string_append or string_combine

Source/DFPSR/base/heap.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,7 @@ namespace dsr {
427427
static void serializeUnknownData(PrintCharacter target, void const * const allocation, uintptr_t maxLength) {
428428
uintptr_t byteCount = heap_getUsedSize(allocation);
429429
target(U'{');
430-
for (intptr_t c = 0; c < byteCount; c++) {
430+
for (uintptr_t c = 0; c < byteCount; c++) {
431431
uint8_t byteValue = ((uint8_t *)allocation)[c];
432432
uint8_t firstHexValue = (byteValue >> 4) & 15;
433433
uint8_t secondHexValue = byteValue & 15;
@@ -750,8 +750,6 @@ namespace dsr {
750750

751751
static void heap_free(void * const allocation) {
752752
lockMemory();
753-
//printf("heap_free(%u) allocationCount: %i -> %i\n", (unsigned int)(uintptr_t)allocation, (int)allocationCount, (int)allocationCount - 1);
754-
//heap_debugPrintAllocation(allocation);
755753
// Get the recycled allocation's header.
756754
HeapHeader *header = headerFromAllocation(allocation);
757755
if (header->isRecycled()) {
@@ -823,22 +821,25 @@ namespace dsr {
823821
}
824822

825823
static void printCharacter(char32_t character) {
826-
if (character > 127) {
824+
if (character < 32) {
825+
putchar(' ');
826+
} else if (character > 127) {
827827
putchar('?');
828828
} else {
829829
putchar((char)character);
830830
}
831831
}
832832

833+
// TODO: Can whole pointers be displayed using printf?
833834
void heap_debugPrintAllocation(void const * const allocation, uintptr_t maxLength) {
834835
uintptr_t size = (int)heap_getUsedSize(allocation);
835836
#ifdef SAFE_POINTER_CHECKS
836-
printf("* %s of %i bytes of use count %i at %u\n", heap_getAllocationName(allocation), (int)size, (int)heap_getUseCount(allocation), (unsigned int)(uintptr_t)allocation);
837+
printf("* %s of %i bytes of use count %i at %p\n", heap_getAllocationName(allocation), (int)size, (int)heap_getUseCount(allocation), allocation);
837838
printf("\t");
838839
getAllocationSerialization(allocation)(printCharacter, allocation, maxLength);
839840
printf("\n");
840841
#else
841-
printf("* Allocation of %i bytes of use count %i at %u\n", (int)size, (int)heap_getUseCount(allocation), (unsigned int)(uintptr_t)allocation);
842+
printf("* Allocation of %i bytes of use count %i at %p\n", (int)size, (int)heap_getUseCount(allocation), allocation);
842843
#endif
843844
}
844845

Source/DFPSR/collection/Array.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -91,13 +91,13 @@ class Array {
9191
}
9292
};
9393
// Move constructor.
94-
Array(Array<T> &&other) noexcept
95-
: impl_elementCount(other.impl_elementCount), impl_elements(other.impl_elements) {
96-
other.impl_elementCount = 0;
97-
other.impl_elements = nullptr;
94+
Array(Array<T> &&source) noexcept
95+
: impl_elementCount(source.impl_elementCount), impl_elements(source.impl_elements) {
96+
source.impl_elementCount = 0;
97+
source.impl_elements = nullptr;
9898
}
99-
// When assigning to the array, memory can be reused when the size is the same.
100-
Array<T>& operator=(const Array<T>& source) {
99+
// Copy assignment.
100+
Array<T>& operator = (const Array<T>& source) {
101101
if (this != &source) {
102102
this->impl_destroy();
103103
this->impl_reallocate(source.impl_elementCount);
@@ -111,6 +111,8 @@ class Array {
111111
// Move assignment.
112112
Array<T>& operator = (Array<T> &&source) {
113113
if (this != &source) {
114+
this->impl_destroy();
115+
this->impl_free();
114116
this->impl_elementCount = source.impl_elementCount;
115117
this->impl_elements = source.impl_elements;
116118
source.impl_elementCount = 0;

Source/test/testTools.h

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "../DFPSR/math/FVector.h"
77
#include <cstdlib>
88
#include <csignal>
9+
#include <stdio.h>
910

1011
using namespace dsr;
1112

@@ -93,22 +94,10 @@ void dsrMain(List<String> args) \
9394
heap_forAllHeapAllocations([](AllocationHeader * header, void * allocation) { \
9495
heap_setAllocationCustomFlags(header, 1u); \
9596
}); \
96-
heap_debugPrintAllocations(); \
9797
{
9898

9999
#define END_TEST \
100100
} \
101-
intptr_t endAllocationCount = heap_getAllocationCount(); \
102-
if (endAllocationCount != startAllocationCount) { \
103-
heap_debugPrintAllocations(); \
104-
printText(U"\tPotentially leaked memory allocations:\n"); \
105-
heap_forAllHeapAllocations([](AllocationHeader * header, void * allocation) { \
106-
if (heap_getAllocationCustomFlags(header) == 0u) { \
107-
heap_debugPrintAllocation(allocation); \
108-
} \
109-
}); \
110-
throwError(U"Leaked ", endAllocationCount - startAllocationCount, U" memory allocations within the main function!\n"); \
111-
} \
112101
printText(U" (done)\n"); \
113102
stateName = U"After test end\n"; \
114103
if (failed) { \
@@ -176,6 +165,21 @@ void dsrMain(List<String> args) \
176165
#define ASSERT_GREATER_OR_EQUAL(A, B) ASSERT_COMP(A, B, OP_GREATER_OR_EQUAL, ">=")
177166
#define ASSERT_NEAR(A, B) ASSERT_COMP(A, B, OP_NEAR, "==")
178167

168+
#define ASSERT_HEAP_DEPTH(DEPTH) { \
169+
intptr_t currentAllocationCount = heap_getAllocationCount(); \
170+
intptr_t expectedAllocationCount = startAllocationCount + (DEPTH); \
171+
if (currentAllocationCount != expectedAllocationCount) { \
172+
printf( \
173+
"\n\n" \
174+
"_______________________________ FAIL _______________________________\n" \
175+
"\n" \
176+
"Expected allocation count %i but found %i allocations instead.\n" \
177+
"____________________________________________________________________\n" \
178+
, (int)expectedAllocationCount, (int)currentAllocationCount); \
179+
failed = true; \
180+
} \
181+
}
182+
179183
const dsr::String inputPath = dsr::string_combine(U"test", file_separator(), U"input", file_separator());
180184
const dsr::String expectedPath = dsr::string_combine(U"test", file_separator(), U"expected", file_separator());
181185

Source/test/tests/ArrayTest.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,17 @@
44

55
START_TEST(Array)
66
{ // Arrays of integers.
7+
ASSERT_HEAP_DEPTH(0);
78
Array<int> a = Array<int>(4, 123);
9+
ASSERT_HEAP_DEPTH(1);
810
a[1] = 85;
911
a[3] = -100;
1012
ASSERT_EQUAL(a.length(), 4);
1113
ASSERT_EQUAL(a[0], 123);
1214
ASSERT_EQUAL(a[1], 85);
1315
ASSERT_EQUAL(a[2], 123);
1416
ASSERT_EQUAL(a[3], -100);
17+
ASSERT_HEAP_DEPTH(1);
1518
ASSERT_EQUAL(string_combine(a),
1619
U"{\n"
1720
U" 123,\n"
@@ -20,10 +23,13 @@ START_TEST(Array)
2023
U" -100\n"
2124
U"}"
2225
);
26+
ASSERT_HEAP_DEPTH(1);
2327
// An initial assignment uses the copy constructor, because there is no pre-existing data in b.
2428
Array<int> b = a;
29+
ASSERT_HEAP_DEPTH(2);
2530
b[0] = 200;
2631
b[2] = 100000;
32+
ASSERT_HEAP_DEPTH(2);
2733
// The b array has changed...
2834
ASSERT_EQUAL(string_combine(b),
2935
U"{\n"
@@ -33,6 +39,7 @@ START_TEST(Array)
3339
U" -100\n"
3440
U"}"
3541
);
42+
ASSERT_HEAP_DEPTH(2);
3643
// ...but a remains the same, because the data was cloned when assigning.
3744
ASSERT_EQUAL(string_combine(a),
3845
U"{\n"
@@ -44,12 +51,15 @@ START_TEST(Array)
4451
);
4552
// They are not equal
4653
ASSERT_NOT_EQUAL(a, b);
47-
// Assigning from copy construction is optimized into an assignment operation, because b already exists.
54+
ASSERT_HEAP_DEPTH(2);
55+
// Assigning from copy construction.
4856
a = Array<int>(b);
57+
ASSERT_HEAP_DEPTH(2);
4958
// Now they are equal
5059
ASSERT_EQUAL(a, b);
5160
// Create another length
5261
Array<int> c = Array<int>(7, 75);
62+
ASSERT_HEAP_DEPTH(3);
5363
ASSERT_EQUAL(string_combine(c),
5464
U"{\n"
5565
U" 75,\n"
@@ -63,6 +73,7 @@ START_TEST(Array)
6373
);
6474
// Assign larger array
6575
a = c;
76+
ASSERT_HEAP_DEPTH(3);
6677
ASSERT_EQUAL(string_combine(a),
6778
U"{\n"
6879
U" 75,\n"
@@ -78,6 +89,7 @@ START_TEST(Array)
7889
ASSERT_NOT_EQUAL(a, b);
7990
// Assign smaller array
8091
c = b;
92+
ASSERT_HEAP_DEPTH(3);
8193
ASSERT_EQUAL(string_combine(c),
8294
U"{\n"
8395
U" 200,\n"

0 commit comments

Comments
 (0)