BehaviorTree
Core Library to create and execute Behavior Trees
Loading...
Searching...
No Matches
simple_string.hpp
1#pragma once
2
3#include <cstdint>
4#include <cstring>
5#include <limits>
6#include <stdexcept>
7#include <string>
8#include <string_view>
9
10namespace SafeAny
11{
12
13// Read only version of String that has size 16 bytes and can store
14// in-place strings with size up to 15 bytes.
15
16// Inspired by https://github.com/elliotgoodrich/SSO-23
17
18class SimpleString
19{
20public:
21 SimpleString()
22 {
23 _storage.soo.capacity_left = CAPACITY;
24 _storage.soo.data[0] = '\0';
25 }
26
27 SimpleString(const std::string& str) : SimpleString(str.data(), str.size())
28 {}
29
30 SimpleString(const std::string_view& str) : SimpleString(str.data(), str.size())
31 {}
32
33 SimpleString(const SimpleString& other) : SimpleString(other.data(), other.size())
34 {}
35
36 SimpleString& operator=(const SimpleString& other)
37 {
38 if(this != &other)
39 {
40 this->~SimpleString();
41 createImpl(other.data(), other.size());
42 }
43 return *this;
44 }
45
46 SimpleString(SimpleString&& other) noexcept : SimpleString()
47 {
48 std::swap(_storage, other._storage);
49 }
50
51 SimpleString& operator=(SimpleString&& other) noexcept
52 {
53 if(this != &other)
54 {
55 std::swap(_storage, other._storage);
56 }
57 return *this;
58 }
59
60 SimpleString(const char* input_data) : SimpleString(input_data, strlen(input_data))
61 {}
62
63 SimpleString(const char* input_data, std::size_t size)
64 {
65 createImpl(input_data, size);
66 }
67
68 ~SimpleString()
69 {
70 if(!isSOO())
71 {
72 delete[] _storage.str.data;
73 }
74 _storage.soo.capacity_left = CAPACITY;
75 }
76
77 std::string toStdString() const
78 {
79 return size() > 0 ? std::string(data(), size()) : std::string();
80 }
81 std::string_view toStdStringView() const
82 {
83 return size() > 0 ? std::string_view(data(), size()) : std::string_view();
84 }
85
86 const char* data() const
87 {
88 if(isSOO())
89 {
90 return _storage.soo.data;
91 }
92 else
93 {
94 return _storage.str.data;
95 }
96 }
97
98 std::size_t size() const
99 {
100 if(isSOO())
101 {
102 return CAPACITY - _storage.soo.capacity_left;
103 }
104 else
105 {
106 return _storage.str.size & LONG_MASK;
107 }
108 }
109
110 bool operator==(const SimpleString& other) const
111 {
112 const size_t N = size();
113 return other.size() == N && std::strncmp(data(), other.data(), N) == 0;
114 }
115
116 bool operator!=(const SimpleString& other) const
117 {
118 const size_t N = size();
119 return other.size() != N || std::strncmp(data(), other.data(), N) != 0;
120 }
121
122 bool operator<=(const SimpleString& other) const
123 {
124 return !(*this > other);
125 }
126
127 bool operator>=(const SimpleString& other) const
128 {
129 return !(*this < other);
130 }
131
132 bool operator<(const SimpleString& other) const
133 {
134 const size_t min_size = std::min(size(), other.size());
135 int cmp = std::memcmp(data(), other.data(), min_size);
136 if(cmp != 0)
137 {
138 return cmp < 0;
139 }
140 return size() < other.size();
141 }
142
143 bool operator>(const SimpleString& other) const
144 {
145 const size_t min_size = std::min(size(), other.size());
146 int cmp = std::memcmp(data(), other.data(), min_size);
147 if(cmp != 0)
148 {
149 return cmp > 0;
150 }
151 return size() > other.size();
152 }
153
154 bool isSOO() const
155 {
156 return (_storage.soo.capacity_left & IS_LONG_BIT) == 0;
157 }
158
159private:
160 struct String
161 {
162 char* data = nullptr;
163 std::size_t size = 0;
164 };
165
166 constexpr static std::size_t CAPACITY = 15; // sizeof(String) - 1);
167 constexpr static std::size_t IS_LONG_BIT = 1 << 7;
168 constexpr static std::size_t LONG_MASK = (~std::size_t(0)) >> 1;
169 constexpr static std::size_t MAX_SIZE = 100UL * 1024UL * 1024UL;
170
171 union
172 {
173 String str;
174
175 struct SOO
176 {
177 char data[CAPACITY];
178 uint8_t capacity_left = CAPACITY;
179 } soo;
180 } _storage = {};
181
182private:
183 void createImpl(const char* input_data, std::size_t size)
184 {
185 if(size > MAX_SIZE)
186 {
187 throw std::invalid_argument("size too large for a simple string");
188 }
189
190 if(size > CAPACITY)
191 {
192 _storage.str.size = size;
193 _storage.soo.capacity_left = IS_LONG_BIT;
194 _storage.str.data = new char[size + 1]; // NOLINT(cppcoreguidelines-owning-memory)
195 std::memcpy(_storage.str.data, input_data, size);
196 _storage.str.data[size] = '\0';
197 }
198 else
199 {
200 _storage.soo.capacity_left = uint8_t(CAPACITY - size);
201 if(size > 0)
202 {
203 std::memcpy(_storage.soo.data, input_data, size);
204 }
205 if(size < CAPACITY)
206 {
207 _storage.soo.data[size] = '\0';
208 }
209 }
210 }
211};
212
213} // namespace SafeAny
Definition: simple_string.hpp:19