Container System 0.1.0
High-performance C++20 type-safe container framework with SIMD-accelerated serialization
Loading...
Searching...
No Matches
value_store.cpp
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2021, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
5#include "value_store.h"
6#include <stdexcept>
7#include <cstring>
8
9namespace kcenon::container {
10
11void value_store::add(const std::string& key, value val) {
12 // Always acquire lock to eliminate TOCTOU vulnerability (see #190)
13 std::unique_lock lock(mutex_);
14 values_[key] = std::move(val);
15 write_count_.fetch_add(1, std::memory_order_relaxed);
16}
17
18std::optional<value> value_store::get(const std::string& key) const {
19 // Always acquire lock to eliminate TOCTOU vulnerability (see #190)
20 std::shared_lock lock(mutex_);
21 auto it = values_.find(key);
22 if (it != values_.end()) {
23 read_count_.fetch_add(1, std::memory_order_relaxed);
24 return it->second;
25 }
26 return std::nullopt;
27}
28
29bool value_store::contains(const std::string& key) const {
30 // Always acquire lock to eliminate TOCTOU vulnerability (see #190)
31 std::shared_lock lock(mutex_);
32 return values_.find(key) != values_.end();
33}
34
35bool value_store::remove(const std::string& key) {
36 // Always acquire lock to eliminate TOCTOU vulnerability (see #190)
37 std::unique_lock lock(mutex_);
38 auto it = values_.find(key);
39 if (it != values_.end()) {
40 values_.erase(it);
41 return true;
42 }
43 return false;
44}
45
46void value_store::clear() {
47 // Always acquire lock to eliminate TOCTOU vulnerability (see #190)
48 std::unique_lock lock(mutex_);
49 values_.clear();
50}
51
52size_t value_store::size() const {
53 // Always acquire lock to eliminate TOCTOU vulnerability (see #190)
54 std::shared_lock lock(mutex_);
55 return values_.size();
56}
57
58bool value_store::empty() const {
59 return size() == 0;
60}
61
62std::string value_store::serialize() const {
63 // Always acquire lock to eliminate TOCTOU vulnerability (see #190)
64 std::shared_lock lock(mutex_);
65 return serialize_impl();
66}
67
68std::string value_store::serialize_impl() const {
69 read_count_.fetch_add(1, std::memory_order_relaxed);
70
71 std::string result = "{";
72 bool first = true;
73
74 for (const auto& [key, val] : values_) {
75 if (!first) {
76 result += ",";
77 }
78 first = false;
79
80 // Escape key for JSON
81 result += "\"";
82 for (char c : key) {
83 switch (c) {
84 case '"': result += "\\\""; break;
85 case '\\': result += "\\\\"; break;
86 case '\n': result += "\\n"; break;
87 case '\r': result += "\\r"; break;
88 case '\t': result += "\\t"; break;
89 default: result += c;
90 }
91 }
92 result += "\":";
93 result += val.to_json();
94 }
95
96 result += "}";
97 return result;
98}
99
100std::vector<uint8_t> value_store::serialize_binary() const {
101 // Always acquire lock to eliminate TOCTOU vulnerability (see #190)
102 std::shared_lock lock(mutex_);
103 return serialize_binary_impl();
104}
105
106std::vector<uint8_t> value_store::serialize_binary_impl() const {
107 read_count_.fetch_add(1, std::memory_order_relaxed);
108
109 std::vector<uint8_t> result;
110
111 // Version byte for future compatibility
112 constexpr uint8_t version = 1;
113 result.push_back(version);
114
115 // Header: number of entries (4 bytes)
116 uint32_t count = static_cast<uint32_t>(values_.size());
117 result.insert(result.end(),
118 reinterpret_cast<const uint8_t*>(&count),
119 reinterpret_cast<const uint8_t*>(&count) + sizeof(count));
120
121 // Serialize each key-value pair
122 for (const auto& [key, val] : values_) {
123 // Key length and key
124 uint32_t key_len = static_cast<uint32_t>(key.size());
125 result.insert(result.end(),
126 reinterpret_cast<const uint8_t*>(&key_len),
127 reinterpret_cast<const uint8_t*>(&key_len) + sizeof(key_len));
128 result.insert(result.end(), key.begin(), key.end());
129
130 // Value serialization
131 auto value_data = val.serialize();
132 uint32_t value_len = static_cast<uint32_t>(value_data.size());
133 result.insert(result.end(),
134 reinterpret_cast<const uint8_t*>(&value_len),
135 reinterpret_cast<const uint8_t*>(&value_len) + sizeof(value_len));
136 result.insert(result.end(), value_data.begin(), value_data.end());
137 }
138
139 return result;
140}
141
142std::unique_ptr<value_store> value_store::deserialize(std::string_view /*json_data*/) {
143 // JSON deserialization requires a JSON parser library
144 // For now, use serialize_binary/deserialize_binary for round-trip serialization
145 throw std::runtime_error(
146 "value_store::deserialize() requires JSON parser - use deserialize_binary() instead");
147}
148
149std::unique_ptr<value_store> value_store::deserialize_binary(const std::vector<uint8_t>& binary_data) {
150 auto store = std::make_unique<value_store>();
151
152 if (binary_data.size() < 1 + sizeof(uint32_t)) {
153 throw std::runtime_error("value_store::deserialize_binary() - invalid data: too small");
154 }
155
156 size_t offset = 0;
157
158 // Read version byte
159 uint8_t version = binary_data[offset++];
160 if (version != 1) {
161 throw std::runtime_error("value_store::deserialize_binary() - unsupported version: "
162 + std::to_string(version));
163 }
164
165 // Read number of entries
166 uint32_t count;
167 std::memcpy(&count, binary_data.data() + offset, sizeof(count));
168 offset += sizeof(count);
169
170 // Read each key-value pair
171 for (uint32_t i = 0; i < count; ++i) {
172 if (offset + sizeof(uint32_t) > binary_data.size()) {
173 throw std::runtime_error("value_store::deserialize_binary() - truncated data at entry "
174 + std::to_string(i));
175 }
176
177 // Read key length
178 uint32_t key_len;
179 std::memcpy(&key_len, binary_data.data() + offset, sizeof(key_len));
180 offset += sizeof(key_len);
181
182 if (offset + key_len + sizeof(uint32_t) > binary_data.size()) {
183 throw std::runtime_error("value_store::deserialize_binary() - truncated key data");
184 }
185
186 // Read key
187 std::string key(binary_data.begin() + offset,
188 binary_data.begin() + offset + key_len);
189 offset += key_len;
190
191 // Read value length
192 uint32_t value_len;
193 std::memcpy(&value_len, binary_data.data() + offset, sizeof(value_len));
194 offset += sizeof(value_len);
195
196 if (offset + value_len > binary_data.size()) {
197 throw std::runtime_error("value_store::deserialize_binary() - truncated value data");
198 }
199
200 // Deserialize value
201 std::vector<uint8_t> value_data(binary_data.begin() + offset,
202 binary_data.begin() + offset + value_len);
203 offset += value_len;
204
205 auto value_opt = value::deserialize(value_data);
206 if (value_opt) {
207 store->values_[key] = std::move(*value_opt);
208 } else {
209 throw std::runtime_error("value_store::deserialize_binary() - failed to deserialize value for key: "
210 + key);
211 }
212 }
213
214 return store;
215}
216
217size_t value_store::get_read_count() const {
218 return read_count_.load(std::memory_order_relaxed);
219}
220
221size_t value_store::get_write_count() const {
222 return write_count_.load(std::memory_order_relaxed);
223}
224
225void value_store::reset_statistics() {
226 read_count_.store(0, std::memory_order_relaxed);
227 write_count_.store(0, std::memory_order_relaxed);
228}
229
230#if CONTAINER_HAS_COMMON_RESULT
231kcenon::common::Result<std::unique_ptr<value_store>>
232value_store::deserialize_result(std::string_view /*json_data*/) noexcept {
233 return kcenon::common::Result<std::unique_ptr<value_store>>(
234 kcenon::common::error_info{
235 error_codes::deserialization_failed,
236 "value_store::deserialize_result() requires JSON parser - use deserialize_binary_result() instead",
237 "container_system"});
238}
239
240kcenon::common::Result<std::unique_ptr<value_store>>
241value_store::deserialize_binary_result(const std::vector<uint8_t>& binary_data) noexcept {
242 try {
243 auto store = std::make_unique<value_store>();
244
245 if (binary_data.size() < 1 + sizeof(uint32_t)) {
246 return kcenon::common::Result<std::unique_ptr<value_store>>(
247 kcenon::common::error_info{
248 error_codes::corrupted_data,
249 "value_store::deserialize_binary_result() - invalid data: too small",
250 "container_system"});
251 }
252
253 size_t offset = 0;
254
255 uint8_t version = binary_data[offset++];
256 if (version != 1) {
257 return kcenon::common::Result<std::unique_ptr<value_store>>(
258 kcenon::common::error_info{
259 error_codes::version_mismatch,
260 "value_store::deserialize_binary_result() - unsupported version: "
261 + std::to_string(version),
262 "container_system"});
263 }
264
265 uint32_t count;
266 std::memcpy(&count, binary_data.data() + offset, sizeof(count));
267 offset += sizeof(count);
268
269 for (uint32_t i = 0; i < count; ++i) {
270 if (offset + sizeof(uint32_t) > binary_data.size()) {
271 return kcenon::common::Result<std::unique_ptr<value_store>>(
272 kcenon::common::error_info{
273 error_codes::corrupted_data,
274 "value_store::deserialize_binary_result() - truncated data at entry "
275 + std::to_string(i),
276 "container_system"});
277 }
278
279 uint32_t key_len;
280 std::memcpy(&key_len, binary_data.data() + offset, sizeof(key_len));
281 offset += sizeof(key_len);
282
283 if (offset + key_len + sizeof(uint32_t) > binary_data.size()) {
284 return kcenon::common::Result<std::unique_ptr<value_store>>(
285 kcenon::common::error_info{
286 error_codes::corrupted_data,
287 "value_store::deserialize_binary_result() - truncated key data",
288 "container_system"});
289 }
290
291 std::string key(binary_data.begin() + offset,
292 binary_data.begin() + offset + key_len);
293 offset += key_len;
294
295 uint32_t value_len;
296 std::memcpy(&value_len, binary_data.data() + offset, sizeof(value_len));
297 offset += sizeof(value_len);
298
299 if (offset + value_len > binary_data.size()) {
300 return kcenon::common::Result<std::unique_ptr<value_store>>(
301 kcenon::common::error_info{
302 error_codes::corrupted_data,
303 "value_store::deserialize_binary_result() - truncated value data",
304 "container_system"});
305 }
306
307 std::vector<uint8_t> value_data(binary_data.begin() + offset,
308 binary_data.begin() + offset + value_len);
309 offset += value_len;
310
311 auto value_opt = value::deserialize(value_data);
312 if (value_opt) {
313 store->values_[key] = std::move(*value_opt);
314 } else {
315 return kcenon::common::Result<std::unique_ptr<value_store>>(
316 kcenon::common::error_info{
317 error_codes::value_parse_failed,
318 "value_store::deserialize_binary_result() - failed to deserialize value for key: "
319 + key,
320 "container_system"});
321 }
322 }
323
324 return kcenon::common::ok(std::move(store));
325 } catch (const std::bad_alloc&) {
326 return kcenon::common::Result<std::unique_ptr<value_store>>(
327 kcenon::common::error_info{
328 error_codes::memory_allocation_failed,
329 "value_store::deserialize_binary_result() - memory allocation failed",
330 "container_system"});
331 } catch (const std::exception& e) {
332 return kcenon::common::Result<std::unique_ptr<value_store>>(
333 kcenon::common::error_info{
334 error_codes::deserialization_failed,
335 std::string("value_store::deserialize_binary_result() - unexpected error: ") + e.what(),
336 "container_system"});
337 }
338}
339#endif
340
341} // namespace kcenon::container
static std::optional< value > deserialize(const std::vector< uint8_t > &data)
Deserialize from binary format (legacy compatible)
Definition value.cpp:555