/src/arduinojson/src/ArduinoJson/Memory/StringNode.hpp
Line | Count | Source |
1 | | // ArduinoJson - https://arduinojson.org |
2 | | // Copyright © 2014-2026, Benoit BLANCHON |
3 | | // MIT License |
4 | | |
5 | | #pragma once |
6 | | |
7 | | #include <ArduinoJson/Memory/Allocator.hpp> |
8 | | #include <ArduinoJson/Namespace.hpp> |
9 | | #include <ArduinoJson/Polyfills/assert.hpp> |
10 | | #include <ArduinoJson/Polyfills/integer.hpp> |
11 | | #include <ArduinoJson/Polyfills/limits.hpp> |
12 | | |
13 | | #include <stddef.h> // offsetof |
14 | | |
15 | | ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE |
16 | | |
17 | | struct StringNode { |
18 | | // Use the same type as SlotId to store the reference count |
19 | | // (there can never be more references than slots) |
20 | | using references_type = uint_t<ARDUINOJSON_SLOT_ID_SIZE * 8>; |
21 | | |
22 | | using length_type = uint_t<ARDUINOJSON_STRING_LENGTH_SIZE * 8>; |
23 | | |
24 | | struct StringNode* next; |
25 | | references_type references; |
26 | | length_type length; |
27 | | char data[1]; |
28 | | |
29 | | static constexpr size_t maxLength = numeric_limits<length_type>::highest(); |
30 | | |
31 | 9.03k | static constexpr size_t sizeForLength(size_t n) { |
32 | 9.03k | return n + 1 + offsetof(StringNode, data); |
33 | 9.03k | } |
34 | | |
35 | 6.34k | static StringNode* create(size_t length, Allocator* allocator) { |
36 | 6.34k | if (length > maxLength) |
37 | 113 | return nullptr; |
38 | 6.23k | auto size = sizeForLength(length); |
39 | 6.23k | if (size < length) // integer overflow |
40 | 0 | return nullptr; // (not testable on 64-bit) |
41 | 6.23k | auto node = reinterpret_cast<StringNode*>(allocator->allocate(size)); |
42 | 6.23k | if (node) { |
43 | 6.23k | node->length = length_type(length); |
44 | 6.23k | node->references = 1; |
45 | 6.23k | } |
46 | 6.23k | return node; |
47 | 6.23k | } |
48 | | |
49 | | static StringNode* resize(StringNode* node, size_t length, |
50 | 2.79k | Allocator* allocator) { |
51 | 2.79k | ARDUINOJSON_ASSERT(node != nullptr); |
52 | 2.79k | StringNode* newNode; |
53 | 2.79k | if (length <= maxLength) |
54 | 2.79k | newNode = reinterpret_cast<StringNode*>( |
55 | 2.79k | allocator->reallocate(node, sizeForLength(length))); |
56 | 0 | else |
57 | 0 | newNode = nullptr; |
58 | 2.79k | if (newNode) |
59 | 2.79k | newNode->length = length_type(length); |
60 | 0 | else |
61 | 0 | allocator->deallocate(node); |
62 | 2.79k | return newNode; |
63 | 2.79k | } |
64 | | |
65 | 6.23k | static void destroy(StringNode* node, Allocator* allocator) { |
66 | 6.23k | allocator->deallocate(node); |
67 | 6.23k | } |
68 | | }; |
69 | | |
70 | | // Returns the size (in bytes) of an string with n characters. |
71 | 0 | constexpr size_t sizeofString(size_t n) { |
72 | 0 | return StringNode::sizeForLength(n); |
73 | 0 | } |
74 | | |
75 | | ARDUINOJSON_END_PRIVATE_NAMESPACE |