pjson 2.0.0
A small, owning JSON value for C++11
Loading...
Searching...
No Matches
pjson.h
1//
2// Copyright 2025 ByteDance Ltd. and/or its affiliates. All rights reserved.
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15//===----------------------------------------------------------------------===//
16// pjson — Praveen's JSON: an ultra-simple JSON value type for C++.
17//
18// A single class, ByteDance::pjson, represents any JSON value and offers an
19// ergonomic obj["key"][i] = value building style plus serialization, lookup,
20// mutation, and equality. Parsing lives in the separate ByteDance::pJsonParser
21// helper declared by <pjson_parser.h>; the DOM does not depend on that parser.
22// JSON Schema validation similarly lives in ByteDance::pJsonSchemaValidator in
23// <pjson_schema.h>, which consumes only the public DOM API.
24//
25// Author: Praveen Babu J D
26// License: Apache 2.0
27//
28#ifndef PRAVEENJSON_H
29#define PRAVEENJSON_H
30
31// Library version. PJSON_VERSION is the string form ("MAJOR.MINOR.PATCH");
32// the numeric parts allow compile-time checks, e.g.
33// #if PJSON_VERSION_MAJOR >= 1
34#define PJSON_VERSION_MAJOR 2
35#define PJSON_VERSION_MINOR 0
36#define PJSON_VERSION_PATCH 0
37#define PJSON_VERSION "2.0.0"
38#define PJSON_ABI_VERSION 2
39
40#if defined(_WIN32) && defined(PJSON_SHARED)
41#if defined(PJSON_BUILDING_LIBRARY)
42#define PJSON_API __declspec(dllexport)
43#else
44#define PJSON_API __declspec(dllimport)
45#endif
46#elif defined(PJSON_SHARED) && (defined(__GNUC__) || defined(__clang__))
47#define PJSON_API __attribute__((visibility("default")))
48#else
49#define PJSON_API
50#endif
51
52#include <cstddef>
53#include <cstdint>
54#include <iosfwd>
55#include <string>
56#include <vector>
57
58namespace ByteDance {
59 struct pjsonImpl;
60 //==[Interface]============================================================
61 /// Owning, mutable JSON value with deep-copy semantics.
62 ///
63 /// Child pointers and string views exposed by lookup/access APIs are borrowed
64 /// from the owning tree. They become invalid when the child or an ancestor is
65 /// destroyed, replaced, reset, erased, moved, swapped, cleared, or successfully
66 /// patched. Unless an operation is `noexcept` or explicitly reports failures,
67 /// allocation and standard-library exceptions may escape.
68 class PJSON_API pjson {
69 public:
70 //== Library version =================================================
71 /// Returns the process-lifetime semantic-version string for this library.
72 static const char* getVersion();
73
74 //== Types ===========================================================
75
76 /// JSON value kind.
77 ///
78 /// Numbers are stored in one of three representations: signed whole
79 /// numbers as a 64-bit signed integer (jsonNumberInt), explicitly
80 /// unsigned whole numbers as a 64-bit unsigned integer (jsonNumberUInt),
81 /// and fractional/exponent values as a double (jsonNumberDouble).
82 enum jsonType : int64_t {
83 jsonNull = 0, ///< JSON null and the stable default discriminator.
84 jsonString, ///< UTF-8 string value.
85 jsonNumberInt, ///< Signed 64-bit integer value.
86 jsonNumberDouble, ///< Binary64 number value.
87 jsonBoolean, ///< Boolean value.
88 jsonArray, ///< Ordered array value.
89 jsonObject, ///< Object with unique string keys.
90 jsonNumberUInt, ///< Unsigned 64-bit integer value.
91 };
92
93 /// Runtime allocator for persistent DOM storage.
94 ///
95 /// The allocator is non-owning and must outlive every pjson value that
96 /// refers to it. Allocation covers pjson child/root nodes, non-null
97 /// private implementations, and the std::string, array, and object
98 /// wrapper objects. Storage used internally by those standard-library
99 /// objects and transient parser/algorithm scratch space continues to use
100 /// the standard allocator.
101 struct PJSON_API Allocator {
102 /// Identifies the purpose and matching deallocation contract of storage.
104 NodeAllocation = 0, ///< Storage for a child or allocator-created root.
105 StringAllocation = 1, ///< Storage for a std::string wrapper.
106 ArrayAllocation = 2, ///< Storage for an array-container wrapper.
107 ObjectAllocation = 3, ///< Storage for an object-container wrapper.
108 ImplementationAllocation = 4 ///< Opaque state of one non-null pjson value.
109 };
110
111 /// Enables destruction through an Allocator base pointer.
112 virtual ~Allocator();
113 /// Returns non-null aligned storage or throws; returning null is unsupported.
114 virtual void* allocate(size_t aSize, size_t aAlignment, AllocationKind aKind) = 0;
115 /// Releases a non-null allocation using its original size, alignment, and kind.
116 virtual void deallocate(void* aPtr, size_t aSize, size_t aAlignment,
117 AllocationKind aKind) noexcept = 0;
118 };
119
120 /// Structured JSON Pointer (RFC 6901) lookup failure.
121 ///
122 /// `tokenIndex` is zero-based and `token` is the decoded token that could
123 /// not be resolved (or the source token when its escape sequence is
124 /// invalid). std::string reporting overloads reset all fields on entry. A
125 /// C-string overload can report allocation failure before copying the
126 /// pointer text.
127 struct PJSON_API PointerError {
128 /// Stable categories for programmatic JSON Pointer failure handling.
129 enum Code {
130 Ok, ///< Lookup succeeded.
131 InvalidSyntax, ///< The pointer does not begin with slash or is malformed.
132 InvalidEscape, ///< A token contains an invalid tilde escape.
133 MissingTarget, ///< An object member or array element does not exist.
134 ExpectedContainer, ///< Traversal encountered a scalar before the final token.
135 InvalidArrayIndex, ///< An array token is not a canonical non-negative index.
136 ArrayIndexOutOfRange, ///< An array token exceeds the current array bounds.
137 AppendTokenNotAllowed, ///< The append token is invalid for lookup.
138 AllocationFailure, ///< Diagnostic construction could not allocate.
139 InternalError ///< An unexpected internal exception was contained.
140 };
141
142 bool ok; ///< True exactly when code is Ok.
143 Code code; ///< Stable machine-readable result category.
144 std::string pointer; ///< Pointer text supplied by the caller.
145 size_t tokenIndex; ///< Zero-based index of the failing token.
146 std::string token; ///< Decoded failing token when available.
147 std::string message; ///< Human-readable diagnostic; wording is not stable.
148 /// Constructs a successful lookup state with no pointer or token details.
149 PointerError();
150 };
151
152 /// Structured JSON Patch (RFC 6902) / Merge Patch (RFC 7396) failure.
153 ///
154 /// Patch application is atomic: failure leaves the target unchanged.
155 /// Reporting patch APIs reset all fields on entry and on success.
156 struct PJSON_API PatchError {
157 /// Stable categories for programmatic JSON Patch failure handling.
158 enum Code {
159 Ok, ///< Patch application succeeded.
160 InvalidPatchDocument, ///< The patch document is not an array.
161 OperationNotObject, ///< An operation entry is not an object.
162 MissingOp, ///< An operation lacks a string `op` member.
163 MissingPath, ///< An operation lacks a string `path` member.
164 MissingFrom, ///< A copy or move lacks a string `from` member.
165 MissingValue, ///< An add, replace, or test lacks `value`.
166 InvalidOp, ///< The operation name is unsupported.
167 InvalidPath, ///< The destination JSON Pointer is invalid.
168 InvalidFrom, ///< The source JSON Pointer is invalid.
169 TargetMissing, ///< A required source, parent, or target is absent.
170 InvalidArrayIndex, ///< An array path token is not a valid index.
171 ArrayIndexOutOfRange, ///< An array path token exceeds valid bounds.
172 MoveRootNotAllowed, ///< A move attempts to remove the document root.
173 MoveIntoDescendant, ///< A move destination lies under its source.
174 TestFailed, ///< A test operation did not compare equal.
175 ResourceLimit, ///< A configured patch-work limit was reached.
176 AllocationFailure, ///< Patch application could not allocate.
177 InternalError ///< An unexpected internal exception was contained.
178 };
179
180 bool ok; ///< True exactly when code is Ok.
181 Code code; ///< Stable machine-readable result category.
182 size_t opIndex; ///< Zero-based index of the failing operation.
183 std::string op; ///< Operation name when available.
184 std::string path; ///< Destination pointer when available.
185 std::string from; ///< Source pointer when available.
186 size_t tokenIndex; ///< Zero-based index of the failing pointer token.
187 std::string token; ///< Decoded failing pointer token when available.
188 std::string message; ///< Human-readable diagnostic; wording is not stable.
189 /// Constructs a successful patch state with no operation or token details.
190 PatchError();
191 };
192
193 /// Bounds transactional patch amplification.
194 ///
195 /// Zero selects the documented built-in ceiling rather than disabling a
196 /// safety limit. Clone bytes include node storage plus string and
197 /// object-key payload bytes.
198 struct PJSON_API PatchOptions {
199 size_t maxOperations; ///< Operation ceiling; zero selects the hard 10,000 limit.
200 size_t maxClonedNodes; ///< Clone-node ceiling; zero selects the hard 1,000,000 limit.
201 size_t maxClonedBytes; ///< Clone-byte ceiling; zero selects the hard 64 MiB limit.
202 size_t maxWork; ///< Work ceiling; zero selects the hard 1,000,000 limit.
203 /// Selects the documented finite default limits.
204 PatchOptions();
205 };
206
207 /// Controls JSON serialization.
208 ///
209 /// The default produces compact output in native object-storage order.
210 /// Pretty output places each array
211 /// element/object member on its own line. Only space and tab are valid
212 /// indentation characters; any other value is treated as a space so
213 /// serialization always remains valid JSON.
214 ///
215 /// Object storage and serialization order are unspecified.
216 struct PJSON_API SerializeOptions {
217 // Governs how a stored non-finite double (NaN, +/-infinity) is
218 // serialized. JSON has no non-finite literal, so the default fails
219 // with a structured error rather than silently changing the value's
220 // type. NonFiniteToNull opts in to the legacy behavior of writing
221 // JSON null; NonFiniteToString writes the strings "NaN",
222 // "Infinity", and "-Infinity" for interoperability with permissive
223 // consumers. The chosen policy applies identically to compact,
224 // pretty, buffered, and streaming output.
225 /// Selects how stored NaN and infinity values are represented.
227 RejectNonFinite, ///< Fail because JSON has no non-finite number literal.
228 NonFiniteToNull, ///< Emit non-finite values as JSON null.
229 NonFiniteToString ///< Emit "NaN" or signed "Infinity" strings.
230 };
231
232 bool pretty; ///< Enables line breaks and indentation.
233 size_t indentWidth; ///< Indentation characters per nesting level.
234 char indentCharacter; ///< Space or tab; invalid values are treated as space.
235 bool escapeNonAscii; ///< Emits non-ASCII code points as Unicode escapes.
236 NonFinitePolicy nonFinite; ///< Policy for NaN and infinity values.
237 size_t maxOutputBytes; ///< Output ceiling; zero explicitly means unlimited.
238
239 /// Selects compact output, two-space indentation, and non-finite rejection.
241 /// Returns the defaults with pretty printing enabled.
243 };
244
245 /// Structured outcome for the non-throwing serialization APIs.
246 struct PJSON_API SerializeError {
247 /// Stable categories for programmatic serialization failure handling.
248 enum Code {
249 None, ///< Serialization succeeded.
250 InvalidUtf8, ///< A stored string or object key is not valid UTF-8.
251 NonFiniteNumber, ///< NaN or infinity was rejected by the active policy.
252 OutputLimit, ///< maxOutputBytes or representable output size was exceeded.
253 AllocationFailure, ///< Temporary serialization storage could not be allocated.
254 StreamFailure, ///< The destination stream rejected a physical write.
255 InternalError ///< An unexpected internal exception was contained.
256 };
257
258 Code code; ///< Stable machine-readable result category.
259 std::string message; ///< Human-readable diagnostic; empty on success.
260 /// Constructs a successful serialization result.
262 /// Resets the result to success.
263 void reset() noexcept;
264 };
265
266 //== Construction / lifetime =========================================
267 /// Constructs null using the process-lifetime default allocator.
268 pjson() noexcept;
269 /// Constructs null bound to borrowed aAlloc, which must outlive this tree.
270 explicit pjson(Allocator& aAlloc) noexcept;
271 /// Destroys this value and its complete owned subtree.
273 /// Deep-copies aFrom using aFrom's borrowed allocator.
274 pjson(const pjson& aFrom);
275 /// Deep-copies aFrom into borrowed aAlloc.
276 pjson(const pjson& aFrom, Allocator& aAlloc);
277 /// Transfers aFrom's storage and allocator in O(1), leaving aFrom null.
278 pjson(pjson&& aFrom) noexcept;
279 /// Transfers in O(1) when allocators match; otherwise deep-copies then clears aFrom.
280 pjson(pjson&& aFrom, Allocator& aAlloc);
281 /// Deep-copies aFrom while preserving this value's allocator.
282 pjson& operator=(const pjson& aFrom);
283 /// Moves aFrom while preserving this allocator; cross-allocator moves may allocate.
284 pjson& operator=(pjson&& aFrom);
285 /// Deep-copies aFrom while preserving this value's allocator.
286 void copyFrom(const pjson& aFrom);
287 /// Destroys the current contents and becomes null.
288 void reset();
289 /// Replaces the value with the empty/default value of a valid jsonType.
290 void resetTo(jsonType aeType);
291 /// Calls resetTo() only when the type differs, otherwise preserving contents.
292 void resetIfNeeded(jsonType aeType);
293 // Same-allocator, non-overlapping swap is O(1). Cross-allocator and
294 // ancestor/descendant swaps are rejected as safe no-ops; use canSwap()
295 // to test before requesting one.
296 /// Exchanges compatible, non-overlapping contents; otherwise does nothing.
297 void swap(pjson& aOther) noexcept;
298 /// Returns the borrowed allocator bound to this value.
299 Allocator& getAllocator() const noexcept;
300 /// Returns whether swap(aOther) can exchange contents safely.
301 bool canSwap(const pjson& aOther) const noexcept;
302
303 //== Serialization ===================================================
304 // Invalid UTF-8 and rejected non-finite doubles are serialization
305 // failures: the convenience toString() overloads throw, while legacy
306 // write() sets failbit (and may propagate enabled stream exceptions).
307 // The SerializeError overloads never throw and expose stable categories.
308 /// Returns compact JSON using the default serialization options.
309 std::string toString() const;
310 /// Returns JSON serialized according to aOpts.
311 std::string toString(const SerializeOptions& aOpts) const;
312 /// Serializes into aOut transactionally and reports failure without throwing.
313 bool toString(std::string& aOut, SerializeError& aError,
314 const SerializeOptions& aOpts = SerializeOptions()) const noexcept;
315 /// Writes compact JSON to aOut using the default serialization options.
316 void write(std::ostream& aOut) const;
317 /// Writes JSON configured by aOpts to aOut.
318 void write(std::ostream& aOut, const SerializeOptions& aOpts) const;
319 /// Writes JSON and reports logical or physical failure without throwing.
320 bool write(std::ostream& aOut, SerializeError& aError,
321 const SerializeOptions& aOpts = SerializeOptions()) const noexcept;
322
323 //== Type inspection =================================================
324 /// Returns this node's stored JSON representation.
325 jsonType getType() const;
326 /// Returns whether this node is null.
327 bool isNull() const;
328 /// Returns whether this node stores a string.
329 bool isString() const;
330 /// Returns whether this node stores any numeric representation.
331 bool isNumber() const;
332 /// Returns whether this node stores a signed-integer representation.
333 bool isInt() const;
334 /// Returns whether this node stores an unsigned-integer representation.
335 bool isUInt() const;
336 /// Returns whether this node stores any integer representation (signed or unsigned).
337 bool isInteger() const;
338 /// Returns whether this node stores a floating-point representation.
339 bool isDouble() const;
340 /// Returns whether this node stores a boolean.
341 bool isBool() const;
342 /// Returns whether this node stores an array.
343 bool isArray() const;
344 /// Returns whether this node stores an object.
345 bool isObject() const;
346
347 /// Minimal C++11-compatible, non-owning view of a JSON string.
348 ///
349 /// A view aliases bytes owned by this pjson node and is valid only while
350 /// that node remains alive and unchanged. Assignment, reset, swap, move,
351 /// destruction, erasing the node, or replacing/resetting an ancestor
352 /// invalidates it. Strings may contain embedded NUL bytes; use size()
353 /// rather than strlen().
354 class PJSON_API StringView {
355 public:
356 /// Constructs an empty view with data() == nullptr.
357 StringView() noexcept;
358 /// Returns the borrowed first byte; a default view returns null.
359 const char* data() const noexcept;
360 /// Returns the number of bytes in the view, including embedded NUL bytes.
361 size_t size() const noexcept;
362 /// Returns whether size() is zero.
363 bool empty() const noexcept;
364
365 private:
366 friend class pjson;
367 /// Constructs the internal borrowed view used by tryGet().
368 StringView(const char* aData, size_t aSize) noexcept;
369
370 const char* _data;
371 size_t _size;
372 };
373
374 // Strict typed access to this node. On a type mismatch, returns false
375 // and leaves aResult unchanged. A signed integer read accepts an
376 // unsigned value only when it fits in int64_t; an unsigned integer read
377 // accepts a signed value only when it is non-negative; a double read
378 // widens any integer. No other coercions are performed. StringView
379 // avoids a string copy.
380 /// Extracts a signed integer; an unsigned value must fit in int64_t.
381 bool tryGet(int64_t& aResult) const noexcept;
382 /// Extracts an unsigned integer; a signed value must be non-negative.
383 bool tryGet(uint64_t& aResult) const noexcept;
384 /// Extracts a numeric value, widening a stored integer when necessary.
385 bool tryGet(double& aResult) const noexcept;
386 /// Extracts a boolean only when this node stores jsonBoolean.
387 bool tryGet(bool& aResult) const noexcept;
388 /// Copies a string only when this node stores jsonString.
389 bool tryGet(std::string& aResult) const;
390 /// Borrows a string view only when this node stores jsonString.
391 bool tryGet(StringView& aResult) const noexcept;
392
393 //== Container queries ===============================================
394 /// Returns the element/member count for containers, or zero for scalars.
395 size_t size() const;
396 /// Returns whether size() is zero; consequently all scalar values are empty.
397 bool empty() const;
398 /// Empties a container without changing its type, or resets a scalar to null.
399 void clear();
400
401 /// Returns copied object keys in unspecified storage order, or an empty vector otherwise.
402 std::vector<std::string> keys() const;
403
404 //== Non-allocating traversal =======================================
405 /// Callback for read-only object-member traversal.
406 typedef bool (*ConstMemberVisitor)(StringView aKey, const pjson& aValue, void* aContext);
407 /// Callback for mutable object-member traversal.
408 typedef bool (*MemberVisitor)(StringView aKey, pjson& aValue, void* aContext);
409 /// Callback for read-only array-element traversal.
410 typedef bool (*ConstElementVisitor)(const pjson& aValue, void* aContext);
411 /// Callback for mutable array-element traversal.
412 typedef bool (*ElementVisitor)(pjson& aValue, void* aContext);
413 ///
414 /// Traversal copies no object names and performs no per-member lookup.
415 /// Object members are visited in unspecified storage order and array
416 /// elements in index order. Borrowed arguments are valid only for the callback. The
417 /// opaque context is forwarded unchanged. Returning false stops early.
418 /// A callback must not resize the traversed container. Calling a traversal
419 /// method on the wrong container type is a no-op that returns true.
420 /// Visits each object member as (key view, const value); false stops early.
421 bool forEachMember(ConstMemberVisitor aVisitor, void* aContext) const;
422 /// Visits each object member as (key view, mutable value); false stops early.
423 bool forEachMember(MemberVisitor aVisitor, void* aContext);
424 /// Visits each array element as a const value; false stops early.
425 bool forEachElement(ConstElementVisitor aVisitor, void* aContext) const;
426 /// Visits each array element as a mutable value; false stops early.
427 bool forEachElement(ElementVisitor aVisitor, void* aContext);
428
429 //== Non-mutating lookup =============================================
430 /// Returns whether this object contains aKey.
431 bool hasKey(const std::string& aKey) const;
432 /// Returns whether this object contains non-null aKey; null returns false.
433 bool hasKey(const char* aKey) const;
434 /// Alias for hasKey(aKey); reads more naturally at call sites.
435 bool contains(const std::string& aKey) const;
436 /// Alias for hasKey(aKey); reads more naturally at call sites.
437 bool contains(const char* aKey) const;
438 /// Returns whether this array contains aIndex; negative indexes count from the end.
439 bool hasIndex(int aIndex) const noexcept;
440
441 // Returns a pointer to the child stored under aKey, or nullptr when
442 // this is not a map or the key is absent. Unlike operator[], this
443 // never creates or mutates anything.
444 /// Returns the borrowed child at aKey, or null when absent or not an object.
445 pjson* find(const std::string& aKey);
446 /// Returns the borrowed child at non-null aKey, or null on failure.
447 pjson* find(const char* aKey);
448 /// Returns the read-only borrowed child at aKey, or null on failure.
449 const pjson* find(const std::string& aKey) const;
450 /// Returns the read-only borrowed child at non-null aKey, or null on failure.
451 const pjson* find(const char* aKey) const;
452
453 // Non-vivifying array lookup. Negative indexes count from the end
454 // (-1 is the last element); indexes outside the array return nullptr.
455 // These overloads never change this node or its size.
456 /// Returns the borrowed array child at aIndex, or null on failure.
457 pjson* find(int aIndex) noexcept;
458 /// Returns the read-only borrowed array child at aIndex, or null on failure.
459 const pjson* find(int aIndex) const noexcept;
460 /// Returns the borrowed array child at a non-negative index, or null on failure.
461 pjson* findIndex(size_t aIndex) noexcept;
462 /// Returns the read-only borrowed array child at a non-negative index, or null.
463 const pjson* findIndex(size_t aIndex) const noexcept;
464
465 // RFC 6901 lookup. The empty pointer addresses this value; every
466 // non-empty pointer must begin with '/'. Lookups are iterative and
467 // never create missing nodes. The '-' token is not a lookup index.
468 /// Escapes one decoded reference token for inclusion in a JSON Pointer.
469 static std::string escapePointerToken(const std::string& aToken);
470 /// Resolves aPointer and returns the borrowed target, or null on failure.
471 pjson* findPointer(const std::string& aPointer);
472 /// Resolves aPointer and returns the read-only borrowed target, or null.
473 const pjson* findPointer(const std::string& aPointer) const;
474 /// Resolves aPointer and reports lookup failure in aError.
475 pjson* findPointer(const std::string& aPointer, PointerError& aError);
476 /// Resolves aPointer read-only and reports lookup failure in aError.
477 const pjson* findPointer(const std::string& aPointer, PointerError& aError) const;
478 /// Resolves a non-null pointer string; null returns failure.
479 pjson* findPointer(const char* aPointer);
480 /// Resolves a non-null pointer string read-only; null returns failure.
481 const pjson* findPointer(const char* aPointer) const;
482 /// Resolves a non-null pointer string and reports failure in aError.
483 pjson* findPointer(const char* aPointer, PointerError& aError);
484 /// Resolves a non-null pointer string read-only and reports failure in aError.
485 const pjson* findPointer(const char* aPointer, PointerError& aError) const;
486
487 // Strict typed child access layered on find() and node-level tryGet().
488 // Missing/null keys, invalid indexes, and type mismatches leave aResult
489 // unchanged. Negative indexes count from the end.
490 /// Extracts the integer child at aKey without mutating this object.
491 bool tryGet(const std::string& aKey, int64_t& aResult) const;
492 /// Extracts the unsigned-integer child at aKey without mutating this object.
493 bool tryGet(const std::string& aKey, uint64_t& aResult) const;
494 /// Extracts the numeric child at aKey as a double.
495 bool tryGet(const std::string& aKey, double& aResult) const;
496 /// Extracts the boolean child at aKey.
497 bool tryGet(const std::string& aKey, bool& aResult) const;
498 /// Copies the string child at aKey.
499 bool tryGet(const std::string& aKey, std::string& aResult) const;
500 /// Borrows a view of the string child at aKey.
501 bool tryGet(const std::string& aKey, StringView& aResult) const;
502
503 /// Extracts the integer child at non-null aKey.
504 bool tryGet(const char* aKey, int64_t& aResult) const;
505 /// Extracts the unsigned-integer child at non-null aKey.
506 bool tryGet(const char* aKey, uint64_t& aResult) const;
507 /// Extracts the numeric child at non-null aKey as a double.
508 bool tryGet(const char* aKey, double& aResult) const;
509 /// Extracts the boolean child at non-null aKey.
510 bool tryGet(const char* aKey, bool& aResult) const;
511 /// Copies the string child at non-null aKey.
512 bool tryGet(const char* aKey, std::string& aResult) const;
513 /// Borrows a view of the string child at non-null aKey.
514 bool tryGet(const char* aKey, StringView& aResult) const;
515
516 /// Extracts the integer array child at aIndex.
517 bool tryGet(int aIndex, int64_t& aResult) const noexcept;
518 /// Extracts the unsigned-integer array child at aIndex.
519 bool tryGet(int aIndex, uint64_t& aResult) const noexcept;
520 /// Extracts the numeric array child at aIndex as a double.
521 bool tryGet(int aIndex, double& aResult) const noexcept;
522 /// Extracts the boolean array child at aIndex.
523 bool tryGet(int aIndex, bool& aResult) const noexcept;
524 /// Copies the string array child at aIndex.
525 bool tryGet(int aIndex, std::string& aResult) const;
526 /// Borrows a view of the string array child at aIndex.
527 bool tryGet(int aIndex, StringView& aResult) const noexcept;
528
529 //== Building / mutable access =======================================
530 // operator[] is a direct builder API. A key access changes a non-object
531 // into an object and creates a missing null child. An index access changes
532 // a non-array into an array; valid negative indexes count from the end,
533 // while an index before the beginning throws std::out_of_range without
534 // mutation. Non-negative indexes past the end grow the array with null
535 // children. A single access that would create more than one million
536 // children throws std::length_error before mutation. Use find()/tryGet()
537 // for reads.
538 /// Returns or creates the child at aString.
539 pjson& operator[](const std::string& aString);
540 /// Returns or creates the child at aSkey; throws std::invalid_argument for null.
541 pjson& operator[](const char* aSkey);
542 /// Returns or creates the child at index under the auto-growth rules above.
543 pjson& operator[](int index);
544 /// Returns or creates the child at a non-negative index.
545 pjson& operator[](size_t index);
546
547 //== Factories and typed construction ================================
548 // Explicit, unambiguous ways to create each JSON kind without relying on
549 // default construction having a particular type. Each uses the default
550 // allocator; the allocator-aware constructors remain available for
551 // custom-allocator trees.
552 /// Returns a JSON null value.
553 static pjson null();
554 /// Returns an empty JSON object value.
555 static pjson object();
556 /// Returns an empty JSON array value.
557 static pjson array();
558 /// Replaces this value with JSON null (std::nullptr_t assignment).
559 pjson& operator=(std::nullptr_t);
560
561 //== Checked access ==================================================
562 // at() is a checked, non-vivifying accessor. Unlike operator[], it never
563 // creates a child: a missing object key, an out-of-range index, or a
564 // wrong container type throws std::out_of_range.
565 /// Returns the existing child at aKey or throws std::out_of_range.
566 pjson& at(const std::string& aKey);
567 /// Returns the read-only child at aKey or throws std::out_of_range.
568 const pjson& at(const std::string& aKey) const;
569 /// Returns the existing element at aIndex or throws std::out_of_range.
570 pjson& at(size_t aIndex);
571 /// Returns the read-only element at aIndex or throws std::out_of_range.
572 const pjson& at(size_t aIndex) const;
573
574 //== Generic child insertion ========================================
575 // Append or assign arbitrary pjson values, not just scalars. A non-array
576 // target is promoted to an array by pushBack. Cross-allocator inserts
577 // deep-copy the value into this node's allocator.
578 /// Appends a deep copy of aValue, promoting this node to an array.
579 pjson& pushBack(const pjson& aValue);
580 /// Moves an independent same-allocator value; otherwise deep-copies it.
581 pjson& pushBack(pjson&& aValue);
582 /// Inserts or replaces the member aKey with a deep copy of aValue.
583 pjson& insertOrAssign(const std::string& aKey, const pjson& aValue);
584 /// Moves an independent same-allocator value; otherwise deep-copies it.
585 pjson& insertOrAssign(const std::string& aKey, pjson&& aValue);
586 /// Reserves capacity for at least aCount array elements (no-op for non-arrays
587 /// unless this node is first made an array); returns *this for chaining.
588 pjson& reserve(size_t aCount);
589
590 // Assign a scalar value, replacing whatever this node was. Numbers are
591 // stored as int64_t (signed integers), uint64_t (unsigned integers), or
592 // double (floating point). An explicit uint64_t assignment retains the
593 // unsigned type identity even for small values.
594 /// Replaces this value with a copy of aString.
595 pjson& operator=(const std::string& aString);
596 /// Replaces this value with aCString; throws std::invalid_argument for null.
597 pjson& operator=(const char* aCString);
598 /// Replaces this value with aBool.
599 pjson& operator=(const bool aBool);
600 /// Replaces this value with a signed integer.
601 pjson& operator=(const int aInt);
602 /// Replaces this value with an unsigned integer.
603 pjson& operator=(const unsigned int aUInt);
604 /// Replaces this value with a signed short integer.
605 pjson& operator=(const short aInt);
606 /// Replaces this value with an unsigned short integer.
607 pjson& operator=(const unsigned short aUInt);
608 /// Replaces this value with a signed long integer.
609 pjson& operator=(const long aInt);
610 /// Replaces this value with an unsigned long integer.
611 pjson& operator=(const unsigned long aUInt);
612 /// Replaces this value with a signed long-long integer.
613 pjson& operator=(const long long aInt);
614 /// Replaces this value with an unsigned long-long integer.
615 pjson& operator=(const unsigned long long aUInt);
616 /// Replaces this value with a floating-point number.
617 pjson& operator=(const float aFloat);
618 /// Replaces this value with aDouble; the non-finite policy governs output.
619 pjson& operator=(const double aDouble);
620 /// Narrows a long double to the library's binary64 number representation.
621 pjson& operator=(const long double aDouble);
622
623 // Vector assignment atomically replaces this node with an array of copied
624 // children allocated through this node's allocator.
625 /// Replaces this value with a copied string array.
626 pjson& operator=(const std::vector<std::string>& aValueArray);
627 /// Replaces this value with a copied boolean array.
628 pjson& operator=(const std::vector<bool>& aValueArray);
629 /// Replaces this value with a copied native-integer array.
630 pjson& operator=(const std::vector<int>& aValueArray);
631 /// Replaces this value with a copied native unsigned-integer array.
632 pjson& operator=(const std::vector<unsigned int>& aValueArray);
633 /// Replaces this value with a copied signed-short array.
634 pjson& operator=(const std::vector<short>& aValueArray);
635 /// Replaces this value with a copied unsigned-short array.
636 pjson& operator=(const std::vector<unsigned short>& aValueArray);
637 /// Replaces this value with a copied signed-long array.
638 pjson& operator=(const std::vector<long>& aValueArray);
639 /// Replaces this value with a copied unsigned-long array.
640 pjson& operator=(const std::vector<unsigned long>& aValueArray);
641 /// Replaces this value with a copied signed-long-long array.
642 pjson& operator=(const std::vector<long long>& aValueArray);
643 /// Replaces this value with a copied unsigned-long-long array.
644 pjson& operator=(const std::vector<unsigned long long>& aValueArray);
645 /// Replaces this value with a copied float array.
646 pjson& operator=(const std::vector<float>& aValueArray);
647 /// Replaces this value with a copied double array.
648 pjson& operator=(const std::vector<double>& aValueArray);
649 /// Replaces this value with a copied long-double array, narrowing each value to double.
650 pjson& operator=(const std::vector<long double>& aValueArray);
651
652 // Scalar append adds one copied child. If this node is not already an
653 // array, its previous value is discarded rather than retained.
654 /// Appends a copy of aValue as a string child.
655 pjson& operator+=(const std::string& aValue);
656 /// Appends aValue as a string child; throws std::invalid_argument for null.
657 pjson& operator+=(const char* aValue);
658 /// Appends aValue as a boolean child.
659 pjson& operator+=(const bool aValue);
660 /// Appends aValue as a signed integer child.
661 pjson& operator+=(const int aValue);
662 /// Appends aValue as an unsigned integer child.
663 pjson& operator+=(const unsigned int aValue);
664 /// Appends aValue as a signed-short child.
665 pjson& operator+=(const short aValue);
666 /// Appends aValue as an unsigned-short child.
667 pjson& operator+=(const unsigned short aValue);
668 /// Appends aValue as a signed-long child.
669 pjson& operator+=(const long aValue);
670 /// Appends aValue as an unsigned-long child.
671 pjson& operator+=(const unsigned long aValue);
672 /// Appends aValue as a signed-long-long child.
673 pjson& operator+=(const long long aValue);
674 /// Appends aValue as an unsigned-long-long child.
675 pjson& operator+=(const unsigned long long aValue);
676 /// Appends aValue as a floating-point child.
677 pjson& operator+=(const float aValue);
678 /// Appends aValue as a double child.
679 pjson& operator+=(const double aValue);
680 /// Narrows aValue to the library's binary64 number representation and appends it.
681 pjson& operator+=(const long double aValue);
682
683 // Vector append copies every element. A non-array's prior value is
684 // discarded; even an empty vector promotes a non-array to an empty array.
685 /// Appends every string in aValueArray.
686 pjson& operator+=(const std::vector<std::string>& aValueArray);
687 /// Appends every boolean in aValueArray.
688 pjson& operator+=(const std::vector<bool>& aValueArray);
689 /// Appends every native integer in aValueArray.
690 pjson& operator+=(const std::vector<int>& aValueArray);
691 /// Appends every native unsigned integer in aValueArray.
692 pjson& operator+=(const std::vector<unsigned int>& aValueArray);
693 /// Appends every signed short in aValueArray.
694 pjson& operator+=(const std::vector<short>& aValueArray);
695 /// Appends every unsigned short in aValueArray.
696 pjson& operator+=(const std::vector<unsigned short>& aValueArray);
697 /// Appends every signed long in aValueArray.
698 pjson& operator+=(const std::vector<long>& aValueArray);
699 /// Appends every unsigned long in aValueArray.
700 pjson& operator+=(const std::vector<unsigned long>& aValueArray);
701 /// Appends every signed long long in aValueArray.
702 pjson& operator+=(const std::vector<long long>& aValueArray);
703 /// Appends every unsigned long long in aValueArray.
704 pjson& operator+=(const std::vector<unsigned long long>& aValueArray);
705 /// Appends every float in aValueArray.
706 pjson& operator+=(const std::vector<float>& aValueArray);
707 /// Appends every double in aValueArray.
708 pjson& operator+=(const std::vector<double>& aValueArray);
709 /// Narrows and appends every long double in aValueArray.
710 pjson& operator+=(const std::vector<long double>& aValueArray);
711
712 // Remove and free the child under a map key / at an array index.
713 // Array indexes are zero-based and erasure shifts later elements left.
714 /// Erases aKey and returns whether an object member was removed.
715 bool erase(const std::string& aKey);
716 /// Erases non-null aKey; null or a non-object returns false.
717 bool erase(const char* aKey);
718 /// Erases aIndex and returns whether an array element was removed.
719 bool erase(size_t aIndex);
720
721 // Applies all RFC 6902 operations to a scratch document and commits
722 // only if every operation succeeds. RFC 7396 Merge Patch is likewise
723 // atomic and uses an iterative traversal for deeply nested objects.
724 // These bool-returning boundaries convert allocation and internal
725 // exceptions into PatchError instead of allowing them to escape. Patch
726 // input is borrowed and unchanged; successful commit invalidates prior
727 // views into the target. Overloads without aError discard diagnostics.
728 /// Atomically applies an RFC 6902 patch document.
729 bool applyPatch(const pjson& aPatch, const PatchOptions& aOpts = PatchOptions()) noexcept;
730 /// Atomically applies RFC 6902 and reports failure details in aError.
731 bool applyPatch(const pjson& aPatch, PatchError& aError,
732 const PatchOptions& aOpts = PatchOptions()) noexcept;
733 /// Atomically applies an RFC 7396 Merge Patch document.
734 bool applyMergePatch(const pjson& aPatch,
735 const PatchOptions& aOpts = PatchOptions()) noexcept;
736 /// Atomically applies RFC 7396 and reports failure details in aError.
737 bool applyMergePatch(const pjson& aPatch, PatchError& aError,
738 const PatchOptions& aOpts = PatchOptions()) noexcept;
739
740 //== Equality (deep, structural) =====================================
741 // Integer and floating nodes compare equal when numerically equal
742 // (e.g. 1 == 1.0). Arrays compare element-wise in order; objects
743 // compare by key/value regardless of insertion order.
744 /// Returns whether this value and aOther are structurally equal.
745 bool operator==(const pjson& aOther) const;
746 /// Returns the negation of operator==.
747 bool operator!=(const pjson& aOther) const;
748
749 //== Numeric ordering ================================================
750 // Exact ordering across the signed, unsigned, and double numeric kinds
751 // without rounding an integer through binary64. On success aOrder is set
752 // to -1, 0, or 1 for this value being less than, equal to, or greater
753 // than aOther. Returns false and leaves aOrder unchanged when either
754 // value is not a number, or when the comparison is unordered because a
755 // NaN is involved. This is the exact comparison callers (including
756 // schema validators) need for numeric bounds; equality alone is exposed
757 // through operator==.
758 /// Compares two stored numbers exactly; false when non-numeric/unordered.
759 bool tryCompareNumber(const pjson& aOther, int& aOrder) const noexcept;
760
761 // NOTE: JSON Schema validation is no longer a member of pjson. It now
762 // lives in the standalone ByteDance::pJsonSchemaValidator helper declared
763 // in <pjson_schema.h>, which consumes only pjson's public API. This keeps
764 // the core DOM free of the schema/regex machinery. The validator carries
765 // its own Error and Options vocabulary types.
766
767 private:
768 //== Internal helpers ================================================
769 // Encoding, ownership, and other DOM operations that need to touch the
770 // data members below live behind the pjsonImpl helper. Schema
771 // validation is deliberately separate and uses only the public API.
772 // pjsonImpl is a friend so it can reach private representation directly;
773 // no instance helper methods are declared here.
774 friend struct pjsonImpl;
775 // These two pointers are the stable ABI handle. Null values share a
776 // private implementation sentinel; non-null state belongs to _allocator.
777 Allocator* _allocator;
778 pjsonImpl* _pImpl;
779 };
780 //========================================================================
781}; // end namespace ByteDance
782#endif /* !PRAVEENJSON_H */
Minimal C++11-compatible, non-owning view of a JSON string.
Definition pjson.h:354
StringView() noexcept
Constructs an empty view with data() == nullptr.
Owning, mutable JSON value with deep-copy semantics.
Definition pjson.h:68
static const char * getVersion()
Returns the process-lifetime semantic-version string for this library.
jsonType
JSON value kind.
Definition pjson.h:82
@ jsonBoolean
Boolean value.
Definition pjson.h:87
@ jsonNumberDouble
Binary64 number value.
Definition pjson.h:86
@ jsonString
UTF-8 string value.
Definition pjson.h:84
@ jsonNumberInt
Signed 64-bit integer value.
Definition pjson.h:85
@ jsonNumberUInt
Unsigned 64-bit integer value.
Definition pjson.h:90
@ jsonArray
Ordered array value.
Definition pjson.h:88
@ jsonObject
Object with unique string keys.
Definition pjson.h:89
Namespace containing the pjson public API.
Definition pjson.h:58
Runtime allocator for persistent DOM storage.
Definition pjson.h:101
virtual ~Allocator()
Enables destruction through an Allocator base pointer.
AllocationKind
Identifies the purpose and matching deallocation contract of storage.
Definition pjson.h:103
virtual void deallocate(void *aPtr, size_t aSize, size_t aAlignment, AllocationKind aKind) noexcept=0
Releases a non-null allocation using its original size, alignment, and kind.
virtual void * allocate(size_t aSize, size_t aAlignment, AllocationKind aKind)=0
Returns non-null aligned storage or throws; returning null is unsupported.
Structured JSON Patch (RFC 6902) / Merge Patch (RFC 7396) failure.
Definition pjson.h:156
std::string token
Decoded failing pointer token when available.
Definition pjson.h:187
size_t opIndex
Zero-based index of the failing operation.
Definition pjson.h:182
bool ok
True exactly when code is Ok.
Definition pjson.h:180
std::string from
Source pointer when available.
Definition pjson.h:185
std::string message
Human-readable diagnostic; wording is not stable. Constructs a successful patch state with no operati...
Definition pjson.h:188
Code code
Stable machine-readable result category.
Definition pjson.h:181
std::string path
Destination pointer when available.
Definition pjson.h:184
std::string op
Operation name when available.
Definition pjson.h:183
Code
Stable categories for programmatic JSON Patch failure handling.
Definition pjson.h:158
@ MissingFrom
A copy or move lacks a string from member.
Definition pjson.h:164
@ MoveIntoDescendant
A move destination lies under its source.
Definition pjson.h:173
@ MissingValue
An add, replace, or test lacks value.
Definition pjson.h:165
@ InvalidOp
The operation name is unsupported.
Definition pjson.h:166
@ InvalidArrayIndex
An array path token is not a valid index.
Definition pjson.h:170
@ AllocationFailure
Patch application could not allocate.
Definition pjson.h:176
@ ArrayIndexOutOfRange
An array path token exceeds valid bounds.
Definition pjson.h:171
@ ResourceLimit
A configured patch-work limit was reached.
Definition pjson.h:175
@ MoveRootNotAllowed
A move attempts to remove the document root.
Definition pjson.h:172
@ InvalidPath
The destination JSON Pointer is invalid.
Definition pjson.h:167
@ MissingOp
An operation lacks a string op member.
Definition pjson.h:162
@ TestFailed
A test operation did not compare equal.
Definition pjson.h:174
@ InvalidPatchDocument
The patch document is not an array.
Definition pjson.h:160
@ OperationNotObject
An operation entry is not an object.
Definition pjson.h:161
@ MissingPath
An operation lacks a string path member.
Definition pjson.h:163
@ Ok
Patch application succeeded.
Definition pjson.h:159
@ TargetMissing
A required source, parent, or target is absent.
Definition pjson.h:169
@ InvalidFrom
The source JSON Pointer is invalid.
Definition pjson.h:168
size_t tokenIndex
Zero-based index of the failing pointer token.
Definition pjson.h:186
Bounds transactional patch amplification.
Definition pjson.h:198
size_t maxClonedBytes
Clone-byte ceiling; zero selects the hard 64 MiB limit.
Definition pjson.h:201
size_t maxOperations
Operation ceiling; zero selects the hard 10,000 limit.
Definition pjson.h:199
size_t maxClonedNodes
Clone-node ceiling; zero selects the hard 1,000,000 limit.
Definition pjson.h:200
size_t maxWork
Work ceiling; zero selects the hard 1,000,000 limit. Selects the documented finite default limits.
Definition pjson.h:202
Structured JSON Pointer (RFC 6901) lookup failure.
Definition pjson.h:127
size_t tokenIndex
Zero-based index of the failing token.
Definition pjson.h:145
Code
Stable categories for programmatic JSON Pointer failure handling.
Definition pjson.h:129
@ InvalidSyntax
The pointer does not begin with slash or is malformed.
Definition pjson.h:131
@ ArrayIndexOutOfRange
An array token exceeds the current array bounds.
Definition pjson.h:136
@ AllocationFailure
Diagnostic construction could not allocate.
Definition pjson.h:138
@ InvalidEscape
A token contains an invalid tilde escape.
Definition pjson.h:132
@ MissingTarget
An object member or array element does not exist.
Definition pjson.h:133
@ AppendTokenNotAllowed
The append token is invalid for lookup.
Definition pjson.h:137
@ InvalidArrayIndex
An array token is not a canonical non-negative index.
Definition pjson.h:135
@ ExpectedContainer
Traversal encountered a scalar before the final token.
Definition pjson.h:134
@ Ok
Lookup succeeded.
Definition pjson.h:130
std::string token
Decoded failing token when available.
Definition pjson.h:146
bool ok
True exactly when code is Ok.
Definition pjson.h:142
std::string message
Human-readable diagnostic; wording is not stable. Constructs a successful lookup state with no pointe...
Definition pjson.h:147
std::string pointer
Pointer text supplied by the caller.
Definition pjson.h:144
Code code
Stable machine-readable result category.
Definition pjson.h:143
Structured outcome for the non-throwing serialization APIs.
Definition pjson.h:246
void reset() noexcept
Resets the result to success.
Code
Stable categories for programmatic serialization failure handling.
Definition pjson.h:248
@ NonFiniteNumber
NaN or infinity was rejected by the active policy.
Definition pjson.h:251
@ OutputLimit
maxOutputBytes or representable output size was exceeded.
Definition pjson.h:252
@ None
Serialization succeeded.
Definition pjson.h:249
@ StreamFailure
The destination stream rejected a physical write.
Definition pjson.h:254
@ AllocationFailure
Temporary serialization storage could not be allocated.
Definition pjson.h:253
@ InvalidUtf8
A stored string or object key is not valid UTF-8.
Definition pjson.h:250
Code code
Stable machine-readable result category.
Definition pjson.h:258
std::string message
Human-readable diagnostic; empty on success. Constructs a successful serialization result.
Definition pjson.h:259
Controls JSON serialization.
Definition pjson.h:216
NonFinitePolicy nonFinite
Policy for NaN and infinity values.
Definition pjson.h:236
size_t maxOutputBytes
Output ceiling; zero explicitly means unlimited.
Definition pjson.h:237
char indentCharacter
Space or tab; invalid values are treated as space.
Definition pjson.h:234
static SerializeOptions prettyPrinted()
Returns the defaults with pretty printing enabled.
size_t indentWidth
Indentation characters per nesting level.
Definition pjson.h:233
bool escapeNonAscii
Emits non-ASCII code points as Unicode escapes.
Definition pjson.h:235
bool pretty
Enables line breaks and indentation.
Definition pjson.h:232
SerializeOptions()
Selects compact output, two-space indentation, and non-finite rejection.
NonFinitePolicy
Selects how stored NaN and infinity values are represented.
Definition pjson.h:226
@ NonFiniteToNull
Emit non-finite values as JSON null.
Definition pjson.h:228
@ RejectNonFinite
Fail because JSON has no non-finite number literal.
Definition pjson.h:227