1#ifndef SIMDJSON_INLINE_DOCUMENT_H
2#define SIMDJSON_INLINE_DOCUMENT_H
3
4// Inline implementations go in here.
5
6#include "simdjson/dom/document.h"
7#include "simdjson/dom/element.h"
8#include "simdjson/internal/tape_ref.h"
9#include "simdjson/internal/jsonformatutils.h"
10#include <ostream>
11#include <cstring>
12
13namespace simdjson {
14namespace dom {
15
16//
17// document inline implementation
18//
19inline element document::root() const noexcept {
20 return element(internal::tape_ref(this, 1));
21}
22simdjson_warn_unused
23inline size_t document::capacity() const noexcept {
24 return allocated_capacity;
25}
26
27simdjson_warn_unused
28inline error_code document::allocate(size_t capacity) noexcept {
29 if (capacity == 0) {
30 string_buf.reset();
31 tape.reset();
32 allocated_capacity = 0;
33 return SUCCESS;
34 }
35
36 // a pathological input like "[[[[..." would generate capacity tape elements, so
37 // need a capacity of at least capacity + 1, but it is also possible to do
38 // worse with "[7,7,7,7,6,7,7,7,6,7,7,6,[7,7,7,7,6,7,7,7,6,7,7,6,7,7,7,7,7,7,6"
39 //where capacity + 1 tape elements are
40 // generated, see issue https://github.com/simdjson/simdjson/issues/345
41 size_t tape_capacity = SIMDJSON_ROUNDUP_N(capacity + 3, 64);
42 // a document with only zero-length strings... could have capacity/3 string
43 // and we would need capacity/3 * 5 bytes on the string buffer
44 size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * capacity / 3 + SIMDJSON_PADDING, 64);
45 string_buf.reset( p: new (std::nothrow) uint8_t[string_capacity]);
46 tape.reset(p: new (std::nothrow) uint64_t[tape_capacity]);
47 if(!(string_buf && tape)) {
48 allocated_capacity = 0;
49 string_buf.reset();
50 tape.reset();
51 return MEMALLOC;
52 }
53 // Technically the allocated_capacity might be larger than capacity
54 // so the next line is pessimistic.
55 allocated_capacity = capacity;
56 return SUCCESS;
57}
58
59inline bool document::dump_raw_tape(std::ostream &os) const noexcept {
60 uint32_t string_length;
61 size_t tape_idx = 0;
62 uint64_t tape_val = tape[tape_idx];
63 uint8_t type = uint8_t(tape_val >> 56);
64 os << tape_idx << " : " << type;
65 tape_idx++;
66 size_t how_many = 0;
67 if (type == 'r') {
68 how_many = size_t(tape_val & internal::JSON_VALUE_MASK);
69 } else {
70 // Error: no starting root node?
71 return false;
72 }
73 os << "\t// pointing to " << how_many << " (right after last node)\n";
74 uint64_t payload;
75 for (; tape_idx < how_many; tape_idx++) {
76 os << tape_idx << " : ";
77 tape_val = tape[tape_idx];
78 payload = tape_val & internal::JSON_VALUE_MASK;
79 type = uint8_t(tape_val >> 56);
80 switch (type) {
81 case '"': // we have a string
82 os << "string \"";
83 std::memcpy(dest: &string_length, src: string_buf.get() + payload, n: sizeof(uint32_t));
84 os << internal::escape_json_string(std::string_view(
85 reinterpret_cast<const char *>(string_buf.get() + payload + sizeof(uint32_t)),
86 string_length
87 ));
88 os << '"';
89 os << '\n';
90 break;
91 case 'l': // we have a long int
92 if (tape_idx + 1 >= how_many) {
93 return false;
94 }
95 os << "integer " << static_cast<int64_t>(tape[++tape_idx]) << "\n";
96 break;
97 case 'u': // we have a long uint
98 if (tape_idx + 1 >= how_many) {
99 return false;
100 }
101 os << "unsigned integer " << tape[++tape_idx] << "\n";
102 break;
103 case 'd': // we have a double
104 os << "float ";
105 if (tape_idx + 1 >= how_many) {
106 return false;
107 }
108 double answer;
109 std::memcpy(dest: &answer, src: &tape[++tape_idx], n: sizeof(answer));
110 os << answer << '\n';
111 break;
112 case 'n': // we have a null
113 os << "null\n";
114 break;
115 case 't': // we have a true
116 os << "true\n";
117 break;
118 case 'f': // we have a false
119 os << "false\n";
120 break;
121 case '{': // we have an object
122 os << "{\t// pointing to next tape location " << uint32_t(payload)
123 << " (first node after the scope), "
124 << " saturated count "
125 << ((payload >> 32) & internal::JSON_COUNT_MASK)<< "\n";
126 break; case '}': // we end an object
127 os << "}\t// pointing to previous tape location " << uint32_t(payload)
128 << " (start of the scope)\n";
129 break;
130 case '[': // we start an array
131 os << "[\t// pointing to next tape location " << uint32_t(payload)
132 << " (first node after the scope), "
133 << " saturated count "
134 << ((payload >> 32) & internal::JSON_COUNT_MASK)<< "\n";
135 break;
136 case ']': // we end an array
137 os << "]\t// pointing to previous tape location " << uint32_t(payload)
138 << " (start of the scope)\n";
139 break;
140 case 'r': // we start and end with the root node
141 // should we be hitting the root node?
142 return false;
143 default:
144 return false;
145 }
146 }
147 tape_val = tape[tape_idx];
148 payload = tape_val & internal::JSON_VALUE_MASK;
149 type = uint8_t(tape_val >> 56);
150 os << tape_idx << " : " << type << "\t// pointing to " << payload
151 << " (start root)\n";
152 return true;
153}
154
155} // namespace dom
156} // namespace simdjson
157
158#endif // SIMDJSON_INLINE_DOCUMENT_H
159