8000 Containers: Add Containers memory dump test · Pagghiu/SaneCppLibraries@2019d98 · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Commit 2019d98

Browse files
committed
Containers: Add Containers memory dump test
1 parent 4073d79 commit 2019d98

File tree

2 files changed

+89
-0
lines changed

2 files changed

+89
-0
lines changed

Libraries/Containers/Tests/GlobalsContainerTest.cpp

+86
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
#include "../../Strings/String.h"
55
#include "../../Testing/Testing.h"
66
#include "../Vector.h"
7+
#include "../VectorMap.h"
8+
#include "../VectorSet.h"
79

810
namespace SC
911
{
@@ -19,9 +21,14 @@ struct SC::GlobalsContainerTest : public SC::TestCase
1921
{
2022
virtualGlobal();
2123
}
24+
if (test_section("virtual memory dump"))
25+
{
26+
virtualMemoryDump();
27+
}
2228
}
2329

2430
void virtualGlobal();
31+
void virtualMemoryDump();
2532
};
2633

2734
void SC::GlobalsContainerTest::virtualGlobal()
@@ -40,6 +47,85 @@ void SC::GlobalsContainerTest::virtualGlobal()
4047
Globals::pop(Globals::ThreadLocal);
4148
}
4249

50+
void SC::GlobalsContainerTest::virtualMemoryDump()
51+
{
52+
//! [GlobalContainerVirtualMemoryDumpSnippet]
53+
// -----------------------------------------------------------------------------
54+
// Example showing how to dump and restore a complex struct to a flat buffer.
55+
// SC::Segment based containers use relative pointers to make this possible.
56+
// DO NOT use this approach when versioning is needed, that means needing to
57+
// de-serialize after adding, removing or moving fields in the structure.
58+
// In such cases consider using SC::SerializationBinary (versioned reflection).
59+
// -----------------------------------------------------------------------------
60+
struct NestedStruct
61+
{
62+
VectorMap<String, int> someMap;
63+
VectorSet<int> someSet;
64+
};
65+
struct ComplexStruct
66+
{
67+
Vector<String> someStrings;
68+
int someField = 0;
69+
String singleString;
70+
NestedStruct nestedStruct;
71+
};
72+
Buffer memoryDump;
73+
74+
// Setup a Virtual Memory allocator with the max upper memory bound
75+
VirtualMemory virtualMemory;
76+
SC_TEST_EXPECT(virtualMemory.reserve(1024 * 1024)); // 1MB is enough here
77+
VirtualAllocator allocator = {virtualMemory};
78+
Globals globals = {allocator};
79+
80+
// Make the allocator current before creating a ComplexStruct
81+
Globals::push(Globals::Global, globals);
82+
ComplexStruct& object = *allocator.create<ComplexStruct>();
83+
object.someField = 42;
84+
object.singleString = "ASDF";
85+
object.someStrings = {"First", "Second"};
86+
SC_TEST_EXPECT(object.nestedStruct.someSet.insert(213));
87+
SC_TEST_EXPECT(object.nestedStruct.someMap.insertIfNotExists({"1", 1}));
88+
89+
// Save used bytes to memoryDump, checking that one page has been committed
90+
Span<const void> memory = {allocator.data(), allocator.size()};
91+
SC_TEST_EXPECT(virtualMemory.committedBytes == virtualMemory.getPageSize());
92+
SC_TEST_EXPECT(memory.sizeInBytes() < virtualMemory.getPageSize());
93+
SC_TEST_EXPECT(memory.data() == &object);
94+
SC_TEST_EXPECT((size_t(memoryDump.data()) % alignof(ComplexStruct)) == 0);
95+
Globals::pop(Globals::Global);
96+
97+
// Dump AFTER Globals::pop, using default allocator, and release virtual memory
98+
SC_TEST_EXPECT(memoryDump.append(memory));
99+
SC_TEST_EXPECT(virtualMemory.release());
100+
101+
// -----------------------------------------------------------------------------
102+
// Obtain a read-only view over ComplexStruct by re-interpreting the memory dump
103+
// NOTE: There's no need to call ComplexStruct destructor at end of scope
104+
// WARN: Using a different struct type or layout than the dumped one is UB
105+
// -----------------------------------------------------------------------------
106+
const Span<const void> span = memoryDump.toSpanConst();
107+
const ComplexStruct& readonly = *span.start_lifetime_as<const ComplexStruct>();
108+
SC_TEST_EXPECT(readonly.someField == 42);
109+
SC_TEST_EXPECT(readonly.singleString == "ASDF");
110+
SC_TEST_EXPECT(readonly.someStrings[0] == "First");
111+
SC_TEST_EXPECT(readonly.someStrings[1] == "Second");
112+
SC_TEST_EXPECT(readonly.someStrings.size() == 2);
113+
SC_TEST_EXPECT(readonly.nestedStruct.someSet.size() == 1);
114+
SC_TEST_EXPECT(readonly.nestedStruct.someSet.contains(213));
115+
SC_TEST_EXPECT(*readonly.nestedStruct.someMap.get("1") == 1);
116+
117+
// -----------------------------------------------------------------------------
118+
// To modify the struct again, copy the read-only view to a new object.
119+
// A Fixed or Virtual allocator can be used here to group sparse allocations in
120+
// a nice single contiguous buffer, before dumping it again to disk or network.
121+
// -----------------------------------------------------------------------------
122+
ComplexStruct modifiable = readonly;
123+
SC_TEST_EXPECT(modifiable.someStrings[0] == "First");
124+
modifiable.someStrings[0] = "First modified";
125+
SC_TEST_EXPECT(modifiable.someStrings[0] == "First modified");
126+
//! [GlobalContainerVirtualMemoryDumpSnippet]
127+
}
128+
43129
namespace SC
44130
{
45131
void runGlobalsContainerTest(SC::TestReport& report) { GlobalsContainerTest test(report); }

Libraries/Foundation/Globals.h

+3
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ struct SC::GlobalSettings
3030
///
3131
/// Example (Virtual Allocator):
3232
/// \snippet Libraries/Foundation/Tests/GlobalsTest.cpp GlobalsSnippetVirtual
33+
///
34+
/// Example (Memory dump):
35+
/// \snippet Libraries/Containers/Tests/GlobalsContainerTest.cpp GlobalContainerVirtualMemoryDumpSnippet
3336
struct SC::Globals
3437
{
3538
enum Type

0 commit comments

Comments
 (0)
0