Skip to content

Commit 5990cc0

Browse files
committed
Add string pool
1 parent d73d191 commit 5990cc0

File tree

7 files changed

+172
-0
lines changed

7 files changed

+172
-0
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ target_sources(scratchcpp
4040
include/scratchcpp/value_functions.h
4141
include/scratchcpp/stringptr.h
4242
include/scratchcpp/string_functions.h
43+
include/scratchcpp/string_pool.h
4344
include/scratchcpp/entity.h
4445
include/scratchcpp/variable.h
4546
include/scratchcpp/list.h

include/scratchcpp/string_pool.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
#pragma once
4+
5+
#include "global.h"
6+
7+
namespace libscratchcpp
8+
{
9+
10+
struct StringPtr;
11+
12+
extern "C"
13+
{
14+
LIBSCRATCHCPP_EXPORT StringPtr *string_pool_new();
15+
LIBSCRATCHCPP_EXPORT void string_pool_free(StringPtr *str);
16+
}
17+
18+
} // namespace libscratchcpp

src/scratch/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ target_sources(scratchcpp
33
value_functions.cpp
44
value_functions_p.h
55
string_functions.cpp
6+
string_pool.cpp
7+
string_pool_p.h
68
drawable.cpp
79
drawable_p.cpp
810
drawable_p.h

src/scratch/string_pool.cpp

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
#include <scratchcpp/string_pool.h>
4+
#include <scratchcpp/stringptr.h>
5+
#include <scratchcpp/string_functions.h>
6+
#include <memory>
7+
#include <unordered_set>
8+
#include <unordered_map>
9+
#include <map>
10+
#include <cassert>
11+
12+
namespace libscratchcpp
13+
{
14+
15+
class Thread;
16+
17+
static std::unordered_set<std::unique_ptr<StringPtr>> strings;
18+
static std::multimap<size_t, StringPtr *> freeStrings; // sorted by allocated space
19+
20+
static std::unordered_map<Thread *, std::unordered_set<StringPtr *>> threadStrings;
21+
static Thread *currentThread = nullptr;
22+
23+
extern "C"
24+
{
25+
/*!
26+
* Use this instead of dynamically allocating StringPtr.
27+
* \note The returned string is uninitialized. Use e. g. string_assign_cstring() to initialize it.
28+
*/
29+
StringPtr *string_pool_new()
30+
{
31+
if (freeStrings.empty()) {
32+
auto str = std::make_unique<StringPtr>();
33+
StringPtr *ptr = str.get();
34+
assert(strings.find(str) == strings.cend());
35+
strings.insert(std::move(str));
36+
37+
if (currentThread)
38+
threadStrings[currentThread].insert(ptr);
39+
40+
return ptr;
41+
}
42+
43+
// Optimization: pick string with the highest capacity to minimize allocs
44+
auto last = std::prev(freeStrings.end());
45+
StringPtr *ptr = last->second;
46+
freeStrings.erase(last);
47+
48+
if (currentThread)
49+
threadStrings[currentThread].insert(ptr);
50+
51+
return ptr;
52+
}
53+
54+
/*! Invalidates the given StringPtr so that it can be used for new strings later. */
55+
void string_pool_free(StringPtr *str)
56+
{
57+
if (currentThread) {
58+
assert(threadStrings[currentThread].find(str) != threadStrings[currentThread].cend());
59+
threadStrings[currentThread].erase(str);
60+
}
61+
62+
freeStrings.insert(std::pair<size_t, StringPtr *>(str->allocatedSize, str));
63+
}
64+
}
65+
66+
/* string_pool_p.h */
67+
68+
void string_pool_add_thread(Thread *thread)
69+
{
70+
// Start capturing allocated strings in the thread
71+
assert(threadStrings.find(thread) == threadStrings.cend());
72+
threadStrings[thread] = {};
73+
}
74+
75+
void string_pool_remove_thread(Thread *thread)
76+
{
77+
// Free all strings in the thread (garbage collection)
78+
assert(threadStrings.find(thread) != threadStrings.cend());
79+
auto &strings = threadStrings[thread];
80+
81+
for (StringPtr *str : strings)
82+
freeStrings.insert(std::pair<size_t, StringPtr *>(str->allocatedSize, str));
83+
84+
strings.clear();
85+
86+
if (currentThread == thread)
87+
currentThread = nullptr;
88+
}
89+
90+
void string_pool_set_thread(Thread *thread)
91+
{
92+
currentThread = thread;
93+
}
94+
95+
} // namespace libscratchcpp

src/scratch/string_pool_p.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
namespace libscratchcpp
4+
{
5+
6+
class Thread;
7+
8+
void string_pool_add_thread(Thread *thread);
9+
void string_pool_remove_thread(Thread *thread);
10+
void string_pool_set_thread(Thread *thread);
11+
12+
} // namespace libscratchcpp

test/scratch_classes/CMakeLists.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,20 @@ target_link_libraries(
135135

136136
gtest_discover_tests(string_functions_test)
137137

138+
# string_pool_test
139+
add_executable(
140+
string_pool_test
141+
string_pool_test.cpp
142+
)
143+
144+
target_link_libraries(
145+
string_pool_test
146+
GTest::gtest_main
147+
scratchcpp
148+
)
149+
150+
gtest_discover_tests(string_pool_test)
151+
138152
# entity_test
139153
add_executable(
140154
entity_test
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#include <scratchcpp/string_pool.h>
2+
#include <scratchcpp/string_functions.h>
3+
#include <scratchcpp/stringptr.h>
4+
5+
#include "../common.h"
6+
7+
using namespace libscratchcpp;
8+
9+
TEST(StringPoolTest, NewAndFree)
10+
{
11+
StringPtr *str1 = string_pool_new();
12+
ASSERT_TRUE(str1);
13+
string_assign_cstring(str1, "test");
14+
ASSERT_EQ(str1->size, 4);
15+
16+
StringPtr *str2 = string_pool_new();
17+
ASSERT_TRUE(str2);
18+
string_assign_cstring(str2, "Lorem ipsum dolor sit amet");
19+
ASSERT_EQ(str2->size, 26);
20+
21+
string_pool_free(str1);
22+
string_pool_free(str2);
23+
24+
StringPtr *str3 = string_pool_new();
25+
ASSERT_TRUE(str3);
26+
string_assign_cstring(str3, "Hello world");
27+
ASSERT_EQ(str3->size, 11);
28+
29+
// str3 will be deallocated later
30+
}

0 commit comments

Comments
 (0)