simdjson 4.3.1
Ridiculously Fast JSON
Loading...
Searching...
No Matches
padded_string-inl.h
1#ifndef SIMDJSON_PADDED_STRING_INL_H
2#define SIMDJSON_PADDED_STRING_INL_H
3
4#include "simdjson/padded_string.h"
5#include "simdjson/padded_string_view.h"
6
7#include "simdjson/error-inl.h"
8#include "simdjson/padded_string_view-inl.h"
9
10#include <climits>
11#include <cwchar>
12
13namespace simdjson {
14namespace internal {
15
16// The allocate_padded_buffer function is a low-level function to allocate memory
17// with padding so we can read past the "length" bytes safely. It is used by
18// the padded_string class automatically. It returns nullptr in case
19// of error: the caller should check for a null pointer.
20// The length parameter is the maximum size in bytes of the string.
21// The caller is responsible to free the memory (e.g., delete[] (...)).
22inline char *allocate_padded_buffer(size_t length) noexcept {
23 const size_t totalpaddedlength = length + SIMDJSON_PADDING;
24 if(totalpaddedlength<length) {
25 // overflow
26 return nullptr;
27 }
28#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
29 // avoid getting out of memory
30 if (totalpaddedlength>(1UL<<20)) {
31 return nullptr;
32 }
33#endif
34
35 char *padded_buffer = new (std::nothrow) char[totalpaddedlength];
36 if (padded_buffer == nullptr) {
37 return nullptr;
38 }
39 // We write nulls in the padded region to avoid having uninitialized
40 // content which may trigger warning for some sanitizers
41 std::memset(padded_buffer + length, 0, totalpaddedlength - length);
42 return padded_buffer;
43} // allocate_padded_buffer()
44
45} // namespace internal
46
47
48inline padded_string::padded_string() noexcept = default;
49inline padded_string::padded_string(size_t length) noexcept
50 : viable_size(length), data_ptr(internal::allocate_padded_buffer(length)) {
51}
52inline padded_string::padded_string(const char *data, size_t length) noexcept
53 : viable_size(length), data_ptr(internal::allocate_padded_buffer(length)) {
54 if ((data != nullptr) && (data_ptr != nullptr)) {
55 std::memcpy(data_ptr, data, length);
56 }
57 if (data_ptr == nullptr) {
58 viable_size = 0;
59 }
60}
61#ifdef __cpp_char8_t
62inline padded_string::padded_string(const char8_t *data, size_t length) noexcept
63 : viable_size(length), data_ptr(internal::allocate_padded_buffer(length)) {
64 if ((data != nullptr) && (data_ptr != nullptr)) {
65 std::memcpy(data_ptr, reinterpret_cast<const char *>(data), length);
66 }
67 if (data_ptr == nullptr) {
68 viable_size = 0;
69 }
70}
71#endif
72// note: do not pass std::string arguments by value
73inline padded_string::padded_string(const std::string & str_ ) noexcept
74 : viable_size(str_.size()), data_ptr(internal::allocate_padded_buffer(str_.size())) {
75 if (data_ptr == nullptr) {
76 viable_size = 0;
77 } else {
78 std::memcpy(data_ptr, str_.data(), str_.size());
79 }
80}
81// note: do pass std::string_view arguments by value
82inline padded_string::padded_string(std::string_view sv_) noexcept
83 : viable_size(sv_.size()), data_ptr(internal::allocate_padded_buffer(sv_.size())) {
84 if(simdjson_unlikely(!data_ptr)) {
85 //allocation failed or zero size
86 viable_size = 0;
87 return;
88 }
89 if (sv_.size()) {
90 std::memcpy(data_ptr, sv_.data(), sv_.size());
91 }
92}
94 : viable_size(o.viable_size), data_ptr(o.data_ptr) {
95 o.data_ptr = nullptr; // we take ownership
96 o.viable_size = 0;
97}
98
100 delete[] data_ptr;
101 data_ptr = o.data_ptr;
102 viable_size = o.viable_size;
103 o.data_ptr = nullptr; // we take ownership
104 o.viable_size = 0;
105 return *this;
106}
107
108inline void padded_string::swap(padded_string &o) noexcept {
109 size_t tmp_viable_size = viable_size;
110 char *tmp_data_ptr = data_ptr;
111 viable_size = o.viable_size;
112 data_ptr = o.data_ptr;
113 o.data_ptr = tmp_data_ptr;
114 o.viable_size = tmp_viable_size;
115}
116
117inline padded_string::~padded_string() noexcept {
118 delete[] data_ptr;
119}
120
121inline size_t padded_string::size() const noexcept { return viable_size; }
122
123inline size_t padded_string::length() const noexcept { return viable_size; }
124
125inline const char *padded_string::data() const noexcept { return data_ptr; }
126
127inline char *padded_string::data() noexcept { return data_ptr; }
128
129inline bool padded_string::append(const char *data, size_t length) noexcept {
130 if (length == 0) {
131 return true; // Nothing to append
132 }
133 size_t new_size = viable_size + length;
134 if (new_size < viable_size) {
135 // Overflow, cannot append
136 return false;
137 }
138 char *new_data_ptr = internal::allocate_padded_buffer(new_size);
139 if (new_data_ptr == nullptr) {
140 // Allocation failed, cannot append
141 return false;
142 }
143 // Copy existing data
144 if (viable_size > 0) {
145 std::memcpy(new_data_ptr, data_ptr, viable_size);
146 }
147 // Copy new data
148 std::memcpy(new_data_ptr + viable_size, data, length);
149 // Update
150 delete[] data_ptr;
151 data_ptr = new_data_ptr;
152 viable_size = new_size;
153 return true;
154}
155
156inline padded_string::operator std::string_view() const simdjson_lifetime_bound { return std::string_view(data(), length()); }
157
158inline padded_string::operator padded_string_view() const noexcept simdjson_lifetime_bound {
159 return padded_string_view(data(), length(), length() + SIMDJSON_PADDING);
160}
161
162inline simdjson_result<padded_string> padded_string::load(std::string_view filename) noexcept {
163 // Open the file
164 SIMDJSON_PUSH_DISABLE_WARNINGS
165 SIMDJSON_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC: manually verified this is safe
166 std::FILE *fp = std::fopen(filename.data(), "rb");
167 SIMDJSON_POP_DISABLE_WARNINGS
168
169 if (fp == nullptr) {
170 return IO_ERROR;
171 }
172
173 // Get the file size
174 int ret;
175#if SIMDJSON_VISUAL_STUDIO && !SIMDJSON_IS_32BITS
176 ret = _fseeki64(fp, 0, SEEK_END);
177#else
178 ret = std::fseek(fp, 0, SEEK_END);
179#endif // _WIN64
180 if(ret < 0) {
181 std::fclose(fp);
182 return IO_ERROR;
183 }
184#if SIMDJSON_VISUAL_STUDIO && !SIMDJSON_IS_32BITS
185 __int64 llen = _ftelli64(fp);
186 if(llen == -1L) {
187 std::fclose(fp);
188 return IO_ERROR;
189 }
190#else
191 long llen = std::ftell(fp);
192 if((llen < 0) || (llen == LONG_MAX)) {
193 std::fclose(fp);
194 return IO_ERROR;
195 }
196#endif
197
198 // Allocate the padded_string
199 size_t len = static_cast<size_t>(llen);
200 padded_string s(len);
201 if (s.data() == nullptr) {
202 std::fclose(fp);
203 return MEMALLOC;
204 }
205
206 // Read the padded_string
207 std::rewind(fp);
208 size_t bytes_read = std::fread(s.data(), 1, len, fp);
209 if (std::fclose(fp) != 0 || bytes_read != len) {
210 return IO_ERROR;
211 }
212
213 return s;
214}
215
216#if defined(_WIN32) && SIMDJSON_CPLUSPLUS17
217inline simdjson_result<padded_string> padded_string::load(std::wstring_view filename) noexcept {
218 // Open the file using the wide characters
219 SIMDJSON_PUSH_DISABLE_WARNINGS
220 SIMDJSON_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC: manually verified this is safe
221 std::FILE *fp = _wfopen(filename.data(), L"rb");
222 SIMDJSON_POP_DISABLE_WARNINGS
223
224 if (fp == nullptr) {
225 return IO_ERROR;
226 }
227
228 // Get the file size
229 int ret;
230#if SIMDJSON_VISUAL_STUDIO && !SIMDJSON_IS_32BITS
231 ret = _fseeki64(fp, 0, SEEK_END);
232#else
233 ret = std::fseek(fp, 0, SEEK_END);
234#endif // _WIN64
235 if(ret < 0) {
236 std::fclose(fp);
237 return IO_ERROR;
238 }
239#if SIMDJSON_VISUAL_STUDIO && !SIMDJSON_IS_32BITS
240 __int64 llen = _ftelli64(fp);
241 if(llen == -1L) {
242 std::fclose(fp);
243 return IO_ERROR;
244 }
245#else
246 long llen = std::ftell(fp);
247 if((llen < 0) || (llen == LONG_MAX)) {
248 std::fclose(fp);
249 return IO_ERROR;
250 }
251#endif
252
253 // Allocate the padded_string
254 size_t len = static_cast<size_t>(llen);
255 padded_string s(len);
256 if (s.data() == nullptr) {
257 std::fclose(fp);
258 return MEMALLOC;
259 }
260
261 // Read the padded_string
262 std::rewind(fp);
263 size_t bytes_read = std::fread(s.data(), 1, len, fp);
264 if (std::fclose(fp) != 0 || bytes_read != len) {
265 return IO_ERROR;
266 }
267
268 return s;
269}
270#endif
271
272// padded_string_builder implementations
273
274inline padded_string_builder::padded_string_builder() noexcept = default;
275
276inline padded_string_builder::padded_string_builder(size_t new_capacity) noexcept {
277 if (new_capacity > 0) {
278 data = internal::allocate_padded_buffer(new_capacity);
279 if (data != nullptr) {
280 this->capacity = new_capacity;
281 }
282 }
283}
284
286 : size(o.size), capacity(o.capacity), data(o.data) {
287 o.size = 0;
288 o.capacity = 0;
289 o.data = nullptr;
290}
291
293 if (this != &o) {
294 delete[] data;
295 size = o.size;
296 capacity = o.capacity;
297 data = o.data;
298 o.size = 0;
299 o.capacity = 0;
300 o.data = nullptr;
301 }
302 return *this;
303}
304
306 delete[] data;
307}
308
309inline bool padded_string_builder::append(const char *newdata, size_t length) noexcept {
310 if (length == 0) {
311 return true;
312 }
313 if (!reserve(length)) {
314 return false;
315 }
316 std::memcpy(data + size, newdata, length);
317 size += length;
318 return true;
319}
320
321inline bool padded_string_builder::append(std::string_view sv) noexcept {
322 return append(sv.data(), sv.size());
323}
324
325inline size_t padded_string_builder::length() const noexcept {
326 return size;
327}
328
330 return padded_string(data, size);
331}
332
334 padded_string result{};
335 result.data_ptr = data;
336 result.viable_size = size;
337 data = nullptr;
338 size = 0;
339 capacity = 0;
340 return result;
341}
342
343inline bool padded_string_builder::reserve(size_t additional) noexcept {
344 size_t needed = size + additional;
345 if (needed <= capacity) {
346 return true;
347 }
348 size_t new_capacity = needed;
349 // We are going to grow the capacity exponentially to avoid
350 // repeated allocations.
351 if (new_capacity < 4096) {
352 new_capacity *= 2;
353 } else {
354 new_capacity += new_capacity/2; // grow by 1.5x
355 }
356 char *new_data = internal::allocate_padded_buffer(new_capacity);
357 if (new_data == nullptr) {
358 return false; // Allocation failed
359 }
360 if (size > 0) {
361 std::memcpy(new_data, data, size);
362 }
363 delete[] data;
364 data = new_data;
365 capacity = new_capacity;
366 return true;
367}
368
369} // namespace simdjson
370
371inline simdjson::padded_string operator ""_padded(const char *str, size_t len) {
372 return simdjson::padded_string(str, len);
373}
374#ifdef __cpp_char8_t
375inline simdjson::padded_string operator ""_padded(const char8_t *str, size_t len) {
376 return simdjson::padded_string(reinterpret_cast<const char *>(str), len);
377}
378#endif
379#endif // SIMDJSON_PADDED_STRING_INL_H
Builder for constructing padded_string incrementally.
padded_string convert() noexcept
Convert the current content into a padded_string.
padded_string_builder & operator=(padded_string_builder &&o) noexcept
Move assignment.
~padded_string_builder() noexcept
Destructor.
size_t length() const noexcept
Get the current length of the built string.
padded_string build() const noexcept
Build a padded_string from the current content.
bool append(const char *newdata, size_t length) noexcept
Append data to the builder.
padded_string_builder() noexcept
Create a new, empty padded string builder.
User-provided string that promises it has extra padded bytes at the end for use with parser::parse().
The top level simdjson namespace, containing everything the library provides.
Definition base.h:8
@ MEMALLOC
Error allocating memory, most likely out of memory.
Definition error.h:22
@ IO_ERROR
Error reading a file.
Definition error.h:41
constexpr size_t SIMDJSON_PADDING
The amount of padding needed in a buffer to parse JSON.
Definition base.h:33
String with extra allocation for ease of use with parser::parse()
size_t size() const noexcept
The length of the string.
bool append(const char *data, size_t length) noexcept
Append data to the padded string.
size_t length() const noexcept
The length of the string.
padded_string() noexcept
Create a new, empty padded string.
padded_string & operator=(padded_string &&o) noexcept
Move one padded string into another.
const char * data() const noexcept
The string data.
static simdjson_result< padded_string > load(std::string_view path) noexcept
Load this padded string from a file.
The result of a simdjson operation that could fail.
Definition error.h:280