From ad7fc19474708c48a8bb69c462c1df41d2dc2558 Mon Sep 17 00:00:00 2001 From: garrettmills Date: Thu, 18 Feb 2021 10:38:21 -0600 Subject: [PATCH] Basic components implementation --- .envrc | 2 +- .idea/vcs.xml | 6 + embuild | 4 +- hello.html | 2 +- hello.js | 1333 ++++----- hello.wasm | Bin 285504 -> 267602 bytes init.js | 12 +- main.cpp | 146 +- shell_minimal.html | 2 +- src/class/Component.cpp | 5 - src/class/Component.h | 19 - src/class/Element.cpp | 17 +- src/class/Element.h | 4 +- src/class/EventBus.cpp | 25 - src/class/EventBus.h | 21 - src/include/rapidjson/allocators.h | 284 ++ src/include/rapidjson/cursorstreamwrapper.h | 78 + src/include/rapidjson/document.h | 2732 +++++++++++++++++++ src/include/rapidjson/encodedstream.h | 299 ++ src/include/rapidjson/encodings.h | 716 +++++ src/include/rapidjson/error/en.h | 74 + src/include/rapidjson/error/error.h | 161 ++ src/include/rapidjson/filereadstream.h | 99 + src/include/rapidjson/filewritestream.h | 104 + src/include/rapidjson/fwd.h | 151 + src/include/rapidjson/internal/biginteger.h | 290 ++ src/include/rapidjson/internal/clzll.h | 71 + src/include/rapidjson/internal/diyfp.h | 257 ++ src/include/rapidjson/internal/dtoa.h | 245 ++ src/include/rapidjson/internal/ieee754.h | 78 + src/include/rapidjson/internal/itoa.h | 308 +++ src/include/rapidjson/internal/meta.h | 186 ++ src/include/rapidjson/internal/pow10.h | 55 + src/include/rapidjson/internal/regex.h | 739 +++++ src/include/rapidjson/internal/stack.h | 232 ++ src/include/rapidjson/internal/strfunc.h | 69 + src/include/rapidjson/internal/strtod.h | 290 ++ src/include/rapidjson/internal/swap.h | 46 + src/include/rapidjson/istreamwrapper.h | 128 + src/include/rapidjson/memorybuffer.h | 70 + src/include/rapidjson/memorystream.h | 71 + src/include/rapidjson/msinttypes/inttypes.h | 316 +++ src/include/rapidjson/msinttypes/stdint.h | 300 ++ src/include/rapidjson/ostreamwrapper.h | 81 + src/include/rapidjson/pointer.h | 1415 ++++++++++ src/include/rapidjson/prettywriter.h | 277 ++ src/include/rapidjson/rapidjson.h | 676 +++++ src/include/rapidjson/reader.h | 2236 +++++++++++++++ src/include/rapidjson/schema.h | 2496 +++++++++++++++++ src/include/rapidjson/stream.h | 223 ++ src/include/rapidjson/stringbuffer.h | 121 + src/include/rapidjson/writer.h | 710 +++++ src/proc/event.cpp | 8 +- 53 files changed, 17349 insertions(+), 941 deletions(-) create mode 100644 .idea/vcs.xml delete mode 100644 src/class/Component.cpp delete mode 100644 src/class/Component.h delete mode 100644 src/class/EventBus.cpp delete mode 100644 src/class/EventBus.h create mode 100755 src/include/rapidjson/allocators.h create mode 100755 src/include/rapidjson/cursorstreamwrapper.h create mode 100755 src/include/rapidjson/document.h create mode 100755 src/include/rapidjson/encodedstream.h create mode 100755 src/include/rapidjson/encodings.h create mode 100755 src/include/rapidjson/error/en.h create mode 100755 src/include/rapidjson/error/error.h create mode 100755 src/include/rapidjson/filereadstream.h create mode 100755 src/include/rapidjson/filewritestream.h create mode 100755 src/include/rapidjson/fwd.h create mode 100755 src/include/rapidjson/internal/biginteger.h create mode 100755 src/include/rapidjson/internal/clzll.h create mode 100755 src/include/rapidjson/internal/diyfp.h create mode 100755 src/include/rapidjson/internal/dtoa.h create mode 100755 src/include/rapidjson/internal/ieee754.h create mode 100755 src/include/rapidjson/internal/itoa.h create mode 100755 src/include/rapidjson/internal/meta.h create mode 100755 src/include/rapidjson/internal/pow10.h create mode 100755 src/include/rapidjson/internal/regex.h create mode 100755 src/include/rapidjson/internal/stack.h create mode 100755 src/include/rapidjson/internal/strfunc.h create mode 100755 src/include/rapidjson/internal/strtod.h create mode 100755 src/include/rapidjson/internal/swap.h create mode 100755 src/include/rapidjson/istreamwrapper.h create mode 100755 src/include/rapidjson/memorybuffer.h create mode 100755 src/include/rapidjson/memorystream.h create mode 100755 src/include/rapidjson/msinttypes/inttypes.h create mode 100755 src/include/rapidjson/msinttypes/stdint.h create mode 100755 src/include/rapidjson/ostreamwrapper.h create mode 100755 src/include/rapidjson/pointer.h create mode 100755 src/include/rapidjson/prettywriter.h create mode 100755 src/include/rapidjson/rapidjson.h create mode 100755 src/include/rapidjson/reader.h create mode 100755 src/include/rapidjson/schema.h create mode 100755 src/include/rapidjson/stream.h create mode 100755 src/include/rapidjson/stringbuffer.h create mode 100755 src/include/rapidjson/writer.h diff --git a/.envrc b/.envrc index 985da80..87a2e6a 100755 --- a/.envrc +++ b/.envrc @@ -1 +1 @@ -export PATH=/home/garrettmills/.clone/emsdk:/home/garrettmills/.clone/emsdk/node/12.9.1_64bit/bin:/home/garrettmills/.clone/emsdk/upstream/emscripten:$PATH +export PATH=/home/garrettmills/.clone/emsdk:/home/garrettmills/.clone/emsdk/node/12.18.1_64bit/bin:/home/garrettmills/.clone/emsdk/upstream/emscripten:$PATH diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/embuild b/embuild index e338c37..a0e17a8 100755 --- a/embuild +++ b/embuild @@ -1,11 +1,13 @@ #!/bin/bash +source /home/garrettmills/.clone/emsdk/emsdk_env.sh + emcc main.cpp --std=c++14 \ --shell-file shell_minimal.html \ --emrun \ -o hello.html \ -s NO_EXIT_RUNTIME=1 \ - -s EXPORTED_FUNCTIONS="['_main', '_itest', '_str_pass_size', '_fire_event_bus']" \ + -s EXPORTED_FUNCTIONS="['_main', '_str_pass_size', '_fire_event_bus']" \ -s EXTRA_EXPORTED_RUNTIME_METHODS="['cwrap', 'ccall', 'stringToUTF8', 'setValue', 'getValue', 'UTF8ToString']" \ -s WASM=1 \ -s DISABLE_EXCEPTION_CATCHING=0 \ diff --git a/hello.html b/hello.html index bf448d7..4a924e4 100644 --- a/hello.html +++ b/hello.html @@ -12,7 +12,7 @@ -->

-

Hello, world!

+

diff --git a/hello.js b/hello.js index 14d945c..bc0a731 100644 --- a/hello.js +++ b/hello.js @@ -1,8 +1,4 @@ -/** - * @license - * Copyright 2010 The Emscripten Authors - * SPDX-License-Identifier: MIT - */ + // The Module object: Our interface to the outside world. We import // and export values on it. There are various ways Module can be used: @@ -19,13 +15,11 @@ // can continue to use Module afterwards as well. var Module = typeof Module !== 'undefined' ? Module : {}; + + // --pre-jses are emitted after the Module integration code, so that they can // refer to Module (if they choose; they can also define Module) -/** - * @license - * Copyright 2013 The Emscripten Authors - * SPDX-License-Identifier: MIT - */ + // Route URL GET parameters to argc+argv if (typeof window === "object") { @@ -103,11 +97,7 @@ if (ENVIRONMENT_IS_NODE) { } -/** - * @license - * Copyright 2019 The Emscripten Authors - * SPDX-License-Identifier: MIT - */ + read_ = function shell_read(filename, binary) { if (!nodeFS) nodeFS = require('fs'); @@ -222,11 +212,7 @@ if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) { { -/** - * @license - * Copyright 2019 The Emscripten Authors - * SPDX-License-Identifier: MIT - */ + read_ = function shell_read(url) { var xhr = new XMLHttpRequest(); @@ -291,9 +277,9 @@ moduleOverrides = null; // to the proper local x. This has two benefits: first, we only emit it if it is // expected to arrive, and second, by using a local everywhere else that can be // minified. -if (Module['arguments']) arguments_ = Module['arguments'];if (!Object.getOwnPropertyDescriptor(Module, 'arguments')) Object.defineProperty(Module, 'arguments', { configurable: true, get: function() { abort('Module.arguments has been replaced with plain arguments_') } }); -if (Module['thisProgram']) thisProgram = Module['thisProgram'];if (!Object.getOwnPropertyDescriptor(Module, 'thisProgram')) Object.defineProperty(Module, 'thisProgram', { configurable: true, get: function() { abort('Module.thisProgram has been replaced with plain thisProgram') } }); -if (Module['quit']) quit_ = Module['quit'];if (!Object.getOwnPropertyDescriptor(Module, 'quit')) Object.defineProperty(Module, 'quit', { configurable: true, get: function() { abort('Module.quit has been replaced with plain quit_') } }); +if (Module['arguments']) arguments_ = Module['arguments'];if (!Object.getOwnPropertyDescriptor(Module, 'arguments')) Object.defineProperty(Module, 'arguments', { configurable: true, get: function() { abort('Module.arguments has been replaced with plain arguments_ (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)') } }); +if (Module['thisProgram']) thisProgram = Module['thisProgram'];if (!Object.getOwnPropertyDescriptor(Module, 'thisProgram')) Object.defineProperty(Module, 'thisProgram', { configurable: true, get: function() { abort('Module.thisProgram has been replaced with plain thisProgram (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)') } }); +if (Module['quit']) quit_ = Module['quit'];if (!Object.getOwnPropertyDescriptor(Module, 'quit')) Object.defineProperty(Module, 'quit', { configurable: true, get: function() { abort('Module.quit has been replaced with plain quit_ (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)') } }); // perform assertions in shell.js after we set up out() and err(), as otherwise if an assertion fails it cannot print the message // Assertions on removed incoming Module JS APIs. @@ -306,10 +292,10 @@ assert(typeof Module['readAsync'] === 'undefined', 'Module.readAsync option was assert(typeof Module['readBinary'] === 'undefined', 'Module.readBinary option was removed (modify readBinary in JS)'); assert(typeof Module['setWindowTitle'] === 'undefined', 'Module.setWindowTitle option was removed (modify setWindowTitle in JS)'); assert(typeof Module['TOTAL_MEMORY'] === 'undefined', 'Module.TOTAL_MEMORY has been renamed Module.INITIAL_MEMORY'); -if (!Object.getOwnPropertyDescriptor(Module, 'read')) Object.defineProperty(Module, 'read', { configurable: true, get: function() { abort('Module.read has been replaced with plain read_') } }); -if (!Object.getOwnPropertyDescriptor(Module, 'readAsync')) Object.defineProperty(Module, 'readAsync', { configurable: true, get: function() { abort('Module.readAsync has been replaced with plain readAsync') } }); -if (!Object.getOwnPropertyDescriptor(Module, 'readBinary')) Object.defineProperty(Module, 'readBinary', { configurable: true, get: function() { abort('Module.readBinary has been replaced with plain readBinary') } }); -if (!Object.getOwnPropertyDescriptor(Module, 'setWindowTitle')) Object.defineProperty(Module, 'setWindowTitle', { configurable: true, get: function() { abort('Module.setWindowTitle has been replaced with plain setWindowTitle') } }); +if (!Object.getOwnPropertyDescriptor(Module, 'read')) Object.defineProperty(Module, 'read', { configurable: true, get: function() { abort('Module.read has been replaced with plain read_ (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)') } }); +if (!Object.getOwnPropertyDescriptor(Module, 'readAsync')) Object.defineProperty(Module, 'readAsync', { configurable: true, get: function() { abort('Module.readAsync has been replaced with plain readAsync (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)') } }); +if (!Object.getOwnPropertyDescriptor(Module, 'readBinary')) Object.defineProperty(Module, 'readBinary', { configurable: true, get: function() { abort('Module.readBinary has been replaced with plain readBinary (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)') } }); +if (!Object.getOwnPropertyDescriptor(Module, 'setWindowTitle')) Object.defineProperty(Module, 'setWindowTitle', { configurable: true, get: function() { abort('Module.setWindowTitle has been replaced with plain setWindowTitle (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)') } }); var IDBFS = 'IDBFS is no longer included by default; build with -lidbfs.js'; var PROXYFS = 'PROXYFS is no longer included by default; build with -lproxyfs.js'; var WORKERFS = 'WORKERFS is no longer included by default; build with -lworkerfs.js'; @@ -318,34 +304,12 @@ var NODEFS = 'NODEFS is no longer included by default; build with -lnodefs.js'; -/** - * @license - * Copyright 2017 The Emscripten Authors - * SPDX-License-Identifier: MIT - */ + // {{PREAMBLE_ADDITIONS}} var STACK_ALIGN = 16; -// stack management, and other functionality that is provided by the compiled code, -// should not be used before it is ready - -/** @suppress{duplicate} */ -var stackSave; -/** @suppress{duplicate} */ -var stackRestore; -/** @suppress{duplicate} */ -var stackAlloc; - -stackSave = stackRestore = stackAlloc = function() { - abort('cannot use the stack before compiled code is ready to run, and has provided stack access'); -}; - -function staticAlloc(size) { - abort('staticAlloc is no longer available at runtime; instead, perform static allocations at compile time (using makeStaticAlloc)'); -} - function dynamicAlloc(size) { assert(DYNAMICTOP_PTR); var ret = HEAP32[DYNAMICTOP_PTR>>2]; @@ -394,13 +358,6 @@ function warnOnce(text) { -/** - * @license - * Copyright 2020 The Emscripten Authors - * SPDX-License-Identifier: MIT - */ - - // Wraps a JS function as a wasm function with a given signature. function convertJsFunctionToWasm(func, sig) { @@ -567,42 +524,9 @@ function removeFunction(index) { -var funcWrappers = {}; -function getFuncWrapper(func, sig) { - if (!func) return; // on null pointer, return undefined - assert(sig); - if (!funcWrappers[sig]) { - funcWrappers[sig] = {}; - } - var sigCache = funcWrappers[sig]; - if (!sigCache[func]) { - // optimize away arguments usage in common cases - if (sig.length === 1) { - sigCache[func] = function dynCall_wrapper() { - return dynCall(sig, func); - }; - } else if (sig.length === 2) { - sigCache[func] = function dynCall_wrapper(arg) { - return dynCall(sig, func, [arg]); - }; - } else { - // general case - sigCache[func] = function dynCall_wrapper() { - return dynCall(sig, func, Array.prototype.slice.call(arguments)); - }; - } - } - return sigCache[func]; -} -/** - * @license - * Copyright 2020 The Emscripten Authors - * SPDX-License-Identifier: MIT - */ - @@ -610,20 +534,6 @@ function makeBigInt(low, high, unsigned) { return unsigned ? ((+((low>>>0)))+((+((high>>>0)))*4294967296.0)) : ((+((low>>>0)))+((+((high|0)))*4294967296.0)); } -/** @param {Array=} args */ -function dynCall(sig, ptr, args) { - if (args && args.length) { - // j (64-bit integer) must be passed in as two numbers [low 32, high 32]. - assert(args.length === sig.substring(1).replace(/j/g, '--').length); - assert(('dynCall_' + sig) in Module, 'bad function pointer type - no table for sig \'' + sig + '\''); - return Module['dynCall_' + sig].apply(null, [ptr].concat(args)); - } else { - assert(sig.length == 1); - assert(('dynCall_' + sig) in Module, 'bad function pointer type - no table for sig \'' + sig + '\''); - return Module['dynCall_' + sig].call(null, ptr); - } -} - var tempRet0 = 0; var setTempRet0 = function(value) { @@ -646,11 +556,7 @@ var GLOBAL_BASE = 1024; -/** - * @license - * Copyright 2010 The Emscripten Authors - * SPDX-License-Identifier: MIT - */ + // === Preamble library stuff === @@ -663,20 +569,16 @@ var GLOBAL_BASE = 1024; // is up at http://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html -var wasmBinary;if (Module['wasmBinary']) wasmBinary = Module['wasmBinary'];if (!Object.getOwnPropertyDescriptor(Module, 'wasmBinary')) Object.defineProperty(Module, 'wasmBinary', { configurable: true, get: function() { abort('Module.wasmBinary has been replaced with plain wasmBinary') } }); -var noExitRuntime;if (Module['noExitRuntime']) noExitRuntime = Module['noExitRuntime'];if (!Object.getOwnPropertyDescriptor(Module, 'noExitRuntime')) Object.defineProperty(Module, 'noExitRuntime', { configurable: true, get: function() { abort('Module.noExitRuntime has been replaced with plain noExitRuntime') } }); +var wasmBinary;if (Module['wasmBinary']) wasmBinary = Module['wasmBinary'];if (!Object.getOwnPropertyDescriptor(Module, 'wasmBinary')) Object.defineProperty(Module, 'wasmBinary', { configurable: true, get: function() { abort('Module.wasmBinary has been replaced with plain wasmBinary (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)') } }); +var noExitRuntime;if (Module['noExitRuntime']) noExitRuntime = Module['noExitRuntime'];if (!Object.getOwnPropertyDescriptor(Module, 'noExitRuntime')) Object.defineProperty(Module, 'noExitRuntime', { configurable: true, get: function() { abort('Module.noExitRuntime has been replaced with plain noExitRuntime (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)') } }); if (typeof WebAssembly !== 'object') { - abort('No WebAssembly support found. Build with -s WASM=0 to target JavaScript instead.'); + abort('no native wasm support detected'); } -/** - * @license - * Copyright 2019 The Emscripten Authors - * SPDX-License-Identifier: MIT - */ + // In MINIMAL_RUNTIME, setValue() and getValue() are only available when building with safe heap enabled, for heap safety checking. // In traditional runtime, setValue() and getValue() are always available (although their use is highly discouraged due to perf penalties) @@ -723,6 +625,7 @@ function getValue(ptr, type, noSafe) { + // Wasm globals var wasmMemory; @@ -730,13 +633,16 @@ var wasmMemory; // In fastcomp asm.js, we don't need a wasm Table at all. // In the wasm backend, we polyfill the WebAssembly object, // so this creates a (non-native-wasm) table for us. + var wasmTable = new WebAssembly.Table({ - 'initial': 626, - 'maximum': 626 + 0, + 'initial': 634, + 'maximum': 634, 'element': 'anyfunc' }); + + //======================================== // Runtime essentials //======================================== @@ -923,11 +829,7 @@ function getMemory(size) { } -/** - * @license - * Copyright 2019 The Emscripten Authors - * SPDX-License-Identifier: MIT - */ + // runtime_strings.js: Strings related runtime functions that are part of both MINIMAL_RUNTIME and regular runtime. @@ -1083,11 +985,7 @@ function lengthBytesUTF8(str) { -/** - * @license - * Copyright 2020 The Emscripten Authors - * SPDX-License-Identifier: MIT - */ + // runtime_strings_extra.js: Strings related runtime functions that are available only in regular runtime. @@ -1115,13 +1013,16 @@ function stringToAscii(str, outPtr) { var UTF16Decoder = typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-16le') : undefined; -function UTF16ToString(ptr) { +function UTF16ToString(ptr, maxBytesToRead) { assert(ptr % 2 == 0, 'Pointer passed to UTF16ToString must be aligned to two bytes!'); var endPtr = ptr; // TextDecoder needs to know the byte length in advance, it doesn't stop on null terminator by itself. // Also, use the length info to avoid running tiny strings through TextDecoder, since .subarray() allocates garbage. var idx = endPtr >> 1; - while (HEAP16[idx]) ++idx; + var maxIdx = idx + maxBytesToRead / 2; + // If maxBytesToRead is not passed explicitly, it will be undefined, and this + // will always evaluate to true. This saves on code size. + while (!(idx >= maxIdx) && HEAPU16[idx]) ++idx; endPtr = idx << 1; if (endPtr - ptr > 32 && UTF16Decoder) { @@ -1132,7 +1033,7 @@ function UTF16ToString(ptr) { var str = ''; while (1) { var codeUnit = HEAP16[(((ptr)+(i*2))>>1)]; - if (codeUnit == 0) return str; + if (codeUnit == 0 || i == maxBytesToRead / 2) return str; ++i; // fromCharCode constructs a character from a UTF-16 code unit, so we can pass the UTF16 string right through. str += String.fromCharCode(codeUnit); @@ -1179,14 +1080,16 @@ function lengthBytesUTF16(str) { return str.length*2; } -function UTF32ToString(ptr) { +function UTF32ToString(ptr, maxBytesToRead) { assert(ptr % 4 == 0, 'Pointer passed to UTF32ToString must be aligned to four bytes!'); var i = 0; var str = ''; - while (1) { + // If maxBytesToRead is not passed explicitly, it will be undefined, and this + // will always evaluate to true. This saves on code size. + while (!(i >= maxBytesToRead / 4)) { var utf32 = HEAP32[(((ptr)+(i*4))>>2)]; - if (utf32 == 0) return str; + if (utf32 == 0) break; ++i; // Gotcha: fromCharCode constructs a character from a UTF-16 encoded code (pair), not from a Unicode code point! So encode the code point to UTF-16 for constructing. // See http://unicode.org/faq/utf_bom.html#utf16-3 @@ -1197,6 +1100,7 @@ function UTF32ToString(ptr) { str += String.fromCharCode(utf32); } } + return str; } // Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr', @@ -1311,7 +1215,6 @@ function writeAsciiToMemory(str, buffer, dontAddNull) { var PAGE_SIZE = 16384; var WASM_PAGE_SIZE = 65536; -var ASMJS_PAGE_SIZE = 16777216; function alignUp(x, multiple) { if (x % multiple > 0) { @@ -1353,21 +1256,20 @@ function updateGlobalBufferAndViews(buf) { } var STATIC_BASE = 1024, - STACK_BASE = 5270112, + STACK_BASE = 5270432, STACKTOP = STACK_BASE, - STACK_MAX = 27232, - DYNAMIC_BASE = 5270112, - DYNAMICTOP_PTR = 27056; + STACK_MAX = 27552, + DYNAMIC_BASE = 5270432, + DYNAMICTOP_PTR = 27536; assert(STACK_BASE % 16 === 0, 'stack must start aligned'); assert(DYNAMIC_BASE % 16 === 0, 'heap must start aligned'); - var TOTAL_STACK = 5242880; if (Module['TOTAL_STACK']) assert(TOTAL_STACK === Module['TOTAL_STACK'], 'the stack size can no longer be determined at runtime') -var INITIAL_INITIAL_MEMORY = Module['INITIAL_MEMORY'] || 16777216;if (!Object.getOwnPropertyDescriptor(Module, 'INITIAL_MEMORY')) Object.defineProperty(Module, 'INITIAL_MEMORY', { configurable: true, get: function() { abort('Module.INITIAL_MEMORY has been replaced with plain INITIAL_INITIAL_MEMORY') } }); +var INITIAL_INITIAL_MEMORY = Module['INITIAL_MEMORY'] || 16777216;if (!Object.getOwnPropertyDescriptor(Module, 'INITIAL_MEMORY')) Object.defineProperty(Module, 'INITIAL_MEMORY', { configurable: true, get: function() { abort('Module.INITIAL_MEMORY has been replaced with plain INITIAL_INITIAL_MEMORY (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)') } }); assert(INITIAL_INITIAL_MEMORY >= TOTAL_STACK, 'INITIAL_MEMORY should be larger than TOTAL_STACK, was ' + INITIAL_INITIAL_MEMORY + '! (TOTAL_STACK=' + TOTAL_STACK + ')'); @@ -1377,23 +1279,14 @@ assert(typeof Int32Array !== 'undefined' && typeof Float64Array !== 'undefined' -/** - * @license - * Copyright 2019 The Emscripten Authors - * SPDX-License-Identifier: MIT - */ -// In standalone mode, the wasm creates the memory, and the user can't provide it. + // In non-standalone/normal mode, we create the memory here. -/** - * @license - * Copyright 2019 The Emscripten Authors - * SPDX-License-Identifier: MIT - */ + // Create the main memory. (Note: this isn't used in STANDALONE_WASM mode since the wasm // memory is created in the wasm, not in JS.) @@ -1425,11 +1318,7 @@ HEAP32[DYNAMICTOP_PTR>>2] = DYNAMIC_BASE; -/** - * @license - * Copyright 2019 The Emscripten Authors - * SPDX-License-Identifier: MIT - */ + // Initializes the stack cookie. Called at the startup of main and at the startup of each thread in pthreads mode. function writeStackCookie() { @@ -1453,18 +1342,9 @@ function checkStackCookie() { if (HEAP32[0] !== 0x63736d65 /* 'emsc' */) abort('Runtime error: The application has corrupted its heap memory area (address zero)!'); } -function abortStackOverflow(allocSize) { - abort('Stack overflow! Attempted to allocate ' + allocSize + ' bytes on the stack, but stack has only ' + (STACK_MAX - stackSave() + allocSize) + ' bytes available!'); -} - -/** - * @license - * Copyright 2019 The Emscripten Authors - * SPDX-License-Identifier: MIT - */ // Endianness check (note: assumes compiler arch was little-endian) (function() { @@ -1480,26 +1360,6 @@ function abortFnPtrError(ptr, sig) { -function callRuntimeCallbacks(callbacks) { - while(callbacks.length > 0) { - var callback = callbacks.shift(); - if (typeof callback == 'function') { - callback(Module); // Pass the module as the first argument. - continue; - } - var func = callback.func; - if (typeof func === 'number') { - if (callback.arg === undefined) { - Module['dynCall_v'](func); - } else { - Module['dynCall_vi'](func, callback.arg); - } - } else { - func(callback.arg === undefined ? null : callback.arg); - } - } -} - var __ATPRERUN__ = []; // functions called before the runtime is initialized var __ATINIT__ = []; // functions called during startup var __ATMAIN__ = []; // functions called when main() is to be run @@ -1574,35 +1434,8 @@ function addOnPostRun(cb) { __ATPOSTRUN__.unshift(cb); } -/** @param {number|boolean=} ignore */ -function unSign(value, bits, ignore) { - if (value >= 0) { - return value; - } - return bits <= 32 ? 2*Math.abs(1 << (bits-1)) + value // Need some trickery, since if bits == 32, we are right at the limit of the bits JS uses in bitshifts - : Math.pow(2, bits) + value; -} -/** @param {number|boolean=} ignore */ -function reSign(value, bits, ignore) { - if (value <= 0) { - return value; - } - var half = bits <= 32 ? Math.abs(1 << (bits-1)) // abs is needed if bits == 32 - : Math.pow(2, bits-1); - if (value >= half && (bits <= 32 || value > half)) { // for huge values, we can hit the precision limit and always get true here. so don't do that - // but, in general there is no perfect solution here. With 64-bit ints, we get rounding and errors - // TODO: In i64 mode 1, resign the two parts separately and safely - value = -2*half + value; // Cannot bitshift half, as it may be at the limit of the bits JS uses in bitshifts - } - return value; -} -/** - * @license - * Copyright 2019 The Emscripten Authors - * SPDX-License-Identifier: MIT - */ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/imul @@ -1726,7 +1559,6 @@ function removeRunDependency(id) { Module["preloadedImages"] = {}; // maps url to image data Module["preloadedAudios"] = {}; // maps url to audio data - /** @param {string|number=} what */ function abort(what) { if (Module['onAbort']) { @@ -1734,7 +1566,6 @@ function abort(what) { } what += ''; - out(what); err(what); ABORT = true; @@ -1743,21 +1574,21 @@ function abort(what) { var output = 'abort(' + what + ') at ' + stackTrace(); what = output; - // Throw a wasm runtime error, because a JS error might be seen as a foreign + // Use a wasm runtime error, because a JS error might be seen as a foreign // exception, which means we'd run destructors on it. We need the error to // simply make the program stop. - throw new WebAssembly.RuntimeError(what); + var e = new WebAssembly.RuntimeError(what); + + // Throw the error whether or not MODULARIZE is set because abort is used + // in code paths apart from instantiation where an exception is expected + // to be thrown when abort is called. + throw e; } var memoryInitializer = null; -/** - * @license - * Copyright 2015 The Emscripten Authors - * SPDX-License-Identifier: MIT - */ @@ -1765,11 +1596,7 @@ var memoryInitializer = null; -/** - * @license - * Copyright 2017 The Emscripten Authors - * SPDX-License-Identifier: MIT - */ + function hasPrefix(str, prefix) { return String.prototype.startsWith ? @@ -1794,6 +1621,22 @@ function isFileURI(filename) { +function createExportWrapper(name, fixedasm) { + return function() { + var displayName = name; + var asm = fixedasm; + if (!fixedasm) { + asm = Module['asm']; + } + assert(runtimeInitialized, 'native function `' + displayName + '` called before runtime initialization'); + assert(!runtimeExited, 'native function `' + displayName + '` called after runtime exit (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); + if (!asm[name]) { + assert(asm[name], 'exported native function `' + displayName + '` not found'); + } + return asm[name].apply(null, arguments); + }; +} + var wasmBinaryFile = 'hello.wasm'; if (!isDataURI(wasmBinaryFile)) { wasmBinaryFile = locateFile(wasmBinaryFile); @@ -1833,9 +1676,7 @@ function getBinaryPromise() { }); } // Otherwise, getBinary should be able to get it synchronously - return new Promise(function(resolve, reject) { - resolve(getBinary()); - }); + return Promise.resolve().then(getBinary); } @@ -1881,6 +1722,8 @@ function createWasm() { return WebAssembly.instantiate(binary, info); }).then(receiver, function(reason) { err('failed to asynchronously prepare wasm: ' + reason); + + abort(reason); }); } @@ -1900,7 +1743,7 @@ function createWasm() { // in which case falling back to ArrayBuffer instantiation should work. err('wasm streaming compile failed: ' + reason); err('falling back to ArrayBuffer instantiation'); - instantiateArrayBuffer(receiveInstantiatedSource); + return instantiateArrayBuffer(receiveInstantiatedSource); }); }); } else { @@ -1924,7 +1767,6 @@ function createWasm() { return {}; // no exports yet; we'll fill them in later } - // Globals used by JS i64 conversions var tempDouble; var tempI64; @@ -1932,20 +1774,17 @@ var tempI64; // === Body === var ASM_CONSTS = { - 1029: function($0, $1, $2) {try { return cjs.string_pass(document.querySelectorAll(cjs.receive($1))[$2].getAttribute(cjs.receive($0))); } catch (e) { return 0; }}, - 1211: function($0, $1, $2, $3) {document.querySelectorAll(cjs.receive($2))[$3].setAttribute(cjs.receive($0), cjs.receive($1));}, - 1310: function($0, $1, $2, $3) {document.querySelectorAll(cjs.receive($2))[$3].addEventListener(cjs.receive($0), () => cjs.fire_event_bus(cjs.receive($1)));}, - 1527: function() {InitWrappers()} + 1025: function($0, $1, $2) {try { return cjs.string_pass(document.querySelectorAll(cjs.receive($1))[$2][cjs.receive($0)]); } catch (e) { return 0; }}, + 1192: function($0, $1, $2) {try { return cjs.string_pass(document.querySelectorAll(cjs.receive($1))[$2].getAttribute(cjs.receive($0))); } catch (e) { return 0; }}, + 1369: function($0, $1, $2, $3) {document.querySelectorAll(cjs.receive($2))[$3][cjs.receive($0)] = cjs.receive($1);}, + 1461: function($0, $1, $2, $3) {document.querySelectorAll(cjs.receive($2))[$3].setAttribute(cjs.receive($0), cjs.receive($1));}, + 1625: function() {InitWrappers()} }; -function _emscripten_asm_const_iii(code, sigPtr, argbuf) { - var args = readAsmConstArgs(sigPtr, argbuf); - return ASM_CONSTS[code].apply(null, args); -} -// STATICTOP = STATIC_BASE + 26208; +// STATICTOP = STATIC_BASE + 26528; /* global initializers */ __ATINIT__.push({ func: function() { ___wasm_call_ctors() } }); @@ -1955,6 +1794,30 @@ function _emscripten_asm_const_iii(code, sigPtr, argbuf) { // {{PRE_LIBRARY}} + function abortStackOverflow(allocSize) { + abort('Stack overflow! Attempted to allocate ' + allocSize + ' bytes on the stack, but stack has only ' + (STACK_MAX - stackSave() + allocSize) + ' bytes available!'); + } + + function callRuntimeCallbacks(callbacks) { + while(callbacks.length > 0) { + var callback = callbacks.shift(); + if (typeof callback == 'function') { + callback(Module); // Pass the module as the first argument. + continue; + } + var func = callback.func; + if (typeof func === 'number') { + if (callback.arg === undefined) { + wasmTable.get(func)(); + } else { + wasmTable.get(func)(callback.arg); + } + } else { + func(callback.arg === undefined ? null : callback.arg); + } + } + } + function demangle(func) { warnOnce('warning: build with -s DEMANGLE_SUPPORT=1 to link in libcxxabi demangling'); return func; @@ -1970,21 +1833,45 @@ function _emscripten_asm_const_iii(code, sigPtr, argbuf) { }); } + + function dynCallLegacy(sig, ptr, args) { + assert(('dynCall_' + sig) in Module, 'bad function pointer type - no table for sig \'' + sig + '\''); + if (args && args.length) { + // j (64-bit integer) must be passed in as two numbers [low 32, high 32]. + assert(args.length === sig.substring(1).replace(/j/g, '--').length); + } else { + assert(sig.length == 1); + } + if (args && args.length) { + return Module['dynCall_' + sig].apply(null, [ptr].concat(args)); + } + return Module['dynCall_' + sig].call(null, ptr); + }function dynCall(sig, ptr, args) { + // Without WASM_BIGINT support we cannot directly call function with i64 as + // part of thier signature, so we rely the dynCall functions generated by + // wasm-emscripten-finalize + if (sig.indexOf('j') != -1) { + return dynCallLegacy(sig, ptr, args); + } + + return wasmTable.get(ptr).apply(null, args) + } + function jsStackTrace() { - var err = new Error(); - if (!err.stack) { + var error = new Error(); + if (!error.stack) { // IE10+ special cases: It does have callstack info, but it is only populated if an Error object is thrown, // so try that as a special-case. try { throw new Error(); } catch(e) { - err = e; + error = e; } - if (!err.stack) { + if (!error.stack) { return '(no stack trace available)'; } } - return err.stack.toString(); + return error.stack.toString(); } function stackTrace() { @@ -1993,190 +1880,303 @@ function _emscripten_asm_const_iii(code, sigPtr, argbuf) { return demangleAll(js); } - function ___cxa_allocate_exception(size) { - return _malloc(size); + + var ExceptionInfoAttrs={DESTRUCTOR_OFFSET:0,REFCOUNT_OFFSET:4,TYPE_OFFSET:8,CAUGHT_OFFSET:12,RETHROWN_OFFSET:13,SIZE:16};function ___cxa_allocate_exception(size) { + // Thrown object is prepended by exception metadata block + return _malloc(size + ExceptionInfoAttrs.SIZE) + ExceptionInfoAttrs.SIZE; } function _atexit(func, arg) { - warnOnce('atexit() called, but EXIT_RUNTIME is not set, so atexits() will not be called. set EXIT_RUNTIME to 1 (see the FAQ)'); - __ATEXIT__.unshift({ func: func, arg: arg }); }function ___cxa_atexit(a0,a1 ) { return _atexit(a0,a1); } - var ___exception_infos={}; - var ___exception_caught= []; + function ExceptionInfo(excPtr) { + this.excPtr = excPtr; + this.ptr = excPtr - ExceptionInfoAttrs.SIZE; - function ___exception_addRef(ptr) { - if (!ptr) return; - var info = ___exception_infos[ptr]; - info.refcount++; - } + this.set_type = function(type) { + HEAP32[(((this.ptr)+(ExceptionInfoAttrs.TYPE_OFFSET))>>2)]=type; + }; - function ___exception_deAdjust(adjusted) { - if (!adjusted || ___exception_infos[adjusted]) return adjusted; - for (var key in ___exception_infos) { - var ptr = +key; // the iteration key is a string, and if we throw this, it must be an integer as that is what we look for - var adj = ___exception_infos[ptr].adjusted; - var len = adj.length; - for (var i = 0; i < len; i++) { - if (adj[i] === adjusted) { - return ptr; - } - } + this.get_type = function() { + return HEAP32[(((this.ptr)+(ExceptionInfoAttrs.TYPE_OFFSET))>>2)]; + }; + + this.set_destructor = function(destructor) { + HEAP32[(((this.ptr)+(ExceptionInfoAttrs.DESTRUCTOR_OFFSET))>>2)]=destructor; + }; + + this.get_destructor = function() { + return HEAP32[(((this.ptr)+(ExceptionInfoAttrs.DESTRUCTOR_OFFSET))>>2)]; + }; + + this.set_refcount = function(refcount) { + HEAP32[(((this.ptr)+(ExceptionInfoAttrs.REFCOUNT_OFFSET))>>2)]=refcount; + }; + + this.set_caught = function (caught) { + caught = caught ? 1 : 0; + HEAP8[(((this.ptr)+(ExceptionInfoAttrs.CAUGHT_OFFSET))>>0)]=caught; + }; + + this.get_caught = function () { + return HEAP8[(((this.ptr)+(ExceptionInfoAttrs.CAUGHT_OFFSET))>>0)] != 0; + }; + + this.set_rethrown = function (rethrown) { + rethrown = rethrown ? 1 : 0; + HEAP8[(((this.ptr)+(ExceptionInfoAttrs.RETHROWN_OFFSET))>>0)]=rethrown; + }; + + this.get_rethrown = function () { + return HEAP8[(((this.ptr)+(ExceptionInfoAttrs.RETHROWN_OFFSET))>>0)] != 0; + }; + + // Initialize native structure fields. Should be called once after allocated. + this.init = function(type, destructor) { + this.set_type(type); + this.set_destructor(destructor); + this.set_refcount(0); + this.set_caught(false); + this.set_rethrown(false); } - return adjusted; + + this.add_ref = function() { + var value = HEAP32[(((this.ptr)+(ExceptionInfoAttrs.REFCOUNT_OFFSET))>>2)]; + HEAP32[(((this.ptr)+(ExceptionInfoAttrs.REFCOUNT_OFFSET))>>2)]=value + 1; + }; + + // Returns true if last reference released. + this.release_ref = function() { + var prev = HEAP32[(((this.ptr)+(ExceptionInfoAttrs.REFCOUNT_OFFSET))>>2)]; + HEAP32[(((this.ptr)+(ExceptionInfoAttrs.REFCOUNT_OFFSET))>>2)]=prev - 1; + assert(prev > 0); + return prev === 1; + }; + }function CatchInfo(ptr) { + + this.free = function() { + _free(this.ptr); + this.ptr = 0; + }; + + this.set_base_ptr = function(basePtr) { + HEAP32[((this.ptr)>>2)]=basePtr; + }; + + this.get_base_ptr = function() { + return HEAP32[((this.ptr)>>2)]; + }; + + this.set_adjusted_ptr = function(adjustedPtr) { + var ptrSize = 4; + HEAP32[(((this.ptr)+(ptrSize))>>2)]=adjustedPtr; + }; + + this.get_adjusted_ptr = function() { + var ptrSize = 4; + return HEAP32[(((this.ptr)+(ptrSize))>>2)]; + }; + + // Get pointer which is expected to be received by catch clause in C++ code. It may be adjusted + // when the pointer is casted to some of the exception object base classes (e.g. when virtual + // inheritance is used). When a pointer is thrown this method should return the thrown pointer + // itself. + this.get_exception_ptr = function() { + // Work around a fastcomp bug, this code is still included for some reason in a build without + // exceptions support. + var isPointer = ___cxa_is_pointer_type( + this.get_exception_info().get_type()); + if (isPointer) { + return HEAP32[((this.get_base_ptr())>>2)]; + } + var adjusted = this.get_adjusted_ptr(); + if (adjusted !== 0) return adjusted; + return this.get_base_ptr(); + }; + + this.get_exception_info = function() { + return new ExceptionInfo(this.get_base_ptr()); + }; + + if (ptr === undefined) { + this.ptr = _malloc(8); + this.set_adjusted_ptr(0); + } else { + this.ptr = ptr; + } + } + + var exceptionCaught= []; + + function exception_addRef(info) { + info.add_ref(); }function ___cxa_begin_catch(ptr) { - var info = ___exception_infos[ptr]; - if (info && !info.caught) { - info.caught = true; + var catchInfo = new CatchInfo(ptr); + var info = catchInfo.get_exception_info(); + if (!info.get_caught()) { + info.set_caught(true); __ZSt18uncaught_exceptionv.uncaught_exceptions--; } - if (info) info.rethrown = false; - ___exception_caught.push(ptr); - ___exception_addRef(___exception_deAdjust(ptr)); - return ptr; + info.set_rethrown(false); + exceptionCaught.push(catchInfo); + exception_addRef(info); + return catchInfo.get_exception_ptr(); } - var ___exception_last=0; + var exceptionLast=0; function ___cxa_free_exception(ptr) { try { - return _free(ptr); + return _free(new ExceptionInfo(ptr).ptr); } catch(e) { err('exception during cxa_free_exception: ' + e); } - }function ___exception_decRef(ptr) { - if (!ptr) return; - var info = ___exception_infos[ptr]; - assert(info.refcount > 0); - info.refcount--; + }function exception_decRef(info) { // A rethrown exception can reach refcount 0; it must not be discarded // Its next handler will clear the rethrown flag and addRef it, prior to // final decRef and destruction here - if (info.refcount === 0 && !info.rethrown) { - if (info.destructor) { + if (info.release_ref() && !info.get_rethrown()) { + var destructor = info.get_destructor(); + if (destructor) { // In Wasm, destructors return 'this' as in ARM - Module['dynCall_ii'](info.destructor, ptr); + wasmTable.get(destructor)(info.excPtr); } - delete ___exception_infos[ptr]; - ___cxa_free_exception(ptr); + ___cxa_free_exception(info.excPtr); } }function ___cxa_end_catch() { // Clear state flag. _setThrew(0); + assert(exceptionCaught.length > 0); // Call destructor if one is registered then clear it. - var ptr = ___exception_caught.pop(); - if (ptr) { - ___exception_decRef(___exception_deAdjust(ptr)); - ___exception_last = 0; // XXX in decRef? - } + var catchInfo = exceptionCaught.pop(); + + exception_decRef(catchInfo.get_exception_info()); + catchInfo.free(); + exceptionLast = 0; // XXX in decRef? } - function ___cxa_find_matching_catch_2() { - var thrown = ___exception_last; + + function ___resumeException(catchInfoPtr) { + var catchInfo = new CatchInfo(catchInfoPtr); + var ptr = catchInfo.get_base_ptr(); + if (!exceptionLast) { exceptionLast = ptr; } + catchInfo.free(); + throw ptr; + } + + var exceptionThrowBuf=0;function ___cxa_find_matching_catch_2() { + var thrown = exceptionLast; if (!thrown) { // just pass through the null ptr return ((setTempRet0(0),0)|0); } - var info = ___exception_infos[thrown]; - var throwntype = info.type; - if (!throwntype) { + var info = new ExceptionInfo(thrown); + var thrownType = info.get_type(); + var catchInfo = new CatchInfo(); + catchInfo.set_base_ptr(thrown); + if (!thrownType) { // just pass through the thrown ptr - return ((setTempRet0(0),thrown)|0); + return ((setTempRet0(0),catchInfo.ptr)|0); } var typeArray = Array.prototype.slice.call(arguments); - var pointer = ___cxa_is_pointer_type(throwntype); // can_catch receives a **, add indirection - var buffer = 27216; - HEAP32[((buffer)>>2)]=thrown; - thrown = buffer; + if (!exceptionThrowBuf) { + exceptionThrowBuf = _malloc(4); + } + HEAP32[((exceptionThrowBuf)>>2)]=thrown; // The different catch blocks are denoted by different types. // Due to inheritance, those types may not precisely match the // type of the thrown object. Find one which matches, and // return the type of the catch block which should be called. for (var i = 0; i < typeArray.length; i++) { - if (typeArray[i] && ___cxa_can_catch(typeArray[i], throwntype, thrown)) { - thrown = HEAP32[((thrown)>>2)]; // undo indirection - info.adjusted.push(thrown); - return ((setTempRet0(typeArray[i]),thrown)|0); + var caughtType = typeArray[i]; + if (caughtType === 0 || caughtType === thrownType) { + // Catch all clause matched or exactly the same type is caught + break; + } + if (___cxa_can_catch(caughtType, thrownType, exceptionThrowBuf)) { + var adjusted = HEAP32[((exceptionThrowBuf)>>2)]; + if (thrown !== adjusted) { + catchInfo.set_adjusted_ptr(adjusted); + } + return ((setTempRet0(caughtType),catchInfo.ptr)|0); } } - // Shouldn't happen unless we have bogus data in typeArray - // or encounter a type for which emscripten doesn't have suitable - // typeinfo defined. Best-efforts match just in case. - thrown = HEAP32[((thrown)>>2)]; // undo indirection - return ((setTempRet0(throwntype),thrown)|0); + return ((setTempRet0(thrownType),catchInfo.ptr)|0); } function ___cxa_find_matching_catch_3() { - var thrown = ___exception_last; + var thrown = exceptionLast; if (!thrown) { // just pass through the null ptr return ((setTempRet0(0),0)|0); } - var info = ___exception_infos[thrown]; - var throwntype = info.type; - if (!throwntype) { + var info = new ExceptionInfo(thrown); + var thrownType = info.get_type(); + var catchInfo = new CatchInfo(); + catchInfo.set_base_ptr(thrown); + if (!thrownType) { // just pass through the thrown ptr - return ((setTempRet0(0),thrown)|0); + return ((setTempRet0(0),catchInfo.ptr)|0); } var typeArray = Array.prototype.slice.call(arguments); - var pointer = ___cxa_is_pointer_type(throwntype); // can_catch receives a **, add indirection - var buffer = 27216; - HEAP32[((buffer)>>2)]=thrown; - thrown = buffer; + if (!exceptionThrowBuf) { + exceptionThrowBuf = _malloc(4); + } + HEAP32[((exceptionThrowBuf)>>2)]=thrown; // The different catch blocks are denoted by different types. // Due to inheritance, those types may not precisely match the // type of the thrown object. Find one which matches, and // return the type of the catch block which should be called. for (var i = 0; i < typeArray.length; i++) { - if (typeArray[i] && ___cxa_can_catch(typeArray[i], throwntype, thrown)) { - thrown = HEAP32[((thrown)>>2)]; // undo indirection - info.adjusted.push(thrown); - return ((setTempRet0(typeArray[i]),thrown)|0); + var caughtType = typeArray[i]; + if (caughtType === 0 || caughtType === thrownType) { + // Catch all clause matched or exactly the same type is caught + break; + } + if (___cxa_can_catch(caughtType, thrownType, exceptionThrowBuf)) { + var adjusted = HEAP32[((exceptionThrowBuf)>>2)]; + if (thrown !== adjusted) { + catchInfo.set_adjusted_ptr(adjusted); + } + return ((setTempRet0(caughtType),catchInfo.ptr)|0); } } - // Shouldn't happen unless we have bogus data in typeArray - // or encounter a type for which emscripten doesn't have suitable - // typeinfo defined. Best-efforts match just in case. - thrown = HEAP32[((thrown)>>2)]; // undo indirection - return ((setTempRet0(throwntype),thrown)|0); + return ((setTempRet0(thrownType),catchInfo.ptr)|0); } function ___cxa_rethrow() { - var ptr = ___exception_caught.pop(); - ptr = ___exception_deAdjust(ptr); - if (!___exception_infos[ptr].rethrown) { + var catchInfo = exceptionCaught.pop(); + var info = catchInfo.get_exception_info(); + var ptr = catchInfo.get_base_ptr(); + if (!info.get_rethrown()) { // Only pop if the corresponding push was through rethrow_primary_exception - ___exception_caught.push(ptr); - ___exception_infos[ptr].rethrown = true; + exceptionCaught.push(catchInfo); + info.set_rethrown(true); + } else { + catchInfo.free(); } - ___exception_last = ptr; + exceptionLast = ptr; throw ptr; } function ___cxa_throw(ptr, type, destructor) { - ___exception_infos[ptr] = { - ptr: ptr, - adjusted: [ptr], - type: type, - destructor: destructor, - refcount: 0, - caught: false, - rethrown: false - }; - ___exception_last = ptr; + var info = new ExceptionInfo(ptr); + // Initialize ExceptionInfo content after it was allocated in __cxa_allocate_exception. + info.init(type, destructor); + exceptionLast = ptr; if (!("uncaught_exception" in __ZSt18uncaught_exceptionv)) { __ZSt18uncaught_exceptionv.uncaught_exceptions = 1; } else { @@ -2189,10 +2189,6 @@ function _emscripten_asm_const_iii(code, sigPtr, argbuf) { return __ZSt18uncaught_exceptionv.uncaught_exceptions; } - function ___handle_stack_overflow() { - abort('stack overflow') - } - function setErrNo(value) { HEAP32[((___errno_location())>>2)]=value; @@ -2202,10 +2198,6 @@ function _emscripten_asm_const_iii(code, sigPtr, argbuf) { return -1; } - function ___resumeException(ptr) { - if (!___exception_last) { ___exception_last = ptr; } - throw ptr; - } @@ -2265,6 +2257,8 @@ function _emscripten_asm_const_iii(code, sigPtr, argbuf) { },basename:function(path) { // EMSCRIPTEN return '/'' for '/', not an empty string if (path === '/') return '/'; + path = PATH.normalize(path); + path = path.replace(/\/$/, ""); var lastSlash = path.lastIndexOf('/'); if (lastSlash === -1) return path; return path.substr(lastSlash+1); @@ -2723,8 +2717,10 @@ function _emscripten_asm_const_iii(code, sigPtr, argbuf) { // Appending to an existing file and we need to reallocate, or source data did not come as a typed array. MEMFS.expandFileStorage(node, position+length); - if (node.contents.subarray && buffer.subarray) node.contents.set(buffer.subarray(offset, offset + length), position); // Use typed array write if available. - else { + if (node.contents.subarray && buffer.subarray) { + // Use typed array write which is available. + node.contents.set(buffer.subarray(offset, offset + length), position); + } else { for (var i = 0; i < length; i++) { node.contents[position + i] = buffer[offset + i]; // Or fall back to manual write if not. } @@ -2747,9 +2743,10 @@ function _emscripten_asm_const_iii(code, sigPtr, argbuf) { },allocate:function(stream, offset, length) { MEMFS.expandFileStorage(stream.node, offset + length); stream.node.usedBytes = Math.max(stream.node.usedBytes, offset + length); - },mmap:function(stream, buffer, offset, length, position, prot, flags) { - // The data buffer should be a typed array view - assert(!(buffer instanceof ArrayBuffer)); + },mmap:function(stream, address, length, position, prot, flags) { + // We don't currently support location hints for the address of the mapping + assert(address === 0); + if (!FS.isFile(stream.node.mode)) { throw new FS.ErrnoError(43); } @@ -2757,8 +2754,7 @@ function _emscripten_asm_const_iii(code, sigPtr, argbuf) { var allocated; var contents = stream.node.contents; // Only make a new copy when MAP_PRIVATE is specified. - if ( !(flags & 2) && - contents.buffer === buffer.buffer ) { + if (!(flags & 2) && contents.buffer === buffer) { // We can't emulate MAP_SHARED when the file is not backed by the buffer // we're mapping to (e.g. the HEAP buffer). allocated = false; @@ -2773,14 +2769,11 @@ function _emscripten_asm_const_iii(code, sigPtr, argbuf) { } } allocated = true; - // malloc() can lead to growing the heap. If targeting the heap, we need to - // re-acquire the heap buffer object in case growth had occurred. - var fromHeap = (buffer.buffer == HEAP8.buffer); - ptr = _malloc(length); + ptr = FS.mmapAlloc(length); if (!ptr) { throw new FS.ErrnoError(48); } - (fromHeap ? HEAP8 : buffer).set(contents, ptr); + HEAP8.set(contents, ptr); } return { ptr: ptr, allocated: allocated }; },msync:function(stream, buffer, offset, length, mmapFlags) { @@ -3290,14 +3283,13 @@ function _emscripten_asm_const_iii(code, sigPtr, argbuf) { var new_name = PATH.basename(new_path); // parents must exist var lookup, old_dir, new_dir; - try { - lookup = FS.lookupPath(old_path, { parent: true }); - old_dir = lookup.node; - lookup = FS.lookupPath(new_path, { parent: true }); - new_dir = lookup.node; - } catch (e) { - throw new FS.ErrnoError(10); - } + + // let the errors from non existant directories percolate up + lookup = FS.lookupPath(old_path, { parent: true }); + old_dir = lookup.node; + lookup = FS.lookupPath(new_path, { parent: true }); + new_dir = lookup.node; + if (!old_dir || !new_dir) throw new FS.ErrnoError(44); // need to be part of the same mount if (old_dir.mount !== new_dir.mount) { @@ -3766,7 +3758,7 @@ function _emscripten_asm_const_iii(code, sigPtr, argbuf) { throw new FS.ErrnoError(138); } stream.stream_ops.allocate(stream, offset, length); - },mmap:function(stream, buffer, offset, length, position, prot, flags) { + },mmap:function(stream, address, length, position, prot, flags) { // User requests writing to file (prot & PROT_WRITE != 0). // Checking if we have permissions to write to the file unless // MAP_PRIVATE flag is set. According to POSIX spec it is possible @@ -3784,7 +3776,7 @@ function _emscripten_asm_const_iii(code, sigPtr, argbuf) { if (!stream.stream_ops.mmap) { throw new FS.ErrnoError(43); } - return stream.stream_ops.mmap(stream, buffer, offset, length, position, prot, flags); + return stream.stream_ops.mmap(stream, address, length, position, prot, flags); },msync:function(stream, buffer, offset, length, mmapFlags) { if (!stream || !stream.stream_ops.msync) { return 0; @@ -4453,6 +4445,11 @@ function _emscripten_asm_const_iii(code, sigPtr, argbuf) { transaction.onerror = onerror; }; openRequest.onerror = onerror; + },mmapAlloc:function(size) { + var alignedSize = alignMemory(size, 16384); + var ptr = _malloc(alignedSize); + while (size < alignedSize) HEAP8[ptr + size++] = 0; + return ptr; }};var SYSCALLS={mappings:{},DEFAULT_POLLMASK:5,umask:511,calculateAt:function(dirfd, path) { if (path[0] !== '/') { // relative path @@ -5061,20 +5058,13 @@ function _emscripten_asm_const_iii(code, sigPtr, argbuf) { var str; if (stdStringIsUTF8) { - //ensure null termination at one-past-end byte if not present yet - var endChar = HEAPU8[value + 4 + length]; - var endCharSwap = 0; - if (endChar != 0) { - endCharSwap = endChar; - HEAPU8[value + 4 + length] = 0; - } - var decodeStartPtr = value + 4; // Looping here to support possible embedded '0' bytes for (var i = 0; i <= length; ++i) { var currentBytePtr = value + 4 + i; - if (HEAPU8[currentBytePtr] == 0) { - var stringSegment = UTF8ToString(decodeStartPtr); + if (i == length || HEAPU8[currentBytePtr] == 0) { + var maxRead = currentBytePtr - decodeStartPtr; + var stringSegment = UTF8ToString(decodeStartPtr, maxRead); if (str === undefined) { str = stringSegment; } else { @@ -5084,10 +5074,6 @@ function _emscripten_asm_const_iii(code, sigPtr, argbuf) { decodeStartPtr = currentBytePtr + 1; } } - - if (endCharSwap != 0) { - HEAPU8[value + 4 + length] = endCharSwap; - } } else { var a = new Array(length); for (var i = 0; i < length; ++i) { @@ -5174,20 +5160,14 @@ function _emscripten_asm_const_iii(code, sigPtr, argbuf) { var length = HEAPU32[value >> 2]; var HEAP = getHeap(); var str; - // Ensure null termination at one-past-end byte if not present yet - var endChar = HEAP[(value + 4 + length * charSize) >> shift]; - var endCharSwap = 0; - if (endChar != 0) { - endCharSwap = endChar; - HEAP[(value + 4 + length * charSize) >> shift] = 0; - } var decodeStartPtr = value + 4; // Looping here to support possible embedded '0' bytes for (var i = 0; i <= length; ++i) { var currentBytePtr = value + 4 + i * charSize; - if (HEAP[currentBytePtr >> shift] == 0) { - var stringSegment = decodeString(decodeStartPtr); + if (i == length || HEAP[currentBytePtr >> shift] == 0) { + var maxReadBytes = currentBytePtr - decodeStartPtr; + var stringSegment = decodeString(decodeStartPtr, maxReadBytes); if (str === undefined) { str = stringSegment; } else { @@ -5198,10 +5178,6 @@ function _emscripten_asm_const_iii(code, sigPtr, argbuf) { } } - if (endCharSwap != 0) { - HEAP[(value + 4 + length * charSize) >> shift] = endCharSwap; - } - _free(value); return str; @@ -5249,8 +5225,13 @@ function _emscripten_asm_const_iii(code, sigPtr, argbuf) { abort(); } + function _emscripten_asm_const_int(code, sigPtr, argbuf) { + var args = readAsmConstArgs(sigPtr, argbuf); + return ASM_CONSTS[code].apply(null, args); + } + function _emscripten_get_sbrk_ptr() { - return 27056; + return 27536; } function _emscripten_memcpy_big(dest, src, num) { @@ -5273,20 +5254,21 @@ function _emscripten_asm_const_iii(code, sigPtr, argbuf) { var ENV={}; - function __getExecutableName() { + function getExecutableName() { return thisProgram || './this.program'; }function getEnvStrings() { if (!getEnvStrings.strings) { // Default values. + // Browser language detection #8751 + var lang = ((typeof navigator === 'object' && navigator.languages && navigator.languages[0]) || 'C').replace('-', '_') + '.UTF-8'; var env = { 'USER': 'web_user', 'LOGNAME': 'web_user', 'PATH': '/', 'PWD': '/', 'HOME': '/home/web_user', - // Browser language detection #8751 - 'LANG': ((typeof navigator === 'object' && navigator.languages && navigator.languages[0]) || 'C').replace('-', '_') + '.UTF-8', - '_': __getExecutableName() + 'LANG': lang, + '_': getExecutableName() }; // Apply the user-provided values, if any. for (var x in ENV) { @@ -5332,30 +5314,6 @@ function _emscripten_asm_const_iii(code, sigPtr, argbuf) { } } - function _fd_seek(fd, offset_low, offset_high, whence, newOffset) {try { - - - var stream = SYSCALLS.getStreamFromFD(fd); - var HIGH_OFFSET = 0x100000000; // 2^32 - // use an unsigned operator on low and shift high by 32-bits - var offset = offset_high * HIGH_OFFSET + (offset_low >>> 0); - - var DOUBLE_LIMIT = 0x20000000000000; // 2^53 - // we also check for equality since DOUBLE_LIMIT + 1 == DOUBLE_LIMIT - if (offset <= -DOUBLE_LIMIT || offset >= DOUBLE_LIMIT) { - return -61; - } - - FS.llseek(stream, offset, whence); - (tempI64 = [stream.position>>>0,(tempDouble=stream.position,(+(Math_abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? ((Math_min((+(Math_floor((tempDouble)/4294967296.0))), 4294967295.0))|0)>>>0 : (~~((+(Math_ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)],HEAP32[((newOffset)>>2)]=tempI64[0],HEAP32[(((newOffset)+(4))>>2)]=tempI64[1]); - if (stream.getdents && offset === 0 && whence === 0) stream.getdents = null; // reset readdir state - return 0; - } catch (e) { - if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e); - return e.errno; - } - } - function _fd_write(fd, iov, iovcnt, pnum) {try { var stream = SYSCALLS.getStreamFromFD(fd); @@ -5742,28 +5700,27 @@ function _emscripten_asm_const_iii(code, sigPtr, argbuf) { return _strftime(s, maxsize, format, tm); // no locale support yet } - function readAsmConstArgs(sigPtr, buf) { - if (!readAsmConstArgs.array) { - readAsmConstArgs.array = []; - } - var args = readAsmConstArgs.array; - args.length = 0; + + var readAsmConstArgsArray=[];function readAsmConstArgs(sigPtr, buf) { + // Nobody should have mutated _readAsmConstArgsArray underneath us to be something else than an array. + assert(Array.isArray(readAsmConstArgsArray)); + // The input buffer is allocated on the stack, so it must be stack-aligned. + assert(buf % 16 == 0); + readAsmConstArgsArray.length = 0; var ch; + // Most arguments are i32s, so shift the buffer pointer so it is a plain + // index into HEAP32. + buf >>= 2; while (ch = HEAPU8[sigPtr++]) { - if (ch === 100/*'d'*/ || ch === 102/*'f'*/) { - buf = (buf + 7) & ~7; - args.push(HEAPF64[(buf >> 3)]); - buf += 8; - } else - if (ch === 105 /*'i'*/) - { - buf = (buf + 3) & ~3; - args.push(HEAP32[(buf >> 2)]); - buf += 4; - } - else abort("unexpected char in asm const signature " + ch); + assert(ch === 100/*'d'*/ || ch === 102/*'f'*/ || ch === 105 /*'i'*/); + // A double takes two 32-bit slots, and must also be aligned - the backend + // will emit padding to avoid that. + var double = ch < 105; + if (double && (buf & 1)) buf++; + readAsmConstArgsArray.push(double ? HEAPF64[buf++ >> 1] : HEAP32[buf]); + ++buf; } - return args; + return readAsmConstArgsArray; } var FSNode = /** @constructor */ function(parent, name, mode, rdev) { if (!parent) { @@ -5817,11 +5774,7 @@ InternalError = Module['InternalError'] = extendError(Error, 'InternalError');; init_emval();; var ASSERTIONS = true; -/** - * @license - * Copyright 2017 The Emscripten Authors - * SPDX-License-Identifier: MIT - */ + /** @type {function(string, boolean=, number=)} */ function intArrayFromString(stringy, dontAddNull, length) { @@ -5848,379 +5801,85 @@ function intArrayToString(array) { } -var asmGlobalArg = {}; -var asmLibraryArg = { "__cxa_allocate_exception": ___cxa_allocate_exception, "__cxa_atexit": ___cxa_atexit, "__cxa_begin_catch": ___cxa_begin_catch, "__cxa_end_catch": ___cxa_end_catch, "__cxa_find_matching_catch_2": ___cxa_find_matching_catch_2, "__cxa_find_matching_catch_3": ___cxa_find_matching_catch_3, "__cxa_free_exception": ___cxa_free_exception, "__cxa_rethrow": ___cxa_rethrow, "__cxa_throw": ___cxa_throw, "__cxa_uncaught_exceptions": ___cxa_uncaught_exceptions, "__handle_stack_overflow": ___handle_stack_overflow, "__map_file": ___map_file, "__resumeException": ___resumeException, "__sys_munmap": ___sys_munmap, "__sys_open": ___sys_open, "__sys_read": ___sys_read, "_embind_register_bool": __embind_register_bool, "_embind_register_emval": __embind_register_emval, "_embind_register_float": __embind_register_float, "_embind_register_integer": __embind_register_integer, "_embind_register_memory_view": __embind_register_memory_view, "_embind_register_std_string": __embind_register_std_string, "_embind_register_std_wstring": __embind_register_std_wstring, "_embind_register_void": __embind_register_void, "abort": _abort, "emscripten_asm_const_iii": _emscripten_asm_const_iii, "emscripten_get_sbrk_ptr": _emscripten_get_sbrk_ptr, "emscripten_memcpy_big": _emscripten_memcpy_big, "emscripten_resize_heap": _emscripten_resize_heap, "environ_get": _environ_get, "environ_sizes_get": _environ_sizes_get, "fd_close": _fd_close, "fd_seek": _fd_seek, "fd_write": _fd_write, "getTempRet0": _getTempRet0, "invoke_diii": invoke_diii, "invoke_fiii": invoke_fiii, "invoke_i": invoke_i, "invoke_ii": invoke_ii, "invoke_iii": invoke_iii, "invoke_iiii": invoke_iiii, "invoke_iiiii": invoke_iiiii, "invoke_iiiiii": invoke_iiiiii, "invoke_iiiiiii": invoke_iiiiiii, "invoke_iiiiiiii": invoke_iiiiiiii, "invoke_iiiiiiiiiii": invoke_iiiiiiiiiii, "invoke_iiiiiiiiiiii": invoke_iiiiiiiiiiii, "invoke_iiiiiiiiiiiii": invoke_iiiiiiiiiiiii, "invoke_jiiii": invoke_jiiii, "invoke_v": invoke_v, "invoke_vi": invoke_vi, "invoke_vii": invoke_vii, "invoke_viii": invoke_viii, "invoke_viiii": invoke_viiii, "invoke_viiiii": invoke_viiiii, "invoke_viiiiiii": invoke_viiiiiii, "invoke_viiiiiiiiii": invoke_viiiiiiiiii, "invoke_viiiiiiiiiiiiiii": invoke_viiiiiiiiiiiiiii, "llvm_eh_typeid_for": _llvm_eh_typeid_for, "memory": wasmMemory, "setTempRet0": _setTempRet0, "strftime_l": _strftime_l, "table": wasmTable }; +var asmLibraryArg = { "__cxa_allocate_exception": ___cxa_allocate_exception, "__cxa_atexit": ___cxa_atexit, "__cxa_begin_catch": ___cxa_begin_catch, "__cxa_end_catch": ___cxa_end_catch, "__cxa_find_matching_catch_2": ___cxa_find_matching_catch_2, "__cxa_find_matching_catch_3": ___cxa_find_matching_catch_3, "__cxa_free_exception": ___cxa_free_exception, "__cxa_rethrow": ___cxa_rethrow, "__cxa_throw": ___cxa_throw, "__cxa_uncaught_exceptions": ___cxa_uncaught_exceptions, "__map_file": ___map_file, "__resumeException": ___resumeException, "__sys_munmap": ___sys_munmap, "__sys_open": ___sys_open, "__sys_read": ___sys_read, "_embind_register_bool": __embind_register_bool, "_embind_register_emval": __embind_register_emval, "_embind_register_float": __embind_register_float, "_embind_register_integer": __embind_register_integer, "_embind_register_memory_view": __embind_register_memory_view, "_embind_register_std_string": __embind_register_std_string, "_embind_register_std_wstring": __embind_register_std_wstring, "_embind_register_void": __embind_register_void, "abort": _abort, "emscripten_asm_const_int": _emscripten_asm_const_int, "emscripten_get_sbrk_ptr": _emscripten_get_sbrk_ptr, "emscripten_memcpy_big": _emscripten_memcpy_big, "emscripten_resize_heap": _emscripten_resize_heap, "environ_get": _environ_get, "environ_sizes_get": _environ_sizes_get, "fd_close": _fd_close, "fd_write": _fd_write, "getTempRet0": _getTempRet0, "invoke_diii": invoke_diii, "invoke_fiii": invoke_fiii, "invoke_i": invoke_i, "invoke_ii": invoke_ii, "invoke_iii": invoke_iii, "invoke_iiii": invoke_iiii, "invoke_iiiii": invoke_iiiii, "invoke_iiiiii": invoke_iiiiii, "invoke_iiiiiii": invoke_iiiiiii, "invoke_iiiiiiii": invoke_iiiiiiii, "invoke_iiiiiiiiiii": invoke_iiiiiiiiiii, "invoke_iiiiiiiiiiii": invoke_iiiiiiiiiiii, "invoke_iiiiiiiiiiiii": invoke_iiiiiiiiiiiii, "invoke_jiiii": invoke_jiiii, "invoke_v": invoke_v, "invoke_vi": invoke_vi, "invoke_vii": invoke_vii, "invoke_viii": invoke_viii, "invoke_viiii": invoke_viiii, "invoke_viiiii": invoke_viiiii, "invoke_viiiiiii": invoke_viiiiiii, "invoke_viiiiiiiiii": invoke_viiiiiiiiii, "invoke_viiiiiiiiiiiiiii": invoke_viiiiiiiiiiiiiii, "llvm_eh_typeid_for": _llvm_eh_typeid_for, "memory": wasmMemory, "setTempRet0": _setTempRet0, "strftime_l": _strftime_l, "table": wasmTable }; var asm = createWasm(); -Module["asm"] = asm; -/** @type {function(...*):?} */ -var ___wasm_call_ctors = Module["___wasm_call_ctors"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["__wasm_call_ctors"].apply(null, arguments) -}; - -/** @type {function(...*):?} */ -var _free = Module["_free"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["free"].apply(null, arguments) -}; - -/** @type {function(...*):?} */ -var _itest = Module["_itest"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["itest"].apply(null, arguments) -}; - -/** @type {function(...*):?} */ -var _str_pass_size = Module["_str_pass_size"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["str_pass_size"].apply(null, arguments) -}; - -/** @type {function(...*):?} */ -var _fire_event_bus = Module["_fire_event_bus"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["fire_event_bus"].apply(null, arguments) -}; - -/** @type {function(...*):?} */ -var _main = Module["_main"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["main"].apply(null, arguments) -}; - -/** @type {function(...*):?} */ -var ___errno_location = Module["___errno_location"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["__errno_location"].apply(null, arguments) -}; - -/** @type {function(...*):?} */ -var _fflush = Module["_fflush"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["fflush"].apply(null, arguments) -}; - -/** @type {function(...*):?} */ -var _setThrew = Module["_setThrew"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["setThrew"].apply(null, arguments) -}; - -/** @type {function(...*):?} */ -var __ZSt18uncaught_exceptionv = Module["__ZSt18uncaught_exceptionv"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["_ZSt18uncaught_exceptionv"].apply(null, arguments) -}; - -/** @type {function(...*):?} */ -var _malloc = Module["_malloc"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["malloc"].apply(null, arguments) -}; - -/** @type {function(...*):?} */ -var ___cxa_can_catch = Module["___cxa_can_catch"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["__cxa_can_catch"].apply(null, arguments) -}; - -/** @type {function(...*):?} */ -var ___cxa_is_pointer_type = Module["___cxa_is_pointer_type"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["__cxa_is_pointer_type"].apply(null, arguments) -}; - -/** @type {function(...*):?} */ -var ___getTypeName = Module["___getTypeName"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["__getTypeName"].apply(null, arguments) -}; - -/** @type {function(...*):?} */ -var ___embind_register_native_and_builtin_types = Module["___embind_register_native_and_builtin_types"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["__embind_register_native_and_builtin_types"].apply(null, arguments) -}; - -/** @type {function(...*):?} */ -var dynCall_v = Module["dynCall_v"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["dynCall_v"].apply(null, arguments) -}; - -/** @type {function(...*):?} */ -var dynCall_vi = Module["dynCall_vi"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["dynCall_vi"].apply(null, arguments) -}; - /** @type {function(...*):?} */ -var dynCall_vii = Module["dynCall_vii"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["dynCall_vii"].apply(null, arguments) -}; +var ___wasm_call_ctors = Module["___wasm_call_ctors"] = createExportWrapper("__wasm_call_ctors"); /** @type {function(...*):?} */ -var dynCall_viii = Module["dynCall_viii"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["dynCall_viii"].apply(null, arguments) -}; +var _free = Module["_free"] = createExportWrapper("free"); /** @type {function(...*):?} */ -var dynCall_viiii = Module["dynCall_viiii"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["dynCall_viiii"].apply(null, arguments) -}; +var _str_pass_size = Module["_str_pass_size"] = createExportWrapper("str_pass_size"); /** @type {function(...*):?} */ -var dynCall_viiiii = Module["dynCall_viiiii"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["dynCall_viiiii"].apply(null, arguments) -}; +var _fire_event_bus = Module["_fire_event_bus"] = createExportWrapper("fire_event_bus"); /** @type {function(...*):?} */ -var dynCall_viiiiiii = Module["dynCall_viiiiiii"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["dynCall_viiiiiii"].apply(null, arguments) -}; +var _main = Module["_main"] = createExportWrapper("main"); /** @type {function(...*):?} */ -var dynCall_viiiiiiiiii = Module["dynCall_viiiiiiiiii"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["dynCall_viiiiiiiiii"].apply(null, arguments) -}; +var ___getTypeName = Module["___getTypeName"] = createExportWrapper("__getTypeName"); /** @type {function(...*):?} */ -var dynCall_viiiiiiiiiiiiiii = Module["dynCall_viiiiiiiiiiiiiii"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["dynCall_viiiiiiiiiiiiiii"].apply(null, arguments) -}; - -/** @type {function(...*):?} */ -var dynCall_i = Module["dynCall_i"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["dynCall_i"].apply(null, arguments) -}; - -/** @type {function(...*):?} */ -var dynCall_ii = Module["dynCall_ii"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["dynCall_ii"].apply(null, arguments) -}; - -/** @type {function(...*):?} */ -var dynCall_iii = Module["dynCall_iii"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["dynCall_iii"].apply(null, arguments) -}; - -/** @type {function(...*):?} */ -var dynCall_iiii = Module["dynCall_iiii"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["dynCall_iiii"].apply(null, arguments) -}; +var ___embind_register_native_and_builtin_types = Module["___embind_register_native_and_builtin_types"] = createExportWrapper("__embind_register_native_and_builtin_types"); /** @type {function(...*):?} */ -var dynCall_iiiii = Module["dynCall_iiiii"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["dynCall_iiiii"].apply(null, arguments) -}; - -/** @type {function(...*):?} */ -var dynCall_iiiiii = Module["dynCall_iiiiii"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["dynCall_iiiiii"].apply(null, arguments) -}; - -/** @type {function(...*):?} */ -var dynCall_iiiiiii = Module["dynCall_iiiiiii"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["dynCall_iiiiiii"].apply(null, arguments) -}; - -/** @type {function(...*):?} */ -var dynCall_iiiiiiii = Module["dynCall_iiiiiiii"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["dynCall_iiiiiiii"].apply(null, arguments) -}; - -/** @type {function(...*):?} */ -var dynCall_iiiiiiiiiii = Module["dynCall_iiiiiiiiiii"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["dynCall_iiiiiiiiiii"].apply(null, arguments) -}; - -/** @type {function(...*):?} */ -var dynCall_iiiiiiiiiiii = Module["dynCall_iiiiiiiiiiii"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["dynCall_iiiiiiiiiiii"].apply(null, arguments) -}; - -/** @type {function(...*):?} */ -var dynCall_iiiiiiiiiiiii = Module["dynCall_iiiiiiiiiiiii"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["dynCall_iiiiiiiiiiiii"].apply(null, arguments) -}; - -/** @type {function(...*):?} */ -var dynCall_jiiii = Module["dynCall_jiiii"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["dynCall_jiiii"].apply(null, arguments) -}; +var ___errno_location = Module["___errno_location"] = createExportWrapper("__errno_location"); /** @type {function(...*):?} */ -var dynCall_fiii = Module["dynCall_fiii"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["dynCall_fiii"].apply(null, arguments) -}; +var _malloc = Module["_malloc"] = createExportWrapper("malloc"); /** @type {function(...*):?} */ -var dynCall_diii = Module["dynCall_diii"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["dynCall_diii"].apply(null, arguments) -}; +var _fflush = Module["_fflush"] = createExportWrapper("fflush"); /** @type {function(...*):?} */ -var ___set_stack_limit = Module["___set_stack_limit"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["__set_stack_limit"].apply(null, arguments) -}; +var _setThrew = Module["_setThrew"] = createExportWrapper("setThrew"); /** @type {function(...*):?} */ -var stackSave = Module["stackSave"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["stackSave"].apply(null, arguments) -}; +var stackSave = Module["stackSave"] = createExportWrapper("stackSave"); /** @type {function(...*):?} */ -var stackAlloc = Module["stackAlloc"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["stackAlloc"].apply(null, arguments) -}; +var stackRestore = Module["stackRestore"] = createExportWrapper("stackRestore"); /** @type {function(...*):?} */ -var stackRestore = Module["stackRestore"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["stackRestore"].apply(null, arguments) -}; +var stackAlloc = Module["stackAlloc"] = createExportWrapper("stackAlloc"); /** @type {function(...*):?} */ -var __growWasmMemory = Module["__growWasmMemory"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["__growWasmMemory"].apply(null, arguments) -}; +var __ZSt18uncaught_exceptionv = Module["__ZSt18uncaught_exceptionv"] = createExportWrapper("_ZSt18uncaught_exceptionv"); /** @type {function(...*):?} */ -var dynCall_viijii = Module["dynCall_viijii"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["dynCall_viijii"].apply(null, arguments) -}; +var ___cxa_can_catch = Module["___cxa_can_catch"] = createExportWrapper("__cxa_can_catch"); /** @type {function(...*):?} */ -var dynCall_iidiiii = Module["dynCall_iidiiii"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["dynCall_iidiiii"].apply(null, arguments) -}; +var ___cxa_is_pointer_type = Module["___cxa_is_pointer_type"] = createExportWrapper("__cxa_is_pointer_type"); /** @type {function(...*):?} */ -var dynCall_iiiiiiiii = Module["dynCall_iiiiiiiii"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["dynCall_iiiiiiiii"].apply(null, arguments) -}; +var dynCall_jiiii = Module["dynCall_jiiii"] = createExportWrapper("dynCall_jiiii"); /** @type {function(...*):?} */ -var dynCall_iiiiij = Module["dynCall_iiiiij"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["dynCall_iiiiij"].apply(null, arguments) -}; +var dynCall_viijii = Module["dynCall_viijii"] = createExportWrapper("dynCall_viijii"); /** @type {function(...*):?} */ -var dynCall_iiiiid = Module["dynCall_iiiiid"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["dynCall_iiiiid"].apply(null, arguments) -}; +var dynCall_iiiiij = Module["dynCall_iiiiij"] = createExportWrapper("dynCall_iiiiij"); /** @type {function(...*):?} */ -var dynCall_iiiiijj = Module["dynCall_iiiiijj"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["dynCall_iiiiijj"].apply(null, arguments) -}; +var dynCall_iiiiijj = Module["dynCall_iiiiijj"] = createExportWrapper("dynCall_iiiiijj"); /** @type {function(...*):?} */ -var dynCall_iiiiiijj = Module["dynCall_iiiiiijj"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["dynCall_iiiiiijj"].apply(null, arguments) -}; +var dynCall_iiiiiijj = Module["dynCall_iiiiiijj"] = createExportWrapper("dynCall_iiiiiijj"); /** @type {function(...*):?} */ -var dynCall_viiiiii = Module["dynCall_viiiiii"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["dynCall_viiiiii"].apply(null, arguments) -}; +var dynCall_jiji = Module["dynCall_jiji"] = createExportWrapper("dynCall_jiji"); /** @type {function(...*):?} */ -var dynCall_jiji = Module["dynCall_jiji"] = function() { - assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)'); - assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); - return Module["asm"]["dynCall_jiji"].apply(null, arguments) -}; +var __growWasmMemory = Module["__growWasmMemory"] = createExportWrapper("__growWasmMemory"); -function invoke_vii(index,a1,a2) { +function invoke_iii(index,a1,a2) { var sp = stackSave(); try { - dynCall_vii(index,a1,a2); + return wasmTable.get(index)(a1,a2); } catch(e) { stackRestore(sp); if (e !== e+0 && e !== 'longjmp') throw e; @@ -6228,10 +5887,10 @@ function invoke_vii(index,a1,a2) { } } -function invoke_iiii(index,a1,a2,a3) { +function invoke_vii(index,a1,a2) { var sp = stackSave(); try { - return dynCall_iiii(index,a1,a2,a3); + wasmTable.get(index)(a1,a2); } catch(e) { stackRestore(sp); if (e !== e+0 && e !== 'longjmp') throw e; @@ -6239,10 +5898,10 @@ function invoke_iiii(index,a1,a2,a3) { } } -function invoke_iii(index,a1,a2) { +function invoke_iiii(index,a1,a2,a3) { var sp = stackSave(); try { - return dynCall_iii(index,a1,a2); + return wasmTable.get(index)(a1,a2,a3); } catch(e) { stackRestore(sp); if (e !== e+0 && e !== 'longjmp') throw e; @@ -6253,7 +5912,7 @@ function invoke_iii(index,a1,a2) { function invoke_ii(index,a1) { var sp = stackSave(); try { - return dynCall_ii(index,a1); + return wasmTable.get(index)(a1); } catch(e) { stackRestore(sp); if (e !== e+0 && e !== 'longjmp') throw e; @@ -6264,7 +5923,7 @@ function invoke_ii(index,a1) { function invoke_viiii(index,a1,a2,a3,a4) { var sp = stackSave(); try { - dynCall_viiii(index,a1,a2,a3,a4); + wasmTable.get(index)(a1,a2,a3,a4); } catch(e) { stackRestore(sp); if (e !== e+0 && e !== 'longjmp') throw e; @@ -6272,10 +5931,10 @@ function invoke_viiii(index,a1,a2,a3,a4) { } } -function invoke_v(index) { +function invoke_viii(index,a1,a2,a3) { var sp = stackSave(); try { - dynCall_v(index); + wasmTable.get(index)(a1,a2,a3); } catch(e) { stackRestore(sp); if (e !== e+0 && e !== 'longjmp') throw e; @@ -6283,10 +5942,10 @@ function invoke_v(index) { } } -function invoke_viii(index,a1,a2,a3) { +function invoke_vi(index,a1) { var sp = stackSave(); try { - dynCall_viii(index,a1,a2,a3); + wasmTable.get(index)(a1); } catch(e) { stackRestore(sp); if (e !== e+0 && e !== 'longjmp') throw e; @@ -6294,10 +5953,10 @@ function invoke_viii(index,a1,a2,a3) { } } -function invoke_vi(index,a1) { +function invoke_v(index) { var sp = stackSave(); try { - dynCall_vi(index,a1); + wasmTable.get(index)(); } catch(e) { stackRestore(sp); if (e !== e+0 && e !== 'longjmp') throw e; @@ -6305,10 +5964,10 @@ function invoke_vi(index,a1) { } } -function invoke_iiiiiii(index,a1,a2,a3,a4,a5,a6) { +function invoke_iiiiii(index,a1,a2,a3,a4,a5) { var sp = stackSave(); try { - return dynCall_iiiiiii(index,a1,a2,a3,a4,a5,a6); + return wasmTable.get(index)(a1,a2,a3,a4,a5); } catch(e) { stackRestore(sp); if (e !== e+0 && e !== 'longjmp') throw e; @@ -6319,7 +5978,7 @@ function invoke_iiiiiii(index,a1,a2,a3,a4,a5,a6) { function invoke_viiiii(index,a1,a2,a3,a4,a5) { var sp = stackSave(); try { - dynCall_viiiii(index,a1,a2,a3,a4,a5); + wasmTable.get(index)(a1,a2,a3,a4,a5); } catch(e) { stackRestore(sp); if (e !== e+0 && e !== 'longjmp') throw e; @@ -6327,10 +5986,10 @@ function invoke_viiiii(index,a1,a2,a3,a4,a5) { } } -function invoke_iiiiii(index,a1,a2,a3,a4,a5) { +function invoke_iiiiiii(index,a1,a2,a3,a4,a5,a6) { var sp = stackSave(); try { - return dynCall_iiiiii(index,a1,a2,a3,a4,a5); + return wasmTable.get(index)(a1,a2,a3,a4,a5,a6); } catch(e) { stackRestore(sp); if (e !== e+0 && e !== 'longjmp') throw e; @@ -6341,7 +6000,7 @@ function invoke_iiiiii(index,a1,a2,a3,a4,a5) { function invoke_iiiiiiii(index,a1,a2,a3,a4,a5,a6,a7) { var sp = stackSave(); try { - return dynCall_iiiiiiii(index,a1,a2,a3,a4,a5,a6,a7); + return wasmTable.get(index)(a1,a2,a3,a4,a5,a6,a7); } catch(e) { stackRestore(sp); if (e !== e+0 && e !== 'longjmp') throw e; @@ -6352,7 +6011,7 @@ function invoke_iiiiiiii(index,a1,a2,a3,a4,a5,a6,a7) { function invoke_iiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) { var sp = stackSave(); try { - return dynCall_iiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10); + return wasmTable.get(index)(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10); } catch(e) { stackRestore(sp); if (e !== e+0 && e !== 'longjmp') throw e; @@ -6363,7 +6022,7 @@ function invoke_iiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) { function invoke_iiiii(index,a1,a2,a3,a4) { var sp = stackSave(); try { - return dynCall_iiiii(index,a1,a2,a3,a4); + return wasmTable.get(index)(a1,a2,a3,a4); } catch(e) { stackRestore(sp); if (e !== e+0 && e !== 'longjmp') throw e; @@ -6374,7 +6033,7 @@ function invoke_iiiii(index,a1,a2,a3,a4) { function invoke_iiiiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12) { var sp = stackSave(); try { - return dynCall_iiiiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12); + return wasmTable.get(index)(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12); } catch(e) { stackRestore(sp); if (e !== e+0 && e !== 'longjmp') throw e; @@ -6385,7 +6044,7 @@ function invoke_iiiiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12) { function invoke_fiii(index,a1,a2,a3) { var sp = stackSave(); try { - return dynCall_fiii(index,a1,a2,a3); + return wasmTable.get(index)(a1,a2,a3); } catch(e) { stackRestore(sp); if (e !== e+0 && e !== 'longjmp') throw e; @@ -6396,7 +6055,7 @@ function invoke_fiii(index,a1,a2,a3) { function invoke_diii(index,a1,a2,a3) { var sp = stackSave(); try { - return dynCall_diii(index,a1,a2,a3); + return wasmTable.get(index)(a1,a2,a3); } catch(e) { stackRestore(sp); if (e !== e+0 && e !== 'longjmp') throw e; @@ -6407,7 +6066,7 @@ function invoke_diii(index,a1,a2,a3) { function invoke_i(index) { var sp = stackSave(); try { - return dynCall_i(index); + return wasmTable.get(index)(); } catch(e) { stackRestore(sp); if (e !== e+0 && e !== 'longjmp') throw e; @@ -6418,7 +6077,7 @@ function invoke_i(index) { function invoke_viiiiiii(index,a1,a2,a3,a4,a5,a6,a7) { var sp = stackSave(); try { - dynCall_viiiiiii(index,a1,a2,a3,a4,a5,a6,a7); + wasmTable.get(index)(a1,a2,a3,a4,a5,a6,a7); } catch(e) { stackRestore(sp); if (e !== e+0 && e !== 'longjmp') throw e; @@ -6429,7 +6088,7 @@ function invoke_viiiiiii(index,a1,a2,a3,a4,a5,a6,a7) { function invoke_iiiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11) { var sp = stackSave(); try { - return dynCall_iiiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11); + return wasmTable.get(index)(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11); } catch(e) { stackRestore(sp); if (e !== e+0 && e !== 'longjmp') throw e; @@ -6440,7 +6099,7 @@ function invoke_iiiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11) { function invoke_viiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) { var sp = stackSave(); try { - dynCall_viiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10); + wasmTable.get(index)(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10); } catch(e) { stackRestore(sp); if (e !== e+0 && e !== 'longjmp') throw e; @@ -6451,7 +6110,7 @@ function invoke_viiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) { function invoke_viiiiiiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15) { var sp = stackSave(); try { - dynCall_viiiiiiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15); + wasmTable.get(index)(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15); } catch(e) { stackRestore(sp); if (e !== e+0 && e !== 'longjmp') throw e; @@ -6471,15 +6130,9 @@ function invoke_jiiii(index,a1,a2,a3,a4) { } -/** - * @license - * Copyright 2010 The Emscripten Authors - * SPDX-License-Identifier: MIT - */ -// === Auto-generated postamble setup entry stuff === -Module['asm'] = asm; +// === Auto-generated postamble setup entry stuff === if (!Object.getOwnPropertyDescriptor(Module, "intArrayFromString")) Module["intArrayFromString"] = function() { abort("'intArrayFromString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "intArrayToString")) Module["intArrayToString"] = function() { abort("'intArrayToString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; @@ -6537,7 +6190,6 @@ if (!Object.getOwnPropertyDescriptor(Module, "stringToNewUTF8")) Module["stringT if (!Object.getOwnPropertyDescriptor(Module, "abortOnCannotGrowMemory")) Module["abortOnCannotGrowMemory"] = function() { abort("'abortOnCannotGrowMemory' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "emscripten_realloc_buffer")) Module["emscripten_realloc_buffer"] = function() { abort("'emscripten_realloc_buffer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "ENV")) Module["ENV"] = function() { abort("'ENV' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; -if (!Object.getOwnPropertyDescriptor(Module, "setjmpId")) Module["setjmpId"] = function() { abort("'setjmpId' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "ERRNO_CODES")) Module["ERRNO_CODES"] = function() { abort("'ERRNO_CODES' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "ERRNO_MESSAGES")) Module["ERRNO_MESSAGES"] = function() { abort("'ERRNO_MESSAGES' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "setErrNo")) Module["setErrNo"] = function() { abort("'setErrNo' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; @@ -6545,11 +6197,25 @@ if (!Object.getOwnPropertyDescriptor(Module, "DNS")) Module["DNS"] = function() if (!Object.getOwnPropertyDescriptor(Module, "GAI_ERRNO_MESSAGES")) Module["GAI_ERRNO_MESSAGES"] = function() { abort("'GAI_ERRNO_MESSAGES' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "Protocols")) Module["Protocols"] = function() { abort("'Protocols' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "Sockets")) Module["Sockets"] = function() { abort("'Sockets' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; +if (!Object.getOwnPropertyDescriptor(Module, "traverseStack")) Module["traverseStack"] = function() { abort("'traverseStack' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "UNWIND_CACHE")) Module["UNWIND_CACHE"] = function() { abort("'UNWIND_CACHE' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; +if (!Object.getOwnPropertyDescriptor(Module, "withBuiltinMalloc")) Module["withBuiltinMalloc"] = function() { abort("'withBuiltinMalloc' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; +if (!Object.getOwnPropertyDescriptor(Module, "readAsmConstArgsArray")) Module["readAsmConstArgsArray"] = function() { abort("'readAsmConstArgsArray' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "readAsmConstArgs")) Module["readAsmConstArgs"] = function() { abort("'readAsmConstArgs' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; +if (!Object.getOwnPropertyDescriptor(Module, "mainThreadEM_ASM")) Module["mainThreadEM_ASM"] = function() { abort("'mainThreadEM_ASM' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "jstoi_q")) Module["jstoi_q"] = function() { abort("'jstoi_q' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "jstoi_s")) Module["jstoi_s"] = function() { abort("'jstoi_s' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; +if (!Object.getOwnPropertyDescriptor(Module, "getExecutableName")) Module["getExecutableName"] = function() { abort("'getExecutableName' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; +if (!Object.getOwnPropertyDescriptor(Module, "listenOnce")) Module["listenOnce"] = function() { abort("'listenOnce' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; +if (!Object.getOwnPropertyDescriptor(Module, "autoResumeAudioContext")) Module["autoResumeAudioContext"] = function() { abort("'autoResumeAudioContext' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; +if (!Object.getOwnPropertyDescriptor(Module, "dynCallLegacy")) Module["dynCallLegacy"] = function() { abort("'dynCallLegacy' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; +if (!Object.getOwnPropertyDescriptor(Module, "getDynCaller")) Module["getDynCaller"] = function() { abort("'getDynCaller' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; +if (!Object.getOwnPropertyDescriptor(Module, "dynCall")) Module["dynCall"] = function() { abort("'dynCall' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; +if (!Object.getOwnPropertyDescriptor(Module, "callRuntimeCallbacks")) Module["callRuntimeCallbacks"] = function() { abort("'callRuntimeCallbacks' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; +if (!Object.getOwnPropertyDescriptor(Module, "abortStackOverflow")) Module["abortStackOverflow"] = function() { abort("'abortStackOverflow' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "reallyNegative")) Module["reallyNegative"] = function() { abort("'reallyNegative' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; +if (!Object.getOwnPropertyDescriptor(Module, "unSign")) Module["unSign"] = function() { abort("'unSign' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; +if (!Object.getOwnPropertyDescriptor(Module, "reSign")) Module["reSign"] = function() { abort("'reSign' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "formatString")) Module["formatString"] = function() { abort("'formatString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "PATH")) Module["PATH"] = function() { abort("'PATH' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "PATH_FS")) Module["PATH_FS"] = function() { abort("'PATH_FS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; @@ -6558,11 +6224,16 @@ if (!Object.getOwnPropertyDescriptor(Module, "syscallMmap2")) Module["syscallMma if (!Object.getOwnPropertyDescriptor(Module, "syscallMunmap")) Module["syscallMunmap"] = function() { abort("'syscallMunmap' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "JSEvents")) Module["JSEvents"] = function() { abort("'JSEvents' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "specialHTMLTargets")) Module["specialHTMLTargets"] = function() { abort("'specialHTMLTargets' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; +if (!Object.getOwnPropertyDescriptor(Module, "maybeCStringToJsString")) Module["maybeCStringToJsString"] = function() { abort("'maybeCStringToJsString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; +if (!Object.getOwnPropertyDescriptor(Module, "findEventTarget")) Module["findEventTarget"] = function() { abort("'findEventTarget' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; +if (!Object.getOwnPropertyDescriptor(Module, "findCanvasEventTarget")) Module["findCanvasEventTarget"] = function() { abort("'findCanvasEventTarget' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; +if (!Object.getOwnPropertyDescriptor(Module, "polyfillSetImmediate")) Module["polyfillSetImmediate"] = function() { abort("'polyfillSetImmediate' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "demangle")) Module["demangle"] = function() { abort("'demangle' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "demangleAll")) Module["demangleAll"] = function() { abort("'demangleAll' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "jsStackTrace")) Module["jsStackTrace"] = function() { abort("'jsStackTrace' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "stackTrace")) Module["stackTrace"] = function() { abort("'stackTrace' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "getEnvStrings")) Module["getEnvStrings"] = function() { abort("'getEnvStrings' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; +if (!Object.getOwnPropertyDescriptor(Module, "checkWasiClock")) Module["checkWasiClock"] = function() { abort("'checkWasiClock' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "writeI53ToI64")) Module["writeI53ToI64"] = function() { abort("'writeI53ToI64' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "writeI53ToI64Clamped")) Module["writeI53ToI64Clamped"] = function() { abort("'writeI53ToI64Clamped' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "writeI53ToI64Signaling")) Module["writeI53ToI64Signaling"] = function() { abort("'writeI53ToI64Signaling' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; @@ -6572,17 +6243,34 @@ if (!Object.getOwnPropertyDescriptor(Module, "readI53FromI64")) Module["readI53F if (!Object.getOwnPropertyDescriptor(Module, "readI53FromU64")) Module["readI53FromU64"] = function() { abort("'readI53FromU64' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "convertI32PairToI53")) Module["convertI32PairToI53"] = function() { abort("'convertI32PairToI53' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "convertU32PairToI53")) Module["convertU32PairToI53"] = function() { abort("'convertU32PairToI53' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; +if (!Object.getOwnPropertyDescriptor(Module, "exceptionLast")) Module["exceptionLast"] = function() { abort("'exceptionLast' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; +if (!Object.getOwnPropertyDescriptor(Module, "exceptionCaught")) Module["exceptionCaught"] = function() { abort("'exceptionCaught' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; +if (!Object.getOwnPropertyDescriptor(Module, "exceptionThrowBuf")) Module["exceptionThrowBuf"] = function() { abort("'exceptionThrowBuf' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; +if (!Object.getOwnPropertyDescriptor(Module, "ExceptionInfoAttrs")) Module["ExceptionInfoAttrs"] = function() { abort("'ExceptionInfoAttrs' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; +if (!Object.getOwnPropertyDescriptor(Module, "ExceptionInfo")) Module["ExceptionInfo"] = function() { abort("'ExceptionInfo' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; +if (!Object.getOwnPropertyDescriptor(Module, "CatchInfo")) Module["CatchInfo"] = function() { abort("'CatchInfo' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; +if (!Object.getOwnPropertyDescriptor(Module, "exception_addRef")) Module["exception_addRef"] = function() { abort("'exception_addRef' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; +if (!Object.getOwnPropertyDescriptor(Module, "exception_decRef")) Module["exception_decRef"] = function() { abort("'exception_decRef' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "Browser")) Module["Browser"] = function() { abort("'Browser' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; +if (!Object.getOwnPropertyDescriptor(Module, "funcWrappers")) Module["funcWrappers"] = function() { abort("'funcWrappers' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; +if (!Object.getOwnPropertyDescriptor(Module, "getFuncWrapper")) Module["getFuncWrapper"] = function() { abort("'getFuncWrapper' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; +if (!Object.getOwnPropertyDescriptor(Module, "setMainLoop")) Module["setMainLoop"] = function() { abort("'setMainLoop' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "FS")) Module["FS"] = function() { abort("'FS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "MEMFS")) Module["MEMFS"] = function() { abort("'MEMFS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "TTY")) Module["TTY"] = function() { abort("'TTY' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "PIPEFS")) Module["PIPEFS"] = function() { abort("'PIPEFS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "SOCKFS")) Module["SOCKFS"] = function() { abort("'SOCKFS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; +if (!Object.getOwnPropertyDescriptor(Module, "tempFixedLengthArray")) Module["tempFixedLengthArray"] = function() { abort("'tempFixedLengthArray' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; +if (!Object.getOwnPropertyDescriptor(Module, "miniTempWebGLFloatBuffers")) Module["miniTempWebGLFloatBuffers"] = function() { abort("'miniTempWebGLFloatBuffers' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; +if (!Object.getOwnPropertyDescriptor(Module, "heapObjectForWebGLType")) Module["heapObjectForWebGLType"] = function() { abort("'heapObjectForWebGLType' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; +if (!Object.getOwnPropertyDescriptor(Module, "heapAccessShiftForWebGLHeap")) Module["heapAccessShiftForWebGLHeap"] = function() { abort("'heapAccessShiftForWebGLHeap' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "GL")) Module["GL"] = function() { abort("'GL' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "emscriptenWebGLGet")) Module["emscriptenWebGLGet"] = function() { abort("'emscriptenWebGLGet' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; +if (!Object.getOwnPropertyDescriptor(Module, "computeUnpackAlignedImageSize")) Module["computeUnpackAlignedImageSize"] = function() { abort("'computeUnpackAlignedImageSize' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "emscriptenWebGLGetTexPixelData")) Module["emscriptenWebGLGetTexPixelData"] = function() { abort("'emscriptenWebGLGetTexPixelData' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "emscriptenWebGLGetUniform")) Module["emscriptenWebGLGetUniform"] = function() { abort("'emscriptenWebGLGetUniform' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "emscriptenWebGLGetVertexAttrib")) Module["emscriptenWebGLGetVertexAttrib"] = function() { abort("'emscriptenWebGLGetVertexAttrib' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; +if (!Object.getOwnPropertyDescriptor(Module, "writeGLArray")) Module["writeGLArray"] = function() { abort("'writeGLArray' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "AL")) Module["AL"] = function() { abort("'AL' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "SDL_unicode")) Module["SDL_unicode"] = function() { abort("'SDL_unicode' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "SDL_ttfContext")) Module["SDL_ttfContext"] = function() { abort("'SDL_ttfContext' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; @@ -6702,17 +6390,14 @@ if (!Object.getOwnPropertyDescriptor(Module, "lengthBytesUTF32")) Module["length if (!Object.getOwnPropertyDescriptor(Module, "allocateUTF8")) Module["allocateUTF8"] = function() { abort("'allocateUTF8' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "allocateUTF8OnStack")) Module["allocateUTF8OnStack"] = function() { abort("'allocateUTF8OnStack' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; Module["writeStackCookie"] = writeStackCookie; -Module["checkStackCookie"] = checkStackCookie; -Module["abortStackOverflow"] = abortStackOverflow;if (!Object.getOwnPropertyDescriptor(Module, "ALLOC_NORMAL")) Object.defineProperty(Module, "ALLOC_NORMAL", { configurable: true, get: function() { abort("'ALLOC_NORMAL' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") } }); +Module["checkStackCookie"] = checkStackCookie;if (!Object.getOwnPropertyDescriptor(Module, "ALLOC_NORMAL")) Object.defineProperty(Module, "ALLOC_NORMAL", { configurable: true, get: function() { abort("'ALLOC_NORMAL' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") } }); if (!Object.getOwnPropertyDescriptor(Module, "ALLOC_STACK")) Object.defineProperty(Module, "ALLOC_STACK", { configurable: true, get: function() { abort("'ALLOC_STACK' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") } }); if (!Object.getOwnPropertyDescriptor(Module, "ALLOC_DYNAMIC")) Object.defineProperty(Module, "ALLOC_DYNAMIC", { configurable: true, get: function() { abort("'ALLOC_DYNAMIC' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") } }); if (!Object.getOwnPropertyDescriptor(Module, "ALLOC_NONE")) Object.defineProperty(Module, "ALLOC_NONE", { configurable: true, get: function() { abort("'ALLOC_NONE' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") } }); - var calledRun; - /** * @constructor * @this {ExitStatus} @@ -6749,10 +6434,8 @@ function callMain(args) { } HEAP32[(argv >> 2) + argc] = 0; - try { - Module['___set_stack_limit'](STACK_MAX); var ret = entryFunction(argc, argv); @@ -6892,7 +6575,8 @@ function exit(status, implicit) { if (noExitRuntime) { // if exit() was called, we may warn the user if the runtime isn't actually being shut down if (!implicit) { - err('program exited (with status: ' + status + '), but EXIT_RUNTIME is not set, so halting execution but not exiting the runtime or preventing further async execution (build with EXIT_RUNTIME=1, if you want a true shutdown)'); + var msg = 'program exited (with status: ' + status + '), but EXIT_RUNTIME is not set, so halting execution but not exiting the runtime or preventing further async execution (build with EXIT_RUNTIME=1, if you want a true shutdown)'; + err(msg); } } else { @@ -6928,15 +6612,12 @@ run(); + // {{MODULE_ADDITIONS}} -/** - * @license - * Copyright 2013 The Emscripten Authors - * SPDX-License-Identifier: MIT - */ + if (typeof window === "object" && (typeof ENVIRONMENT_IS_PTHREAD === 'undefined' || !ENVIRONMENT_IS_PTHREAD)) { var emrun_register_handlers = function() { diff --git a/hello.wasm b/hello.wasm index 2822b92a22212914b2ff43a42a195e9d0366ec2d..10d405f7e7ba72a719d63c6733f53f06be8ebcb5 100644 GIT binary patch literal 267602 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∓2-igtoCR|EX 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 K*iV5v6!?EC`6dtm diff --git a/init.js b/init.js index 646b48c..56eee6c 100644 --- a/init.js +++ b/init.js @@ -2,12 +2,12 @@ var itest; function InitWrappers() { // itest = Module.cwrap('itest', 'string'); - itest = (str) => { - const buffer = Module._malloc(str.length + 1) - console.log({buffer}) - Module.stringToUTF8(str, buffer, str.length + 1) - return Module.ccall('itest', 'string', ['number'], [buffer]) - } + // itest = (str) => { + // const buffer = Module._malloc(str.length + 1) + // console.log({buffer}) + // Module.stringToUTF8(str, buffer, str.length + 1) + // return Module.ccall('itest', 'string', ['number'], [buffer]) + // } window.read_str_pass = Module.cwrap('read_str_pass', 'void', ['number']) } diff --git a/main.cpp b/main.cpp index 3891ba3..6b729c8 100644 --- a/main.cpp +++ b/main.cpp @@ -1,28 +1,18 @@ #include #include #include +#include +#include #include "src/class/Element.h" #include "src/proc/string.cpp" -#include "src/class/EventBus.h" #include "src/proc/event.cpp" #include "src/proc/uuid.cpp" extern "C" { - char* itest(); - int str_pass_size(); - void fire_event_bus(int key_pass); -} - -void say_aye() { - printf("Arrgh mates!\n"); -} - -char* itest() { - Element p_tag("#foo"); - p_tag.addEventListener("click", say_aye); - - return "Hi, there"; +//char* itest(); +int str_pass_size(); +void fire_event_bus(int key_pass); } // These are REQUIRED. @@ -34,8 +24,128 @@ void fire_event_bus(int string_pass) { return cjs::event::handle_bus_fire(string_pass); } +class Properties { +private: + std::map _data = {}; + +public: + bool has(std::string key) { + return _data.find(key) != _data.end(); + } + + std::string get(std::string key) { + return _data[key]; + } + + std::string get(std::string key, std::string fallback) { + if ( !has(key) ) return fallback; + return get(key); + } + + Properties* set(std::string key, std::string value) { + _data[key] = value; + return this; + } +}; + +class Component { +protected: + Element* container; + Properties* _properties; + + virtual void mount_child(std::string selector, Component* component) { + Element* tag = container->querySelectChild(selector); + component->set_container(tag); + component->mount(); + delete tag; + } + + virtual std::string tmpl(std::string base) { + return ""; + } + +public: + virtual ~Component() {} + + Component(Element* in_container) { + container = in_container; + _properties = new Properties(); + } + + Component(std::string selector) { + container = new Element(selector); + _properties = new Properties(); + } + + Component() { + container = nullptr; + _properties = new Properties(); + } + + virtual void set_container(Element* element) { + container = element; + } + + virtual void mount() = 0; + + virtual Properties* properties() { + return _properties; + } +}; + +class InputComponent : public Component { +public: + using Component::Component; + + void mount() { + std::stringstream html; + + if ( properties()->has("label") ) { + html << ""; + } + + html << "
get("type", "text") << "\""; + + if ( properties()->get("required", "false") == "true" ) { + html << " required"; + } + + if ( properties()->has("placeholder") ) { + html << " placeholder=\"" << properties()->get("placeholder") << "\""; + } + + html << "/>"; + } +}; + +class GreeterComponent : public Component { +public: + using Component::Component; + + void mount() { + container->setInnerHTML("

Hello, World!

"); + container->append("

This is being rendered via a C++ component!

"); + container->append("
"); + + InputComponent* input = new InputComponent(); + input->properties() + ->set("label", "What is your name?") + ->set("required", "true") + ->set("placeholder", "John Doe"); + + this->mount_child("#input-container", input); + } +}; + int main(int argc, char** argv) { - EM_ASM(InitWrappers()); - printf("C++.js has initialized!\n"); - return 0; + EM_ASM(InitWrappers()); + printf("C++.js has initialized!\n"); + + Element* p_tag = new Element("#container"); + GreeterComponent* cpt = new GreeterComponent(p_tag); + + cpt->mount(); + + delete p_tag; + return 0; } diff --git a/shell_minimal.html b/shell_minimal.html index cc120c2..8e39e79 100644 --- a/shell_minimal.html +++ b/shell_minimal.html @@ -12,7 +12,7 @@ -->

-

Hello, world!

+

{{{ SCRIPT }}} diff --git a/src/class/Component.cpp b/src/class/Component.cpp deleted file mode 100644 index a7c3eb1..0000000 --- a/src/class/Component.cpp +++ /dev/null @@ -1,5 +0,0 @@ -// -// Created by garrettmills on 5/6/20. -// - -#include "Component.h" diff --git a/src/class/Component.h b/src/class/Component.h deleted file mode 100644 index 37b1460..0000000 --- a/src/class/Component.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef CPPJS_COMPONENT_H -#define CPPJS_COMPONENT_H - - -class Component { -private: - -// =================== HTML TEMPLATE =================== // - char* tmpl = R"V0G0N( -

Hello, world!

-

This is a test hello message!

-)V0G0N"; -// ================= / HTML TEMPLATE =================== // - - -}; - - -#endif //CPPJS_COMPONENT_H diff --git a/src/class/Element.cpp b/src/class/Element.cpp index 073f529..59faaf0 100644 --- a/src/class/Element.cpp +++ b/src/class/Element.cpp @@ -4,7 +4,6 @@ #include "../proc/document.cpp" #include "../proc/string.cpp" #include "../proc/uuid.cpp" -#include "../class/EventBus.h" using namespace cjs; @@ -144,18 +143,12 @@ void Element::append(std::string html) { this->setInnerHTML(this->getInnerHTML()+html); } -void Element::addEventListener(std::string dom_event, void(*func)()) { - // Generate the unique function key using the dom_event and uuid - std::string event_key = this->getUUID() + "-" + dom_event; - - // Add the function and the key to the event bus - g_event_bus.addHandler(event_key, func); - - // Add the event bus link to the element's dom event - doc::link_event_bus(dom_event, event_key, this->_selector_ref, this->_selector_nth_elem); -} - void Element::rebase(std::string query_selector, int nth_elem) { this->_selector_ref = query_selector; this->_selector_nth_elem = nth_elem; } + +Element* Element::querySelectChild(std::string selector, int nth_elem) { + std::string scope = "[data-cjs-uuid='" + this->getUUID() + "']"; + return new Element(scope + " " + selector, nth_elem); +} diff --git a/src/class/Element.h b/src/class/Element.h index 32d8253..d536109 100644 --- a/src/class/Element.h +++ b/src/class/Element.h @@ -33,9 +33,11 @@ public: void setData(std::string key, std::string value); void append(std::string html); - void addEventListener(std::string dom_event, void(*func)()); +// void addEventListener(std::string dom_event, void(*func)()); void rebase(std::string query_selector, int nth_elem = 0); + + Element* querySelectChild(std::string selector, int nth_elem = 0); }; #include "Element.cpp" diff --git a/src/class/EventBus.cpp b/src/class/EventBus.cpp deleted file mode 100644 index 4579fc4..0000000 --- a/src/class/EventBus.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "EventBus.h" - -void EventBus::addHandler(std::string key, void (*func)()) { - // If the bus already has this key, add a handler - auto search = this->_bus.find(key); - if ( search != this->_bus.end() ) { - std::vector func_arr = this->_bus[key]; - func_arr.push_back(func); - this->_bus[key] = func_arr; - } else { - std::vector func_arr; - func_arr.push_back(func); - this->_bus[key] = func_arr; - } -} - -void EventBus::fire(std::string key) { - auto search = this->_bus.find(key); - if ( search != this->_bus.end() ) { - std::vector func_arr = this->_bus[key]; - for ( void(*func)() : func_arr ) { - (*func)(); - } - } -} diff --git a/src/class/EventBus.h b/src/class/EventBus.h deleted file mode 100644 index 3034bd9..0000000 --- a/src/class/EventBus.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef CPPJS_EVENTBUS_H -#define CPPJS_EVENTBUS_H - -#include -#include - -class EventBus { -private: - std::map> _bus; - -public: - void addHandler(std::string key, void (*func)()); - void fire(std::string key); -}; - -extern EventBus g_event_bus; -EventBus g_event_bus; - -#include "EventBus.cpp" - -#endif //CPPJS_EVENTBUS_H diff --git a/src/include/rapidjson/allocators.h b/src/include/rapidjson/allocators.h new file mode 100755 index 0000000..cc67c89 --- /dev/null +++ b/src/include/rapidjson/allocators.h @@ -0,0 +1,284 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_ALLOCATORS_H_ +#define RAPIDJSON_ALLOCATORS_H_ + +#include "rapidjson.h" + +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// Allocator + +/*! \class rapidjson::Allocator + \brief Concept for allocating, resizing and freeing memory block. + + Note that Malloc() and Realloc() are non-static but Free() is static. + + So if an allocator need to support Free(), it needs to put its pointer in + the header of memory block. + +\code +concept Allocator { + static const bool kNeedFree; //!< Whether this allocator needs to call Free(). + + // Allocate a memory block. + // \param size of the memory block in bytes. + // \returns pointer to the memory block. + void* Malloc(size_t size); + + // Resize a memory block. + // \param originalPtr The pointer to current memory block. Null pointer is permitted. + // \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.) + // \param newSize the new size in bytes. + void* Realloc(void* originalPtr, size_t originalSize, size_t newSize); + + // Free a memory block. + // \param pointer to the memory block. Null pointer is permitted. + static void Free(void *ptr); +}; +\endcode +*/ + + +/*! \def RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY + \ingroup RAPIDJSON_CONFIG + \brief User-defined kDefaultChunkCapacity definition. + + User can define this as any \c size that is a power of 2. +*/ + +#ifndef RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY +#define RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY (64 * 1024) +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// CrtAllocator + +//! C-runtime library allocator. +/*! This class is just wrapper for standard C library memory routines. + \note implements Allocator concept +*/ +class CrtAllocator { +public: + static const bool kNeedFree = true; + void* Malloc(size_t size) { + if (size) // behavior of malloc(0) is implementation defined. + return std::malloc(size); + else + return NULL; // standardize to returning NULL. + } + void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { + (void)originalSize; + if (newSize == 0) { + std::free(originalPtr); + return NULL; + } + return std::realloc(originalPtr, newSize); + } + static void Free(void *ptr) { std::free(ptr); } +}; + +/////////////////////////////////////////////////////////////////////////////// +// MemoryPoolAllocator + +//! Default memory allocator used by the parser and DOM. +/*! This allocator allocate memory blocks from pre-allocated memory chunks. + + It does not free memory blocks. And Realloc() only allocate new memory. + + The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default. + + User may also supply a buffer as the first chunk. + + If the user-buffer is full then additional chunks are allocated by BaseAllocator. + + The user-buffer is not deallocated by this allocator. + + \tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator. + \note implements Allocator concept +*/ +template +class MemoryPoolAllocator { +public: + static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator) + + //! Constructor with chunkSize. + /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. + \param baseAllocator The allocator for allocating memory chunks. + */ + MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : + chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0) + { + } + + //! Constructor with user-supplied buffer. + /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size. + + The user buffer will not be deallocated when this allocator is destructed. + + \param buffer User supplied buffer. + \param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader). + \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. + \param baseAllocator The allocator for allocating memory chunks. + */ + MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : + chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0) + { + RAPIDJSON_ASSERT(buffer != 0); + RAPIDJSON_ASSERT(size > sizeof(ChunkHeader)); + chunkHead_ = reinterpret_cast(buffer); + chunkHead_->capacity = size - sizeof(ChunkHeader); + chunkHead_->size = 0; + chunkHead_->next = 0; + } + + //! Destructor. + /*! This deallocates all memory chunks, excluding the user-supplied buffer. + */ + ~MemoryPoolAllocator() { + Clear(); + RAPIDJSON_DELETE(ownBaseAllocator_); + } + + //! Deallocates all memory chunks, excluding the user-supplied buffer. + void Clear() { + while (chunkHead_ && chunkHead_ != userBuffer_) { + ChunkHeader* next = chunkHead_->next; + baseAllocator_->Free(chunkHead_); + chunkHead_ = next; + } + if (chunkHead_ && chunkHead_ == userBuffer_) + chunkHead_->size = 0; // Clear user buffer + } + + //! Computes the total capacity of allocated memory chunks. + /*! \return total capacity in bytes. + */ + size_t Capacity() const { + size_t capacity = 0; + for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) + capacity += c->capacity; + return capacity; + } + + //! Computes the memory blocks allocated. + /*! \return total used bytes. + */ + size_t Size() const { + size_t size = 0; + for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) + size += c->size; + return size; + } + + //! Allocates a memory block. (concept Allocator) + void* Malloc(size_t size) { + if (!size) + return NULL; + + size = RAPIDJSON_ALIGN(size); + if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity) + if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size)) + return NULL; + + void *buffer = reinterpret_cast(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size; + chunkHead_->size += size; + return buffer; + } + + //! Resizes a memory block (concept Allocator) + void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { + if (originalPtr == 0) + return Malloc(newSize); + + if (newSize == 0) + return NULL; + + originalSize = RAPIDJSON_ALIGN(originalSize); + newSize = RAPIDJSON_ALIGN(newSize); + + // Do not shrink if new size is smaller than original + if (originalSize >= newSize) + return originalPtr; + + // Simply expand it if it is the last allocation and there is sufficient space + if (originalPtr == reinterpret_cast(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) { + size_t increment = static_cast(newSize - originalSize); + if (chunkHead_->size + increment <= chunkHead_->capacity) { + chunkHead_->size += increment; + return originalPtr; + } + } + + // Realloc process: allocate and copy memory, do not free original buffer. + if (void* newBuffer = Malloc(newSize)) { + if (originalSize) + std::memcpy(newBuffer, originalPtr, originalSize); + return newBuffer; + } + else + return NULL; + } + + //! Frees a memory block (concept Allocator) + static void Free(void *ptr) { (void)ptr; } // Do nothing + +private: + //! Copy constructor is not permitted. + MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */; + //! Copy assignment operator is not permitted. + MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */; + + //! Creates a new chunk. + /*! \param capacity Capacity of the chunk in bytes. + \return true if success. + */ + bool AddChunk(size_t capacity) { + if (!baseAllocator_) + ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator)(); + if (ChunkHeader* chunk = reinterpret_cast(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) { + chunk->capacity = capacity; + chunk->size = 0; + chunk->next = chunkHead_; + chunkHead_ = chunk; + return true; + } + else + return false; + } + + static const int kDefaultChunkCapacity = RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY; //!< Default chunk capacity. + + //! Chunk header for perpending to each chunk. + /*! Chunks are stored as a singly linked list. + */ + struct ChunkHeader { + size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself). + size_t size; //!< Current size of allocated memory in bytes. + ChunkHeader *next; //!< Next chunk in the linked list. + }; + + ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation. + size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated. + void *userBuffer_; //!< User supplied buffer. + BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks. + BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object. +}; + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_ENCODINGS_H_ diff --git a/src/include/rapidjson/cursorstreamwrapper.h b/src/include/rapidjson/cursorstreamwrapper.h new file mode 100755 index 0000000..52c11a7 --- /dev/null +++ b/src/include/rapidjson/cursorstreamwrapper.h @@ -0,0 +1,78 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_CURSORSTREAMWRAPPER_H_ +#define RAPIDJSON_CURSORSTREAMWRAPPER_H_ + +#include "stream.h" + +#if defined(__GNUC__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#endif + +#if defined(_MSC_VER) && _MSC_VER <= 1800 +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4702) // unreachable code +RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated +#endif + +RAPIDJSON_NAMESPACE_BEGIN + + +//! Cursor stream wrapper for counting line and column number if error exists. +/*! + \tparam InputStream Any stream that implements Stream Concept +*/ +template > +class CursorStreamWrapper : public GenericStreamWrapper { +public: + typedef typename Encoding::Ch Ch; + + CursorStreamWrapper(InputStream& is): + GenericStreamWrapper(is), line_(1), col_(0) {} + + // counting line and column number + Ch Take() { + Ch ch = this->is_.Take(); + if(ch == '\n') { + line_ ++; + col_ = 0; + } else { + col_ ++; + } + return ch; + } + + //! Get the error line number, if error exists. + size_t GetLine() const { return line_; } + //! Get the error column number, if error exists. + size_t GetColumn() const { return col_; } + +private: + size_t line_; //!< Current Line + size_t col_; //!< Current Column +}; + +#if defined(_MSC_VER) && _MSC_VER <= 1800 +RAPIDJSON_DIAG_POP +#endif + +#if defined(__GNUC__) +RAPIDJSON_DIAG_POP +#endif + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_CURSORSTREAMWRAPPER_H_ diff --git a/src/include/rapidjson/document.h b/src/include/rapidjson/document.h new file mode 100755 index 0000000..68aaae7 --- /dev/null +++ b/src/include/rapidjson/document.h @@ -0,0 +1,2732 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_DOCUMENT_H_ +#define RAPIDJSON_DOCUMENT_H_ + +/*! \file document.h */ + +#include "reader.h" +#include "internal/meta.h" +#include "internal/strfunc.h" +#include "memorystream.h" +#include "encodedstream.h" +#include // placement new +#include +#ifdef __cpp_lib_three_way_comparison +#include +#endif + +RAPIDJSON_DIAG_PUSH +#ifdef __clang__ +RAPIDJSON_DIAG_OFF(padded) +RAPIDJSON_DIAG_OFF(switch-enum) +RAPIDJSON_DIAG_OFF(c++98-compat) +#elif defined(_MSC_VER) +RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant +RAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible loss of data +#endif + +#ifdef __GNUC__ +RAPIDJSON_DIAG_OFF(effc++) +#endif // __GNUC__ + +#ifndef RAPIDJSON_NOMEMBERITERATORCLASS +#include // std::random_access_iterator_tag +#endif + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS +#include // std::move +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +// Forward declaration. +template +class GenericValue; + +template +class GenericDocument; + +/*! \def RAPIDJSON_DEFAULT_ALLOCATOR + \ingroup RAPIDJSON_CONFIG + \brief Allows to choose default allocator. + + User can define this to use CrtAllocator or MemoryPoolAllocator. +*/ +#ifndef RAPIDJSON_DEFAULT_ALLOCATOR +#define RAPIDJSON_DEFAULT_ALLOCATOR MemoryPoolAllocator +#endif + +/*! \def RAPIDJSON_DEFAULT_STACK_ALLOCATOR + \ingroup RAPIDJSON_CONFIG + \brief Allows to choose default stack allocator for Document. + + User can define this to use CrtAllocator or MemoryPoolAllocator. +*/ +#ifndef RAPIDJSON_DEFAULT_STACK_ALLOCATOR +#define RAPIDJSON_DEFAULT_STACK_ALLOCATOR CrtAllocator +#endif + +/*! \def RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY + \ingroup RAPIDJSON_CONFIG + \brief User defined kDefaultObjectCapacity value. + + User can define this as any natural number. +*/ +#ifndef RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY +// number of objects that rapidjson::Value allocates memory for by default +#define RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY 16 +#endif + +/*! \def RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY + \ingroup RAPIDJSON_CONFIG + \brief User defined kDefaultArrayCapacity value. + + User can define this as any natural number. +*/ +#ifndef RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY +// number of array elements that rapidjson::Value allocates memory for by default +#define RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY 16 +#endif + +//! Name-value pair in a JSON object value. +/*! + This class was internal to GenericValue. It used to be a inner struct. + But a compiler (IBM XL C/C++ for AIX) have reported to have problem with that so it moved as a namespace scope struct. + https://code.google.com/p/rapidjson/issues/detail?id=64 +*/ +template +class GenericMember { +public: + GenericValue name; //!< name of member (must be a string) + GenericValue value; //!< value of member. + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + //! Move constructor in C++11 + GenericMember(GenericMember&& rhs) RAPIDJSON_NOEXCEPT + : name(std::move(rhs.name)), + value(std::move(rhs.value)) + { + } + + //! Move assignment in C++11 + GenericMember& operator=(GenericMember&& rhs) RAPIDJSON_NOEXCEPT { + return *this = static_cast(rhs); + } +#endif + + //! Assignment with move semantics. + /*! \param rhs Source of the assignment. Its name and value will become a null value after assignment. + */ + GenericMember& operator=(GenericMember& rhs) RAPIDJSON_NOEXCEPT { + if (RAPIDJSON_LIKELY(this != &rhs)) { + name = rhs.name; + value = rhs.value; + } + return *this; + } + + // swap() for std::sort() and other potential use in STL. + friend inline void swap(GenericMember& a, GenericMember& b) RAPIDJSON_NOEXCEPT { + a.name.Swap(b.name); + a.value.Swap(b.value); + } + +private: + //! Copy constructor is not permitted. + GenericMember(const GenericMember& rhs); +}; + +/////////////////////////////////////////////////////////////////////////////// +// GenericMemberIterator + +#ifndef RAPIDJSON_NOMEMBERITERATORCLASS + +//! (Constant) member iterator for a JSON object value +/*! + \tparam Const Is this a constant iterator? + \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document) + \tparam Allocator Allocator type for allocating memory of object, array and string. + + This class implements a Random Access Iterator for GenericMember elements + of a GenericValue, see ISO/IEC 14882:2003(E) C++ standard, 24.1 [lib.iterator.requirements]. + + \note This iterator implementation is mainly intended to avoid implicit + conversions from iterator values to \c NULL, + e.g. from GenericValue::FindMember. + + \note Define \c RAPIDJSON_NOMEMBERITERATORCLASS to fall back to a + pointer-based implementation, if your platform doesn't provide + the C++ header. + + \see GenericMember, GenericValue::MemberIterator, GenericValue::ConstMemberIterator + */ +template +class GenericMemberIterator { + + friend class GenericValue; + template friend class GenericMemberIterator; + + typedef GenericMember PlainType; + typedef typename internal::MaybeAddConst::Type ValueType; + +public: + //! Iterator type itself + typedef GenericMemberIterator Iterator; + //! Constant iterator type + typedef GenericMemberIterator ConstIterator; + //! Non-constant iterator type + typedef GenericMemberIterator NonConstIterator; + + /** \name std::iterator_traits support */ + //@{ + typedef ValueType value_type; + typedef ValueType * pointer; + typedef ValueType & reference; + typedef std::ptrdiff_t difference_type; + typedef std::random_access_iterator_tag iterator_category; + //@} + + //! Pointer to (const) GenericMember + typedef pointer Pointer; + //! Reference to (const) GenericMember + typedef reference Reference; + //! Signed integer type (e.g. \c ptrdiff_t) + typedef difference_type DifferenceType; + + //! Default constructor (singular value) + /*! Creates an iterator pointing to no element. + \note All operations, except for comparisons, are undefined on such values. + */ + GenericMemberIterator() : ptr_() {} + + //! Iterator conversions to more const + /*! + \param it (Non-const) iterator to copy from + + Allows the creation of an iterator from another GenericMemberIterator + that is "less const". Especially, creating a non-constant iterator + from a constant iterator are disabled: + \li const -> non-const (not ok) + \li const -> const (ok) + \li non-const -> const (ok) + \li non-const -> non-const (ok) + + \note If the \c Const template parameter is already \c false, this + constructor effectively defines a regular copy-constructor. + Otherwise, the copy constructor is implicitly defined. + */ + GenericMemberIterator(const NonConstIterator & it) : ptr_(it.ptr_) {} + Iterator& operator=(const NonConstIterator & it) { ptr_ = it.ptr_; return *this; } + + //! @name stepping + //@{ + Iterator& operator++(){ ++ptr_; return *this; } + Iterator& operator--(){ --ptr_; return *this; } + Iterator operator++(int){ Iterator old(*this); ++ptr_; return old; } + Iterator operator--(int){ Iterator old(*this); --ptr_; return old; } + //@} + + //! @name increment/decrement + //@{ + Iterator operator+(DifferenceType n) const { return Iterator(ptr_+n); } + Iterator operator-(DifferenceType n) const { return Iterator(ptr_-n); } + + Iterator& operator+=(DifferenceType n) { ptr_+=n; return *this; } + Iterator& operator-=(DifferenceType n) { ptr_-=n; return *this; } + //@} + + //! @name relations + //@{ + template bool operator==(const GenericMemberIterator& that) const { return ptr_ == that.ptr_; } + template bool operator!=(const GenericMemberIterator& that) const { return ptr_ != that.ptr_; } + template bool operator<=(const GenericMemberIterator& that) const { return ptr_ <= that.ptr_; } + template bool operator>=(const GenericMemberIterator& that) const { return ptr_ >= that.ptr_; } + template bool operator< (const GenericMemberIterator& that) const { return ptr_ < that.ptr_; } + template bool operator> (const GenericMemberIterator& that) const { return ptr_ > that.ptr_; } + +#ifdef __cpp_lib_three_way_comparison + template std::strong_ordering operator<=>(const GenericMemberIterator& that) const { return ptr_ <=> that.ptr_; } +#endif + //@} + + //! @name dereference + //@{ + Reference operator*() const { return *ptr_; } + Pointer operator->() const { return ptr_; } + Reference operator[](DifferenceType n) const { return ptr_[n]; } + //@} + + //! Distance + DifferenceType operator-(ConstIterator that) const { return ptr_-that.ptr_; } + +private: + //! Internal constructor from plain pointer + explicit GenericMemberIterator(Pointer p) : ptr_(p) {} + + Pointer ptr_; //!< raw pointer +}; + +#else // RAPIDJSON_NOMEMBERITERATORCLASS + +// class-based member iterator implementation disabled, use plain pointers + +template +class GenericMemberIterator; + +//! non-const GenericMemberIterator +template +class GenericMemberIterator { + //! use plain pointer as iterator type + typedef GenericMember* Iterator; +}; +//! const GenericMemberIterator +template +class GenericMemberIterator { + //! use plain const pointer as iterator type + typedef const GenericMember* Iterator; +}; + +#endif // RAPIDJSON_NOMEMBERITERATORCLASS + +/////////////////////////////////////////////////////////////////////////////// +// GenericStringRef + +//! Reference to a constant string (not taking a copy) +/*! + \tparam CharType character type of the string + + This helper class is used to automatically infer constant string + references for string literals, especially from \c const \b (!) + character arrays. + + The main use is for creating JSON string values without copying the + source string via an \ref Allocator. This requires that the referenced + string pointers have a sufficient lifetime, which exceeds the lifetime + of the associated GenericValue. + + \b Example + \code + Value v("foo"); // ok, no need to copy & calculate length + const char foo[] = "foo"; + v.SetString(foo); // ok + + const char* bar = foo; + // Value x(bar); // not ok, can't rely on bar's lifetime + Value x(StringRef(bar)); // lifetime explicitly guaranteed by user + Value y(StringRef(bar, 3)); // ok, explicitly pass length + \endcode + + \see StringRef, GenericValue::SetString +*/ +template +struct GenericStringRef { + typedef CharType Ch; //!< character type of the string + + //! Create string reference from \c const character array +#ifndef __clang__ // -Wdocumentation + /*! + This constructor implicitly creates a constant string reference from + a \c const character array. It has better performance than + \ref StringRef(const CharType*) by inferring the string \ref length + from the array length, and also supports strings containing null + characters. + + \tparam N length of the string, automatically inferred + + \param str Constant character array, lifetime assumed to be longer + than the use of the string in e.g. a GenericValue + + \post \ref s == str + + \note Constant complexity. + \note There is a hidden, private overload to disallow references to + non-const character arrays to be created via this constructor. + By this, e.g. function-scope arrays used to be filled via + \c snprintf are excluded from consideration. + In such cases, the referenced string should be \b copied to the + GenericValue instead. + */ +#endif + template + GenericStringRef(const CharType (&str)[N]) RAPIDJSON_NOEXCEPT + : s(str), length(N-1) {} + + //! Explicitly create string reference from \c const character pointer +#ifndef __clang__ // -Wdocumentation + /*! + This constructor can be used to \b explicitly create a reference to + a constant string pointer. + + \see StringRef(const CharType*) + + \param str Constant character pointer, lifetime assumed to be longer + than the use of the string in e.g. a GenericValue + + \post \ref s == str + + \note There is a hidden, private overload to disallow references to + non-const character arrays to be created via this constructor. + By this, e.g. function-scope arrays used to be filled via + \c snprintf are excluded from consideration. + In such cases, the referenced string should be \b copied to the + GenericValue instead. + */ +#endif + explicit GenericStringRef(const CharType* str) + : s(str), length(NotNullStrLen(str)) {} + + //! Create constant string reference from pointer and length +#ifndef __clang__ // -Wdocumentation + /*! \param str constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue + \param len length of the string, excluding the trailing NULL terminator + + \post \ref s == str && \ref length == len + \note Constant complexity. + */ +#endif + GenericStringRef(const CharType* str, SizeType len) + : s(RAPIDJSON_LIKELY(str) ? str : emptyString), length(len) { RAPIDJSON_ASSERT(str != 0 || len == 0u); } + + GenericStringRef(const GenericStringRef& rhs) : s(rhs.s), length(rhs.length) {} + + //! implicit conversion to plain CharType pointer + operator const Ch *() const { return s; } + + const Ch* const s; //!< plain CharType pointer + const SizeType length; //!< length of the string (excluding the trailing NULL terminator) + +private: + SizeType NotNullStrLen(const CharType* str) { + RAPIDJSON_ASSERT(str != 0); + return internal::StrLen(str); + } + + /// Empty string - used when passing in a NULL pointer + static const Ch emptyString[]; + + //! Disallow construction from non-const array + template + GenericStringRef(CharType (&str)[N]) /* = delete */; + //! Copy assignment operator not permitted - immutable type + GenericStringRef& operator=(const GenericStringRef& rhs) /* = delete */; +}; + +template +const CharType GenericStringRef::emptyString[] = { CharType() }; + +//! Mark a character pointer as constant string +/*! Mark a plain character pointer as a "string literal". This function + can be used to avoid copying a character string to be referenced as a + value in a JSON GenericValue object, if the string's lifetime is known + to be valid long enough. + \tparam CharType Character type of the string + \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue + \return GenericStringRef string reference object + \relatesalso GenericStringRef + + \see GenericValue::GenericValue(StringRefType), GenericValue::operator=(StringRefType), GenericValue::SetString(StringRefType), GenericValue::PushBack(StringRefType, Allocator&), GenericValue::AddMember +*/ +template +inline GenericStringRef StringRef(const CharType* str) { + return GenericStringRef(str); +} + +//! Mark a character pointer as constant string +/*! Mark a plain character pointer as a "string literal". This function + can be used to avoid copying a character string to be referenced as a + value in a JSON GenericValue object, if the string's lifetime is known + to be valid long enough. + + This version has better performance with supplied length, and also + supports string containing null characters. + + \tparam CharType character type of the string + \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue + \param length The length of source string. + \return GenericStringRef string reference object + \relatesalso GenericStringRef +*/ +template +inline GenericStringRef StringRef(const CharType* str, size_t length) { + return GenericStringRef(str, SizeType(length)); +} + +#if RAPIDJSON_HAS_STDSTRING +//! Mark a string object as constant string +/*! Mark a string object (e.g. \c std::string) as a "string literal". + This function can be used to avoid copying a string to be referenced as a + value in a JSON GenericValue object, if the string's lifetime is known + to be valid long enough. + + \tparam CharType character type of the string + \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue + \return GenericStringRef string reference object + \relatesalso GenericStringRef + \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. +*/ +template +inline GenericStringRef StringRef(const std::basic_string& str) { + return GenericStringRef(str.data(), SizeType(str.size())); +} +#endif + +/////////////////////////////////////////////////////////////////////////////// +// GenericValue type traits +namespace internal { + +template +struct IsGenericValueImpl : FalseType {}; + +// select candidates according to nested encoding and allocator types +template struct IsGenericValueImpl::Type, typename Void::Type> + : IsBaseOf, T>::Type {}; + +// helper to match arbitrary GenericValue instantiations, including derived classes +template struct IsGenericValue : IsGenericValueImpl::Type {}; + +} // namespace internal + +/////////////////////////////////////////////////////////////////////////////// +// TypeHelper + +namespace internal { + +template +struct TypeHelper {}; + +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsBool(); } + static bool Get(const ValueType& v) { return v.GetBool(); } + static ValueType& Set(ValueType& v, bool data) { return v.SetBool(data); } + static ValueType& Set(ValueType& v, bool data, typename ValueType::AllocatorType&) { return v.SetBool(data); } +}; + +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsInt(); } + static int Get(const ValueType& v) { return v.GetInt(); } + static ValueType& Set(ValueType& v, int data) { return v.SetInt(data); } + static ValueType& Set(ValueType& v, int data, typename ValueType::AllocatorType&) { return v.SetInt(data); } +}; + +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsUint(); } + static unsigned Get(const ValueType& v) { return v.GetUint(); } + static ValueType& Set(ValueType& v, unsigned data) { return v.SetUint(data); } + static ValueType& Set(ValueType& v, unsigned data, typename ValueType::AllocatorType&) { return v.SetUint(data); } +}; + +#ifdef _MSC_VER +RAPIDJSON_STATIC_ASSERT(sizeof(long) == sizeof(int)); +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsInt(); } + static long Get(const ValueType& v) { return v.GetInt(); } + static ValueType& Set(ValueType& v, long data) { return v.SetInt(data); } + static ValueType& Set(ValueType& v, long data, typename ValueType::AllocatorType&) { return v.SetInt(data); } +}; + +RAPIDJSON_STATIC_ASSERT(sizeof(unsigned long) == sizeof(unsigned)); +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsUint(); } + static unsigned long Get(const ValueType& v) { return v.GetUint(); } + static ValueType& Set(ValueType& v, unsigned long data) { return v.SetUint(data); } + static ValueType& Set(ValueType& v, unsigned long data, typename ValueType::AllocatorType&) { return v.SetUint(data); } +}; +#endif + +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsInt64(); } + static int64_t Get(const ValueType& v) { return v.GetInt64(); } + static ValueType& Set(ValueType& v, int64_t data) { return v.SetInt64(data); } + static ValueType& Set(ValueType& v, int64_t data, typename ValueType::AllocatorType&) { return v.SetInt64(data); } +}; + +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsUint64(); } + static uint64_t Get(const ValueType& v) { return v.GetUint64(); } + static ValueType& Set(ValueType& v, uint64_t data) { return v.SetUint64(data); } + static ValueType& Set(ValueType& v, uint64_t data, typename ValueType::AllocatorType&) { return v.SetUint64(data); } +}; + +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsDouble(); } + static double Get(const ValueType& v) { return v.GetDouble(); } + static ValueType& Set(ValueType& v, double data) { return v.SetDouble(data); } + static ValueType& Set(ValueType& v, double data, typename ValueType::AllocatorType&) { return v.SetDouble(data); } +}; + +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsFloat(); } + static float Get(const ValueType& v) { return v.GetFloat(); } + static ValueType& Set(ValueType& v, float data) { return v.SetFloat(data); } + static ValueType& Set(ValueType& v, float data, typename ValueType::AllocatorType&) { return v.SetFloat(data); } +}; + +template +struct TypeHelper { + typedef const typename ValueType::Ch* StringType; + static bool Is(const ValueType& v) { return v.IsString(); } + static StringType Get(const ValueType& v) { return v.GetString(); } + static ValueType& Set(ValueType& v, const StringType data) { return v.SetString(typename ValueType::StringRefType(data)); } + static ValueType& Set(ValueType& v, const StringType data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); } +}; + +#if RAPIDJSON_HAS_STDSTRING +template +struct TypeHelper > { + typedef std::basic_string StringType; + static bool Is(const ValueType& v) { return v.IsString(); } + static StringType Get(const ValueType& v) { return StringType(v.GetString(), v.GetStringLength()); } + static ValueType& Set(ValueType& v, const StringType& data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); } +}; +#endif + +template +struct TypeHelper { + typedef typename ValueType::Array ArrayType; + static bool Is(const ValueType& v) { return v.IsArray(); } + static ArrayType Get(ValueType& v) { return v.GetArray(); } + static ValueType& Set(ValueType& v, ArrayType data) { return v = data; } + static ValueType& Set(ValueType& v, ArrayType data, typename ValueType::AllocatorType&) { return v = data; } +}; + +template +struct TypeHelper { + typedef typename ValueType::ConstArray ArrayType; + static bool Is(const ValueType& v) { return v.IsArray(); } + static ArrayType Get(const ValueType& v) { return v.GetArray(); } +}; + +template +struct TypeHelper { + typedef typename ValueType::Object ObjectType; + static bool Is(const ValueType& v) { return v.IsObject(); } + static ObjectType Get(ValueType& v) { return v.GetObject(); } + static ValueType& Set(ValueType& v, ObjectType data) { return v = data; } + static ValueType& Set(ValueType& v, ObjectType data, typename ValueType::AllocatorType&) { return v = data; } +}; + +template +struct TypeHelper { + typedef typename ValueType::ConstObject ObjectType; + static bool Is(const ValueType& v) { return v.IsObject(); } + static ObjectType Get(const ValueType& v) { return v.GetObject(); } +}; + +} // namespace internal + +// Forward declarations +template class GenericArray; +template class GenericObject; + +/////////////////////////////////////////////////////////////////////////////// +// GenericValue + +//! Represents a JSON value. Use Value for UTF8 encoding and default allocator. +/*! + A JSON value can be one of 7 types. This class is a variant type supporting + these types. + + Use the Value if UTF8 and default allocator + + \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document) + \tparam Allocator Allocator type for allocating memory of object, array and string. +*/ +template +class GenericValue { +public: + //! Name-value pair in an object. + typedef GenericMember Member; + typedef Encoding EncodingType; //!< Encoding type from template parameter. + typedef Allocator AllocatorType; //!< Allocator type from template parameter. + typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. + typedef GenericStringRef StringRefType; //!< Reference to a constant string + typedef typename GenericMemberIterator::Iterator MemberIterator; //!< Member iterator for iterating in object. + typedef typename GenericMemberIterator::Iterator ConstMemberIterator; //!< Constant member iterator for iterating in object. + typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array. + typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array. + typedef GenericValue ValueType; //!< Value type of itself. + typedef GenericArray Array; + typedef GenericArray ConstArray; + typedef GenericObject Object; + typedef GenericObject ConstObject; + + //!@name Constructors and destructor. + //@{ + + //! Default constructor creates a null value. + GenericValue() RAPIDJSON_NOEXCEPT : data_() { data_.f.flags = kNullFlag; } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + //! Move constructor in C++11 + GenericValue(GenericValue&& rhs) RAPIDJSON_NOEXCEPT : data_(rhs.data_) { + rhs.data_.f.flags = kNullFlag; // give up contents + } +#endif + +private: + //! Copy constructor is not permitted. + GenericValue(const GenericValue& rhs); + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + //! Moving from a GenericDocument is not permitted. + template + GenericValue(GenericDocument&& rhs); + + //! Move assignment from a GenericDocument is not permitted. + template + GenericValue& operator=(GenericDocument&& rhs); +#endif + +public: + + //! Constructor with JSON value type. + /*! This creates a Value of specified type with default content. + \param type Type of the value. + \note Default content for number is zero. + */ + explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_() { + static const uint16_t defaultFlags[] = { + kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag, + kNumberAnyFlag + }; + RAPIDJSON_NOEXCEPT_ASSERT(type >= kNullType && type <= kNumberType); + data_.f.flags = defaultFlags[type]; + + // Use ShortString to store empty string. + if (type == kStringType) + data_.ss.SetLength(0); + } + + //! Explicit copy constructor (with allocator) + /*! Creates a copy of a Value by using the given Allocator + \tparam SourceAllocator allocator of \c rhs + \param rhs Value to copy from (read-only) + \param allocator Allocator for allocating copied elements and buffers. Commonly use GenericDocument::GetAllocator(). + \param copyConstStrings Force copying of constant strings (e.g. referencing an in-situ buffer) + \see CopyFrom() + */ + template + GenericValue(const GenericValue& rhs, Allocator& allocator, bool copyConstStrings = false) { + switch (rhs.GetType()) { + case kObjectType: { + SizeType count = rhs.data_.o.size; + Member* lm = reinterpret_cast(allocator.Malloc(count * sizeof(Member))); + const typename GenericValue::Member* rm = rhs.GetMembersPointer(); + for (SizeType i = 0; i < count; i++) { + new (&lm[i].name) GenericValue(rm[i].name, allocator, copyConstStrings); + new (&lm[i].value) GenericValue(rm[i].value, allocator, copyConstStrings); + } + data_.f.flags = kObjectFlag; + data_.o.size = data_.o.capacity = count; + SetMembersPointer(lm); + } + break; + case kArrayType: { + SizeType count = rhs.data_.a.size; + GenericValue* le = reinterpret_cast(allocator.Malloc(count * sizeof(GenericValue))); + const GenericValue* re = rhs.GetElementsPointer(); + for (SizeType i = 0; i < count; i++) + new (&le[i]) GenericValue(re[i], allocator, copyConstStrings); + data_.f.flags = kArrayFlag; + data_.a.size = data_.a.capacity = count; + SetElementsPointer(le); + } + break; + case kStringType: + if (rhs.data_.f.flags == kConstStringFlag && !copyConstStrings) { + data_.f.flags = rhs.data_.f.flags; + data_ = *reinterpret_cast(&rhs.data_); + } + else + SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator); + break; + default: + data_.f.flags = rhs.data_.f.flags; + data_ = *reinterpret_cast(&rhs.data_); + break; + } + } + + //! Constructor for boolean value. + /*! \param b Boolean value + \note This constructor is limited to \em real boolean values and rejects + implicitly converted types like arbitrary pointers. Use an explicit cast + to \c bool, if you want to construct a boolean JSON value in such cases. + */ +#ifndef RAPIDJSON_DOXYGEN_RUNNING // hide SFINAE from Doxygen + template + explicit GenericValue(T b, RAPIDJSON_ENABLEIF((internal::IsSame))) RAPIDJSON_NOEXCEPT // See #472 +#else + explicit GenericValue(bool b) RAPIDJSON_NOEXCEPT +#endif + : data_() { + // safe-guard against failing SFINAE + RAPIDJSON_STATIC_ASSERT((internal::IsSame::Value)); + data_.f.flags = b ? kTrueFlag : kFalseFlag; + } + + //! Constructor for int value. + explicit GenericValue(int i) RAPIDJSON_NOEXCEPT : data_() { + data_.n.i64 = i; + data_.f.flags = (i >= 0) ? (kNumberIntFlag | kUintFlag | kUint64Flag) : kNumberIntFlag; + } + + //! Constructor for unsigned value. + explicit GenericValue(unsigned u) RAPIDJSON_NOEXCEPT : data_() { + data_.n.u64 = u; + data_.f.flags = (u & 0x80000000) ? kNumberUintFlag : (kNumberUintFlag | kIntFlag | kInt64Flag); + } + + //! Constructor for int64_t value. + explicit GenericValue(int64_t i64) RAPIDJSON_NOEXCEPT : data_() { + data_.n.i64 = i64; + data_.f.flags = kNumberInt64Flag; + if (i64 >= 0) { + data_.f.flags |= kNumberUint64Flag; + if (!(static_cast(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) + data_.f.flags |= kUintFlag; + if (!(static_cast(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) + data_.f.flags |= kIntFlag; + } + else if (i64 >= static_cast(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) + data_.f.flags |= kIntFlag; + } + + //! Constructor for uint64_t value. + explicit GenericValue(uint64_t u64) RAPIDJSON_NOEXCEPT : data_() { + data_.n.u64 = u64; + data_.f.flags = kNumberUint64Flag; + if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000))) + data_.f.flags |= kInt64Flag; + if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) + data_.f.flags |= kUintFlag; + if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) + data_.f.flags |= kIntFlag; + } + + //! Constructor for double value. + explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = d; data_.f.flags = kNumberDoubleFlag; } + + //! Constructor for float value. + explicit GenericValue(float f) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = static_cast(f); data_.f.flags = kNumberDoubleFlag; } + + //! Constructor for constant string (i.e. do not make a copy of string) + GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(StringRef(s, length)); } + + //! Constructor for constant string (i.e. do not make a copy of string) + explicit GenericValue(StringRefType s) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(s); } + + //! Constructor for copy-string (i.e. do make a copy of string) + GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_() { SetStringRaw(StringRef(s, length), allocator); } + + //! Constructor for copy-string (i.e. do make a copy of string) + GenericValue(const Ch*s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); } + +#if RAPIDJSON_HAS_STDSTRING + //! Constructor for copy-string from a string object (i.e. do make a copy of string) + /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. + */ + GenericValue(const std::basic_string& s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); } +#endif + + //! Constructor for Array. + /*! + \param a An array obtained by \c GetArray(). + \note \c Array is always pass-by-value. + \note the source array is moved into this value and the sourec array becomes empty. + */ + GenericValue(Array a) RAPIDJSON_NOEXCEPT : data_(a.value_.data_) { + a.value_.data_ = Data(); + a.value_.data_.f.flags = kArrayFlag; + } + + //! Constructor for Object. + /*! + \param o An object obtained by \c GetObject(). + \note \c Object is always pass-by-value. + \note the source object is moved into this value and the sourec object becomes empty. + */ + GenericValue(Object o) RAPIDJSON_NOEXCEPT : data_(o.value_.data_) { + o.value_.data_ = Data(); + o.value_.data_.f.flags = kObjectFlag; + } + + //! Destructor. + /*! Need to destruct elements of array, members of object, or copy-string. + */ + ~GenericValue() { + if (Allocator::kNeedFree) { // Shortcut by Allocator's trait + switch(data_.f.flags) { + case kArrayFlag: + { + GenericValue* e = GetElementsPointer(); + for (GenericValue* v = e; v != e + data_.a.size; ++v) + v->~GenericValue(); + Allocator::Free(e); + } + break; + + case kObjectFlag: + for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) + m->~Member(); + Allocator::Free(GetMembersPointer()); + break; + + case kCopyStringFlag: + Allocator::Free(const_cast(GetStringPointer())); + break; + + default: + break; // Do nothing for other types. + } + } + } + + //@} + + //!@name Assignment operators + //@{ + + //! Assignment with move semantics. + /*! \param rhs Source of the assignment. It will become a null value after assignment. + */ + GenericValue& operator=(GenericValue& rhs) RAPIDJSON_NOEXCEPT { + if (RAPIDJSON_LIKELY(this != &rhs)) { + this->~GenericValue(); + RawAssign(rhs); + } + return *this; + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + //! Move assignment in C++11 + GenericValue& operator=(GenericValue&& rhs) RAPIDJSON_NOEXCEPT { + return *this = rhs.Move(); + } +#endif + + //! Assignment of constant string reference (no copy) + /*! \param str Constant string reference to be assigned + \note This overload is needed to avoid clashes with the generic primitive type assignment overload below. + \see GenericStringRef, operator=(T) + */ + GenericValue& operator=(StringRefType str) RAPIDJSON_NOEXCEPT { + GenericValue s(str); + return *this = s; + } + + //! Assignment with primitive types. + /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t + \param value The value to be assigned. + + \note The source type \c T explicitly disallows all pointer types, + especially (\c const) \ref Ch*. This helps avoiding implicitly + referencing character strings with insufficient lifetime, use + \ref SetString(const Ch*, Allocator&) (for copying) or + \ref StringRef() (to explicitly mark the pointer as constant) instead. + All other pointer types would implicitly convert to \c bool, + use \ref SetBool() instead. + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::IsPointer), (GenericValue&)) + operator=(T value) { + GenericValue v(value); + return *this = v; + } + + //! Deep-copy assignment from Value + /*! Assigns a \b copy of the Value to the current Value object + \tparam SourceAllocator Allocator type of \c rhs + \param rhs Value to copy from (read-only) + \param allocator Allocator to use for copying + \param copyConstStrings Force copying of constant strings (e.g. referencing an in-situ buffer) + */ + template + GenericValue& CopyFrom(const GenericValue& rhs, Allocator& allocator, bool copyConstStrings = false) { + RAPIDJSON_ASSERT(static_cast(this) != static_cast(&rhs)); + this->~GenericValue(); + new (this) GenericValue(rhs, allocator, copyConstStrings); + return *this; + } + + //! Exchange the contents of this value with those of other. + /*! + \param other Another value. + \note Constant complexity. + */ + GenericValue& Swap(GenericValue& other) RAPIDJSON_NOEXCEPT { + GenericValue temp; + temp.RawAssign(*this); + RawAssign(other); + other.RawAssign(temp); + return *this; + } + + //! free-standing swap function helper + /*! + Helper function to enable support for common swap implementation pattern based on \c std::swap: + \code + void swap(MyClass& a, MyClass& b) { + using std::swap; + swap(a.value, b.value); + // ... + } + \endcode + \see Swap() + */ + friend inline void swap(GenericValue& a, GenericValue& b) RAPIDJSON_NOEXCEPT { a.Swap(b); } + + //! Prepare Value for move semantics + /*! \return *this */ + GenericValue& Move() RAPIDJSON_NOEXCEPT { return *this; } + //@} + + //!@name Equal-to and not-equal-to operators + //@{ + //! Equal-to operator + /*! + \note If an object contains duplicated named member, comparing equality with any object is always \c false. + \note Complexity is quadratic in Object's member number and linear for the rest (number of all values in the subtree and total lengths of all strings). + */ + template + bool operator==(const GenericValue& rhs) const { + typedef GenericValue RhsType; + if (GetType() != rhs.GetType()) + return false; + + switch (GetType()) { + case kObjectType: // Warning: O(n^2) inner-loop + if (data_.o.size != rhs.data_.o.size) + return false; + for (ConstMemberIterator lhsMemberItr = MemberBegin(); lhsMemberItr != MemberEnd(); ++lhsMemberItr) { + typename RhsType::ConstMemberIterator rhsMemberItr = rhs.FindMember(lhsMemberItr->name); + if (rhsMemberItr == rhs.MemberEnd() || lhsMemberItr->value != rhsMemberItr->value) + return false; + } + return true; + + case kArrayType: + if (data_.a.size != rhs.data_.a.size) + return false; + for (SizeType i = 0; i < data_.a.size; i++) + if ((*this)[i] != rhs[i]) + return false; + return true; + + case kStringType: + return StringEqual(rhs); + + case kNumberType: + if (IsDouble() || rhs.IsDouble()) { + double a = GetDouble(); // May convert from integer to double. + double b = rhs.GetDouble(); // Ditto + return a >= b && a <= b; // Prevent -Wfloat-equal + } + else + return data_.n.u64 == rhs.data_.n.u64; + + default: + return true; + } + } + + //! Equal-to operator with const C-string pointer + bool operator==(const Ch* rhs) const { return *this == GenericValue(StringRef(rhs)); } + +#if RAPIDJSON_HAS_STDSTRING + //! Equal-to operator with string object + /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. + */ + bool operator==(const std::basic_string& rhs) const { return *this == GenericValue(StringRef(rhs)); } +#endif + + //! Equal-to operator with primitive types + /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c true, \c false + */ + template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr,internal::IsGenericValue >), (bool)) operator==(const T& rhs) const { return *this == GenericValue(rhs); } + + //! Not-equal-to operator + /*! \return !(*this == rhs) + */ + template + bool operator!=(const GenericValue& rhs) const { return !(*this == rhs); } + + //! Not-equal-to operator with const C-string pointer + bool operator!=(const Ch* rhs) const { return !(*this == rhs); } + + //! Not-equal-to operator with arbitrary types + /*! \return !(*this == rhs) + */ + template RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator!=(const T& rhs) const { return !(*this == rhs); } + + //! Equal-to operator with arbitrary types (symmetric version) + /*! \return (rhs == lhs) + */ + template friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator==(const T& lhs, const GenericValue& rhs) { return rhs == lhs; } + + //! Not-Equal-to operator with arbitrary types (symmetric version) + /*! \return !(rhs == lhs) + */ + template friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); } + //@} + + //!@name Type + //@{ + + Type GetType() const { return static_cast(data_.f.flags & kTypeMask); } + bool IsNull() const { return data_.f.flags == kNullFlag; } + bool IsFalse() const { return data_.f.flags == kFalseFlag; } + bool IsTrue() const { return data_.f.flags == kTrueFlag; } + bool IsBool() const { return (data_.f.flags & kBoolFlag) != 0; } + bool IsObject() const { return data_.f.flags == kObjectFlag; } + bool IsArray() const { return data_.f.flags == kArrayFlag; } + bool IsNumber() const { return (data_.f.flags & kNumberFlag) != 0; } + bool IsInt() const { return (data_.f.flags & kIntFlag) != 0; } + bool IsUint() const { return (data_.f.flags & kUintFlag) != 0; } + bool IsInt64() const { return (data_.f.flags & kInt64Flag) != 0; } + bool IsUint64() const { return (data_.f.flags & kUint64Flag) != 0; } + bool IsDouble() const { return (data_.f.flags & kDoubleFlag) != 0; } + bool IsString() const { return (data_.f.flags & kStringFlag) != 0; } + + // Checks whether a number can be losslessly converted to a double. + bool IsLosslessDouble() const { + if (!IsNumber()) return false; + if (IsUint64()) { + uint64_t u = GetUint64(); + volatile double d = static_cast(u); + return (d >= 0.0) + && (d < static_cast((std::numeric_limits::max)())) + && (u == static_cast(d)); + } + if (IsInt64()) { + int64_t i = GetInt64(); + volatile double d = static_cast(i); + return (d >= static_cast((std::numeric_limits::min)())) + && (d < static_cast((std::numeric_limits::max)())) + && (i == static_cast(d)); + } + return true; // double, int, uint are always lossless + } + + // Checks whether a number is a float (possible lossy). + bool IsFloat() const { + if ((data_.f.flags & kDoubleFlag) == 0) + return false; + double d = GetDouble(); + return d >= -3.4028234e38 && d <= 3.4028234e38; + } + // Checks whether a number can be losslessly converted to a float. + bool IsLosslessFloat() const { + if (!IsNumber()) return false; + double a = GetDouble(); + if (a < static_cast(-(std::numeric_limits::max)()) + || a > static_cast((std::numeric_limits::max)())) + return false; + double b = static_cast(static_cast(a)); + return a >= b && a <= b; // Prevent -Wfloat-equal + } + + //@} + + //!@name Null + //@{ + + GenericValue& SetNull() { this->~GenericValue(); new (this) GenericValue(); return *this; } + + //@} + + //!@name Bool + //@{ + + bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return data_.f.flags == kTrueFlag; } + //!< Set boolean value + /*! \post IsBool() == true */ + GenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; } + + //@} + + //!@name Object + //@{ + + //! Set this value as an empty object. + /*! \post IsObject() == true */ + GenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; } + + //! Get the number of members in the object. + SizeType MemberCount() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size; } + + //! Get the capacity of object. + SizeType MemberCapacity() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.capacity; } + + //! Check whether the object is empty. + bool ObjectEmpty() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size == 0; } + + //! Get a value from an object associated with the name. + /*! \pre IsObject() == true + \tparam T Either \c Ch or \c const \c Ch (template used for disambiguation with \ref operator[](SizeType)) + \note In version 0.1x, if the member is not found, this function returns a null value. This makes issue 7. + Since 0.2, if the name is not correct, it will assert. + If user is unsure whether a member exists, user should use HasMember() first. + A better approach is to use FindMember(). + \note Linear time complexity. + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >),(GenericValue&)) operator[](T* name) { + GenericValue n(StringRef(name)); + return (*this)[n]; + } + template + RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >),(const GenericValue&)) operator[](T* name) const { return const_cast(*this)[name]; } + + //! Get a value from an object associated with the name. + /*! \pre IsObject() == true + \tparam SourceAllocator Allocator of the \c name value + + \note Compared to \ref operator[](T*), this version is faster because it does not need a StrLen(). + And it can also handle strings with embedded null characters. + + \note Linear time complexity. + */ + template + GenericValue& operator[](const GenericValue& name) { + MemberIterator member = FindMember(name); + if (member != MemberEnd()) + return member->value; + else { + RAPIDJSON_ASSERT(false); // see above note + + // This will generate -Wexit-time-destructors in clang + // static GenericValue NullValue; + // return NullValue; + + // Use static buffer and placement-new to prevent destruction + static char buffer[sizeof(GenericValue)]; + return *new (buffer) GenericValue(); + } + } + template + const GenericValue& operator[](const GenericValue& name) const { return const_cast(*this)[name]; } + +#if RAPIDJSON_HAS_STDSTRING + //! Get a value from an object associated with name (string object). + GenericValue& operator[](const std::basic_string& name) { return (*this)[GenericValue(StringRef(name))]; } + const GenericValue& operator[](const std::basic_string& name) const { return (*this)[GenericValue(StringRef(name))]; } +#endif + + //! Const member iterator + /*! \pre IsObject() == true */ + ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer()); } + //! Const \em past-the-end member iterator + /*! \pre IsObject() == true */ + ConstMemberIterator MemberEnd() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer() + data_.o.size); } + //! Member iterator + /*! \pre IsObject() == true */ + MemberIterator MemberBegin() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer()); } + //! \em Past-the-end member iterator + /*! \pre IsObject() == true */ + MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer() + data_.o.size); } + + //! Request the object to have enough capacity to store members. + /*! \param newCapacity The capacity that the object at least need to have. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \note Linear time complexity. + */ + GenericValue& MemberReserve(SizeType newCapacity, Allocator &allocator) { + RAPIDJSON_ASSERT(IsObject()); + if (newCapacity > data_.o.capacity) { + SetMembersPointer(reinterpret_cast(allocator.Realloc(GetMembersPointer(), data_.o.capacity * sizeof(Member), newCapacity * sizeof(Member)))); + data_.o.capacity = newCapacity; + } + return *this; + } + + //! Check whether a member exists in the object. + /*! + \param name Member name to be searched. + \pre IsObject() == true + \return Whether a member with that name exists. + \note It is better to use FindMember() directly if you need the obtain the value as well. + \note Linear time complexity. + */ + bool HasMember(const Ch* name) const { return FindMember(name) != MemberEnd(); } + +#if RAPIDJSON_HAS_STDSTRING + //! Check whether a member exists in the object with string object. + /*! + \param name Member name to be searched. + \pre IsObject() == true + \return Whether a member with that name exists. + \note It is better to use FindMember() directly if you need the obtain the value as well. + \note Linear time complexity. + */ + bool HasMember(const std::basic_string& name) const { return FindMember(name) != MemberEnd(); } +#endif + + //! Check whether a member exists in the object with GenericValue name. + /*! + This version is faster because it does not need a StrLen(). It can also handle string with null character. + \param name Member name to be searched. + \pre IsObject() == true + \return Whether a member with that name exists. + \note It is better to use FindMember() directly if you need the obtain the value as well. + \note Linear time complexity. + */ + template + bool HasMember(const GenericValue& name) const { return FindMember(name) != MemberEnd(); } + + //! Find member by name. + /*! + \param name Member name to be searched. + \pre IsObject() == true + \return Iterator to member, if it exists. + Otherwise returns \ref MemberEnd(). + + \note Earlier versions of Rapidjson returned a \c NULL pointer, in case + the requested member doesn't exist. For consistency with e.g. + \c std::map, this has been changed to MemberEnd() now. + \note Linear time complexity. + */ + MemberIterator FindMember(const Ch* name) { + GenericValue n(StringRef(name)); + return FindMember(n); + } + + ConstMemberIterator FindMember(const Ch* name) const { return const_cast(*this).FindMember(name); } + + //! Find member by name. + /*! + This version is faster because it does not need a StrLen(). It can also handle string with null character. + \param name Member name to be searched. + \pre IsObject() == true + \return Iterator to member, if it exists. + Otherwise returns \ref MemberEnd(). + + \note Earlier versions of Rapidjson returned a \c NULL pointer, in case + the requested member doesn't exist. For consistency with e.g. + \c std::map, this has been changed to MemberEnd() now. + \note Linear time complexity. + */ + template + MemberIterator FindMember(const GenericValue& name) { + RAPIDJSON_ASSERT(IsObject()); + RAPIDJSON_ASSERT(name.IsString()); + MemberIterator member = MemberBegin(); + for ( ; member != MemberEnd(); ++member) + if (name.StringEqual(member->name)) + break; + return member; + } + template ConstMemberIterator FindMember(const GenericValue& name) const { return const_cast(*this).FindMember(name); } + +#if RAPIDJSON_HAS_STDSTRING + //! Find member by string object name. + /*! + \param name Member name to be searched. + \pre IsObject() == true + \return Iterator to member, if it exists. + Otherwise returns \ref MemberEnd(). + */ + MemberIterator FindMember(const std::basic_string& name) { return FindMember(GenericValue(StringRef(name))); } + ConstMemberIterator FindMember(const std::basic_string& name) const { return FindMember(GenericValue(StringRef(name))); } +#endif + + //! Add a member (name-value pair) to the object. + /*! \param name A string value as name of member. + \param value Value of any type. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \note The ownership of \c name and \c value will be transferred to this object on success. + \pre IsObject() && name.IsString() + \post name.IsNull() && value.IsNull() + \note Amortized Constant time complexity. + */ + GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) { + RAPIDJSON_ASSERT(IsObject()); + RAPIDJSON_ASSERT(name.IsString()); + + ObjectData& o = data_.o; + if (o.size >= o.capacity) + MemberReserve(o.capacity == 0 ? kDefaultObjectCapacity : (o.capacity + (o.capacity + 1) / 2), allocator); + Member* members = GetMembersPointer(); + members[o.size].name.RawAssign(name); + members[o.size].value.RawAssign(value); + o.size++; + return *this; + } + + //! Add a constant string value as member (name-value pair) to the object. + /*! \param name A string value as name of member. + \param value constant string reference as value of member. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \pre IsObject() + \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below. + \note Amortized Constant time complexity. + */ + GenericValue& AddMember(GenericValue& name, StringRefType value, Allocator& allocator) { + GenericValue v(value); + return AddMember(name, v, allocator); + } + +#if RAPIDJSON_HAS_STDSTRING + //! Add a string object as member (name-value pair) to the object. + /*! \param name A string value as name of member. + \param value constant string reference as value of member. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \pre IsObject() + \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below. + \note Amortized Constant time complexity. + */ + GenericValue& AddMember(GenericValue& name, std::basic_string& value, Allocator& allocator) { + GenericValue v(value, allocator); + return AddMember(name, v, allocator); + } +#endif + + //! Add any primitive value as member (name-value pair) to the object. + /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t + \param name A string value as name of member. + \param value Value of primitive type \c T as value of member + \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \pre IsObject() + + \note The source type \c T explicitly disallows all pointer types, + especially (\c const) \ref Ch*. This helps avoiding implicitly + referencing character strings with insufficient lifetime, use + \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref + AddMember(StringRefType, StringRefType, Allocator&). + All other pointer types would implicitly convert to \c bool, + use an explicit cast instead, if needed. + \note Amortized Constant time complexity. + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&)) + AddMember(GenericValue& name, T value, Allocator& allocator) { + GenericValue v(value); + return AddMember(name, v, allocator); + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + GenericValue& AddMember(GenericValue&& name, GenericValue&& value, Allocator& allocator) { + return AddMember(name, value, allocator); + } + GenericValue& AddMember(GenericValue&& name, GenericValue& value, Allocator& allocator) { + return AddMember(name, value, allocator); + } + GenericValue& AddMember(GenericValue& name, GenericValue&& value, Allocator& allocator) { + return AddMember(name, value, allocator); + } + GenericValue& AddMember(StringRefType name, GenericValue&& value, Allocator& allocator) { + GenericValue n(name); + return AddMember(n, value, allocator); + } +#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS + + + //! Add a member (name-value pair) to the object. + /*! \param name A constant string reference as name of member. + \param value Value of any type. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \note The ownership of \c value will be transferred to this object on success. + \pre IsObject() + \post value.IsNull() + \note Amortized Constant time complexity. + */ + GenericValue& AddMember(StringRefType name, GenericValue& value, Allocator& allocator) { + GenericValue n(name); + return AddMember(n, value, allocator); + } + + //! Add a constant string value as member (name-value pair) to the object. + /*! \param name A constant string reference as name of member. + \param value constant string reference as value of member. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \pre IsObject() + \note This overload is needed to avoid clashes with the generic primitive type AddMember(StringRefType,T,Allocator&) overload below. + \note Amortized Constant time complexity. + */ + GenericValue& AddMember(StringRefType name, StringRefType value, Allocator& allocator) { + GenericValue v(value); + return AddMember(name, v, allocator); + } + + //! Add any primitive value as member (name-value pair) to the object. + /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t + \param name A constant string reference as name of member. + \param value Value of primitive type \c T as value of member + \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \pre IsObject() + + \note The source type \c T explicitly disallows all pointer types, + especially (\c const) \ref Ch*. This helps avoiding implicitly + referencing character strings with insufficient lifetime, use + \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref + AddMember(StringRefType, StringRefType, Allocator&). + All other pointer types would implicitly convert to \c bool, + use an explicit cast instead, if needed. + \note Amortized Constant time complexity. + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&)) + AddMember(StringRefType name, T value, Allocator& allocator) { + GenericValue n(name); + return AddMember(n, value, allocator); + } + + //! Remove all members in the object. + /*! This function do not deallocate memory in the object, i.e. the capacity is unchanged. + \note Linear time complexity. + */ + void RemoveAllMembers() { + RAPIDJSON_ASSERT(IsObject()); + for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) + m->~Member(); + data_.o.size = 0; + } + + //! Remove a member in object by its name. + /*! \param name Name of member to be removed. + \return Whether the member existed. + \note This function may reorder the object members. Use \ref + EraseMember(ConstMemberIterator) if you need to preserve the + relative order of the remaining members. + \note Linear time complexity. + */ + bool RemoveMember(const Ch* name) { + GenericValue n(StringRef(name)); + return RemoveMember(n); + } + +#if RAPIDJSON_HAS_STDSTRING + bool RemoveMember(const std::basic_string& name) { return RemoveMember(GenericValue(StringRef(name))); } +#endif + + template + bool RemoveMember(const GenericValue& name) { + MemberIterator m = FindMember(name); + if (m != MemberEnd()) { + RemoveMember(m); + return true; + } + else + return false; + } + + //! Remove a member in object by iterator. + /*! \param m member iterator (obtained by FindMember() or MemberBegin()). + \return the new iterator after removal. + \note This function may reorder the object members. Use \ref + EraseMember(ConstMemberIterator) if you need to preserve the + relative order of the remaining members. + \note Constant time complexity. + */ + MemberIterator RemoveMember(MemberIterator m) { + RAPIDJSON_ASSERT(IsObject()); + RAPIDJSON_ASSERT(data_.o.size > 0); + RAPIDJSON_ASSERT(GetMembersPointer() != 0); + RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd()); + + MemberIterator last(GetMembersPointer() + (data_.o.size - 1)); + if (data_.o.size > 1 && m != last) + *m = *last; // Move the last one to this place + else + m->~Member(); // Only one left, just destroy + --data_.o.size; + return m; + } + + //! Remove a member from an object by iterator. + /*! \param pos iterator to the member to remove + \pre IsObject() == true && \ref MemberBegin() <= \c pos < \ref MemberEnd() + \return Iterator following the removed element. + If the iterator \c pos refers to the last element, the \ref MemberEnd() iterator is returned. + \note This function preserves the relative order of the remaining object + members. If you do not need this, use the more efficient \ref RemoveMember(MemberIterator). + \note Linear time complexity. + */ + MemberIterator EraseMember(ConstMemberIterator pos) { + return EraseMember(pos, pos +1); + } + + //! Remove members in the range [first, last) from an object. + /*! \param first iterator to the first member to remove + \param last iterator following the last member to remove + \pre IsObject() == true && \ref MemberBegin() <= \c first <= \c last <= \ref MemberEnd() + \return Iterator following the last removed element. + \note This function preserves the relative order of the remaining object + members. + \note Linear time complexity. + */ + MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) { + RAPIDJSON_ASSERT(IsObject()); + RAPIDJSON_ASSERT(data_.o.size > 0); + RAPIDJSON_ASSERT(GetMembersPointer() != 0); + RAPIDJSON_ASSERT(first >= MemberBegin()); + RAPIDJSON_ASSERT(first <= last); + RAPIDJSON_ASSERT(last <= MemberEnd()); + + MemberIterator pos = MemberBegin() + (first - MemberBegin()); + for (MemberIterator itr = pos; itr != last; ++itr) + itr->~Member(); + std::memmove(static_cast(&*pos), &*last, static_cast(MemberEnd() - last) * sizeof(Member)); + data_.o.size -= static_cast(last - first); + return pos; + } + + //! Erase a member in object by its name. + /*! \param name Name of member to be removed. + \return Whether the member existed. + \note Linear time complexity. + */ + bool EraseMember(const Ch* name) { + GenericValue n(StringRef(name)); + return EraseMember(n); + } + +#if RAPIDJSON_HAS_STDSTRING + bool EraseMember(const std::basic_string& name) { return EraseMember(GenericValue(StringRef(name))); } +#endif + + template + bool EraseMember(const GenericValue& name) { + MemberIterator m = FindMember(name); + if (m != MemberEnd()) { + EraseMember(m); + return true; + } + else + return false; + } + + Object GetObject() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); } + ConstObject GetObject() const { RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); } + + //@} + + //!@name Array + //@{ + + //! Set this value as an empty array. + /*! \post IsArray == true */ + GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; } + + //! Get the number of elements in array. + SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; } + + //! Get the capacity of array. + SizeType Capacity() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.capacity; } + + //! Check whether the array is empty. + bool Empty() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size == 0; } + + //! Remove all elements in the array. + /*! This function do not deallocate memory in the array, i.e. the capacity is unchanged. + \note Linear time complexity. + */ + void Clear() { + RAPIDJSON_ASSERT(IsArray()); + GenericValue* e = GetElementsPointer(); + for (GenericValue* v = e; v != e + data_.a.size; ++v) + v->~GenericValue(); + data_.a.size = 0; + } + + //! Get an element from array by index. + /*! \pre IsArray() == true + \param index Zero-based index of element. + \see operator[](T*) + */ + GenericValue& operator[](SizeType index) { + RAPIDJSON_ASSERT(IsArray()); + RAPIDJSON_ASSERT(index < data_.a.size); + return GetElementsPointer()[index]; + } + const GenericValue& operator[](SizeType index) const { return const_cast(*this)[index]; } + + //! Element iterator + /*! \pre IsArray() == true */ + ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer(); } + //! \em Past-the-end element iterator + /*! \pre IsArray() == true */ + ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer() + data_.a.size; } + //! Constant element iterator + /*! \pre IsArray() == true */ + ConstValueIterator Begin() const { return const_cast(*this).Begin(); } + //! Constant \em past-the-end element iterator + /*! \pre IsArray() == true */ + ConstValueIterator End() const { return const_cast(*this).End(); } + + //! Request the array to have enough capacity to store elements. + /*! \param newCapacity The capacity that the array at least need to have. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \note Linear time complexity. + */ + GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) { + RAPIDJSON_ASSERT(IsArray()); + if (newCapacity > data_.a.capacity) { + SetElementsPointer(reinterpret_cast(allocator.Realloc(GetElementsPointer(), data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue)))); + data_.a.capacity = newCapacity; + } + return *this; + } + + //! Append a GenericValue at the end of the array. + /*! \param value Value to be appended. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \pre IsArray() == true + \post value.IsNull() == true + \return The value itself for fluent API. + \note The ownership of \c value will be transferred to this array on success. + \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. + \note Amortized constant time complexity. + */ + GenericValue& PushBack(GenericValue& value, Allocator& allocator) { + RAPIDJSON_ASSERT(IsArray()); + if (data_.a.size >= data_.a.capacity) + Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : (data_.a.capacity + (data_.a.capacity + 1) / 2), allocator); + GetElementsPointer()[data_.a.size++].RawAssign(value); + return *this; + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + GenericValue& PushBack(GenericValue&& value, Allocator& allocator) { + return PushBack(value, allocator); + } +#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS + + //! Append a constant string reference at the end of the array. + /*! \param value Constant string reference to be appended. + \param allocator Allocator for reallocating memory. It must be the same one used previously. Commonly use GenericDocument::GetAllocator(). + \pre IsArray() == true + \return The value itself for fluent API. + \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. + \note Amortized constant time complexity. + \see GenericStringRef + */ + GenericValue& PushBack(StringRefType value, Allocator& allocator) { + return (*this).template PushBack(value, allocator); + } + + //! Append a primitive value at the end of the array. + /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t + \param value Value of primitive type T to be appended. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \pre IsArray() == true + \return The value itself for fluent API. + \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. + + \note The source type \c T explicitly disallows all pointer types, + especially (\c const) \ref Ch*. This helps avoiding implicitly + referencing character strings with insufficient lifetime, use + \ref PushBack(GenericValue&, Allocator&) or \ref + PushBack(StringRefType, Allocator&). + All other pointer types would implicitly convert to \c bool, + use an explicit cast instead, if needed. + \note Amortized constant time complexity. + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&)) + PushBack(T value, Allocator& allocator) { + GenericValue v(value); + return PushBack(v, allocator); + } + + //! Remove the last element in the array. + /*! + \note Constant time complexity. + */ + GenericValue& PopBack() { + RAPIDJSON_ASSERT(IsArray()); + RAPIDJSON_ASSERT(!Empty()); + GetElementsPointer()[--data_.a.size].~GenericValue(); + return *this; + } + + //! Remove an element of array by iterator. + /*! + \param pos iterator to the element to remove + \pre IsArray() == true && \ref Begin() <= \c pos < \ref End() + \return Iterator following the removed element. If the iterator pos refers to the last element, the End() iterator is returned. + \note Linear time complexity. + */ + ValueIterator Erase(ConstValueIterator pos) { + return Erase(pos, pos + 1); + } + + //! Remove elements in the range [first, last) of the array. + /*! + \param first iterator to the first element to remove + \param last iterator following the last element to remove + \pre IsArray() == true && \ref Begin() <= \c first <= \c last <= \ref End() + \return Iterator following the last removed element. + \note Linear time complexity. + */ + ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) { + RAPIDJSON_ASSERT(IsArray()); + RAPIDJSON_ASSERT(data_.a.size > 0); + RAPIDJSON_ASSERT(GetElementsPointer() != 0); + RAPIDJSON_ASSERT(first >= Begin()); + RAPIDJSON_ASSERT(first <= last); + RAPIDJSON_ASSERT(last <= End()); + ValueIterator pos = Begin() + (first - Begin()); + for (ValueIterator itr = pos; itr != last; ++itr) + itr->~GenericValue(); + std::memmove(static_cast(pos), last, static_cast(End() - last) * sizeof(GenericValue)); + data_.a.size -= static_cast(last - first); + return pos; + } + + Array GetArray() { RAPIDJSON_ASSERT(IsArray()); return Array(*this); } + ConstArray GetArray() const { RAPIDJSON_ASSERT(IsArray()); return ConstArray(*this); } + + //@} + + //!@name Number + //@{ + + int GetInt() const { RAPIDJSON_ASSERT(data_.f.flags & kIntFlag); return data_.n.i.i; } + unsigned GetUint() const { RAPIDJSON_ASSERT(data_.f.flags & kUintFlag); return data_.n.u.u; } + int64_t GetInt64() const { RAPIDJSON_ASSERT(data_.f.flags & kInt64Flag); return data_.n.i64; } + uint64_t GetUint64() const { RAPIDJSON_ASSERT(data_.f.flags & kUint64Flag); return data_.n.u64; } + + //! Get the value as double type. + /*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessDouble() to check whether the converison is lossless. + */ + double GetDouble() const { + RAPIDJSON_ASSERT(IsNumber()); + if ((data_.f.flags & kDoubleFlag) != 0) return data_.n.d; // exact type, no conversion. + if ((data_.f.flags & kIntFlag) != 0) return data_.n.i.i; // int -> double + if ((data_.f.flags & kUintFlag) != 0) return data_.n.u.u; // unsigned -> double + if ((data_.f.flags & kInt64Flag) != 0) return static_cast(data_.n.i64); // int64_t -> double (may lose precision) + RAPIDJSON_ASSERT((data_.f.flags & kUint64Flag) != 0); return static_cast(data_.n.u64); // uint64_t -> double (may lose precision) + } + + //! Get the value as float type. + /*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessFloat() to check whether the converison is lossless. + */ + float GetFloat() const { + return static_cast(GetDouble()); + } + + GenericValue& SetInt(int i) { this->~GenericValue(); new (this) GenericValue(i); return *this; } + GenericValue& SetUint(unsigned u) { this->~GenericValue(); new (this) GenericValue(u); return *this; } + GenericValue& SetInt64(int64_t i64) { this->~GenericValue(); new (this) GenericValue(i64); return *this; } + GenericValue& SetUint64(uint64_t u64) { this->~GenericValue(); new (this) GenericValue(u64); return *this; } + GenericValue& SetDouble(double d) { this->~GenericValue(); new (this) GenericValue(d); return *this; } + GenericValue& SetFloat(float f) { this->~GenericValue(); new (this) GenericValue(static_cast(f)); return *this; } + + //@} + + //!@name String + //@{ + + const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return (data_.f.flags & kInlineStrFlag) ? data_.ss.str : GetStringPointer(); } + + //! Get the length of string. + /*! Since rapidjson permits "\\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength(). + */ + SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return ((data_.f.flags & kInlineStrFlag) ? (data_.ss.GetLength()) : data_.s.length); } + + //! Set this value as a string without copying source string. + /*! This version has better performance with supplied length, and also support string containing null character. + \param s source string pointer. + \param length The length of source string, excluding the trailing null terminator. + \return The value itself for fluent API. + \post IsString() == true && GetString() == s && GetStringLength() == length + \see SetString(StringRefType) + */ + GenericValue& SetString(const Ch* s, SizeType length) { return SetString(StringRef(s, length)); } + + //! Set this value as a string without copying source string. + /*! \param s source string reference + \return The value itself for fluent API. + \post IsString() == true && GetString() == s && GetStringLength() == s.length + */ + GenericValue& SetString(StringRefType s) { this->~GenericValue(); SetStringRaw(s); return *this; } + + //! Set this value as a string by copying from source string. + /*! This version has better performance with supplied length, and also support string containing null character. + \param s source string. + \param length The length of source string, excluding the trailing null terminator. + \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length + */ + GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { return SetString(StringRef(s, length), allocator); } + + //! Set this value as a string by copying from source string. + /*! \param s source string. + \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length + */ + GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(StringRef(s), allocator); } + + //! Set this value as a string by copying from source string. + /*! \param s source string reference + \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \post IsString() == true && GetString() != s.s && strcmp(GetString(),s) == 0 && GetStringLength() == length + */ + GenericValue& SetString(StringRefType s, Allocator& allocator) { this->~GenericValue(); SetStringRaw(s, allocator); return *this; } + +#if RAPIDJSON_HAS_STDSTRING + //! Set this value as a string by copying from source string. + /*! \param s source string. + \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \post IsString() == true && GetString() != s.data() && strcmp(GetString(),s.data() == 0 && GetStringLength() == s.size() + \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. + */ + GenericValue& SetString(const std::basic_string& s, Allocator& allocator) { return SetString(StringRef(s), allocator); } +#endif + + //@} + + //!@name Array + //@{ + + //! Templated version for checking whether this value is type T. + /*! + \tparam T Either \c bool, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c float, \c const \c char*, \c std::basic_string + */ + template + bool Is() const { return internal::TypeHelper::Is(*this); } + + template + T Get() const { return internal::TypeHelper::Get(*this); } + + template + T Get() { return internal::TypeHelper::Get(*this); } + + template + ValueType& Set(const T& data) { return internal::TypeHelper::Set(*this, data); } + + template + ValueType& Set(const T& data, AllocatorType& allocator) { return internal::TypeHelper::Set(*this, data, allocator); } + + //@} + + //! Generate events of this value to a Handler. + /*! This function adopts the GoF visitor pattern. + Typical usage is to output this JSON value as JSON text via Writer, which is a Handler. + It can also be used to deep clone this value via GenericDocument, which is also a Handler. + \tparam Handler type of handler. + \param handler An object implementing concept Handler. + */ + template + bool Accept(Handler& handler) const { + switch(GetType()) { + case kNullType: return handler.Null(); + case kFalseType: return handler.Bool(false); + case kTrueType: return handler.Bool(true); + + case kObjectType: + if (RAPIDJSON_UNLIKELY(!handler.StartObject())) + return false; + for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) { + RAPIDJSON_ASSERT(m->name.IsString()); // User may change the type of name by MemberIterator. + if (RAPIDJSON_UNLIKELY(!handler.Key(m->name.GetString(), m->name.GetStringLength(), (m->name.data_.f.flags & kCopyFlag) != 0))) + return false; + if (RAPIDJSON_UNLIKELY(!m->value.Accept(handler))) + return false; + } + return handler.EndObject(data_.o.size); + + case kArrayType: + if (RAPIDJSON_UNLIKELY(!handler.StartArray())) + return false; + for (const GenericValue* v = Begin(); v != End(); ++v) + if (RAPIDJSON_UNLIKELY(!v->Accept(handler))) + return false; + return handler.EndArray(data_.a.size); + + case kStringType: + return handler.String(GetString(), GetStringLength(), (data_.f.flags & kCopyFlag) != 0); + + default: + RAPIDJSON_ASSERT(GetType() == kNumberType); + if (IsDouble()) return handler.Double(data_.n.d); + else if (IsInt()) return handler.Int(data_.n.i.i); + else if (IsUint()) return handler.Uint(data_.n.u.u); + else if (IsInt64()) return handler.Int64(data_.n.i64); + else return handler.Uint64(data_.n.u64); + } + } + +private: + template friend class GenericValue; + template friend class GenericDocument; + + enum { + kBoolFlag = 0x0008, + kNumberFlag = 0x0010, + kIntFlag = 0x0020, + kUintFlag = 0x0040, + kInt64Flag = 0x0080, + kUint64Flag = 0x0100, + kDoubleFlag = 0x0200, + kStringFlag = 0x0400, + kCopyFlag = 0x0800, + kInlineStrFlag = 0x1000, + + // Initial flags of different types. + kNullFlag = kNullType, + kTrueFlag = kTrueType | kBoolFlag, + kFalseFlag = kFalseType | kBoolFlag, + kNumberIntFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag, + kNumberUintFlag = kNumberType | kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag, + kNumberInt64Flag = kNumberType | kNumberFlag | kInt64Flag, + kNumberUint64Flag = kNumberType | kNumberFlag | kUint64Flag, + kNumberDoubleFlag = kNumberType | kNumberFlag | kDoubleFlag, + kNumberAnyFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag, + kConstStringFlag = kStringType | kStringFlag, + kCopyStringFlag = kStringType | kStringFlag | kCopyFlag, + kShortStringFlag = kStringType | kStringFlag | kCopyFlag | kInlineStrFlag, + kObjectFlag = kObjectType, + kArrayFlag = kArrayType, + + kTypeMask = 0x07 + }; + + static const SizeType kDefaultArrayCapacity = RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY; + static const SizeType kDefaultObjectCapacity = RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY; + + struct Flag { +#if RAPIDJSON_48BITPOINTER_OPTIMIZATION + char payload[sizeof(SizeType) * 2 + 6]; // 2 x SizeType + lower 48-bit pointer +#elif RAPIDJSON_64BIT + char payload[sizeof(SizeType) * 2 + sizeof(void*) + 6]; // 6 padding bytes +#else + char payload[sizeof(SizeType) * 2 + sizeof(void*) + 2]; // 2 padding bytes +#endif + uint16_t flags; + }; + + struct String { + SizeType length; + SizeType hashcode; //!< reserved + const Ch* str; + }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode + + // implementation detail: ShortString can represent zero-terminated strings up to MaxSize chars + // (excluding the terminating zero) and store a value to determine the length of the contained + // string in the last character str[LenPos] by storing "MaxSize - length" there. If the string + // to store has the maximal length of MaxSize then str[LenPos] will be 0 and therefore act as + // the string terminator as well. For getting the string length back from that value just use + // "MaxSize - str[LenPos]". + // This allows to store 13-chars strings in 32-bit mode, 21-chars strings in 64-bit mode, + // 13-chars strings for RAPIDJSON_48BITPOINTER_OPTIMIZATION=1 inline (for `UTF8`-encoded strings). + struct ShortString { + enum { MaxChars = sizeof(static_cast(0)->payload) / sizeof(Ch), MaxSize = MaxChars - 1, LenPos = MaxSize }; + Ch str[MaxChars]; + + inline static bool Usable(SizeType len) { return (MaxSize >= len); } + inline void SetLength(SizeType len) { str[LenPos] = static_cast(MaxSize - len); } + inline SizeType GetLength() const { return static_cast(MaxSize - str[LenPos]); } + }; // at most as many bytes as "String" above => 12 bytes in 32-bit mode, 16 bytes in 64-bit mode + + // By using proper binary layout, retrieval of different integer types do not need conversions. + union Number { +#if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN + struct I { + int i; + char padding[4]; + }i; + struct U { + unsigned u; + char padding2[4]; + }u; +#else + struct I { + char padding[4]; + int i; + }i; + struct U { + char padding2[4]; + unsigned u; + }u; +#endif + int64_t i64; + uint64_t u64; + double d; + }; // 8 bytes + + struct ObjectData { + SizeType size; + SizeType capacity; + Member* members; + }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode + + struct ArrayData { + SizeType size; + SizeType capacity; + GenericValue* elements; + }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode + + union Data { + String s; + ShortString ss; + Number n; + ObjectData o; + ArrayData a; + Flag f; + }; // 16 bytes in 32-bit mode, 24 bytes in 64-bit mode, 16 bytes in 64-bit with RAPIDJSON_48BITPOINTER_OPTIMIZATION + + RAPIDJSON_FORCEINLINE const Ch* GetStringPointer() const { return RAPIDJSON_GETPOINTER(Ch, data_.s.str); } + RAPIDJSON_FORCEINLINE const Ch* SetStringPointer(const Ch* str) { return RAPIDJSON_SETPOINTER(Ch, data_.s.str, str); } + RAPIDJSON_FORCEINLINE GenericValue* GetElementsPointer() const { return RAPIDJSON_GETPOINTER(GenericValue, data_.a.elements); } + RAPIDJSON_FORCEINLINE GenericValue* SetElementsPointer(GenericValue* elements) { return RAPIDJSON_SETPOINTER(GenericValue, data_.a.elements, elements); } + RAPIDJSON_FORCEINLINE Member* GetMembersPointer() const { return RAPIDJSON_GETPOINTER(Member, data_.o.members); } + RAPIDJSON_FORCEINLINE Member* SetMembersPointer(Member* members) { return RAPIDJSON_SETPOINTER(Member, data_.o.members, members); } + + // Initialize this value as array with initial data, without calling destructor. + void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) { + data_.f.flags = kArrayFlag; + if (count) { + GenericValue* e = static_cast(allocator.Malloc(count * sizeof(GenericValue))); + SetElementsPointer(e); + std::memcpy(static_cast(e), values, count * sizeof(GenericValue)); + } + else + SetElementsPointer(0); + data_.a.size = data_.a.capacity = count; + } + + //! Initialize this value as object with initial data, without calling destructor. + void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) { + data_.f.flags = kObjectFlag; + if (count) { + Member* m = static_cast(allocator.Malloc(count * sizeof(Member))); + SetMembersPointer(m); + std::memcpy(static_cast(m), members, count * sizeof(Member)); + } + else + SetMembersPointer(0); + data_.o.size = data_.o.capacity = count; + } + + //! Initialize this value as constant string, without calling destructor. + void SetStringRaw(StringRefType s) RAPIDJSON_NOEXCEPT { + data_.f.flags = kConstStringFlag; + SetStringPointer(s); + data_.s.length = s.length; + } + + //! Initialize this value as copy string with initial data, without calling destructor. + void SetStringRaw(StringRefType s, Allocator& allocator) { + Ch* str = 0; + if (ShortString::Usable(s.length)) { + data_.f.flags = kShortStringFlag; + data_.ss.SetLength(s.length); + str = data_.ss.str; + } else { + data_.f.flags = kCopyStringFlag; + data_.s.length = s.length; + str = static_cast(allocator.Malloc((s.length + 1) * sizeof(Ch))); + SetStringPointer(str); + } + std::memcpy(str, s, s.length * sizeof(Ch)); + str[s.length] = '\0'; + } + + //! Assignment without calling destructor + void RawAssign(GenericValue& rhs) RAPIDJSON_NOEXCEPT { + data_ = rhs.data_; + // data_.f.flags = rhs.data_.f.flags; + rhs.data_.f.flags = kNullFlag; + } + + template + bool StringEqual(const GenericValue& rhs) const { + RAPIDJSON_ASSERT(IsString()); + RAPIDJSON_ASSERT(rhs.IsString()); + + const SizeType len1 = GetStringLength(); + const SizeType len2 = rhs.GetStringLength(); + if(len1 != len2) { return false; } + + const Ch* const str1 = GetString(); + const Ch* const str2 = rhs.GetString(); + if(str1 == str2) { return true; } // fast path for constant string + + return (std::memcmp(str1, str2, sizeof(Ch) * len1) == 0); + } + + Data data_; +}; + +//! GenericValue with UTF8 encoding +typedef GenericValue > Value; + +/////////////////////////////////////////////////////////////////////////////// +// GenericDocument + +//! A document for parsing JSON text as DOM. +/*! + \note implements Handler concept + \tparam Encoding Encoding for both parsing and string storage. + \tparam Allocator Allocator for allocating memory for the DOM + \tparam StackAllocator Allocator for allocating memory for stack during parsing. + \warning Although GenericDocument inherits from GenericValue, the API does \b not provide any virtual functions, especially no virtual destructor. To avoid memory leaks, do not \c delete a GenericDocument object via a pointer to a GenericValue. +*/ +template +class GenericDocument : public GenericValue { +public: + typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. + typedef GenericValue ValueType; //!< Value type of the document. + typedef Allocator AllocatorType; //!< Allocator type from template parameter. + + //! Constructor + /*! Creates an empty document of specified type. + \param type Mandatory type of object to create. + \param allocator Optional allocator for allocating memory. + \param stackCapacity Optional initial capacity of stack in bytes. + \param stackAllocator Optional allocator for allocating memory for stack. + */ + explicit GenericDocument(Type type, Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) : + GenericValue(type), allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_() + { + if (!allocator_) + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); + } + + //! Constructor + /*! Creates an empty document which type is Null. + \param allocator Optional allocator for allocating memory. + \param stackCapacity Optional initial capacity of stack in bytes. + \param stackAllocator Optional allocator for allocating memory for stack. + */ + GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) : + allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_() + { + if (!allocator_) + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + //! Move constructor in C++11 + GenericDocument(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT + : ValueType(std::forward(rhs)), // explicit cast to avoid prohibited move from Document + allocator_(rhs.allocator_), + ownAllocator_(rhs.ownAllocator_), + stack_(std::move(rhs.stack_)), + parseResult_(rhs.parseResult_) + { + rhs.allocator_ = 0; + rhs.ownAllocator_ = 0; + rhs.parseResult_ = ParseResult(); + } +#endif + + ~GenericDocument() { + Destroy(); + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + //! Move assignment in C++11 + GenericDocument& operator=(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT + { + // The cast to ValueType is necessary here, because otherwise it would + // attempt to call GenericValue's templated assignment operator. + ValueType::operator=(std::forward(rhs)); + + // Calling the destructor here would prematurely call stack_'s destructor + Destroy(); + + allocator_ = rhs.allocator_; + ownAllocator_ = rhs.ownAllocator_; + stack_ = std::move(rhs.stack_); + parseResult_ = rhs.parseResult_; + + rhs.allocator_ = 0; + rhs.ownAllocator_ = 0; + rhs.parseResult_ = ParseResult(); + + return *this; + } +#endif + + //! Exchange the contents of this document with those of another. + /*! + \param rhs Another document. + \note Constant complexity. + \see GenericValue::Swap + */ + GenericDocument& Swap(GenericDocument& rhs) RAPIDJSON_NOEXCEPT { + ValueType::Swap(rhs); + stack_.Swap(rhs.stack_); + internal::Swap(allocator_, rhs.allocator_); + internal::Swap(ownAllocator_, rhs.ownAllocator_); + internal::Swap(parseResult_, rhs.parseResult_); + return *this; + } + + // Allow Swap with ValueType. + // Refer to Effective C++ 3rd Edition/Item 33: Avoid hiding inherited names. + using ValueType::Swap; + + //! free-standing swap function helper + /*! + Helper function to enable support for common swap implementation pattern based on \c std::swap: + \code + void swap(MyClass& a, MyClass& b) { + using std::swap; + swap(a.doc, b.doc); + // ... + } + \endcode + \see Swap() + */ + friend inline void swap(GenericDocument& a, GenericDocument& b) RAPIDJSON_NOEXCEPT { a.Swap(b); } + + //! Populate this document by a generator which produces SAX events. + /*! \tparam Generator A functor with bool f(Handler) prototype. + \param g Generator functor which sends SAX events to the parameter. + \return The document itself for fluent API. + */ + template + GenericDocument& Populate(Generator& g) { + ClearStackOnExit scope(*this); + if (g(*this)) { + RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object + ValueType::operator=(*stack_.template Pop(1));// Move value from stack to document + } + return *this; + } + + //!@name Parse from stream + //!@{ + + //! Parse JSON text from an input stream (with Encoding conversion) + /*! \tparam parseFlags Combination of \ref ParseFlag. + \tparam SourceEncoding Encoding of input stream + \tparam InputStream Type of input stream, implementing Stream concept + \param is Input stream to be parsed. + \return The document itself for fluent API. + */ + template + GenericDocument& ParseStream(InputStream& is) { + GenericReader reader( + stack_.HasAllocator() ? &stack_.GetAllocator() : 0); + ClearStackOnExit scope(*this); + parseResult_ = reader.template Parse(is, *this); + if (parseResult_) { + RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object + ValueType::operator=(*stack_.template Pop(1));// Move value from stack to document + } + return *this; + } + + //! Parse JSON text from an input stream + /*! \tparam parseFlags Combination of \ref ParseFlag. + \tparam InputStream Type of input stream, implementing Stream concept + \param is Input stream to be parsed. + \return The document itself for fluent API. + */ + template + GenericDocument& ParseStream(InputStream& is) { + return ParseStream(is); + } + + //! Parse JSON text from an input stream (with \ref kParseDefaultFlags) + /*! \tparam InputStream Type of input stream, implementing Stream concept + \param is Input stream to be parsed. + \return The document itself for fluent API. + */ + template + GenericDocument& ParseStream(InputStream& is) { + return ParseStream(is); + } + //!@} + + //!@name Parse in-place from mutable string + //!@{ + + //! Parse JSON text from a mutable string + /*! \tparam parseFlags Combination of \ref ParseFlag. + \param str Mutable zero-terminated string to be parsed. + \return The document itself for fluent API. + */ + template + GenericDocument& ParseInsitu(Ch* str) { + GenericInsituStringStream s(str); + return ParseStream(s); + } + + //! Parse JSON text from a mutable string (with \ref kParseDefaultFlags) + /*! \param str Mutable zero-terminated string to be parsed. + \return The document itself for fluent API. + */ + GenericDocument& ParseInsitu(Ch* str) { + return ParseInsitu(str); + } + //!@} + + //!@name Parse from read-only string + //!@{ + + //! Parse JSON text from a read-only string (with Encoding conversion) + /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag). + \tparam SourceEncoding Transcoding from input Encoding + \param str Read-only zero-terminated string to be parsed. + */ + template + GenericDocument& Parse(const typename SourceEncoding::Ch* str) { + RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); + GenericStringStream s(str); + return ParseStream(s); + } + + //! Parse JSON text from a read-only string + /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag). + \param str Read-only zero-terminated string to be parsed. + */ + template + GenericDocument& Parse(const Ch* str) { + return Parse(str); + } + + //! Parse JSON text from a read-only string (with \ref kParseDefaultFlags) + /*! \param str Read-only zero-terminated string to be parsed. + */ + GenericDocument& Parse(const Ch* str) { + return Parse(str); + } + + template + GenericDocument& Parse(const typename SourceEncoding::Ch* str, size_t length) { + RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); + MemoryStream ms(reinterpret_cast(str), length * sizeof(typename SourceEncoding::Ch)); + EncodedInputStream is(ms); + ParseStream(is); + return *this; + } + + template + GenericDocument& Parse(const Ch* str, size_t length) { + return Parse(str, length); + } + + GenericDocument& Parse(const Ch* str, size_t length) { + return Parse(str, length); + } + +#if RAPIDJSON_HAS_STDSTRING + template + GenericDocument& Parse(const std::basic_string& str) { + // c_str() is constant complexity according to standard. Should be faster than Parse(const char*, size_t) + return Parse(str.c_str()); + } + + template + GenericDocument& Parse(const std::basic_string& str) { + return Parse(str.c_str()); + } + + GenericDocument& Parse(const std::basic_string& str) { + return Parse(str); + } +#endif // RAPIDJSON_HAS_STDSTRING + + //!@} + + //!@name Handling parse errors + //!@{ + + //! Whether a parse error has occurred in the last parsing. + bool HasParseError() const { return parseResult_.IsError(); } + + //! Get the \ref ParseErrorCode of last parsing. + ParseErrorCode GetParseError() const { return parseResult_.Code(); } + + //! Get the position of last parsing error in input, 0 otherwise. + size_t GetErrorOffset() const { return parseResult_.Offset(); } + + //! Implicit conversion to get the last parse result +#ifndef __clang // -Wdocumentation + /*! \return \ref ParseResult of the last parse operation + + \code + Document doc; + ParseResult ok = doc.Parse(json); + if (!ok) + printf( "JSON parse error: %s (%u)\n", GetParseError_En(ok.Code()), ok.Offset()); + \endcode + */ +#endif + operator ParseResult() const { return parseResult_; } + //!@} + + //! Get the allocator of this document. + Allocator& GetAllocator() { + RAPIDJSON_ASSERT(allocator_); + return *allocator_; + } + + //! Get the capacity of stack in bytes. + size_t GetStackCapacity() const { return stack_.GetCapacity(); } + +private: + // clear stack on any exit from ParseStream, e.g. due to exception + struct ClearStackOnExit { + explicit ClearStackOnExit(GenericDocument& d) : d_(d) {} + ~ClearStackOnExit() { d_.ClearStack(); } + private: + ClearStackOnExit(const ClearStackOnExit&); + ClearStackOnExit& operator=(const ClearStackOnExit&); + GenericDocument& d_; + }; + + // callers of the following private Handler functions + // template friend class GenericReader; // for parsing + template friend class GenericValue; // for deep copying + +public: + // Implementation of Handler + bool Null() { new (stack_.template Push()) ValueType(); return true; } + bool Bool(bool b) { new (stack_.template Push()) ValueType(b); return true; } + bool Int(int i) { new (stack_.template Push()) ValueType(i); return true; } + bool Uint(unsigned i) { new (stack_.template Push()) ValueType(i); return true; } + bool Int64(int64_t i) { new (stack_.template Push()) ValueType(i); return true; } + bool Uint64(uint64_t i) { new (stack_.template Push()) ValueType(i); return true; } + bool Double(double d) { new (stack_.template Push()) ValueType(d); return true; } + + bool RawNumber(const Ch* str, SizeType length, bool copy) { + if (copy) + new (stack_.template Push()) ValueType(str, length, GetAllocator()); + else + new (stack_.template Push()) ValueType(str, length); + return true; + } + + bool String(const Ch* str, SizeType length, bool copy) { + if (copy) + new (stack_.template Push()) ValueType(str, length, GetAllocator()); + else + new (stack_.template Push()) ValueType(str, length); + return true; + } + + bool StartObject() { new (stack_.template Push()) ValueType(kObjectType); return true; } + + bool Key(const Ch* str, SizeType length, bool copy) { return String(str, length, copy); } + + bool EndObject(SizeType memberCount) { + typename ValueType::Member* members = stack_.template Pop(memberCount); + stack_.template Top()->SetObjectRaw(members, memberCount, GetAllocator()); + return true; + } + + bool StartArray() { new (stack_.template Push()) ValueType(kArrayType); return true; } + + bool EndArray(SizeType elementCount) { + ValueType* elements = stack_.template Pop(elementCount); + stack_.template Top()->SetArrayRaw(elements, elementCount, GetAllocator()); + return true; + } + +private: + //! Prohibit copying + GenericDocument(const GenericDocument&); + //! Prohibit assignment + GenericDocument& operator=(const GenericDocument&); + + void ClearStack() { + if (Allocator::kNeedFree) + while (stack_.GetSize() > 0) // Here assumes all elements in stack array are GenericValue (Member is actually 2 GenericValue objects) + (stack_.template Pop(1))->~ValueType(); + else + stack_.Clear(); + stack_.ShrinkToFit(); + } + + void Destroy() { + RAPIDJSON_DELETE(ownAllocator_); + } + + static const size_t kDefaultStackCapacity = 1024; + Allocator* allocator_; + Allocator* ownAllocator_; + internal::Stack stack_; + ParseResult parseResult_; +}; + +//! GenericDocument with UTF8 encoding +typedef GenericDocument > Document; + + +//! Helper class for accessing Value of array type. +/*! + Instance of this helper class is obtained by \c GenericValue::GetArray(). + In addition to all APIs for array type, it provides range-based for loop if \c RAPIDJSON_HAS_CXX11_RANGE_FOR=1. +*/ +template +class GenericArray { +public: + typedef GenericArray ConstArray; + typedef GenericArray Array; + typedef ValueT PlainType; + typedef typename internal::MaybeAddConst::Type ValueType; + typedef ValueType* ValueIterator; // This may be const or non-const iterator + typedef const ValueT* ConstValueIterator; + typedef typename ValueType::AllocatorType AllocatorType; + typedef typename ValueType::StringRefType StringRefType; + + template + friend class GenericValue; + + GenericArray(const GenericArray& rhs) : value_(rhs.value_) {} + GenericArray& operator=(const GenericArray& rhs) { value_ = rhs.value_; return *this; } + ~GenericArray() {} + + SizeType Size() const { return value_.Size(); } + SizeType Capacity() const { return value_.Capacity(); } + bool Empty() const { return value_.Empty(); } + void Clear() const { value_.Clear(); } + ValueType& operator[](SizeType index) const { return value_[index]; } + ValueIterator Begin() const { return value_.Begin(); } + ValueIterator End() const { return value_.End(); } + GenericArray Reserve(SizeType newCapacity, AllocatorType &allocator) const { value_.Reserve(newCapacity, allocator); return *this; } + GenericArray PushBack(ValueType& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + GenericArray PushBack(ValueType&& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } +#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS + GenericArray PushBack(StringRefType value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } + template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (const GenericArray&)) PushBack(T value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } + GenericArray PopBack() const { value_.PopBack(); return *this; } + ValueIterator Erase(ConstValueIterator pos) const { return value_.Erase(pos); } + ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) const { return value_.Erase(first, last); } + +#if RAPIDJSON_HAS_CXX11_RANGE_FOR + ValueIterator begin() const { return value_.Begin(); } + ValueIterator end() const { return value_.End(); } +#endif + +private: + GenericArray(); + GenericArray(ValueType& value) : value_(value) {} + ValueType& value_; +}; + +//! Helper class for accessing Value of object type. +/*! + Instance of this helper class is obtained by \c GenericValue::GetObject(). + In addition to all APIs for array type, it provides range-based for loop if \c RAPIDJSON_HAS_CXX11_RANGE_FOR=1. +*/ +template +class GenericObject { +public: + typedef GenericObject ConstObject; + typedef GenericObject Object; + typedef ValueT PlainType; + typedef typename internal::MaybeAddConst::Type ValueType; + typedef GenericMemberIterator MemberIterator; // This may be const or non-const iterator + typedef GenericMemberIterator ConstMemberIterator; + typedef typename ValueType::AllocatorType AllocatorType; + typedef typename ValueType::StringRefType StringRefType; + typedef typename ValueType::EncodingType EncodingType; + typedef typename ValueType::Ch Ch; + + template + friend class GenericValue; + + GenericObject(const GenericObject& rhs) : value_(rhs.value_) {} + GenericObject& operator=(const GenericObject& rhs) { value_ = rhs.value_; return *this; } + ~GenericObject() {} + + SizeType MemberCount() const { return value_.MemberCount(); } + SizeType MemberCapacity() const { return value_.MemberCapacity(); } + bool ObjectEmpty() const { return value_.ObjectEmpty(); } + template ValueType& operator[](T* name) const { return value_[name]; } + template ValueType& operator[](const GenericValue& name) const { return value_[name]; } +#if RAPIDJSON_HAS_STDSTRING + ValueType& operator[](const std::basic_string& name) const { return value_[name]; } +#endif + MemberIterator MemberBegin() const { return value_.MemberBegin(); } + MemberIterator MemberEnd() const { return value_.MemberEnd(); } + GenericObject MemberReserve(SizeType newCapacity, AllocatorType &allocator) const { value_.MemberReserve(newCapacity, allocator); return *this; } + bool HasMember(const Ch* name) const { return value_.HasMember(name); } +#if RAPIDJSON_HAS_STDSTRING + bool HasMember(const std::basic_string& name) const { return value_.HasMember(name); } +#endif + template bool HasMember(const GenericValue& name) const { return value_.HasMember(name); } + MemberIterator FindMember(const Ch* name) const { return value_.FindMember(name); } + template MemberIterator FindMember(const GenericValue& name) const { return value_.FindMember(name); } +#if RAPIDJSON_HAS_STDSTRING + MemberIterator FindMember(const std::basic_string& name) const { return value_.FindMember(name); } +#endif + GenericObject AddMember(ValueType& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } + GenericObject AddMember(ValueType& name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } +#if RAPIDJSON_HAS_STDSTRING + GenericObject AddMember(ValueType& name, std::basic_string& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } +#endif + template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) AddMember(ValueType& name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + GenericObject AddMember(ValueType&& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } + GenericObject AddMember(ValueType&& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } + GenericObject AddMember(ValueType& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } + GenericObject AddMember(StringRefType name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } +#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS + GenericObject AddMember(StringRefType name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } + GenericObject AddMember(StringRefType name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } + template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericObject)) AddMember(StringRefType name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } + void RemoveAllMembers() { value_.RemoveAllMembers(); } + bool RemoveMember(const Ch* name) const { return value_.RemoveMember(name); } +#if RAPIDJSON_HAS_STDSTRING + bool RemoveMember(const std::basic_string& name) const { return value_.RemoveMember(name); } +#endif + template bool RemoveMember(const GenericValue& name) const { return value_.RemoveMember(name); } + MemberIterator RemoveMember(MemberIterator m) const { return value_.RemoveMember(m); } + MemberIterator EraseMember(ConstMemberIterator pos) const { return value_.EraseMember(pos); } + MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) const { return value_.EraseMember(first, last); } + bool EraseMember(const Ch* name) const { return value_.EraseMember(name); } +#if RAPIDJSON_HAS_STDSTRING + bool EraseMember(const std::basic_string& name) const { return EraseMember(ValueType(StringRef(name))); } +#endif + template bool EraseMember(const GenericValue& name) const { return value_.EraseMember(name); } + +#if RAPIDJSON_HAS_CXX11_RANGE_FOR + MemberIterator begin() const { return value_.MemberBegin(); } + MemberIterator end() const { return value_.MemberEnd(); } +#endif + +private: + GenericObject(); + GenericObject(ValueType& value) : value_(value) {} + ValueType& value_; +}; + +RAPIDJSON_NAMESPACE_END +RAPIDJSON_DIAG_POP + +#endif // RAPIDJSON_DOCUMENT_H_ diff --git a/src/include/rapidjson/encodedstream.h b/src/include/rapidjson/encodedstream.h new file mode 100755 index 0000000..223601c --- /dev/null +++ b/src/include/rapidjson/encodedstream.h @@ -0,0 +1,299 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_ENCODEDSTREAM_H_ +#define RAPIDJSON_ENCODEDSTREAM_H_ + +#include "stream.h" +#include "memorystream.h" + +#ifdef __GNUC__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#endif + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! Input byte stream wrapper with a statically bound encoding. +/*! + \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE. + \tparam InputByteStream Type of input byte stream. For example, FileReadStream. +*/ +template +class EncodedInputStream { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); +public: + typedef typename Encoding::Ch Ch; + + EncodedInputStream(InputByteStream& is) : is_(is) { + current_ = Encoding::TakeBOM(is_); + } + + Ch Peek() const { return current_; } + Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; } + size_t Tell() const { return is_.Tell(); } + + // Not implemented + void Put(Ch) { RAPIDJSON_ASSERT(false); } + void Flush() { RAPIDJSON_ASSERT(false); } + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + +private: + EncodedInputStream(const EncodedInputStream&); + EncodedInputStream& operator=(const EncodedInputStream&); + + InputByteStream& is_; + Ch current_; +}; + +//! Specialized for UTF8 MemoryStream. +template <> +class EncodedInputStream, MemoryStream> { +public: + typedef UTF8<>::Ch Ch; + + EncodedInputStream(MemoryStream& is) : is_(is) { + if (static_cast(is_.Peek()) == 0xEFu) is_.Take(); + if (static_cast(is_.Peek()) == 0xBBu) is_.Take(); + if (static_cast(is_.Peek()) == 0xBFu) is_.Take(); + } + Ch Peek() const { return is_.Peek(); } + Ch Take() { return is_.Take(); } + size_t Tell() const { return is_.Tell(); } + + // Not implemented + void Put(Ch) {} + void Flush() {} + Ch* PutBegin() { return 0; } + size_t PutEnd(Ch*) { return 0; } + + MemoryStream& is_; + +private: + EncodedInputStream(const EncodedInputStream&); + EncodedInputStream& operator=(const EncodedInputStream&); +}; + +//! Output byte stream wrapper with statically bound encoding. +/*! + \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE. + \tparam OutputByteStream Type of input byte stream. For example, FileWriteStream. +*/ +template +class EncodedOutputStream { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); +public: + typedef typename Encoding::Ch Ch; + + EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) { + if (putBOM) + Encoding::PutBOM(os_); + } + + void Put(Ch c) { Encoding::Put(os_, c); } + void Flush() { os_.Flush(); } + + // Not implemented + Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;} + Ch Take() { RAPIDJSON_ASSERT(false); return 0;} + size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + +private: + EncodedOutputStream(const EncodedOutputStream&); + EncodedOutputStream& operator=(const EncodedOutputStream&); + + OutputByteStream& os_; +}; + +#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8::x, UTF16LE::x, UTF16BE::x, UTF32LE::x, UTF32BE::x + +//! Input stream wrapper with dynamically bound encoding and automatic encoding detection. +/*! + \tparam CharType Type of character for reading. + \tparam InputByteStream type of input byte stream to be wrapped. +*/ +template +class AutoUTFInputStream { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); +public: + typedef CharType Ch; + + //! Constructor. + /*! + \param is input stream to be wrapped. + \param type UTF encoding type if it is not detected from the stream. + */ + AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) { + RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE); + DetectType(); + static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) }; + takeFunc_ = f[type_]; + current_ = takeFunc_(*is_); + } + + UTFType GetType() const { return type_; } + bool HasBOM() const { return hasBOM_; } + + Ch Peek() const { return current_; } + Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; } + size_t Tell() const { return is_->Tell(); } + + // Not implemented + void Put(Ch) { RAPIDJSON_ASSERT(false); } + void Flush() { RAPIDJSON_ASSERT(false); } + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + +private: + AutoUTFInputStream(const AutoUTFInputStream&); + AutoUTFInputStream& operator=(const AutoUTFInputStream&); + + // Detect encoding type with BOM or RFC 4627 + void DetectType() { + // BOM (Byte Order Mark): + // 00 00 FE FF UTF-32BE + // FF FE 00 00 UTF-32LE + // FE FF UTF-16BE + // FF FE UTF-16LE + // EF BB BF UTF-8 + + const unsigned char* c = reinterpret_cast(is_->Peek4()); + if (!c) + return; + + unsigned bom = static_cast(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24)); + hasBOM_ = false; + if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } + else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } + else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take(); } + else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take(); } + else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); } + + // RFC 4627: Section 3 + // "Since the first two characters of a JSON text will always be ASCII + // characters [RFC0020], it is possible to determine whether an octet + // stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking + // at the pattern of nulls in the first four octets." + // 00 00 00 xx UTF-32BE + // 00 xx 00 xx UTF-16BE + // xx 00 00 00 UTF-32LE + // xx 00 xx 00 UTF-16LE + // xx xx xx xx UTF-8 + + if (!hasBOM_) { + int pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0); + switch (pattern) { + case 0x08: type_ = kUTF32BE; break; + case 0x0A: type_ = kUTF16BE; break; + case 0x01: type_ = kUTF32LE; break; + case 0x05: type_ = kUTF16LE; break; + case 0x0F: type_ = kUTF8; break; + default: break; // Use type defined by user. + } + } + + // Runtime check whether the size of character type is sufficient. It only perform checks with assertion. + if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2); + if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4); + } + + typedef Ch (*TakeFunc)(InputByteStream& is); + InputByteStream* is_; + UTFType type_; + Ch current_; + TakeFunc takeFunc_; + bool hasBOM_; +}; + +//! Output stream wrapper with dynamically bound encoding and automatic encoding detection. +/*! + \tparam CharType Type of character for writing. + \tparam OutputByteStream type of output byte stream to be wrapped. +*/ +template +class AutoUTFOutputStream { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); +public: + typedef CharType Ch; + + //! Constructor. + /*! + \param os output stream to be wrapped. + \param type UTF encoding type. + \param putBOM Whether to write BOM at the beginning of the stream. + */ + AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) { + RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE); + + // Runtime check whether the size of character type is sufficient. It only perform checks with assertion. + if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2); + if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4); + + static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) }; + putFunc_ = f[type_]; + + if (putBOM) + PutBOM(); + } + + UTFType GetType() const { return type_; } + + void Put(Ch c) { putFunc_(*os_, c); } + void Flush() { os_->Flush(); } + + // Not implemented + Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;} + Ch Take() { RAPIDJSON_ASSERT(false); return 0;} + size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + +private: + AutoUTFOutputStream(const AutoUTFOutputStream&); + AutoUTFOutputStream& operator=(const AutoUTFOutputStream&); + + void PutBOM() { + typedef void (*PutBOMFunc)(OutputByteStream&); + static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) }; + f[type_](*os_); + } + + typedef void (*PutFunc)(OutputByteStream&, Ch); + + OutputByteStream* os_; + UTFType type_; + PutFunc putFunc_; +}; + +#undef RAPIDJSON_ENCODINGS_FUNC + +RAPIDJSON_NAMESPACE_END + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +#ifdef __GNUC__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_FILESTREAM_H_ diff --git a/src/include/rapidjson/encodings.h b/src/include/rapidjson/encodings.h new file mode 100755 index 0000000..0b24467 --- /dev/null +++ b/src/include/rapidjson/encodings.h @@ -0,0 +1,716 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_ENCODINGS_H_ +#define RAPIDJSON_ENCODINGS_H_ + +#include "rapidjson.h" + +#if defined(_MSC_VER) && !defined(__clang__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data +RAPIDJSON_DIAG_OFF(4702) // unreachable code +#elif defined(__GNUC__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +RAPIDJSON_DIAG_OFF(overflow) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// Encoding + +/*! \class rapidjson::Encoding + \brief Concept for encoding of Unicode characters. + +\code +concept Encoding { + typename Ch; //! Type of character. A "character" is actually a code unit in unicode's definition. + + enum { supportUnicode = 1 }; // or 0 if not supporting unicode + + //! \brief Encode a Unicode codepoint to an output stream. + //! \param os Output stream. + //! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively. + template + static void Encode(OutputStream& os, unsigned codepoint); + + //! \brief Decode a Unicode codepoint from an input stream. + //! \param is Input stream. + //! \param codepoint Output of the unicode codepoint. + //! \return true if a valid codepoint can be decoded from the stream. + template + static bool Decode(InputStream& is, unsigned* codepoint); + + //! \brief Validate one Unicode codepoint from an encoded stream. + //! \param is Input stream to obtain codepoint. + //! \param os Output for copying one codepoint. + //! \return true if it is valid. + //! \note This function just validating and copying the codepoint without actually decode it. + template + static bool Validate(InputStream& is, OutputStream& os); + + // The following functions are deal with byte streams. + + //! Take a character from input byte stream, skip BOM if exist. + template + static CharType TakeBOM(InputByteStream& is); + + //! Take a character from input byte stream. + template + static Ch Take(InputByteStream& is); + + //! Put BOM to output byte stream. + template + static void PutBOM(OutputByteStream& os); + + //! Put a character to output byte stream. + template + static void Put(OutputByteStream& os, Ch c); +}; +\endcode +*/ + +/////////////////////////////////////////////////////////////////////////////// +// UTF8 + +//! UTF-8 encoding. +/*! http://en.wikipedia.org/wiki/UTF-8 + http://tools.ietf.org/html/rfc3629 + \tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char. + \note implements Encoding concept +*/ +template +struct UTF8 { + typedef CharType Ch; + + enum { supportUnicode = 1 }; + + template + static void Encode(OutputStream& os, unsigned codepoint) { + if (codepoint <= 0x7F) + os.Put(static_cast(codepoint & 0xFF)); + else if (codepoint <= 0x7FF) { + os.Put(static_cast(0xC0 | ((codepoint >> 6) & 0xFF))); + os.Put(static_cast(0x80 | ((codepoint & 0x3F)))); + } + else if (codepoint <= 0xFFFF) { + os.Put(static_cast(0xE0 | ((codepoint >> 12) & 0xFF))); + os.Put(static_cast(0x80 | ((codepoint >> 6) & 0x3F))); + os.Put(static_cast(0x80 | (codepoint & 0x3F))); + } + else { + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + os.Put(static_cast(0xF0 | ((codepoint >> 18) & 0xFF))); + os.Put(static_cast(0x80 | ((codepoint >> 12) & 0x3F))); + os.Put(static_cast(0x80 | ((codepoint >> 6) & 0x3F))); + os.Put(static_cast(0x80 | (codepoint & 0x3F))); + } + } + + template + static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { + if (codepoint <= 0x7F) + PutUnsafe(os, static_cast(codepoint & 0xFF)); + else if (codepoint <= 0x7FF) { + PutUnsafe(os, static_cast(0xC0 | ((codepoint >> 6) & 0xFF))); + PutUnsafe(os, static_cast(0x80 | ((codepoint & 0x3F)))); + } + else if (codepoint <= 0xFFFF) { + PutUnsafe(os, static_cast(0xE0 | ((codepoint >> 12) & 0xFF))); + PutUnsafe(os, static_cast(0x80 | ((codepoint >> 6) & 0x3F))); + PutUnsafe(os, static_cast(0x80 | (codepoint & 0x3F))); + } + else { + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + PutUnsafe(os, static_cast(0xF0 | ((codepoint >> 18) & 0xFF))); + PutUnsafe(os, static_cast(0x80 | ((codepoint >> 12) & 0x3F))); + PutUnsafe(os, static_cast(0x80 | ((codepoint >> 6) & 0x3F))); + PutUnsafe(os, static_cast(0x80 | (codepoint & 0x3F))); + } + } + + template + static bool Decode(InputStream& is, unsigned* codepoint) { +#define RAPIDJSON_COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast(c) & 0x3Fu) +#define RAPIDJSON_TRANS(mask) result &= ((GetRange(static_cast(c)) & mask) != 0) +#define RAPIDJSON_TAIL() RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x70) + typename InputStream::Ch c = is.Take(); + if (!(c & 0x80)) { + *codepoint = static_cast(c); + return true; + } + + unsigned char type = GetRange(static_cast(c)); + if (type >= 32) { + *codepoint = 0; + } else { + *codepoint = (0xFFu >> type) & static_cast(c); + } + bool result = true; + switch (type) { + case 2: RAPIDJSON_TAIL(); return result; + case 3: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; + case 4: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x50); RAPIDJSON_TAIL(); return result; + case 5: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x10); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; + case 6: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; + case 10: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x20); RAPIDJSON_TAIL(); return result; + case 11: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x60); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; + default: return false; + } +#undef RAPIDJSON_COPY +#undef RAPIDJSON_TRANS +#undef RAPIDJSON_TAIL + } + + template + static bool Validate(InputStream& is, OutputStream& os) { +#define RAPIDJSON_COPY() os.Put(c = is.Take()) +#define RAPIDJSON_TRANS(mask) result &= ((GetRange(static_cast(c)) & mask) != 0) +#define RAPIDJSON_TAIL() RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x70) + Ch c; + RAPIDJSON_COPY(); + if (!(c & 0x80)) + return true; + + bool result = true; + switch (GetRange(static_cast(c))) { + case 2: RAPIDJSON_TAIL(); return result; + case 3: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; + case 4: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x50); RAPIDJSON_TAIL(); return result; + case 5: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x10); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; + case 6: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; + case 10: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x20); RAPIDJSON_TAIL(); return result; + case 11: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x60); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; + default: return false; + } +#undef RAPIDJSON_COPY +#undef RAPIDJSON_TRANS +#undef RAPIDJSON_TAIL + } + + static unsigned char GetRange(unsigned char c) { + // Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ + // With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types. + static const unsigned char type[] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, + 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, + 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8, + }; + return type[c]; + } + + template + static CharType TakeBOM(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + typename InputByteStream::Ch c = Take(is); + if (static_cast(c) != 0xEFu) return c; + c = is.Take(); + if (static_cast(c) != 0xBBu) return c; + c = is.Take(); + if (static_cast(c) != 0xBFu) return c; + c = is.Take(); + return c; + } + + template + static Ch Take(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + return static_cast(is.Take()); + } + + template + static void PutBOM(OutputByteStream& os) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast(0xEFu)); + os.Put(static_cast(0xBBu)); + os.Put(static_cast(0xBFu)); + } + + template + static void Put(OutputByteStream& os, Ch c) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast(c)); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// UTF16 + +//! UTF-16 encoding. +/*! http://en.wikipedia.org/wiki/UTF-16 + http://tools.ietf.org/html/rfc2781 + \tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead. + \note implements Encoding concept + + \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness. + For streaming, use UTF16LE and UTF16BE, which handle endianness. +*/ +template +struct UTF16 { + typedef CharType Ch; + RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2); + + enum { supportUnicode = 1 }; + + template + static void Encode(OutputStream& os, unsigned codepoint) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); + if (codepoint <= 0xFFFF) { + RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair + os.Put(static_cast(codepoint)); + } + else { + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + unsigned v = codepoint - 0x10000; + os.Put(static_cast((v >> 10) | 0xD800)); + os.Put(static_cast((v & 0x3FF) | 0xDC00)); + } + } + + + template + static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); + if (codepoint <= 0xFFFF) { + RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair + PutUnsafe(os, static_cast(codepoint)); + } + else { + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + unsigned v = codepoint - 0x10000; + PutUnsafe(os, static_cast((v >> 10) | 0xD800)); + PutUnsafe(os, static_cast((v & 0x3FF) | 0xDC00)); + } + } + + template + static bool Decode(InputStream& is, unsigned* codepoint) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); + typename InputStream::Ch c = is.Take(); + if (c < 0xD800 || c > 0xDFFF) { + *codepoint = static_cast(c); + return true; + } + else if (c <= 0xDBFF) { + *codepoint = (static_cast(c) & 0x3FF) << 10; + c = is.Take(); + *codepoint |= (static_cast(c) & 0x3FF); + *codepoint += 0x10000; + return c >= 0xDC00 && c <= 0xDFFF; + } + return false; + } + + template + static bool Validate(InputStream& is, OutputStream& os) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); + typename InputStream::Ch c; + os.Put(static_cast(c = is.Take())); + if (c < 0xD800 || c > 0xDFFF) + return true; + else if (c <= 0xDBFF) { + os.Put(c = is.Take()); + return c >= 0xDC00 && c <= 0xDFFF; + } + return false; + } +}; + +//! UTF-16 little endian encoding. +template +struct UTF16LE : UTF16 { + template + static CharType TakeBOM(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + CharType c = Take(is); + return static_cast(c) == 0xFEFFu ? Take(is) : c; + } + + template + static CharType Take(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + unsigned c = static_cast(is.Take()); + c |= static_cast(static_cast(is.Take())) << 8; + return static_cast(c); + } + + template + static void PutBOM(OutputByteStream& os) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast(0xFFu)); + os.Put(static_cast(0xFEu)); + } + + template + static void Put(OutputByteStream& os, CharType c) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast(static_cast(c) & 0xFFu)); + os.Put(static_cast((static_cast(c) >> 8) & 0xFFu)); + } +}; + +//! UTF-16 big endian encoding. +template +struct UTF16BE : UTF16 { + template + static CharType TakeBOM(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + CharType c = Take(is); + return static_cast(c) == 0xFEFFu ? Take(is) : c; + } + + template + static CharType Take(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + unsigned c = static_cast(static_cast(is.Take())) << 8; + c |= static_cast(static_cast(is.Take())); + return static_cast(c); + } + + template + static void PutBOM(OutputByteStream& os) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast(0xFEu)); + os.Put(static_cast(0xFFu)); + } + + template + static void Put(OutputByteStream& os, CharType c) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast((static_cast(c) >> 8) & 0xFFu)); + os.Put(static_cast(static_cast(c) & 0xFFu)); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// UTF32 + +//! UTF-32 encoding. +/*! http://en.wikipedia.org/wiki/UTF-32 + \tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead. + \note implements Encoding concept + + \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness. + For streaming, use UTF32LE and UTF32BE, which handle endianness. +*/ +template +struct UTF32 { + typedef CharType Ch; + RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4); + + enum { supportUnicode = 1 }; + + template + static void Encode(OutputStream& os, unsigned codepoint) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4); + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + os.Put(codepoint); + } + + template + static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4); + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + PutUnsafe(os, codepoint); + } + + template + static bool Decode(InputStream& is, unsigned* codepoint) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4); + Ch c = is.Take(); + *codepoint = c; + return c <= 0x10FFFF; + } + + template + static bool Validate(InputStream& is, OutputStream& os) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4); + Ch c; + os.Put(c = is.Take()); + return c <= 0x10FFFF; + } +}; + +//! UTF-32 little endian enocoding. +template +struct UTF32LE : UTF32 { + template + static CharType TakeBOM(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + CharType c = Take(is); + return static_cast(c) == 0x0000FEFFu ? Take(is) : c; + } + + template + static CharType Take(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + unsigned c = static_cast(is.Take()); + c |= static_cast(static_cast(is.Take())) << 8; + c |= static_cast(static_cast(is.Take())) << 16; + c |= static_cast(static_cast(is.Take())) << 24; + return static_cast(c); + } + + template + static void PutBOM(OutputByteStream& os) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast(0xFFu)); + os.Put(static_cast(0xFEu)); + os.Put(static_cast(0x00u)); + os.Put(static_cast(0x00u)); + } + + template + static void Put(OutputByteStream& os, CharType c) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast(c & 0xFFu)); + os.Put(static_cast((c >> 8) & 0xFFu)); + os.Put(static_cast((c >> 16) & 0xFFu)); + os.Put(static_cast((c >> 24) & 0xFFu)); + } +}; + +//! UTF-32 big endian encoding. +template +struct UTF32BE : UTF32 { + template + static CharType TakeBOM(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + CharType c = Take(is); + return static_cast(c) == 0x0000FEFFu ? Take(is) : c; + } + + template + static CharType Take(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + unsigned c = static_cast(static_cast(is.Take())) << 24; + c |= static_cast(static_cast(is.Take())) << 16; + c |= static_cast(static_cast(is.Take())) << 8; + c |= static_cast(static_cast(is.Take())); + return static_cast(c); + } + + template + static void PutBOM(OutputByteStream& os) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast(0x00u)); + os.Put(static_cast(0x00u)); + os.Put(static_cast(0xFEu)); + os.Put(static_cast(0xFFu)); + } + + template + static void Put(OutputByteStream& os, CharType c) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast((c >> 24) & 0xFFu)); + os.Put(static_cast((c >> 16) & 0xFFu)); + os.Put(static_cast((c >> 8) & 0xFFu)); + os.Put(static_cast(c & 0xFFu)); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// ASCII + +//! ASCII encoding. +/*! http://en.wikipedia.org/wiki/ASCII + \tparam CharType Code unit for storing 7-bit ASCII data. Default is char. + \note implements Encoding concept +*/ +template +struct ASCII { + typedef CharType Ch; + + enum { supportUnicode = 0 }; + + template + static void Encode(OutputStream& os, unsigned codepoint) { + RAPIDJSON_ASSERT(codepoint <= 0x7F); + os.Put(static_cast(codepoint & 0xFF)); + } + + template + static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { + RAPIDJSON_ASSERT(codepoint <= 0x7F); + PutUnsafe(os, static_cast(codepoint & 0xFF)); + } + + template + static bool Decode(InputStream& is, unsigned* codepoint) { + uint8_t c = static_cast(is.Take()); + *codepoint = c; + return c <= 0X7F; + } + + template + static bool Validate(InputStream& is, OutputStream& os) { + uint8_t c = static_cast(is.Take()); + os.Put(static_cast(c)); + return c <= 0x7F; + } + + template + static CharType TakeBOM(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + uint8_t c = static_cast(Take(is)); + return static_cast(c); + } + + template + static Ch Take(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + return static_cast(is.Take()); + } + + template + static void PutBOM(OutputByteStream& os) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + (void)os; + } + + template + static void Put(OutputByteStream& os, Ch c) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast(c)); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// AutoUTF + +//! Runtime-specified UTF encoding type of a stream. +enum UTFType { + kUTF8 = 0, //!< UTF-8. + kUTF16LE = 1, //!< UTF-16 little endian. + kUTF16BE = 2, //!< UTF-16 big endian. + kUTF32LE = 3, //!< UTF-32 little endian. + kUTF32BE = 4 //!< UTF-32 big endian. +}; + +//! Dynamically select encoding according to stream's runtime-specified UTF encoding type. +/*! \note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType(). +*/ +template +struct AutoUTF { + typedef CharType Ch; + + enum { supportUnicode = 1 }; + +#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8::x, UTF16LE::x, UTF16BE::x, UTF32LE::x, UTF32BE::x + + template + static RAPIDJSON_FORCEINLINE void Encode(OutputStream& os, unsigned codepoint) { + typedef void (*EncodeFunc)(OutputStream&, unsigned); + static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) }; + (*f[os.GetType()])(os, codepoint); + } + + template + static RAPIDJSON_FORCEINLINE void EncodeUnsafe(OutputStream& os, unsigned codepoint) { + typedef void (*EncodeFunc)(OutputStream&, unsigned); + static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(EncodeUnsafe) }; + (*f[os.GetType()])(os, codepoint); + } + + template + static RAPIDJSON_FORCEINLINE bool Decode(InputStream& is, unsigned* codepoint) { + typedef bool (*DecodeFunc)(InputStream&, unsigned*); + static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) }; + return (*f[is.GetType()])(is, codepoint); + } + + template + static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) { + typedef bool (*ValidateFunc)(InputStream&, OutputStream&); + static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) }; + return (*f[is.GetType()])(is, os); + } + +#undef RAPIDJSON_ENCODINGS_FUNC +}; + +/////////////////////////////////////////////////////////////////////////////// +// Transcoder + +//! Encoding conversion. +template +struct Transcoder { + //! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream. + template + static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) { + unsigned codepoint; + if (!SourceEncoding::Decode(is, &codepoint)) + return false; + TargetEncoding::Encode(os, codepoint); + return true; + } + + template + static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) { + unsigned codepoint; + if (!SourceEncoding::Decode(is, &codepoint)) + return false; + TargetEncoding::EncodeUnsafe(os, codepoint); + return true; + } + + //! Validate one Unicode codepoint from an encoded stream. + template + static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) { + return Transcode(is, os); // Since source/target encoding is different, must transcode. + } +}; + +// Forward declaration. +template +inline void PutUnsafe(Stream& stream, typename Stream::Ch c); + +//! Specialization of Transcoder with same source and target encoding. +template +struct Transcoder { + template + static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) { + os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class. + return true; + } + + template + static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) { + PutUnsafe(os, is.Take()); // Just copy one code unit. This semantic is different from primary template class. + return true; + } + + template + static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) { + return Encoding::Validate(is, os); // source/target encoding are the same + } +}; + +RAPIDJSON_NAMESPACE_END + +#if defined(__GNUC__) || (defined(_MSC_VER) && !defined(__clang__)) +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_ENCODINGS_H_ diff --git a/src/include/rapidjson/error/en.h b/src/include/rapidjson/error/en.h new file mode 100755 index 0000000..2db838b --- /dev/null +++ b/src/include/rapidjson/error/en.h @@ -0,0 +1,74 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_ERROR_EN_H_ +#define RAPIDJSON_ERROR_EN_H_ + +#include "error.h" + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(switch-enum) +RAPIDJSON_DIAG_OFF(covered-switch-default) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! Maps error code of parsing into error message. +/*! + \ingroup RAPIDJSON_ERRORS + \param parseErrorCode Error code obtained in parsing. + \return the error message. + \note User can make a copy of this function for localization. + Using switch-case is safer for future modification of error codes. +*/ +inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) { + switch (parseErrorCode) { + case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error."); + + case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty."); + case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values."); + + case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value."); + + case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member."); + case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member."); + case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member."); + + case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element."); + + case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string."); + case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid."); + case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string."); + case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string."); + case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string."); + + case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double."); + case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number."); + case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number."); + + case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error."); + case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error."); + + default: return RAPIDJSON_ERROR_STRING("Unknown error."); + } +} + +RAPIDJSON_NAMESPACE_END + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_ERROR_EN_H_ diff --git a/src/include/rapidjson/error/error.h b/src/include/rapidjson/error/error.h new file mode 100755 index 0000000..9311d2f --- /dev/null +++ b/src/include/rapidjson/error/error.h @@ -0,0 +1,161 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_ERROR_ERROR_H_ +#define RAPIDJSON_ERROR_ERROR_H_ + +#include "../rapidjson.h" + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +#endif + +/*! \file error.h */ + +/*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */ + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_ERROR_CHARTYPE + +//! Character type of error messages. +/*! \ingroup RAPIDJSON_ERRORS + The default character type is \c char. + On Windows, user can define this macro as \c TCHAR for supporting both + unicode/non-unicode settings. +*/ +#ifndef RAPIDJSON_ERROR_CHARTYPE +#define RAPIDJSON_ERROR_CHARTYPE char +#endif + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_ERROR_STRING + +//! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[]. +/*! \ingroup RAPIDJSON_ERRORS + By default this conversion macro does nothing. + On Windows, user can define this macro as \c _T(x) for supporting both + unicode/non-unicode settings. +*/ +#ifndef RAPIDJSON_ERROR_STRING +#define RAPIDJSON_ERROR_STRING(x) x +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// ParseErrorCode + +//! Error code of parsing. +/*! \ingroup RAPIDJSON_ERRORS + \see GenericReader::Parse, GenericReader::GetParseErrorCode +*/ +enum ParseErrorCode { + kParseErrorNone = 0, //!< No error. + + kParseErrorDocumentEmpty, //!< The document is empty. + kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values. + + kParseErrorValueInvalid, //!< Invalid value. + + kParseErrorObjectMissName, //!< Missing a name for object member. + kParseErrorObjectMissColon, //!< Missing a colon after a name of object member. + kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member. + + kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element. + + kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string. + kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid. + kParseErrorStringEscapeInvalid, //!< Invalid escape character in string. + kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string. + kParseErrorStringInvalidEncoding, //!< Invalid encoding in string. + + kParseErrorNumberTooBig, //!< Number too big to be stored in double. + kParseErrorNumberMissFraction, //!< Miss fraction part in number. + kParseErrorNumberMissExponent, //!< Miss exponent in number. + + kParseErrorTermination, //!< Parsing was terminated. + kParseErrorUnspecificSyntaxError //!< Unspecific syntax error. +}; + +//! Result of parsing (wraps ParseErrorCode) +/*! + \ingroup RAPIDJSON_ERRORS + \code + Document doc; + ParseResult ok = doc.Parse("[42]"); + if (!ok) { + fprintf(stderr, "JSON parse error: %s (%u)", + GetParseError_En(ok.Code()), ok.Offset()); + exit(EXIT_FAILURE); + } + \endcode + \see GenericReader::Parse, GenericDocument::Parse +*/ +struct ParseResult { + //!! Unspecified boolean type + typedef bool (ParseResult::*BooleanType)() const; +public: + //! Default constructor, no error. + ParseResult() : code_(kParseErrorNone), offset_(0) {} + //! Constructor to set an error. + ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {} + + //! Get the error code. + ParseErrorCode Code() const { return code_; } + //! Get the error offset, if \ref IsError(), 0 otherwise. + size_t Offset() const { return offset_; } + + //! Explicit conversion to \c bool, returns \c true, iff !\ref IsError(). + operator BooleanType() const { return !IsError() ? &ParseResult::IsError : NULL; } + //! Whether the result is an error. + bool IsError() const { return code_ != kParseErrorNone; } + + bool operator==(const ParseResult& that) const { return code_ == that.code_; } + bool operator==(ParseErrorCode code) const { return code_ == code; } + friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; } + + bool operator!=(const ParseResult& that) const { return !(*this == that); } + bool operator!=(ParseErrorCode code) const { return !(*this == code); } + friend bool operator!=(ParseErrorCode code, const ParseResult & err) { return err != code; } + + //! Reset error code. + void Clear() { Set(kParseErrorNone); } + //! Update error code and offset. + void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; } + +private: + ParseErrorCode code_; + size_t offset_; +}; + +//! Function pointer type of GetParseError(). +/*! \ingroup RAPIDJSON_ERRORS + + This is the prototype for \c GetParseError_X(), where \c X is a locale. + User can dynamically change locale in runtime, e.g.: +\code + GetParseErrorFunc GetParseError = GetParseError_En; // or whatever + const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode()); +\endcode +*/ +typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode); + +RAPIDJSON_NAMESPACE_END + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_ERROR_ERROR_H_ diff --git a/src/include/rapidjson/filereadstream.h b/src/include/rapidjson/filereadstream.h new file mode 100755 index 0000000..6b34370 --- /dev/null +++ b/src/include/rapidjson/filereadstream.h @@ -0,0 +1,99 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_FILEREADSTREAM_H_ +#define RAPIDJSON_FILEREADSTREAM_H_ + +#include "stream.h" +#include + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +RAPIDJSON_DIAG_OFF(unreachable-code) +RAPIDJSON_DIAG_OFF(missing-noreturn) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! File byte stream for input using fread(). +/*! + \note implements Stream concept +*/ +class FileReadStream { +public: + typedef char Ch; //!< Character type (byte). + + //! Constructor. + /*! + \param fp File pointer opened for read. + \param buffer user-supplied buffer. + \param bufferSize size of buffer in bytes. Must >=4 bytes. + */ + FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { + RAPIDJSON_ASSERT(fp_ != 0); + RAPIDJSON_ASSERT(bufferSize >= 4); + Read(); + } + + Ch Peek() const { return *current_; } + Ch Take() { Ch c = *current_; Read(); return c; } + size_t Tell() const { return count_ + static_cast(current_ - buffer_); } + + // Not implemented + void Put(Ch) { RAPIDJSON_ASSERT(false); } + void Flush() { RAPIDJSON_ASSERT(false); } + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + + // For encoding detection only. + const Ch* Peek4() const { + return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0; + } + +private: + void Read() { + if (current_ < bufferLast_) + ++current_; + else if (!eof_) { + count_ += readCount_; + readCount_ = std::fread(buffer_, 1, bufferSize_, fp_); + bufferLast_ = buffer_ + readCount_ - 1; + current_ = buffer_; + + if (readCount_ < bufferSize_) { + buffer_[readCount_] = '\0'; + ++bufferLast_; + eof_ = true; + } + } + } + + std::FILE* fp_; + Ch *buffer_; + size_t bufferSize_; + Ch *bufferLast_; + Ch *current_; + size_t readCount_; + size_t count_; //!< Number of characters read + bool eof_; +}; + +RAPIDJSON_NAMESPACE_END + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_FILESTREAM_H_ diff --git a/src/include/rapidjson/filewritestream.h b/src/include/rapidjson/filewritestream.h new file mode 100755 index 0000000..8b48fee --- /dev/null +++ b/src/include/rapidjson/filewritestream.h @@ -0,0 +1,104 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_FILEWRITESTREAM_H_ +#define RAPIDJSON_FILEWRITESTREAM_H_ + +#include "stream.h" +#include + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(unreachable-code) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! Wrapper of C file stream for output using fwrite(). +/*! + \note implements Stream concept +*/ +class FileWriteStream { +public: + typedef char Ch; //!< Character type. Only support char. + + FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) { + RAPIDJSON_ASSERT(fp_ != 0); + } + + void Put(char c) { + if (current_ >= bufferEnd_) + Flush(); + + *current_++ = c; + } + + void PutN(char c, size_t n) { + size_t avail = static_cast(bufferEnd_ - current_); + while (n > avail) { + std::memset(current_, c, avail); + current_ += avail; + Flush(); + n -= avail; + avail = static_cast(bufferEnd_ - current_); + } + + if (n > 0) { + std::memset(current_, c, n); + current_ += n; + } + } + + void Flush() { + if (current_ != buffer_) { + size_t result = std::fwrite(buffer_, 1, static_cast(current_ - buffer_), fp_); + if (result < static_cast(current_ - buffer_)) { + // failure deliberately ignored at this time + // added to avoid warn_unused_result build errors + } + current_ = buffer_; + } + } + + // Not implemented + char Peek() const { RAPIDJSON_ASSERT(false); return 0; } + char Take() { RAPIDJSON_ASSERT(false); return 0; } + size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } + char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } + +private: + // Prohibit copy constructor & assignment operator. + FileWriteStream(const FileWriteStream&); + FileWriteStream& operator=(const FileWriteStream&); + + std::FILE* fp_; + char *buffer_; + char *bufferEnd_; + char *current_; +}; + +//! Implement specialized version of PutN() with memset() for better performance. +template<> +inline void PutN(FileWriteStream& stream, char c, size_t n) { + stream.PutN(c, n); +} + +RAPIDJSON_NAMESPACE_END + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_FILESTREAM_H_ diff --git a/src/include/rapidjson/fwd.h b/src/include/rapidjson/fwd.h new file mode 100755 index 0000000..b74a2b8 --- /dev/null +++ b/src/include/rapidjson/fwd.h @@ -0,0 +1,151 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_FWD_H_ +#define RAPIDJSON_FWD_H_ + +#include "rapidjson.h" + +RAPIDJSON_NAMESPACE_BEGIN + +// encodings.h + +template struct UTF8; +template struct UTF16; +template struct UTF16BE; +template struct UTF16LE; +template struct UTF32; +template struct UTF32BE; +template struct UTF32LE; +template struct ASCII; +template struct AutoUTF; + +template +struct Transcoder; + +// allocators.h + +class CrtAllocator; + +template +class MemoryPoolAllocator; + +// stream.h + +template +struct GenericStringStream; + +typedef GenericStringStream > StringStream; + +template +struct GenericInsituStringStream; + +typedef GenericInsituStringStream > InsituStringStream; + +// stringbuffer.h + +template +class GenericStringBuffer; + +typedef GenericStringBuffer, CrtAllocator> StringBuffer; + +// filereadstream.h + +class FileReadStream; + +// filewritestream.h + +class FileWriteStream; + +// memorybuffer.h + +template +struct GenericMemoryBuffer; + +typedef GenericMemoryBuffer MemoryBuffer; + +// memorystream.h + +struct MemoryStream; + +// reader.h + +template +struct BaseReaderHandler; + +template +class GenericReader; + +typedef GenericReader, UTF8, CrtAllocator> Reader; + +// writer.h + +template +class Writer; + +// prettywriter.h + +template +class PrettyWriter; + +// document.h + +template +class GenericMember; + +template +class GenericMemberIterator; + +template +struct GenericStringRef; + +template +class GenericValue; + +typedef GenericValue, MemoryPoolAllocator > Value; + +template +class GenericDocument; + +typedef GenericDocument, MemoryPoolAllocator, CrtAllocator> Document; + +// pointer.h + +template +class GenericPointer; + +typedef GenericPointer Pointer; + +// schema.h + +template +class IGenericRemoteSchemaDocumentProvider; + +template +class GenericSchemaDocument; + +typedef GenericSchemaDocument SchemaDocument; +typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProvider; + +template < + typename SchemaDocumentType, + typename OutputHandler, + typename StateAllocator> +class GenericSchemaValidator; + +typedef GenericSchemaValidator, void>, CrtAllocator> SchemaValidator; + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_RAPIDJSONFWD_H_ diff --git a/src/include/rapidjson/internal/biginteger.h b/src/include/rapidjson/internal/biginteger.h new file mode 100755 index 0000000..8eb87c7 --- /dev/null +++ b/src/include/rapidjson/internal/biginteger.h @@ -0,0 +1,290 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_BIGINTEGER_H_ +#define RAPIDJSON_BIGINTEGER_H_ + +#include "../rapidjson.h" + +#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && defined(_M_AMD64) +#include // for _umul128 +#pragma intrinsic(_umul128) +#endif + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +class BigInteger { +public: + typedef uint64_t Type; + + BigInteger(const BigInteger& rhs) : count_(rhs.count_) { + std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type)); + } + + explicit BigInteger(uint64_t u) : count_(1) { + digits_[0] = u; + } + + BigInteger(const char* decimals, size_t length) : count_(1) { + RAPIDJSON_ASSERT(length > 0); + digits_[0] = 0; + size_t i = 0; + const size_t kMaxDigitPerIteration = 19; // 2^64 = 18446744073709551616 > 10^19 + while (length >= kMaxDigitPerIteration) { + AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration); + length -= kMaxDigitPerIteration; + i += kMaxDigitPerIteration; + } + + if (length > 0) + AppendDecimal64(decimals + i, decimals + i + length); + } + + BigInteger& operator=(const BigInteger &rhs) + { + if (this != &rhs) { + count_ = rhs.count_; + std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type)); + } + return *this; + } + + BigInteger& operator=(uint64_t u) { + digits_[0] = u; + count_ = 1; + return *this; + } + + BigInteger& operator+=(uint64_t u) { + Type backup = digits_[0]; + digits_[0] += u; + for (size_t i = 0; i < count_ - 1; i++) { + if (digits_[i] >= backup) + return *this; // no carry + backup = digits_[i + 1]; + digits_[i + 1] += 1; + } + + // Last carry + if (digits_[count_ - 1] < backup) + PushBack(1); + + return *this; + } + + BigInteger& operator*=(uint64_t u) { + if (u == 0) return *this = 0; + if (u == 1) return *this; + if (*this == 1) return *this = u; + + uint64_t k = 0; + for (size_t i = 0; i < count_; i++) { + uint64_t hi; + digits_[i] = MulAdd64(digits_[i], u, k, &hi); + k = hi; + } + + if (k > 0) + PushBack(k); + + return *this; + } + + BigInteger& operator*=(uint32_t u) { + if (u == 0) return *this = 0; + if (u == 1) return *this; + if (*this == 1) return *this = u; + + uint64_t k = 0; + for (size_t i = 0; i < count_; i++) { + const uint64_t c = digits_[i] >> 32; + const uint64_t d = digits_[i] & 0xFFFFFFFF; + const uint64_t uc = u * c; + const uint64_t ud = u * d; + const uint64_t p0 = ud + k; + const uint64_t p1 = uc + (p0 >> 32); + digits_[i] = (p0 & 0xFFFFFFFF) | (p1 << 32); + k = p1 >> 32; + } + + if (k > 0) + PushBack(k); + + return *this; + } + + BigInteger& operator<<=(size_t shift) { + if (IsZero() || shift == 0) return *this; + + size_t offset = shift / kTypeBit; + size_t interShift = shift % kTypeBit; + RAPIDJSON_ASSERT(count_ + offset <= kCapacity); + + if (interShift == 0) { + std::memmove(digits_ + offset, digits_, count_ * sizeof(Type)); + count_ += offset; + } + else { + digits_[count_] = 0; + for (size_t i = count_; i > 0; i--) + digits_[i + offset] = (digits_[i] << interShift) | (digits_[i - 1] >> (kTypeBit - interShift)); + digits_[offset] = digits_[0] << interShift; + count_ += offset; + if (digits_[count_]) + count_++; + } + + std::memset(digits_, 0, offset * sizeof(Type)); + + return *this; + } + + bool operator==(const BigInteger& rhs) const { + return count_ == rhs.count_ && std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0; + } + + bool operator==(const Type rhs) const { + return count_ == 1 && digits_[0] == rhs; + } + + BigInteger& MultiplyPow5(unsigned exp) { + static const uint32_t kPow5[12] = { + 5, + 5 * 5, + 5 * 5 * 5, + 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 + }; + if (exp == 0) return *this; + for (; exp >= 27; exp -= 27) *this *= RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27 + for (; exp >= 13; exp -= 13) *this *= static_cast(1220703125u); // 5^13 + if (exp > 0) *this *= kPow5[exp - 1]; + return *this; + } + + // Compute absolute difference of this and rhs. + // Assume this != rhs + bool Difference(const BigInteger& rhs, BigInteger* out) const { + int cmp = Compare(rhs); + RAPIDJSON_ASSERT(cmp != 0); + const BigInteger *a, *b; // Makes a > b + bool ret; + if (cmp < 0) { a = &rhs; b = this; ret = true; } + else { a = this; b = &rhs; ret = false; } + + Type borrow = 0; + for (size_t i = 0; i < a->count_; i++) { + Type d = a->digits_[i] - borrow; + if (i < b->count_) + d -= b->digits_[i]; + borrow = (d > a->digits_[i]) ? 1 : 0; + out->digits_[i] = d; + if (d != 0) + out->count_ = i + 1; + } + + return ret; + } + + int Compare(const BigInteger& rhs) const { + if (count_ != rhs.count_) + return count_ < rhs.count_ ? -1 : 1; + + for (size_t i = count_; i-- > 0;) + if (digits_[i] != rhs.digits_[i]) + return digits_[i] < rhs.digits_[i] ? -1 : 1; + + return 0; + } + + size_t GetCount() const { return count_; } + Type GetDigit(size_t index) const { RAPIDJSON_ASSERT(index < count_); return digits_[index]; } + bool IsZero() const { return count_ == 1 && digits_[0] == 0; } + +private: + void AppendDecimal64(const char* begin, const char* end) { + uint64_t u = ParseUint64(begin, end); + if (IsZero()) + *this = u; + else { + unsigned exp = static_cast(end - begin); + (MultiplyPow5(exp) <<= exp) += u; // *this = *this * 10^exp + u + } + } + + void PushBack(Type digit) { + RAPIDJSON_ASSERT(count_ < kCapacity); + digits_[count_++] = digit; + } + + static uint64_t ParseUint64(const char* begin, const char* end) { + uint64_t r = 0; + for (const char* p = begin; p != end; ++p) { + RAPIDJSON_ASSERT(*p >= '0' && *p <= '9'); + r = r * 10u + static_cast(*p - '0'); + } + return r; + } + + // Assume a * b + k < 2^128 + static uint64_t MulAdd64(uint64_t a, uint64_t b, uint64_t k, uint64_t* outHigh) { +#if defined(_MSC_VER) && defined(_M_AMD64) + uint64_t low = _umul128(a, b, outHigh) + k; + if (low < k) + (*outHigh)++; + return low; +#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__) + __extension__ typedef unsigned __int128 uint128; + uint128 p = static_cast(a) * static_cast(b); + p += k; + *outHigh = static_cast(p >> 64); + return static_cast(p); +#else + const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32; + uint64_t x0 = a0 * b0, x1 = a0 * b1, x2 = a1 * b0, x3 = a1 * b1; + x1 += (x0 >> 32); // can't give carry + x1 += x2; + if (x1 < x2) + x3 += (static_cast(1) << 32); + uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF); + uint64_t hi = x3 + (x1 >> 32); + + lo += k; + if (lo < k) + hi++; + *outHigh = hi; + return lo; +#endif + } + + static const size_t kBitCount = 3328; // 64bit * 54 > 10^1000 + static const size_t kCapacity = kBitCount / sizeof(Type); + static const size_t kTypeBit = sizeof(Type) * 8; + + Type digits_[kCapacity]; + size_t count_; +}; + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_BIGINTEGER_H_ diff --git a/src/include/rapidjson/internal/clzll.h b/src/include/rapidjson/internal/clzll.h new file mode 100755 index 0000000..6cd7923 --- /dev/null +++ b/src/include/rapidjson/internal/clzll.h @@ -0,0 +1,71 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_CLZLL_H_ +#define RAPIDJSON_CLZLL_H_ + +#include "../rapidjson.h" + +#if defined(_MSC_VER) +#include +#if defined(_WIN64) +#pragma intrinsic(_BitScanReverse64) +#else +#pragma intrinsic(_BitScanReverse) +#endif +#endif + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +inline uint32_t clzll(uint64_t x) { + // Passing 0 to __builtin_clzll is UB in GCC and results in an + // infinite loop in the software implementation. + RAPIDJSON_ASSERT(x != 0); + +#if defined(_MSC_VER) + unsigned long r = 0; +#if defined(_WIN64) + _BitScanReverse64(&r, x); +#else + // Scan the high 32 bits. + if (_BitScanReverse(&r, static_cast(x >> 32))) + return 63 - (r + 32); + + // Scan the low 32 bits. + _BitScanReverse(&r, static_cast(x & 0xFFFFFFFF)); +#endif // _WIN64 + + return 63 - r; +#elif (defined(__GNUC__) && __GNUC__ >= 4) || RAPIDJSON_HAS_BUILTIN(__builtin_clzll) + // __builtin_clzll wrapper + return static_cast(__builtin_clzll(x)); +#else + // naive version + uint32_t r; + while (!(x & (static_cast(1) << 63))) { + x <<= 1; + ++r; + } + + return r; +#endif // _MSC_VER +} + +#define RAPIDJSON_CLZLL RAPIDJSON_NAMESPACE::internal::clzll + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_CLZLL_H_ diff --git a/src/include/rapidjson/internal/diyfp.h b/src/include/rapidjson/internal/diyfp.h new file mode 100755 index 0000000..8f7d853 --- /dev/null +++ b/src/include/rapidjson/internal/diyfp.h @@ -0,0 +1,257 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +// This is a C++ header-only implementation of Grisu2 algorithm from the publication: +// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with +// integers." ACM Sigplan Notices 45.6 (2010): 233-243. + +#ifndef RAPIDJSON_DIYFP_H_ +#define RAPIDJSON_DIYFP_H_ + +#include "../rapidjson.h" +#include "clzll.h" +#include + +#if defined(_MSC_VER) && defined(_M_AMD64) && !defined(__INTEL_COMPILER) +#include +#pragma intrinsic(_umul128) +#endif + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +#ifdef __GNUC__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#endif + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +#endif + +struct DiyFp { + DiyFp() : f(), e() {} + + DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {} + + explicit DiyFp(double d) { + union { + double d; + uint64_t u64; + } u = { d }; + + int biased_e = static_cast((u.u64 & kDpExponentMask) >> kDpSignificandSize); + uint64_t significand = (u.u64 & kDpSignificandMask); + if (biased_e != 0) { + f = significand + kDpHiddenBit; + e = biased_e - kDpExponentBias; + } + else { + f = significand; + e = kDpMinExponent + 1; + } + } + + DiyFp operator-(const DiyFp& rhs) const { + return DiyFp(f - rhs.f, e); + } + + DiyFp operator*(const DiyFp& rhs) const { +#if defined(_MSC_VER) && defined(_M_AMD64) + uint64_t h; + uint64_t l = _umul128(f, rhs.f, &h); + if (l & (uint64_t(1) << 63)) // rounding + h++; + return DiyFp(h, e + rhs.e + 64); +#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__) + __extension__ typedef unsigned __int128 uint128; + uint128 p = static_cast(f) * static_cast(rhs.f); + uint64_t h = static_cast(p >> 64); + uint64_t l = static_cast(p); + if (l & (uint64_t(1) << 63)) // rounding + h++; + return DiyFp(h, e + rhs.e + 64); +#else + const uint64_t M32 = 0xFFFFFFFF; + const uint64_t a = f >> 32; + const uint64_t b = f & M32; + const uint64_t c = rhs.f >> 32; + const uint64_t d = rhs.f & M32; + const uint64_t ac = a * c; + const uint64_t bc = b * c; + const uint64_t ad = a * d; + const uint64_t bd = b * d; + uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32); + tmp += 1U << 31; /// mult_round + return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64); +#endif + } + + DiyFp Normalize() const { + int s = static_cast(clzll(f)); + return DiyFp(f << s, e - s); + } + + DiyFp NormalizeBoundary() const { + DiyFp res = *this; + while (!(res.f & (kDpHiddenBit << 1))) { + res.f <<= 1; + res.e--; + } + res.f <<= (kDiySignificandSize - kDpSignificandSize - 2); + res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2); + return res; + } + + void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const { + DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary(); + DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1); + mi.f <<= mi.e - pl.e; + mi.e = pl.e; + *plus = pl; + *minus = mi; + } + + double ToDouble() const { + union { + double d; + uint64_t u64; + }u; + RAPIDJSON_ASSERT(f <= kDpHiddenBit + kDpSignificandMask); + if (e < kDpDenormalExponent) { + // Underflow. + return 0.0; + } + if (e >= kDpMaxExponent) { + // Overflow. + return std::numeric_limits::infinity(); + } + const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 : + static_cast(e + kDpExponentBias); + u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize); + return u.d; + } + + static const int kDiySignificandSize = 64; + static const int kDpSignificandSize = 52; + static const int kDpExponentBias = 0x3FF + kDpSignificandSize; + static const int kDpMaxExponent = 0x7FF - kDpExponentBias; + static const int kDpMinExponent = -kDpExponentBias; + static const int kDpDenormalExponent = -kDpExponentBias + 1; + static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); + static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); + static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); + + uint64_t f; + int e; +}; + +inline DiyFp GetCachedPowerByIndex(size_t index) { + // 10^-348, 10^-340, ..., 10^340 + static const uint64_t kCachedPowers_F[] = { + RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76), + RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea), + RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df), + RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f), + RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c), + RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5), + RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d), + RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637), + RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7), + RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5), + RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b), + RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996), + RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6), + RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8), + RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053), + RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd), + RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94), + RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b), + RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac), + RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3), + RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb), + RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c), + RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000), + RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984), + RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70), + RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245), + RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8), + RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a), + RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea), + RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85), + RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2), + RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3), + RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25), + RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece), + RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5), + RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a), + RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c), + RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a), + RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129), + RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429), + RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d), + RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841), + RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9), + RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b) + }; + static const int16_t kCachedPowers_E[] = { + -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, + -954, -927, -901, -874, -847, -821, -794, -768, -741, -715, + -688, -661, -635, -608, -582, -555, -529, -502, -475, -449, + -422, -396, -369, -343, -316, -289, -263, -236, -210, -183, + -157, -130, -103, -77, -50, -24, 3, 30, 56, 83, + 109, 136, 162, 189, 216, 242, 269, 295, 322, 348, + 375, 402, 428, 455, 481, 508, 534, 561, 588, 614, + 641, 667, 694, 720, 747, 774, 800, 827, 853, 880, + 907, 933, 960, 986, 1013, 1039, 1066 + }; + RAPIDJSON_ASSERT(index < 87); + return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]); +} + +inline DiyFp GetCachedPower(int e, int* K) { + + //int k = static_cast(ceil((-61 - e) * 0.30102999566398114)) + 374; + double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive + int k = static_cast(dk); + if (dk - k > 0.0) + k++; + + unsigned index = static_cast((k >> 3) + 1); + *K = -(-348 + static_cast(index << 3)); // decimal exponent no need lookup table + + return GetCachedPowerByIndex(index); +} + +inline DiyFp GetCachedPower10(int exp, int *outExp) { + RAPIDJSON_ASSERT(exp >= -348); + unsigned index = static_cast(exp + 348) / 8u; + *outExp = -348 + static_cast(index) * 8; + return GetCachedPowerByIndex(index); +} + +#ifdef __GNUC__ +RAPIDJSON_DIAG_POP +#endif + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +RAPIDJSON_DIAG_OFF(padded) +#endif + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_DIYFP_H_ diff --git a/src/include/rapidjson/internal/dtoa.h b/src/include/rapidjson/internal/dtoa.h new file mode 100755 index 0000000..bf2e9b2 --- /dev/null +++ b/src/include/rapidjson/internal/dtoa.h @@ -0,0 +1,245 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +// This is a C++ header-only implementation of Grisu2 algorithm from the publication: +// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with +// integers." ACM Sigplan Notices 45.6 (2010): 233-243. + +#ifndef RAPIDJSON_DTOA_ +#define RAPIDJSON_DTOA_ + +#include "itoa.h" // GetDigitsLut() +#include "diyfp.h" +#include "ieee754.h" + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +#ifdef __GNUC__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +RAPIDJSON_DIAG_OFF(array-bounds) // some gcc versions generate wrong warnings https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124 +#endif + +inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) { + while (rest < wp_w && delta - rest >= ten_kappa && + (rest + ten_kappa < wp_w || /// closer + wp_w - rest > rest + ten_kappa - wp_w)) { + buffer[len - 1]--; + rest += ten_kappa; + } +} + +inline int CountDecimalDigit32(uint32_t n) { + // Simple pure C++ implementation was faster than __builtin_clz version in this situation. + if (n < 10) return 1; + if (n < 100) return 2; + if (n < 1000) return 3; + if (n < 10000) return 4; + if (n < 100000) return 5; + if (n < 1000000) return 6; + if (n < 10000000) return 7; + if (n < 100000000) return 8; + // Will not reach 10 digits in DigitGen() + //if (n < 1000000000) return 9; + //return 10; + return 9; +} + +inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) { + static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; + const DiyFp one(uint64_t(1) << -Mp.e, Mp.e); + const DiyFp wp_w = Mp - W; + uint32_t p1 = static_cast(Mp.f >> -one.e); + uint64_t p2 = Mp.f & (one.f - 1); + int kappa = CountDecimalDigit32(p1); // kappa in [0, 9] + *len = 0; + + while (kappa > 0) { + uint32_t d = 0; + switch (kappa) { + case 9: d = p1 / 100000000; p1 %= 100000000; break; + case 8: d = p1 / 10000000; p1 %= 10000000; break; + case 7: d = p1 / 1000000; p1 %= 1000000; break; + case 6: d = p1 / 100000; p1 %= 100000; break; + case 5: d = p1 / 10000; p1 %= 10000; break; + case 4: d = p1 / 1000; p1 %= 1000; break; + case 3: d = p1 / 100; p1 %= 100; break; + case 2: d = p1 / 10; p1 %= 10; break; + case 1: d = p1; p1 = 0; break; + default:; + } + if (d || *len) + buffer[(*len)++] = static_cast('0' + static_cast(d)); + kappa--; + uint64_t tmp = (static_cast(p1) << -one.e) + p2; + if (tmp <= delta) { + *K += kappa; + GrisuRound(buffer, *len, delta, tmp, static_cast(kPow10[kappa]) << -one.e, wp_w.f); + return; + } + } + + // kappa = 0 + for (;;) { + p2 *= 10; + delta *= 10; + char d = static_cast(p2 >> -one.e); + if (d || *len) + buffer[(*len)++] = static_cast('0' + d); + p2 &= one.f - 1; + kappa--; + if (p2 < delta) { + *K += kappa; + int index = -kappa; + GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[index] : 0)); + return; + } + } +} + +inline void Grisu2(double value, char* buffer, int* length, int* K) { + const DiyFp v(value); + DiyFp w_m, w_p; + v.NormalizedBoundaries(&w_m, &w_p); + + const DiyFp c_mk = GetCachedPower(w_p.e, K); + const DiyFp W = v.Normalize() * c_mk; + DiyFp Wp = w_p * c_mk; + DiyFp Wm = w_m * c_mk; + Wm.f++; + Wp.f--; + DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K); +} + +inline char* WriteExponent(int K, char* buffer) { + if (K < 0) { + *buffer++ = '-'; + K = -K; + } + + if (K >= 100) { + *buffer++ = static_cast('0' + static_cast(K / 100)); + K %= 100; + const char* d = GetDigitsLut() + K * 2; + *buffer++ = d[0]; + *buffer++ = d[1]; + } + else if (K >= 10) { + const char* d = GetDigitsLut() + K * 2; + *buffer++ = d[0]; + *buffer++ = d[1]; + } + else + *buffer++ = static_cast('0' + static_cast(K)); + + return buffer; +} + +inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) { + const int kk = length + k; // 10^(kk-1) <= v < 10^kk + + if (0 <= k && kk <= 21) { + // 1234e7 -> 12340000000 + for (int i = length; i < kk; i++) + buffer[i] = '0'; + buffer[kk] = '.'; + buffer[kk + 1] = '0'; + return &buffer[kk + 2]; + } + else if (0 < kk && kk <= 21) { + // 1234e-2 -> 12.34 + std::memmove(&buffer[kk + 1], &buffer[kk], static_cast(length - kk)); + buffer[kk] = '.'; + if (0 > k + maxDecimalPlaces) { + // When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1 + // Remove extra trailing zeros (at least one) after truncation. + for (int i = kk + maxDecimalPlaces; i > kk + 1; i--) + if (buffer[i] != '0') + return &buffer[i + 1]; + return &buffer[kk + 2]; // Reserve one zero + } + else + return &buffer[length + 1]; + } + else if (-6 < kk && kk <= 0) { + // 1234e-6 -> 0.001234 + const int offset = 2 - kk; + std::memmove(&buffer[offset], &buffer[0], static_cast(length)); + buffer[0] = '0'; + buffer[1] = '.'; + for (int i = 2; i < offset; i++) + buffer[i] = '0'; + if (length - kk > maxDecimalPlaces) { + // When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1 + // Remove extra trailing zeros (at least one) after truncation. + for (int i = maxDecimalPlaces + 1; i > 2; i--) + if (buffer[i] != '0') + return &buffer[i + 1]; + return &buffer[3]; // Reserve one zero + } + else + return &buffer[length + offset]; + } + else if (kk < -maxDecimalPlaces) { + // Truncate to zero + buffer[0] = '0'; + buffer[1] = '.'; + buffer[2] = '0'; + return &buffer[3]; + } + else if (length == 1) { + // 1e30 + buffer[1] = 'e'; + return WriteExponent(kk - 1, &buffer[2]); + } + else { + // 1234e30 -> 1.234e33 + std::memmove(&buffer[2], &buffer[1], static_cast(length - 1)); + buffer[1] = '.'; + buffer[length + 1] = 'e'; + return WriteExponent(kk - 1, &buffer[0 + length + 2]); + } +} + +inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324) { + RAPIDJSON_ASSERT(maxDecimalPlaces >= 1); + Double d(value); + if (d.IsZero()) { + if (d.Sign()) + *buffer++ = '-'; // -0.0, Issue #289 + buffer[0] = '0'; + buffer[1] = '.'; + buffer[2] = '0'; + return &buffer[3]; + } + else { + if (value < 0) { + *buffer++ = '-'; + value = -value; + } + int length, K; + Grisu2(value, buffer, &length, &K); + return Prettify(buffer, length, K, maxDecimalPlaces); + } +} + +#ifdef __GNUC__ +RAPIDJSON_DIAG_POP +#endif + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_DTOA_ diff --git a/src/include/rapidjson/internal/ieee754.h b/src/include/rapidjson/internal/ieee754.h new file mode 100755 index 0000000..c2684ba --- /dev/null +++ b/src/include/rapidjson/internal/ieee754.h @@ -0,0 +1,78 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_IEEE754_ +#define RAPIDJSON_IEEE754_ + +#include "../rapidjson.h" + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +class Double { +public: + Double() {} + Double(double d) : d_(d) {} + Double(uint64_t u) : u_(u) {} + + double Value() const { return d_; } + uint64_t Uint64Value() const { return u_; } + + double NextPositiveDouble() const { + RAPIDJSON_ASSERT(!Sign()); + return Double(u_ + 1).Value(); + } + + bool Sign() const { return (u_ & kSignMask) != 0; } + uint64_t Significand() const { return u_ & kSignificandMask; } + int Exponent() const { return static_cast(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); } + + bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; } + bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; } + bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; } + bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; } + bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; } + + uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); } + int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; } + uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; } + + static int EffectiveSignificandSize(int order) { + if (order >= -1021) + return 53; + else if (order <= -1074) + return 0; + else + return order + 1074; + } + +private: + static const int kSignificandSize = 52; + static const int kExponentBias = 0x3FF; + static const int kDenormalExponent = 1 - kExponentBias; + static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000); + static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); + static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); + static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); + + union { + double d_; + uint64_t u_; + }; +}; + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_IEEE754_ diff --git a/src/include/rapidjson/internal/itoa.h b/src/include/rapidjson/internal/itoa.h new file mode 100755 index 0000000..9b1c45c --- /dev/null +++ b/src/include/rapidjson/internal/itoa.h @@ -0,0 +1,308 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_ITOA_ +#define RAPIDJSON_ITOA_ + +#include "../rapidjson.h" + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +inline const char* GetDigitsLut() { + static const char cDigitsLut[200] = { + '0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9', + '1','0','1','1','1','2','1','3','1','4','1','5','1','6','1','7','1','8','1','9', + '2','0','2','1','2','2','2','3','2','4','2','5','2','6','2','7','2','8','2','9', + '3','0','3','1','3','2','3','3','3','4','3','5','3','6','3','7','3','8','3','9', + '4','0','4','1','4','2','4','3','4','4','4','5','4','6','4','7','4','8','4','9', + '5','0','5','1','5','2','5','3','5','4','5','5','5','6','5','7','5','8','5','9', + '6','0','6','1','6','2','6','3','6','4','6','5','6','6','6','7','6','8','6','9', + '7','0','7','1','7','2','7','3','7','4','7','5','7','6','7','7','7','8','7','9', + '8','0','8','1','8','2','8','3','8','4','8','5','8','6','8','7','8','8','8','9', + '9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9' + }; + return cDigitsLut; +} + +inline char* u32toa(uint32_t value, char* buffer) { + RAPIDJSON_ASSERT(buffer != 0); + + const char* cDigitsLut = GetDigitsLut(); + + if (value < 10000) { + const uint32_t d1 = (value / 100) << 1; + const uint32_t d2 = (value % 100) << 1; + + if (value >= 1000) + *buffer++ = cDigitsLut[d1]; + if (value >= 100) + *buffer++ = cDigitsLut[d1 + 1]; + if (value >= 10) + *buffer++ = cDigitsLut[d2]; + *buffer++ = cDigitsLut[d2 + 1]; + } + else if (value < 100000000) { + // value = bbbbcccc + const uint32_t b = value / 10000; + const uint32_t c = value % 10000; + + const uint32_t d1 = (b / 100) << 1; + const uint32_t d2 = (b % 100) << 1; + + const uint32_t d3 = (c / 100) << 1; + const uint32_t d4 = (c % 100) << 1; + + if (value >= 10000000) + *buffer++ = cDigitsLut[d1]; + if (value >= 1000000) + *buffer++ = cDigitsLut[d1 + 1]; + if (value >= 100000) + *buffer++ = cDigitsLut[d2]; + *buffer++ = cDigitsLut[d2 + 1]; + + *buffer++ = cDigitsLut[d3]; + *buffer++ = cDigitsLut[d3 + 1]; + *buffer++ = cDigitsLut[d4]; + *buffer++ = cDigitsLut[d4 + 1]; + } + else { + // value = aabbbbcccc in decimal + + const uint32_t a = value / 100000000; // 1 to 42 + value %= 100000000; + + if (a >= 10) { + const unsigned i = a << 1; + *buffer++ = cDigitsLut[i]; + *buffer++ = cDigitsLut[i + 1]; + } + else + *buffer++ = static_cast('0' + static_cast(a)); + + const uint32_t b = value / 10000; // 0 to 9999 + const uint32_t c = value % 10000; // 0 to 9999 + + const uint32_t d1 = (b / 100) << 1; + const uint32_t d2 = (b % 100) << 1; + + const uint32_t d3 = (c / 100) << 1; + const uint32_t d4 = (c % 100) << 1; + + *buffer++ = cDigitsLut[d1]; + *buffer++ = cDigitsLut[d1 + 1]; + *buffer++ = cDigitsLut[d2]; + *buffer++ = cDigitsLut[d2 + 1]; + *buffer++ = cDigitsLut[d3]; + *buffer++ = cDigitsLut[d3 + 1]; + *buffer++ = cDigitsLut[d4]; + *buffer++ = cDigitsLut[d4 + 1]; + } + return buffer; +} + +inline char* i32toa(int32_t value, char* buffer) { + RAPIDJSON_ASSERT(buffer != 0); + uint32_t u = static_cast(value); + if (value < 0) { + *buffer++ = '-'; + u = ~u + 1; + } + + return u32toa(u, buffer); +} + +inline char* u64toa(uint64_t value, char* buffer) { + RAPIDJSON_ASSERT(buffer != 0); + const char* cDigitsLut = GetDigitsLut(); + const uint64_t kTen8 = 100000000; + const uint64_t kTen9 = kTen8 * 10; + const uint64_t kTen10 = kTen8 * 100; + const uint64_t kTen11 = kTen8 * 1000; + const uint64_t kTen12 = kTen8 * 10000; + const uint64_t kTen13 = kTen8 * 100000; + const uint64_t kTen14 = kTen8 * 1000000; + const uint64_t kTen15 = kTen8 * 10000000; + const uint64_t kTen16 = kTen8 * kTen8; + + if (value < kTen8) { + uint32_t v = static_cast(value); + if (v < 10000) { + const uint32_t d1 = (v / 100) << 1; + const uint32_t d2 = (v % 100) << 1; + + if (v >= 1000) + *buffer++ = cDigitsLut[d1]; + if (v >= 100) + *buffer++ = cDigitsLut[d1 + 1]; + if (v >= 10) + *buffer++ = cDigitsLut[d2]; + *buffer++ = cDigitsLut[d2 + 1]; + } + else { + // value = bbbbcccc + const uint32_t b = v / 10000; + const uint32_t c = v % 10000; + + const uint32_t d1 = (b / 100) << 1; + const uint32_t d2 = (b % 100) << 1; + + const uint32_t d3 = (c / 100) << 1; + const uint32_t d4 = (c % 100) << 1; + + if (value >= 10000000) + *buffer++ = cDigitsLut[d1]; + if (value >= 1000000) + *buffer++ = cDigitsLut[d1 + 1]; + if (value >= 100000) + *buffer++ = cDigitsLut[d2]; + *buffer++ = cDigitsLut[d2 + 1]; + + *buffer++ = cDigitsLut[d3]; + *buffer++ = cDigitsLut[d3 + 1]; + *buffer++ = cDigitsLut[d4]; + *buffer++ = cDigitsLut[d4 + 1]; + } + } + else if (value < kTen16) { + const uint32_t v0 = static_cast(value / kTen8); + const uint32_t v1 = static_cast(value % kTen8); + + const uint32_t b0 = v0 / 10000; + const uint32_t c0 = v0 % 10000; + + const uint32_t d1 = (b0 / 100) << 1; + const uint32_t d2 = (b0 % 100) << 1; + + const uint32_t d3 = (c0 / 100) << 1; + const uint32_t d4 = (c0 % 100) << 1; + + const uint32_t b1 = v1 / 10000; + const uint32_t c1 = v1 % 10000; + + const uint32_t d5 = (b1 / 100) << 1; + const uint32_t d6 = (b1 % 100) << 1; + + const uint32_t d7 = (c1 / 100) << 1; + const uint32_t d8 = (c1 % 100) << 1; + + if (value >= kTen15) + *buffer++ = cDigitsLut[d1]; + if (value >= kTen14) + *buffer++ = cDigitsLut[d1 + 1]; + if (value >= kTen13) + *buffer++ = cDigitsLut[d2]; + if (value >= kTen12) + *buffer++ = cDigitsLut[d2 + 1]; + if (value >= kTen11) + *buffer++ = cDigitsLut[d3]; + if (value >= kTen10) + *buffer++ = cDigitsLut[d3 + 1]; + if (value >= kTen9) + *buffer++ = cDigitsLut[d4]; + + *buffer++ = cDigitsLut[d4 + 1]; + *buffer++ = cDigitsLut[d5]; + *buffer++ = cDigitsLut[d5 + 1]; + *buffer++ = cDigitsLut[d6]; + *buffer++ = cDigitsLut[d6 + 1]; + *buffer++ = cDigitsLut[d7]; + *buffer++ = cDigitsLut[d7 + 1]; + *buffer++ = cDigitsLut[d8]; + *buffer++ = cDigitsLut[d8 + 1]; + } + else { + const uint32_t a = static_cast(value / kTen16); // 1 to 1844 + value %= kTen16; + + if (a < 10) + *buffer++ = static_cast('0' + static_cast(a)); + else if (a < 100) { + const uint32_t i = a << 1; + *buffer++ = cDigitsLut[i]; + *buffer++ = cDigitsLut[i + 1]; + } + else if (a < 1000) { + *buffer++ = static_cast('0' + static_cast(a / 100)); + + const uint32_t i = (a % 100) << 1; + *buffer++ = cDigitsLut[i]; + *buffer++ = cDigitsLut[i + 1]; + } + else { + const uint32_t i = (a / 100) << 1; + const uint32_t j = (a % 100) << 1; + *buffer++ = cDigitsLut[i]; + *buffer++ = cDigitsLut[i + 1]; + *buffer++ = cDigitsLut[j]; + *buffer++ = cDigitsLut[j + 1]; + } + + const uint32_t v0 = static_cast(value / kTen8); + const uint32_t v1 = static_cast(value % kTen8); + + const uint32_t b0 = v0 / 10000; + const uint32_t c0 = v0 % 10000; + + const uint32_t d1 = (b0 / 100) << 1; + const uint32_t d2 = (b0 % 100) << 1; + + const uint32_t d3 = (c0 / 100) << 1; + const uint32_t d4 = (c0 % 100) << 1; + + const uint32_t b1 = v1 / 10000; + const uint32_t c1 = v1 % 10000; + + const uint32_t d5 = (b1 / 100) << 1; + const uint32_t d6 = (b1 % 100) << 1; + + const uint32_t d7 = (c1 / 100) << 1; + const uint32_t d8 = (c1 % 100) << 1; + + *buffer++ = cDigitsLut[d1]; + *buffer++ = cDigitsLut[d1 + 1]; + *buffer++ = cDigitsLut[d2]; + *buffer++ = cDigitsLut[d2 + 1]; + *buffer++ = cDigitsLut[d3]; + *buffer++ = cDigitsLut[d3 + 1]; + *buffer++ = cDigitsLut[d4]; + *buffer++ = cDigitsLut[d4 + 1]; + *buffer++ = cDigitsLut[d5]; + *buffer++ = cDigitsLut[d5 + 1]; + *buffer++ = cDigitsLut[d6]; + *buffer++ = cDigitsLut[d6 + 1]; + *buffer++ = cDigitsLut[d7]; + *buffer++ = cDigitsLut[d7 + 1]; + *buffer++ = cDigitsLut[d8]; + *buffer++ = cDigitsLut[d8 + 1]; + } + + return buffer; +} + +inline char* i64toa(int64_t value, char* buffer) { + RAPIDJSON_ASSERT(buffer != 0); + uint64_t u = static_cast(value); + if (value < 0) { + *buffer++ = '-'; + u = ~u + 1; + } + + return u64toa(u, buffer); +} + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_ITOA_ diff --git a/src/include/rapidjson/internal/meta.h b/src/include/rapidjson/internal/meta.h new file mode 100755 index 0000000..d401edf --- /dev/null +++ b/src/include/rapidjson/internal/meta.h @@ -0,0 +1,186 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_INTERNAL_META_H_ +#define RAPIDJSON_INTERNAL_META_H_ + +#include "../rapidjson.h" + +#ifdef __GNUC__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#endif + +#if defined(_MSC_VER) && !defined(__clang__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(6334) +#endif + +#if RAPIDJSON_HAS_CXX11_TYPETRAITS +#include +#endif + +//@cond RAPIDJSON_INTERNAL +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +// Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching +template struct Void { typedef void Type; }; + +/////////////////////////////////////////////////////////////////////////////// +// BoolType, TrueType, FalseType +// +template struct BoolType { + static const bool Value = Cond; + typedef BoolType Type; +}; +typedef BoolType TrueType; +typedef BoolType FalseType; + + +/////////////////////////////////////////////////////////////////////////////// +// SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr +// + +template struct SelectIfImpl { template struct Apply { typedef T1 Type; }; }; +template <> struct SelectIfImpl { template struct Apply { typedef T2 Type; }; }; +template struct SelectIfCond : SelectIfImpl::template Apply {}; +template struct SelectIf : SelectIfCond {}; + +template struct AndExprCond : FalseType {}; +template <> struct AndExprCond : TrueType {}; +template struct OrExprCond : TrueType {}; +template <> struct OrExprCond : FalseType {}; + +template struct BoolExpr : SelectIf::Type {}; +template struct NotExpr : SelectIf::Type {}; +template struct AndExpr : AndExprCond::Type {}; +template struct OrExpr : OrExprCond::Type {}; + + +/////////////////////////////////////////////////////////////////////////////// +// AddConst, MaybeAddConst, RemoveConst +template struct AddConst { typedef const T Type; }; +template struct MaybeAddConst : SelectIfCond {}; +template struct RemoveConst { typedef T Type; }; +template struct RemoveConst { typedef T Type; }; + + +/////////////////////////////////////////////////////////////////////////////// +// IsSame, IsConst, IsMoreConst, IsPointer +// +template struct IsSame : FalseType {}; +template struct IsSame : TrueType {}; + +template struct IsConst : FalseType {}; +template struct IsConst : TrueType {}; + +template +struct IsMoreConst + : AndExpr::Type, typename RemoveConst::Type>, + BoolType::Value >= IsConst::Value> >::Type {}; + +template struct IsPointer : FalseType {}; +template struct IsPointer : TrueType {}; + +/////////////////////////////////////////////////////////////////////////////// +// IsBaseOf +// +#if RAPIDJSON_HAS_CXX11_TYPETRAITS + +template struct IsBaseOf + : BoolType< ::std::is_base_of::value> {}; + +#else // simplified version adopted from Boost + +template struct IsBaseOfImpl { + RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0); + RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0); + + typedef char (&Yes)[1]; + typedef char (&No) [2]; + + template + static Yes Check(const D*, T); + static No Check(const B*, int); + + struct Host { + operator const B*() const; + operator const D*(); + }; + + enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) }; +}; + +template struct IsBaseOf + : OrExpr, BoolExpr > >::Type {}; + +#endif // RAPIDJSON_HAS_CXX11_TYPETRAITS + + +////////////////////////////////////////////////////////////////////////// +// EnableIf / DisableIf +// +template struct EnableIfCond { typedef T Type; }; +template struct EnableIfCond { /* empty */ }; + +template struct DisableIfCond { typedef T Type; }; +template struct DisableIfCond { /* empty */ }; + +template +struct EnableIf : EnableIfCond {}; + +template +struct DisableIf : DisableIfCond {}; + +// SFINAE helpers +struct SfinaeTag {}; +template struct RemoveSfinaeTag; +template struct RemoveSfinaeTag { typedef T Type; }; + +#define RAPIDJSON_REMOVEFPTR_(type) \ + typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \ + < ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type + +#define RAPIDJSON_ENABLEIF(cond) \ + typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ + ::Type * = NULL + +#define RAPIDJSON_DISABLEIF(cond) \ + typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ + ::Type * = NULL + +#define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \ + typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ + ::Type + +#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \ + typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ + ::Type + +} // namespace internal +RAPIDJSON_NAMESPACE_END +//@endcond + +#if defined(_MSC_VER) && !defined(__clang__) +RAPIDJSON_DIAG_POP +#endif + +#ifdef __GNUC__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_INTERNAL_META_H_ diff --git a/src/include/rapidjson/internal/pow10.h b/src/include/rapidjson/internal/pow10.h new file mode 100755 index 0000000..02f475d --- /dev/null +++ b/src/include/rapidjson/internal/pow10.h @@ -0,0 +1,55 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_POW10_ +#define RAPIDJSON_POW10_ + +#include "../rapidjson.h" + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +//! Computes integer powers of 10 in double (10.0^n). +/*! This function uses lookup table for fast and accurate results. + \param n non-negative exponent. Must <= 308. + \return 10.0^n +*/ +inline double Pow10(int n) { + static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes + 1e+0, + 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20, + 1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40, + 1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60, + 1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80, + 1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100, + 1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120, + 1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140, + 1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160, + 1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180, + 1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200, + 1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220, + 1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240, + 1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260, + 1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280, + 1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300, + 1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308 + }; + RAPIDJSON_ASSERT(n >= 0 && n <= 308); + return e[n]; +} + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_POW10_ diff --git a/src/include/rapidjson/internal/regex.h b/src/include/rapidjson/internal/regex.h new file mode 100755 index 0000000..af7e06d --- /dev/null +++ b/src/include/rapidjson/internal/regex.h @@ -0,0 +1,739 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_INTERNAL_REGEX_H_ +#define RAPIDJSON_INTERNAL_REGEX_H_ + +#include "../allocators.h" +#include "../stream.h" +#include "stack.h" + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +RAPIDJSON_DIAG_OFF(switch-enum) +#elif defined(_MSC_VER) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated +#endif + +#ifdef __GNUC__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#endif + +#ifndef RAPIDJSON_REGEX_VERBOSE +#define RAPIDJSON_REGEX_VERBOSE 0 +#endif + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +/////////////////////////////////////////////////////////////////////////////// +// DecodedStream + +template +class DecodedStream { +public: + DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); } + unsigned Peek() { return codepoint_; } + unsigned Take() { + unsigned c = codepoint_; + if (c) // No further decoding when '\0' + Decode(); + return c; + } + +private: + void Decode() { + if (!Encoding::Decode(ss_, &codepoint_)) + codepoint_ = 0; + } + + SourceStream& ss_; + unsigned codepoint_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// GenericRegex + +static const SizeType kRegexInvalidState = ~SizeType(0); //!< Represents an invalid index in GenericRegex::State::out, out1 +static const SizeType kRegexInvalidRange = ~SizeType(0); + +template +class GenericRegexSearch; + +//! Regular expression engine with subset of ECMAscript grammar. +/*! + Supported regular expression syntax: + - \c ab Concatenation + - \c a|b Alternation + - \c a? Zero or one + - \c a* Zero or more + - \c a+ One or more + - \c a{3} Exactly 3 times + - \c a{3,} At least 3 times + - \c a{3,5} 3 to 5 times + - \c (ab) Grouping + - \c ^a At the beginning + - \c a$ At the end + - \c . Any character + - \c [abc] Character classes + - \c [a-c] Character class range + - \c [a-z0-9_] Character class combination + - \c [^abc] Negated character classes + - \c [^a-c] Negated character class range + - \c [\b] Backspace (U+0008) + - \c \\| \\\\ ... Escape characters + - \c \\f Form feed (U+000C) + - \c \\n Line feed (U+000A) + - \c \\r Carriage return (U+000D) + - \c \\t Tab (U+0009) + - \c \\v Vertical tab (U+000B) + + \note This is a Thompson NFA engine, implemented with reference to + Cox, Russ. "Regular Expression Matching Can Be Simple And Fast (but is slow in Java, Perl, PHP, Python, Ruby,...).", + https://swtch.com/~rsc/regexp/regexp1.html +*/ +template +class GenericRegex { +public: + typedef Encoding EncodingType; + typedef typename Encoding::Ch Ch; + template friend class GenericRegexSearch; + + GenericRegex(const Ch* source, Allocator* allocator = 0) : + ownAllocator_(allocator ? 0 : RAPIDJSON_NEW(Allocator)()), allocator_(allocator ? allocator : ownAllocator_), + states_(allocator_, 256), ranges_(allocator_, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(), + anchorBegin_(), anchorEnd_() + { + GenericStringStream ss(source); + DecodedStream, Encoding> ds(ss); + Parse(ds); + } + + ~GenericRegex() + { + RAPIDJSON_DELETE(ownAllocator_); + } + + bool IsValid() const { + return root_ != kRegexInvalidState; + } + +private: + enum Operator { + kZeroOrOne, + kZeroOrMore, + kOneOrMore, + kConcatenation, + kAlternation, + kLeftParenthesis + }; + + static const unsigned kAnyCharacterClass = 0xFFFFFFFF; //!< For '.' + static const unsigned kRangeCharacterClass = 0xFFFFFFFE; + static const unsigned kRangeNegationFlag = 0x80000000; + + struct Range { + unsigned start; // + unsigned end; + SizeType next; + }; + + struct State { + SizeType out; //!< Equals to kInvalid for matching state + SizeType out1; //!< Equals to non-kInvalid for split + SizeType rangeStart; + unsigned codepoint; + }; + + struct Frag { + Frag(SizeType s, SizeType o, SizeType m) : start(s), out(o), minIndex(m) {} + SizeType start; + SizeType out; //!< link-list of all output states + SizeType minIndex; + }; + + State& GetState(SizeType index) { + RAPIDJSON_ASSERT(index < stateCount_); + return states_.template Bottom()[index]; + } + + const State& GetState(SizeType index) const { + RAPIDJSON_ASSERT(index < stateCount_); + return states_.template Bottom()[index]; + } + + Range& GetRange(SizeType index) { + RAPIDJSON_ASSERT(index < rangeCount_); + return ranges_.template Bottom()[index]; + } + + const Range& GetRange(SizeType index) const { + RAPIDJSON_ASSERT(index < rangeCount_); + return ranges_.template Bottom()[index]; + } + + template + void Parse(DecodedStream& ds) { + Stack operandStack(allocator_, 256); // Frag + Stack operatorStack(allocator_, 256); // Operator + Stack atomCountStack(allocator_, 256); // unsigned (Atom per parenthesis) + + *atomCountStack.template Push() = 0; + + unsigned codepoint; + while (ds.Peek() != 0) { + switch (codepoint = ds.Take()) { + case '^': + anchorBegin_ = true; + break; + + case '$': + anchorEnd_ = true; + break; + + case '|': + while (!operatorStack.Empty() && *operatorStack.template Top() < kAlternation) + if (!Eval(operandStack, *operatorStack.template Pop(1))) + return; + *operatorStack.template Push() = kAlternation; + *atomCountStack.template Top() = 0; + break; + + case '(': + *operatorStack.template Push() = kLeftParenthesis; + *atomCountStack.template Push() = 0; + break; + + case ')': + while (!operatorStack.Empty() && *operatorStack.template Top() != kLeftParenthesis) + if (!Eval(operandStack, *operatorStack.template Pop(1))) + return; + if (operatorStack.Empty()) + return; + operatorStack.template Pop(1); + atomCountStack.template Pop(1); + ImplicitConcatenation(atomCountStack, operatorStack); + break; + + case '?': + if (!Eval(operandStack, kZeroOrOne)) + return; + break; + + case '*': + if (!Eval(operandStack, kZeroOrMore)) + return; + break; + + case '+': + if (!Eval(operandStack, kOneOrMore)) + return; + break; + + case '{': + { + unsigned n, m; + if (!ParseUnsigned(ds, &n)) + return; + + if (ds.Peek() == ',') { + ds.Take(); + if (ds.Peek() == '}') + m = kInfinityQuantifier; + else if (!ParseUnsigned(ds, &m) || m < n) + return; + } + else + m = n; + + if (!EvalQuantifier(operandStack, n, m) || ds.Peek() != '}') + return; + ds.Take(); + } + break; + + case '.': + PushOperand(operandStack, kAnyCharacterClass); + ImplicitConcatenation(atomCountStack, operatorStack); + break; + + case '[': + { + SizeType range; + if (!ParseRange(ds, &range)) + return; + SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, kRangeCharacterClass); + GetState(s).rangeStart = range; + *operandStack.template Push() = Frag(s, s, s); + } + ImplicitConcatenation(atomCountStack, operatorStack); + break; + + case '\\': // Escape character + if (!CharacterEscape(ds, &codepoint)) + return; // Unsupported escape character + // fall through to default + RAPIDJSON_DELIBERATE_FALLTHROUGH; + + default: // Pattern character + PushOperand(operandStack, codepoint); + ImplicitConcatenation(atomCountStack, operatorStack); + } + } + + while (!operatorStack.Empty()) + if (!Eval(operandStack, *operatorStack.template Pop(1))) + return; + + // Link the operand to matching state. + if (operandStack.GetSize() == sizeof(Frag)) { + Frag* e = operandStack.template Pop(1); + Patch(e->out, NewState(kRegexInvalidState, kRegexInvalidState, 0)); + root_ = e->start; + +#if RAPIDJSON_REGEX_VERBOSE + printf("root: %d\n", root_); + for (SizeType i = 0; i < stateCount_ ; i++) { + State& s = GetState(i); + printf("[%2d] out: %2d out1: %2d c: '%c'\n", i, s.out, s.out1, (char)s.codepoint); + } + printf("\n"); +#endif + } + } + + SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) { + State* s = states_.template Push(); + s->out = out; + s->out1 = out1; + s->codepoint = codepoint; + s->rangeStart = kRegexInvalidRange; + return stateCount_++; + } + + void PushOperand(Stack& operandStack, unsigned codepoint) { + SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, codepoint); + *operandStack.template Push() = Frag(s, s, s); + } + + void ImplicitConcatenation(Stack& atomCountStack, Stack& operatorStack) { + if (*atomCountStack.template Top()) + *operatorStack.template Push() = kConcatenation; + (*atomCountStack.template Top())++; + } + + SizeType Append(SizeType l1, SizeType l2) { + SizeType old = l1; + while (GetState(l1).out != kRegexInvalidState) + l1 = GetState(l1).out; + GetState(l1).out = l2; + return old; + } + + void Patch(SizeType l, SizeType s) { + for (SizeType next; l != kRegexInvalidState; l = next) { + next = GetState(l).out; + GetState(l).out = s; + } + } + + bool Eval(Stack& operandStack, Operator op) { + switch (op) { + case kConcatenation: + RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag) * 2); + { + Frag e2 = *operandStack.template Pop(1); + Frag e1 = *operandStack.template Pop(1); + Patch(e1.out, e2.start); + *operandStack.template Push() = Frag(e1.start, e2.out, Min(e1.minIndex, e2.minIndex)); + } + return true; + + case kAlternation: + if (operandStack.GetSize() >= sizeof(Frag) * 2) { + Frag e2 = *operandStack.template Pop(1); + Frag e1 = *operandStack.template Pop(1); + SizeType s = NewState(e1.start, e2.start, 0); + *operandStack.template Push() = Frag(s, Append(e1.out, e2.out), Min(e1.minIndex, e2.minIndex)); + return true; + } + return false; + + case kZeroOrOne: + if (operandStack.GetSize() >= sizeof(Frag)) { + Frag e = *operandStack.template Pop(1); + SizeType s = NewState(kRegexInvalidState, e.start, 0); + *operandStack.template Push() = Frag(s, Append(e.out, s), e.minIndex); + return true; + } + return false; + + case kZeroOrMore: + if (operandStack.GetSize() >= sizeof(Frag)) { + Frag e = *operandStack.template Pop(1); + SizeType s = NewState(kRegexInvalidState, e.start, 0); + Patch(e.out, s); + *operandStack.template Push() = Frag(s, s, e.minIndex); + return true; + } + return false; + + case kOneOrMore: + if (operandStack.GetSize() >= sizeof(Frag)) { + Frag e = *operandStack.template Pop(1); + SizeType s = NewState(kRegexInvalidState, e.start, 0); + Patch(e.out, s); + *operandStack.template Push() = Frag(e.start, s, e.minIndex); + return true; + } + return false; + + default: + // syntax error (e.g. unclosed kLeftParenthesis) + return false; + } + } + + bool EvalQuantifier(Stack& operandStack, unsigned n, unsigned m) { + RAPIDJSON_ASSERT(n <= m); + RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag)); + + if (n == 0) { + if (m == 0) // a{0} not support + return false; + else if (m == kInfinityQuantifier) + Eval(operandStack, kZeroOrMore); // a{0,} -> a* + else { + Eval(operandStack, kZeroOrOne); // a{0,5} -> a? + for (unsigned i = 0; i < m - 1; i++) + CloneTopOperand(operandStack); // a{0,5} -> a? a? a? a? a? + for (unsigned i = 0; i < m - 1; i++) + Eval(operandStack, kConcatenation); // a{0,5} -> a?a?a?a?a? + } + return true; + } + + for (unsigned i = 0; i < n - 1; i++) // a{3} -> a a a + CloneTopOperand(operandStack); + + if (m == kInfinityQuantifier) + Eval(operandStack, kOneOrMore); // a{3,} -> a a a+ + else if (m > n) { + CloneTopOperand(operandStack); // a{3,5} -> a a a a + Eval(operandStack, kZeroOrOne); // a{3,5} -> a a a a? + for (unsigned i = n; i < m - 1; i++) + CloneTopOperand(operandStack); // a{3,5} -> a a a a? a? + for (unsigned i = n; i < m; i++) + Eval(operandStack, kConcatenation); // a{3,5} -> a a aa?a? + } + + for (unsigned i = 0; i < n - 1; i++) + Eval(operandStack, kConcatenation); // a{3} -> aaa, a{3,} -> aaa+, a{3.5} -> aaaa?a? + + return true; + } + + static SizeType Min(SizeType a, SizeType b) { return a < b ? a : b; } + + void CloneTopOperand(Stack& operandStack) { + const Frag src = *operandStack.template Top(); // Copy constructor to prevent invalidation + SizeType count = stateCount_ - src.minIndex; // Assumes top operand contains states in [src->minIndex, stateCount_) + State* s = states_.template Push(count); + memcpy(s, &GetState(src.minIndex), count * sizeof(State)); + for (SizeType j = 0; j < count; j++) { + if (s[j].out != kRegexInvalidState) + s[j].out += count; + if (s[j].out1 != kRegexInvalidState) + s[j].out1 += count; + } + *operandStack.template Push() = Frag(src.start + count, src.out + count, src.minIndex + count); + stateCount_ += count; + } + + template + bool ParseUnsigned(DecodedStream& ds, unsigned* u) { + unsigned r = 0; + if (ds.Peek() < '0' || ds.Peek() > '9') + return false; + while (ds.Peek() >= '0' && ds.Peek() <= '9') { + if (r >= 429496729 && ds.Peek() > '5') // 2^32 - 1 = 4294967295 + return false; // overflow + r = r * 10 + (ds.Take() - '0'); + } + *u = r; + return true; + } + + template + bool ParseRange(DecodedStream& ds, SizeType* range) { + bool isBegin = true; + bool negate = false; + int step = 0; + SizeType start = kRegexInvalidRange; + SizeType current = kRegexInvalidRange; + unsigned codepoint; + while ((codepoint = ds.Take()) != 0) { + if (isBegin) { + isBegin = false; + if (codepoint == '^') { + negate = true; + continue; + } + } + + switch (codepoint) { + case ']': + if (start == kRegexInvalidRange) + return false; // Error: nothing inside [] + if (step == 2) { // Add trailing '-' + SizeType r = NewRange('-'); + RAPIDJSON_ASSERT(current != kRegexInvalidRange); + GetRange(current).next = r; + } + if (negate) + GetRange(start).start |= kRangeNegationFlag; + *range = start; + return true; + + case '\\': + if (ds.Peek() == 'b') { + ds.Take(); + codepoint = 0x0008; // Escape backspace character + } + else if (!CharacterEscape(ds, &codepoint)) + return false; + // fall through to default + RAPIDJSON_DELIBERATE_FALLTHROUGH; + + default: + switch (step) { + case 1: + if (codepoint == '-') { + step++; + break; + } + // fall through to step 0 for other characters + RAPIDJSON_DELIBERATE_FALLTHROUGH; + + case 0: + { + SizeType r = NewRange(codepoint); + if (current != kRegexInvalidRange) + GetRange(current).next = r; + if (start == kRegexInvalidRange) + start = r; + current = r; + } + step = 1; + break; + + default: + RAPIDJSON_ASSERT(step == 2); + GetRange(current).end = codepoint; + step = 0; + } + } + } + return false; + } + + SizeType NewRange(unsigned codepoint) { + Range* r = ranges_.template Push(); + r->start = r->end = codepoint; + r->next = kRegexInvalidRange; + return rangeCount_++; + } + + template + bool CharacterEscape(DecodedStream& ds, unsigned* escapedCodepoint) { + unsigned codepoint; + switch (codepoint = ds.Take()) { + case '^': + case '$': + case '|': + case '(': + case ')': + case '?': + case '*': + case '+': + case '.': + case '[': + case ']': + case '{': + case '}': + case '\\': + *escapedCodepoint = codepoint; return true; + case 'f': *escapedCodepoint = 0x000C; return true; + case 'n': *escapedCodepoint = 0x000A; return true; + case 'r': *escapedCodepoint = 0x000D; return true; + case 't': *escapedCodepoint = 0x0009; return true; + case 'v': *escapedCodepoint = 0x000B; return true; + default: + return false; // Unsupported escape character + } + } + + Allocator* ownAllocator_; + Allocator* allocator_; + Stack states_; + Stack ranges_; + SizeType root_; + SizeType stateCount_; + SizeType rangeCount_; + + static const unsigned kInfinityQuantifier = ~0u; + + // For SearchWithAnchoring() + bool anchorBegin_; + bool anchorEnd_; +}; + +template +class GenericRegexSearch { +public: + typedef typename RegexType::EncodingType Encoding; + typedef typename Encoding::Ch Ch; + + GenericRegexSearch(const RegexType& regex, Allocator* allocator = 0) : + regex_(regex), allocator_(allocator), ownAllocator_(0), + state0_(allocator, 0), state1_(allocator, 0), stateSet_() + { + RAPIDJSON_ASSERT(regex_.IsValid()); + if (!allocator_) + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); + stateSet_ = static_cast(allocator_->Malloc(GetStateSetSize())); + state0_.template Reserve(regex_.stateCount_); + state1_.template Reserve(regex_.stateCount_); + } + + ~GenericRegexSearch() { + Allocator::Free(stateSet_); + RAPIDJSON_DELETE(ownAllocator_); + } + + template + bool Match(InputStream& is) { + return SearchWithAnchoring(is, true, true); + } + + bool Match(const Ch* s) { + GenericStringStream is(s); + return Match(is); + } + + template + bool Search(InputStream& is) { + return SearchWithAnchoring(is, regex_.anchorBegin_, regex_.anchorEnd_); + } + + bool Search(const Ch* s) { + GenericStringStream is(s); + return Search(is); + } + +private: + typedef typename RegexType::State State; + typedef typename RegexType::Range Range; + + template + bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) { + DecodedStream ds(is); + + state0_.Clear(); + Stack *current = &state0_, *next = &state1_; + const size_t stateSetSize = GetStateSetSize(); + std::memset(stateSet_, 0, stateSetSize); + + bool matched = AddState(*current, regex_.root_); + unsigned codepoint; + while (!current->Empty() && (codepoint = ds.Take()) != 0) { + std::memset(stateSet_, 0, stateSetSize); + next->Clear(); + matched = false; + for (const SizeType* s = current->template Bottom(); s != current->template End(); ++s) { + const State& sr = regex_.GetState(*s); + if (sr.codepoint == codepoint || + sr.codepoint == RegexType::kAnyCharacterClass || + (sr.codepoint == RegexType::kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint))) + { + matched = AddState(*next, sr.out) || matched; + if (!anchorEnd && matched) + return true; + } + if (!anchorBegin) + AddState(*next, regex_.root_); + } + internal::Swap(current, next); + } + + return matched; + } + + size_t GetStateSetSize() const { + return (regex_.stateCount_ + 31) / 32 * 4; + } + + // Return whether the added states is a match state + bool AddState(Stack& l, SizeType index) { + RAPIDJSON_ASSERT(index != kRegexInvalidState); + + const State& s = regex_.GetState(index); + if (s.out1 != kRegexInvalidState) { // Split + bool matched = AddState(l, s.out); + return AddState(l, s.out1) || matched; + } + else if (!(stateSet_[index >> 5] & (1u << (index & 31)))) { + stateSet_[index >> 5] |= (1u << (index & 31)); + *l.template PushUnsafe() = index; + } + return s.out == kRegexInvalidState; // by using PushUnsafe() above, we can ensure s is not validated due to reallocation. + } + + bool MatchRange(SizeType rangeIndex, unsigned codepoint) const { + bool yes = (regex_.GetRange(rangeIndex).start & RegexType::kRangeNegationFlag) == 0; + while (rangeIndex != kRegexInvalidRange) { + const Range& r = regex_.GetRange(rangeIndex); + if (codepoint >= (r.start & ~RegexType::kRangeNegationFlag) && codepoint <= r.end) + return yes; + rangeIndex = r.next; + } + return !yes; + } + + const RegexType& regex_; + Allocator* allocator_; + Allocator* ownAllocator_; + Stack state0_; + Stack state1_; + uint32_t* stateSet_; +}; + +typedef GenericRegex > Regex; +typedef GenericRegexSearch RegexSearch; + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#ifdef __GNUC__ +RAPIDJSON_DIAG_POP +#endif + +#if defined(__clang__) || defined(_MSC_VER) +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_INTERNAL_REGEX_H_ diff --git a/src/include/rapidjson/internal/stack.h b/src/include/rapidjson/internal/stack.h new file mode 100755 index 0000000..45dca6a --- /dev/null +++ b/src/include/rapidjson/internal/stack.h @@ -0,0 +1,232 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_INTERNAL_STACK_H_ +#define RAPIDJSON_INTERNAL_STACK_H_ + +#include "../allocators.h" +#include "swap.h" +#include + +#if defined(__clang__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(c++98-compat) +#endif + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +/////////////////////////////////////////////////////////////////////////////// +// Stack + +//! A type-unsafe stack for storing different types of data. +/*! \tparam Allocator Allocator for allocating stack memory. +*/ +template +class Stack { +public: + // Optimization note: Do not allocate memory for stack_ in constructor. + // Do it lazily when first Push() -> Expand() -> Resize(). + Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) { + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + Stack(Stack&& rhs) + : allocator_(rhs.allocator_), + ownAllocator_(rhs.ownAllocator_), + stack_(rhs.stack_), + stackTop_(rhs.stackTop_), + stackEnd_(rhs.stackEnd_), + initialCapacity_(rhs.initialCapacity_) + { + rhs.allocator_ = 0; + rhs.ownAllocator_ = 0; + rhs.stack_ = 0; + rhs.stackTop_ = 0; + rhs.stackEnd_ = 0; + rhs.initialCapacity_ = 0; + } +#endif + + ~Stack() { + Destroy(); + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + Stack& operator=(Stack&& rhs) { + if (&rhs != this) + { + Destroy(); + + allocator_ = rhs.allocator_; + ownAllocator_ = rhs.ownAllocator_; + stack_ = rhs.stack_; + stackTop_ = rhs.stackTop_; + stackEnd_ = rhs.stackEnd_; + initialCapacity_ = rhs.initialCapacity_; + + rhs.allocator_ = 0; + rhs.ownAllocator_ = 0; + rhs.stack_ = 0; + rhs.stackTop_ = 0; + rhs.stackEnd_ = 0; + rhs.initialCapacity_ = 0; + } + return *this; + } +#endif + + void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT { + internal::Swap(allocator_, rhs.allocator_); + internal::Swap(ownAllocator_, rhs.ownAllocator_); + internal::Swap(stack_, rhs.stack_); + internal::Swap(stackTop_, rhs.stackTop_); + internal::Swap(stackEnd_, rhs.stackEnd_); + internal::Swap(initialCapacity_, rhs.initialCapacity_); + } + + void Clear() { stackTop_ = stack_; } + + void ShrinkToFit() { + if (Empty()) { + // If the stack is empty, completely deallocate the memory. + Allocator::Free(stack_); // NOLINT (+clang-analyzer-unix.Malloc) + stack_ = 0; + stackTop_ = 0; + stackEnd_ = 0; + } + else + Resize(GetSize()); + } + + // Optimization note: try to minimize the size of this function for force inline. + // Expansion is run very infrequently, so it is moved to another (probably non-inline) function. + template + RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) { + // Expand the stack if needed + if (RAPIDJSON_UNLIKELY(static_cast(sizeof(T) * count) > (stackEnd_ - stackTop_))) + Expand(count); + } + + template + RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) { + Reserve(count); + return PushUnsafe(count); + } + + template + RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) { + RAPIDJSON_ASSERT(stackTop_); + RAPIDJSON_ASSERT(static_cast(sizeof(T) * count) <= (stackEnd_ - stackTop_)); + T* ret = reinterpret_cast(stackTop_); + stackTop_ += sizeof(T) * count; + return ret; + } + + template + T* Pop(size_t count) { + RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T)); + stackTop_ -= count * sizeof(T); + return reinterpret_cast(stackTop_); + } + + template + T* Top() { + RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); + return reinterpret_cast(stackTop_ - sizeof(T)); + } + + template + const T* Top() const { + RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); + return reinterpret_cast(stackTop_ - sizeof(T)); + } + + template + T* End() { return reinterpret_cast(stackTop_); } + + template + const T* End() const { return reinterpret_cast(stackTop_); } + + template + T* Bottom() { return reinterpret_cast(stack_); } + + template + const T* Bottom() const { return reinterpret_cast(stack_); } + + bool HasAllocator() const { + return allocator_ != 0; + } + + Allocator& GetAllocator() { + RAPIDJSON_ASSERT(allocator_); + return *allocator_; + } + + bool Empty() const { return stackTop_ == stack_; } + size_t GetSize() const { return static_cast(stackTop_ - stack_); } + size_t GetCapacity() const { return static_cast(stackEnd_ - stack_); } + +private: + template + void Expand(size_t count) { + // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity. + size_t newCapacity; + if (stack_ == 0) { + if (!allocator_) + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); + newCapacity = initialCapacity_; + } else { + newCapacity = GetCapacity(); + newCapacity += (newCapacity + 1) / 2; + } + size_t newSize = GetSize() + sizeof(T) * count; + if (newCapacity < newSize) + newCapacity = newSize; + + Resize(newCapacity); + } + + void Resize(size_t newCapacity) { + const size_t size = GetSize(); // Backup the current size + stack_ = static_cast(allocator_->Realloc(stack_, GetCapacity(), newCapacity)); + stackTop_ = stack_ + size; + stackEnd_ = stack_ + newCapacity; + } + + void Destroy() { + Allocator::Free(stack_); + RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack + } + + // Prohibit copy constructor & assignment operator. + Stack(const Stack&); + Stack& operator=(const Stack&); + + Allocator* allocator_; + Allocator* ownAllocator_; + char *stack_; + char *stackTop_; + char *stackEnd_; + size_t initialCapacity_; +}; + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#if defined(__clang__) +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_STACK_H_ diff --git a/src/include/rapidjson/internal/strfunc.h b/src/include/rapidjson/internal/strfunc.h new file mode 100755 index 0000000..226439a --- /dev/null +++ b/src/include/rapidjson/internal/strfunc.h @@ -0,0 +1,69 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_ +#define RAPIDJSON_INTERNAL_STRFUNC_H_ + +#include "../stream.h" +#include + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +//! Custom strlen() which works on different character types. +/*! \tparam Ch Character type (e.g. char, wchar_t, short) + \param s Null-terminated input string. + \return Number of characters in the string. + \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints. +*/ +template +inline SizeType StrLen(const Ch* s) { + RAPIDJSON_ASSERT(s != 0); + const Ch* p = s; + while (*p) ++p; + return SizeType(p - s); +} + +template <> +inline SizeType StrLen(const char* s) { + return SizeType(std::strlen(s)); +} + +template <> +inline SizeType StrLen(const wchar_t* s) { + return SizeType(std::wcslen(s)); +} + +//! Returns number of code points in a encoded string. +template +bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) { + RAPIDJSON_ASSERT(s != 0); + RAPIDJSON_ASSERT(outCount != 0); + GenericStringStream is(s); + const typename Encoding::Ch* end = s + length; + SizeType count = 0; + while (is.src_ < end) { + unsigned codepoint; + if (!Encoding::Decode(is, &codepoint)) + return false; + count++; + } + *outCount = count; + return true; +} + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_INTERNAL_STRFUNC_H_ diff --git a/src/include/rapidjson/internal/strtod.h b/src/include/rapidjson/internal/strtod.h new file mode 100755 index 0000000..dfca22b --- /dev/null +++ b/src/include/rapidjson/internal/strtod.h @@ -0,0 +1,290 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_STRTOD_ +#define RAPIDJSON_STRTOD_ + +#include "ieee754.h" +#include "biginteger.h" +#include "diyfp.h" +#include "pow10.h" +#include +#include + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +inline double FastPath(double significand, int exp) { + if (exp < -308) + return 0.0; + else if (exp >= 0) + return significand * internal::Pow10(exp); + else + return significand / internal::Pow10(-exp); +} + +inline double StrtodNormalPrecision(double d, int p) { + if (p < -308) { + // Prevent expSum < -308, making Pow10(p) = 0 + d = FastPath(d, -308); + d = FastPath(d, p + 308); + } + else + d = FastPath(d, p); + return d; +} + +template +inline T Min3(T a, T b, T c) { + T m = a; + if (m > b) m = b; + if (m > c) m = c; + return m; +} + +inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) { + const Double db(b); + const uint64_t bInt = db.IntegerSignificand(); + const int bExp = db.IntegerExponent(); + const int hExp = bExp - 1; + + int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0; + + // Adjust for decimal exponent + if (dExp >= 0) { + dS_Exp2 += dExp; + dS_Exp5 += dExp; + } + else { + bS_Exp2 -= dExp; + bS_Exp5 -= dExp; + hS_Exp2 -= dExp; + hS_Exp5 -= dExp; + } + + // Adjust for binary exponent + if (bExp >= 0) + bS_Exp2 += bExp; + else { + dS_Exp2 -= bExp; + hS_Exp2 -= bExp; + } + + // Adjust for half ulp exponent + if (hExp >= 0) + hS_Exp2 += hExp; + else { + dS_Exp2 -= hExp; + bS_Exp2 -= hExp; + } + + // Remove common power of two factor from all three scaled values + int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2); + dS_Exp2 -= common_Exp2; + bS_Exp2 -= common_Exp2; + hS_Exp2 -= common_Exp2; + + BigInteger dS = d; + dS.MultiplyPow5(static_cast(dS_Exp5)) <<= static_cast(dS_Exp2); + + BigInteger bS(bInt); + bS.MultiplyPow5(static_cast(bS_Exp5)) <<= static_cast(bS_Exp2); + + BigInteger hS(1); + hS.MultiplyPow5(static_cast(hS_Exp5)) <<= static_cast(hS_Exp2); + + BigInteger delta(0); + dS.Difference(bS, &delta); + + return delta.Compare(hS); +} + +inline bool StrtodFast(double d, int p, double* result) { + // Use fast path for string-to-double conversion if possible + // see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/ + if (p > 22 && p < 22 + 16) { + // Fast Path Cases In Disguise + d *= internal::Pow10(p - 22); + p = 22; + } + + if (p >= -22 && p <= 22 && d <= 9007199254740991.0) { // 2^53 - 1 + *result = FastPath(d, p); + return true; + } + else + return false; +} + +// Compute an approximation and see if it is within 1/2 ULP +inline bool StrtodDiyFp(const char* decimals, int dLen, int dExp, double* result) { + uint64_t significand = 0; + int i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999 + for (; i < dLen; i++) { + if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || + (significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5')) + break; + significand = significand * 10u + static_cast(decimals[i] - '0'); + } + + if (i < dLen && decimals[i] >= '5') // Rounding + significand++; + + int remaining = dLen - i; + const int kUlpShift = 3; + const int kUlp = 1 << kUlpShift; + int64_t error = (remaining == 0) ? 0 : kUlp / 2; + + DiyFp v(significand, 0); + v = v.Normalize(); + error <<= -v.e; + + dExp += remaining; + + int actualExp; + DiyFp cachedPower = GetCachedPower10(dExp, &actualExp); + if (actualExp != dExp) { + static const DiyFp kPow10[] = { + DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 0x00000000), -60), // 10^1 + DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 0x00000000), -57), // 10^2 + DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 0x00000000), -54), // 10^3 + DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), -50), // 10^4 + DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 0x00000000), -47), // 10^5 + DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 0x00000000), -44), // 10^6 + DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 0x00000000), -40) // 10^7 + }; + int adjustment = dExp - actualExp; + RAPIDJSON_ASSERT(adjustment >= 1 && adjustment < 8); + v = v * kPow10[adjustment - 1]; + if (dLen + adjustment > 19) // has more digits than decimal digits in 64-bit + error += kUlp / 2; + } + + v = v * cachedPower; + + error += kUlp + (error == 0 ? 0 : 1); + + const int oldExp = v.e; + v = v.Normalize(); + error <<= oldExp - v.e; + + const int effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e); + int precisionSize = 64 - effectiveSignificandSize; + if (precisionSize + kUlpShift >= 64) { + int scaleExp = (precisionSize + kUlpShift) - 63; + v.f >>= scaleExp; + v.e += scaleExp; + error = (error >> scaleExp) + 1 + kUlp; + precisionSize -= scaleExp; + } + + DiyFp rounded(v.f >> precisionSize, v.e + precisionSize); + const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp; + const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp; + if (precisionBits >= halfWay + static_cast(error)) { + rounded.f++; + if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340) + rounded.f >>= 1; + rounded.e++; + } + } + + *result = rounded.ToDouble(); + + return halfWay - static_cast(error) >= precisionBits || precisionBits >= halfWay + static_cast(error); +} + +inline double StrtodBigInteger(double approx, const char* decimals, int dLen, int dExp) { + RAPIDJSON_ASSERT(dLen >= 0); + const BigInteger dInt(decimals, static_cast(dLen)); + Double a(approx); + int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp); + if (cmp < 0) + return a.Value(); // within half ULP + else if (cmp == 0) { + // Round towards even + if (a.Significand() & 1) + return a.NextPositiveDouble(); + else + return a.Value(); + } + else // adjustment + return a.NextPositiveDouble(); +} + +inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) { + RAPIDJSON_ASSERT(d >= 0.0); + RAPIDJSON_ASSERT(length >= 1); + + double result = 0.0; + if (StrtodFast(d, p, &result)) + return result; + + RAPIDJSON_ASSERT(length <= INT_MAX); + int dLen = static_cast(length); + + RAPIDJSON_ASSERT(length >= decimalPosition); + RAPIDJSON_ASSERT(length - decimalPosition <= INT_MAX); + int dExpAdjust = static_cast(length - decimalPosition); + + RAPIDJSON_ASSERT(exp >= INT_MIN + dExpAdjust); + int dExp = exp - dExpAdjust; + + // Make sure length+dExp does not overflow + RAPIDJSON_ASSERT(dExp <= INT_MAX - dLen); + + // Trim leading zeros + while (dLen > 0 && *decimals == '0') { + dLen--; + decimals++; + } + + // Trim trailing zeros + while (dLen > 0 && decimals[dLen - 1] == '0') { + dLen--; + dExp++; + } + + if (dLen == 0) { // Buffer only contains zeros. + return 0.0; + } + + // Trim right-most digits + const int kMaxDecimalDigit = 767 + 1; + if (dLen > kMaxDecimalDigit) { + dExp += dLen - kMaxDecimalDigit; + dLen = kMaxDecimalDigit; + } + + // If too small, underflow to zero. + // Any x <= 10^-324 is interpreted as zero. + if (dLen + dExp <= -324) + return 0.0; + + // If too large, overflow to infinity. + // Any x >= 10^309 is interpreted as +infinity. + if (dLen + dExp > 309) + return std::numeric_limits::infinity(); + + if (StrtodDiyFp(decimals, dLen, dExp, &result)) + return result; + + // Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison + return StrtodBigInteger(result, decimals, dLen, dExp); +} + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_STRTOD_ diff --git a/src/include/rapidjson/internal/swap.h b/src/include/rapidjson/internal/swap.h new file mode 100755 index 0000000..666e49f --- /dev/null +++ b/src/include/rapidjson/internal/swap.h @@ -0,0 +1,46 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_INTERNAL_SWAP_H_ +#define RAPIDJSON_INTERNAL_SWAP_H_ + +#include "../rapidjson.h" + +#if defined(__clang__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(c++98-compat) +#endif + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +//! Custom swap() to avoid dependency on C++ header +/*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only. + \note This has the same semantics as std::swap(). +*/ +template +inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT { + T tmp = a; + a = b; + b = tmp; +} + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#if defined(__clang__) +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_INTERNAL_SWAP_H_ diff --git a/src/include/rapidjson/istreamwrapper.h b/src/include/rapidjson/istreamwrapper.h new file mode 100755 index 0000000..c4950b9 --- /dev/null +++ b/src/include/rapidjson/istreamwrapper.h @@ -0,0 +1,128 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_ISTREAMWRAPPER_H_ +#define RAPIDJSON_ISTREAMWRAPPER_H_ + +#include "stream.h" +#include +#include + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +#elif defined(_MSC_VER) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! Wrapper of \c std::basic_istream into RapidJSON's Stream concept. +/*! + The classes can be wrapped including but not limited to: + + - \c std::istringstream + - \c std::stringstream + - \c std::wistringstream + - \c std::wstringstream + - \c std::ifstream + - \c std::fstream + - \c std::wifstream + - \c std::wfstream + + \tparam StreamType Class derived from \c std::basic_istream. +*/ + +template +class BasicIStreamWrapper { +public: + typedef typename StreamType::char_type Ch; + + //! Constructor. + /*! + \param stream stream opened for read. + */ + BasicIStreamWrapper(StreamType &stream) : stream_(stream), buffer_(peekBuffer_), bufferSize_(4), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { + Read(); + } + + //! Constructor. + /*! + \param stream stream opened for read. + \param buffer user-supplied buffer. + \param bufferSize size of buffer in bytes. Must >=4 bytes. + */ + BasicIStreamWrapper(StreamType &stream, char* buffer, size_t bufferSize) : stream_(stream), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { + RAPIDJSON_ASSERT(bufferSize >= 4); + Read(); + } + + Ch Peek() const { return *current_; } + Ch Take() { Ch c = *current_; Read(); return c; } + size_t Tell() const { return count_ + static_cast(current_ - buffer_); } + + // Not implemented + void Put(Ch) { RAPIDJSON_ASSERT(false); } + void Flush() { RAPIDJSON_ASSERT(false); } + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + + // For encoding detection only. + const Ch* Peek4() const { + return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0; + } + +private: + BasicIStreamWrapper(); + BasicIStreamWrapper(const BasicIStreamWrapper&); + BasicIStreamWrapper& operator=(const BasicIStreamWrapper&); + + void Read() { + if (current_ < bufferLast_) + ++current_; + else if (!eof_) { + count_ += readCount_; + readCount_ = bufferSize_; + bufferLast_ = buffer_ + readCount_ - 1; + current_ = buffer_; + + if (!stream_.read(buffer_, static_cast(bufferSize_))) { + readCount_ = static_cast(stream_.gcount()); + *(bufferLast_ = buffer_ + readCount_) = '\0'; + eof_ = true; + } + } + } + + StreamType &stream_; + Ch peekBuffer_[4], *buffer_; + size_t bufferSize_; + Ch *bufferLast_; + Ch *current_; + size_t readCount_; + size_t count_; //!< Number of characters read + bool eof_; +}; + +typedef BasicIStreamWrapper IStreamWrapper; +typedef BasicIStreamWrapper WIStreamWrapper; + +#if defined(__clang__) || defined(_MSC_VER) +RAPIDJSON_DIAG_POP +#endif + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_ISTREAMWRAPPER_H_ diff --git a/src/include/rapidjson/memorybuffer.h b/src/include/rapidjson/memorybuffer.h new file mode 100755 index 0000000..39bee1d --- /dev/null +++ b/src/include/rapidjson/memorybuffer.h @@ -0,0 +1,70 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_MEMORYBUFFER_H_ +#define RAPIDJSON_MEMORYBUFFER_H_ + +#include "stream.h" +#include "internal/stack.h" + +RAPIDJSON_NAMESPACE_BEGIN + +//! Represents an in-memory output byte stream. +/*! + This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream. + + It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file. + + Differences between MemoryBuffer and StringBuffer: + 1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer. + 2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator. + + \tparam Allocator type for allocating memory buffer. + \note implements Stream concept +*/ +template +struct GenericMemoryBuffer { + typedef char Ch; // byte + + GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} + + void Put(Ch c) { *stack_.template Push() = c; } + void Flush() {} + + void Clear() { stack_.Clear(); } + void ShrinkToFit() { stack_.ShrinkToFit(); } + Ch* Push(size_t count) { return stack_.template Push(count); } + void Pop(size_t count) { stack_.template Pop(count); } + + const Ch* GetBuffer() const { + return stack_.template Bottom(); + } + + size_t GetSize() const { return stack_.GetSize(); } + + static const size_t kDefaultCapacity = 256; + mutable internal::Stack stack_; +}; + +typedef GenericMemoryBuffer<> MemoryBuffer; + +//! Implement specialized version of PutN() with memset() for better performance. +template<> +inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) { + std::memset(memoryBuffer.stack_.Push(n), c, n * sizeof(c)); +} + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_MEMORYBUFFER_H_ diff --git a/src/include/rapidjson/memorystream.h b/src/include/rapidjson/memorystream.h new file mode 100755 index 0000000..1d71d8a --- /dev/null +++ b/src/include/rapidjson/memorystream.h @@ -0,0 +1,71 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_MEMORYSTREAM_H_ +#define RAPIDJSON_MEMORYSTREAM_H_ + +#include "stream.h" + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(unreachable-code) +RAPIDJSON_DIAG_OFF(missing-noreturn) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! Represents an in-memory input byte stream. +/*! + This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream. + + It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file. + + Differences between MemoryStream and StringStream: + 1. StringStream has encoding but MemoryStream is a byte stream. + 2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source. + 3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4(). + \note implements Stream concept +*/ +struct MemoryStream { + typedef char Ch; // byte + + MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {} + + Ch Peek() const { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_; } + Ch Take() { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_++; } + size_t Tell() const { return static_cast(src_ - begin_); } + + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + void Put(Ch) { RAPIDJSON_ASSERT(false); } + void Flush() { RAPIDJSON_ASSERT(false); } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + + // For encoding detection only. + const Ch* Peek4() const { + return Tell() + 4 <= size_ ? src_ : 0; + } + + const Ch* src_; //!< Current read position. + const Ch* begin_; //!< Original head of the string. + const Ch* end_; //!< End of stream. + size_t size_; //!< Size of the stream. +}; + +RAPIDJSON_NAMESPACE_END + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_MEMORYBUFFER_H_ diff --git a/src/include/rapidjson/msinttypes/inttypes.h b/src/include/rapidjson/msinttypes/inttypes.h new file mode 100755 index 0000000..1811128 --- /dev/null +++ b/src/include/rapidjson/msinttypes/inttypes.h @@ -0,0 +1,316 @@ +// ISO C9x compliant inttypes.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006-2013 Alexander Chemeris +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the product nor the names of its contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////////// + +// The above software in this distribution may have been modified by +// THL A29 Limited ("Tencent Modifications"). +// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited. + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_INTTYPES_H_ // [ +#define _MSC_INTTYPES_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include "stdint.h" + +// miloyip: VC supports inttypes.h since VC2013 +#if _MSC_VER >= 1800 +#include +#else + +// 7.8 Format conversion of integer types + +typedef struct { + intmax_t quot; + intmax_t rem; +} imaxdiv_t; + +// 7.8.1 Macros for format specifiers + +#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198 + +// The fprintf macros for signed integers are: +#define PRId8 "d" +#define PRIi8 "i" +#define PRIdLEAST8 "d" +#define PRIiLEAST8 "i" +#define PRIdFAST8 "d" +#define PRIiFAST8 "i" + +#define PRId16 "hd" +#define PRIi16 "hi" +#define PRIdLEAST16 "hd" +#define PRIiLEAST16 "hi" +#define PRIdFAST16 "hd" +#define PRIiFAST16 "hi" + +#define PRId32 "I32d" +#define PRIi32 "I32i" +#define PRIdLEAST32 "I32d" +#define PRIiLEAST32 "I32i" +#define PRIdFAST32 "I32d" +#define PRIiFAST32 "I32i" + +#define PRId64 "I64d" +#define PRIi64 "I64i" +#define PRIdLEAST64 "I64d" +#define PRIiLEAST64 "I64i" +#define PRIdFAST64 "I64d" +#define PRIiFAST64 "I64i" + +#define PRIdMAX "I64d" +#define PRIiMAX "I64i" + +#define PRIdPTR "Id" +#define PRIiPTR "Ii" + +// The fprintf macros for unsigned integers are: +#define PRIo8 "o" +#define PRIu8 "u" +#define PRIx8 "x" +#define PRIX8 "X" +#define PRIoLEAST8 "o" +#define PRIuLEAST8 "u" +#define PRIxLEAST8 "x" +#define PRIXLEAST8 "X" +#define PRIoFAST8 "o" +#define PRIuFAST8 "u" +#define PRIxFAST8 "x" +#define PRIXFAST8 "X" + +#define PRIo16 "ho" +#define PRIu16 "hu" +#define PRIx16 "hx" +#define PRIX16 "hX" +#define PRIoLEAST16 "ho" +#define PRIuLEAST16 "hu" +#define PRIxLEAST16 "hx" +#define PRIXLEAST16 "hX" +#define PRIoFAST16 "ho" +#define PRIuFAST16 "hu" +#define PRIxFAST16 "hx" +#define PRIXFAST16 "hX" + +#define PRIo32 "I32o" +#define PRIu32 "I32u" +#define PRIx32 "I32x" +#define PRIX32 "I32X" +#define PRIoLEAST32 "I32o" +#define PRIuLEAST32 "I32u" +#define PRIxLEAST32 "I32x" +#define PRIXLEAST32 "I32X" +#define PRIoFAST32 "I32o" +#define PRIuFAST32 "I32u" +#define PRIxFAST32 "I32x" +#define PRIXFAST32 "I32X" + +#define PRIo64 "I64o" +#define PRIu64 "I64u" +#define PRIx64 "I64x" +#define PRIX64 "I64X" +#define PRIoLEAST64 "I64o" +#define PRIuLEAST64 "I64u" +#define PRIxLEAST64 "I64x" +#define PRIXLEAST64 "I64X" +#define PRIoFAST64 "I64o" +#define PRIuFAST64 "I64u" +#define PRIxFAST64 "I64x" +#define PRIXFAST64 "I64X" + +#define PRIoMAX "I64o" +#define PRIuMAX "I64u" +#define PRIxMAX "I64x" +#define PRIXMAX "I64X" + +#define PRIoPTR "Io" +#define PRIuPTR "Iu" +#define PRIxPTR "Ix" +#define PRIXPTR "IX" + +// The fscanf macros for signed integers are: +#define SCNd8 "d" +#define SCNi8 "i" +#define SCNdLEAST8 "d" +#define SCNiLEAST8 "i" +#define SCNdFAST8 "d" +#define SCNiFAST8 "i" + +#define SCNd16 "hd" +#define SCNi16 "hi" +#define SCNdLEAST16 "hd" +#define SCNiLEAST16 "hi" +#define SCNdFAST16 "hd" +#define SCNiFAST16 "hi" + +#define SCNd32 "ld" +#define SCNi32 "li" +#define SCNdLEAST32 "ld" +#define SCNiLEAST32 "li" +#define SCNdFAST32 "ld" +#define SCNiFAST32 "li" + +#define SCNd64 "I64d" +#define SCNi64 "I64i" +#define SCNdLEAST64 "I64d" +#define SCNiLEAST64 "I64i" +#define SCNdFAST64 "I64d" +#define SCNiFAST64 "I64i" + +#define SCNdMAX "I64d" +#define SCNiMAX "I64i" + +#ifdef _WIN64 // [ +# define SCNdPTR "I64d" +# define SCNiPTR "I64i" +#else // _WIN64 ][ +# define SCNdPTR "ld" +# define SCNiPTR "li" +#endif // _WIN64 ] + +// The fscanf macros for unsigned integers are: +#define SCNo8 "o" +#define SCNu8 "u" +#define SCNx8 "x" +#define SCNX8 "X" +#define SCNoLEAST8 "o" +#define SCNuLEAST8 "u" +#define SCNxLEAST8 "x" +#define SCNXLEAST8 "X" +#define SCNoFAST8 "o" +#define SCNuFAST8 "u" +#define SCNxFAST8 "x" +#define SCNXFAST8 "X" + +#define SCNo16 "ho" +#define SCNu16 "hu" +#define SCNx16 "hx" +#define SCNX16 "hX" +#define SCNoLEAST16 "ho" +#define SCNuLEAST16 "hu" +#define SCNxLEAST16 "hx" +#define SCNXLEAST16 "hX" +#define SCNoFAST16 "ho" +#define SCNuFAST16 "hu" +#define SCNxFAST16 "hx" +#define SCNXFAST16 "hX" + +#define SCNo32 "lo" +#define SCNu32 "lu" +#define SCNx32 "lx" +#define SCNX32 "lX" +#define SCNoLEAST32 "lo" +#define SCNuLEAST32 "lu" +#define SCNxLEAST32 "lx" +#define SCNXLEAST32 "lX" +#define SCNoFAST32 "lo" +#define SCNuFAST32 "lu" +#define SCNxFAST32 "lx" +#define SCNXFAST32 "lX" + +#define SCNo64 "I64o" +#define SCNu64 "I64u" +#define SCNx64 "I64x" +#define SCNX64 "I64X" +#define SCNoLEAST64 "I64o" +#define SCNuLEAST64 "I64u" +#define SCNxLEAST64 "I64x" +#define SCNXLEAST64 "I64X" +#define SCNoFAST64 "I64o" +#define SCNuFAST64 "I64u" +#define SCNxFAST64 "I64x" +#define SCNXFAST64 "I64X" + +#define SCNoMAX "I64o" +#define SCNuMAX "I64u" +#define SCNxMAX "I64x" +#define SCNXMAX "I64X" + +#ifdef _WIN64 // [ +# define SCNoPTR "I64o" +# define SCNuPTR "I64u" +# define SCNxPTR "I64x" +# define SCNXPTR "I64X" +#else // _WIN64 ][ +# define SCNoPTR "lo" +# define SCNuPTR "lu" +# define SCNxPTR "lx" +# define SCNXPTR "lX" +#endif // _WIN64 ] + +#endif // __STDC_FORMAT_MACROS ] + +// 7.8.2 Functions for greatest-width integer types + +// 7.8.2.1 The imaxabs function +#define imaxabs _abs64 + +// 7.8.2.2 The imaxdiv function + +// This is modified version of div() function from Microsoft's div.c found +// in %MSVC.NET%\crt\src\div.c +#ifdef STATIC_IMAXDIV // [ +static +#else // STATIC_IMAXDIV ][ +_inline +#endif // STATIC_IMAXDIV ] +imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom) +{ + imaxdiv_t result; + + result.quot = numer / denom; + result.rem = numer % denom; + + if (numer < 0 && result.rem > 0) { + // did division wrong; must fix up + ++result.quot; + result.rem -= denom; + } + + return result; +} + +// 7.8.2.3 The strtoimax and strtoumax functions +#define strtoimax _strtoi64 +#define strtoumax _strtoui64 + +// 7.8.2.4 The wcstoimax and wcstoumax functions +#define wcstoimax _wcstoi64 +#define wcstoumax _wcstoui64 + +#endif // _MSC_VER >= 1800 + +#endif // _MSC_INTTYPES_H_ ] diff --git a/src/include/rapidjson/msinttypes/stdint.h b/src/include/rapidjson/msinttypes/stdint.h new file mode 100755 index 0000000..3d4477b --- /dev/null +++ b/src/include/rapidjson/msinttypes/stdint.h @@ -0,0 +1,300 @@ +// ISO C9x compliant stdint.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006-2013 Alexander Chemeris +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the product nor the names of its contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////////// + +// The above software in this distribution may have been modified by +// THL A29 Limited ("Tencent Modifications"). +// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited. + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_STDINT_H_ // [ +#define _MSC_STDINT_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +// miloyip: Originally Visual Studio 2010 uses its own stdint.h. However it generates warning with INT64_C(), so change to use this file for vs2010. +#if _MSC_VER >= 1600 // [ +#include + +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 + +#undef INT8_C +#undef INT16_C +#undef INT32_C +#undef INT64_C +#undef UINT8_C +#undef UINT16_C +#undef UINT32_C +#undef UINT64_C + +// 7.18.4.1 Macros for minimum-width integer constants + +#define INT8_C(val) val##i8 +#define INT16_C(val) val##i16 +#define INT32_C(val) val##i32 +#define INT64_C(val) val##i64 + +#define UINT8_C(val) val##ui8 +#define UINT16_C(val) val##ui16 +#define UINT32_C(val) val##ui32 +#define UINT64_C(val) val##ui64 + +// 7.18.4.2 Macros for greatest-width integer constants +// These #ifndef's are needed to prevent collisions with . +// Check out Issue 9 for the details. +#ifndef INTMAX_C // [ +# define INTMAX_C INT64_C +#endif // INTMAX_C ] +#ifndef UINTMAX_C // [ +# define UINTMAX_C UINT64_C +#endif // UINTMAX_C ] + +#endif // __STDC_CONSTANT_MACROS ] + +#else // ] _MSC_VER >= 1700 [ + +#include + +// For Visual Studio 6 in C++ mode and for many Visual Studio versions when +// compiling for ARM we have to wrap include with 'extern "C++" {}' +// or compiler would give many errors like this: +// error C2733: second C linkage of overloaded function 'wmemchr' not allowed +#if defined(__cplusplus) && !defined(_M_ARM) +extern "C" { +#endif +# include +#if defined(__cplusplus) && !defined(_M_ARM) +} +#endif + +// Define _W64 macros to mark types changing their size, like intptr_t. +#ifndef _W64 +# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 +# define _W64 __w64 +# else +# define _W64 +# endif +#endif + + +// 7.18.1 Integer types + +// 7.18.1.1 Exact-width integer types + +// Visual Studio 6 and Embedded Visual C++ 4 doesn't +// realize that, e.g. char has the same size as __int8 +// so we give up on __intX for them. +#if (_MSC_VER < 1300) + typedef signed char int8_t; + typedef signed short int16_t; + typedef signed int int32_t; + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; +#else + typedef signed __int8 int8_t; + typedef signed __int16 int16_t; + typedef signed __int32 int32_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; +#endif +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; + + +// 7.18.1.2 Minimum-width integer types +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +typedef int64_t int_least64_t; +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +typedef uint64_t uint_least64_t; + +// 7.18.1.3 Fastest minimum-width integer types +typedef int8_t int_fast8_t; +typedef int16_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef int64_t int_fast64_t; +typedef uint8_t uint_fast8_t; +typedef uint16_t uint_fast16_t; +typedef uint32_t uint_fast32_t; +typedef uint64_t uint_fast64_t; + +// 7.18.1.4 Integer types capable of holding object pointers +#ifdef _WIN64 // [ + typedef signed __int64 intptr_t; + typedef unsigned __int64 uintptr_t; +#else // _WIN64 ][ + typedef _W64 signed int intptr_t; + typedef _W64 unsigned int uintptr_t; +#endif // _WIN64 ] + +// 7.18.1.5 Greatest-width integer types +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; + + +// 7.18.2 Limits of specified-width integer types + +#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 + +// 7.18.2.1 Limits of exact-width integer types +#define INT8_MIN ((int8_t)_I8_MIN) +#define INT8_MAX _I8_MAX +#define INT16_MIN ((int16_t)_I16_MIN) +#define INT16_MAX _I16_MAX +#define INT32_MIN ((int32_t)_I32_MIN) +#define INT32_MAX _I32_MAX +#define INT64_MIN ((int64_t)_I64_MIN) +#define INT64_MAX _I64_MAX +#define UINT8_MAX _UI8_MAX +#define UINT16_MAX _UI16_MAX +#define UINT32_MAX _UI32_MAX +#define UINT64_MAX _UI64_MAX + +// 7.18.2.2 Limits of minimum-width integer types +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MIN INT64_MIN +#define INT_LEAST64_MAX INT64_MAX +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +// 7.18.2.3 Limits of fastest minimum-width integer types +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MIN INT64_MIN +#define INT_FAST64_MAX INT64_MAX +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +// 7.18.2.4 Limits of integer types capable of holding object pointers +#ifdef _WIN64 // [ +# define INTPTR_MIN INT64_MIN +# define INTPTR_MAX INT64_MAX +# define UINTPTR_MAX UINT64_MAX +#else // _WIN64 ][ +# define INTPTR_MIN INT32_MIN +# define INTPTR_MAX INT32_MAX +# define UINTPTR_MAX UINT32_MAX +#endif // _WIN64 ] + +// 7.18.2.5 Limits of greatest-width integer types +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +// 7.18.3 Limits of other integer types + +#ifdef _WIN64 // [ +# define PTRDIFF_MIN _I64_MIN +# define PTRDIFF_MAX _I64_MAX +#else // _WIN64 ][ +# define PTRDIFF_MIN _I32_MIN +# define PTRDIFF_MAX _I32_MAX +#endif // _WIN64 ] + +#define SIG_ATOMIC_MIN INT_MIN +#define SIG_ATOMIC_MAX INT_MAX + +#ifndef SIZE_MAX // [ +# ifdef _WIN64 // [ +# define SIZE_MAX _UI64_MAX +# else // _WIN64 ][ +# define SIZE_MAX _UI32_MAX +# endif // _WIN64 ] +#endif // SIZE_MAX ] + +// WCHAR_MIN and WCHAR_MAX are also defined in +#ifndef WCHAR_MIN // [ +# define WCHAR_MIN 0 +#endif // WCHAR_MIN ] +#ifndef WCHAR_MAX // [ +# define WCHAR_MAX _UI16_MAX +#endif // WCHAR_MAX ] + +#define WINT_MIN 0 +#define WINT_MAX _UI16_MAX + +#endif // __STDC_LIMIT_MACROS ] + + +// 7.18.4 Limits of other integer types + +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 + +// 7.18.4.1 Macros for minimum-width integer constants + +#define INT8_C(val) val##i8 +#define INT16_C(val) val##i16 +#define INT32_C(val) val##i32 +#define INT64_C(val) val##i64 + +#define UINT8_C(val) val##ui8 +#define UINT16_C(val) val##ui16 +#define UINT32_C(val) val##ui32 +#define UINT64_C(val) val##ui64 + +// 7.18.4.2 Macros for greatest-width integer constants +// These #ifndef's are needed to prevent collisions with . +// Check out Issue 9 for the details. +#ifndef INTMAX_C // [ +# define INTMAX_C INT64_C +#endif // INTMAX_C ] +#ifndef UINTMAX_C // [ +# define UINTMAX_C UINT64_C +#endif // UINTMAX_C ] + +#endif // __STDC_CONSTANT_MACROS ] + +#endif // _MSC_VER >= 1600 ] + +#endif // _MSC_STDINT_H_ ] diff --git a/src/include/rapidjson/ostreamwrapper.h b/src/include/rapidjson/ostreamwrapper.h new file mode 100755 index 0000000..6f4667c --- /dev/null +++ b/src/include/rapidjson/ostreamwrapper.h @@ -0,0 +1,81 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_OSTREAMWRAPPER_H_ +#define RAPIDJSON_OSTREAMWRAPPER_H_ + +#include "stream.h" +#include + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! Wrapper of \c std::basic_ostream into RapidJSON's Stream concept. +/*! + The classes can be wrapped including but not limited to: + + - \c std::ostringstream + - \c std::stringstream + - \c std::wpstringstream + - \c std::wstringstream + - \c std::ifstream + - \c std::fstream + - \c std::wofstream + - \c std::wfstream + + \tparam StreamType Class derived from \c std::basic_ostream. +*/ + +template +class BasicOStreamWrapper { +public: + typedef typename StreamType::char_type Ch; + BasicOStreamWrapper(StreamType& stream) : stream_(stream) {} + + void Put(Ch c) { + stream_.put(c); + } + + void Flush() { + stream_.flush(); + } + + // Not implemented + char Peek() const { RAPIDJSON_ASSERT(false); return 0; } + char Take() { RAPIDJSON_ASSERT(false); return 0; } + size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } + char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } + +private: + BasicOStreamWrapper(const BasicOStreamWrapper&); + BasicOStreamWrapper& operator=(const BasicOStreamWrapper&); + + StreamType& stream_; +}; + +typedef BasicOStreamWrapper OStreamWrapper; +typedef BasicOStreamWrapper WOStreamWrapper; + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_OSTREAMWRAPPER_H_ diff --git a/src/include/rapidjson/pointer.h b/src/include/rapidjson/pointer.h new file mode 100755 index 0000000..b8143b6 --- /dev/null +++ b/src/include/rapidjson/pointer.h @@ -0,0 +1,1415 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_POINTER_H_ +#define RAPIDJSON_POINTER_H_ + +#include "document.h" +#include "internal/itoa.h" + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(switch-enum) +#elif defined(_MSC_VER) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +static const SizeType kPointerInvalidIndex = ~SizeType(0); //!< Represents an invalid index in GenericPointer::Token + +//! Error code of parsing. +/*! \ingroup RAPIDJSON_ERRORS + \see GenericPointer::GenericPointer, GenericPointer::GetParseErrorCode +*/ +enum PointerParseErrorCode { + kPointerParseErrorNone = 0, //!< The parse is successful + + kPointerParseErrorTokenMustBeginWithSolidus, //!< A token must begin with a '/' + kPointerParseErrorInvalidEscape, //!< Invalid escape + kPointerParseErrorInvalidPercentEncoding, //!< Invalid percent encoding in URI fragment + kPointerParseErrorCharacterMustPercentEncode //!< A character must percent encoded in URI fragment +}; + +/////////////////////////////////////////////////////////////////////////////// +// GenericPointer + +//! Represents a JSON Pointer. Use Pointer for UTF8 encoding and default allocator. +/*! + This class implements RFC 6901 "JavaScript Object Notation (JSON) Pointer" + (https://tools.ietf.org/html/rfc6901). + + A JSON pointer is for identifying a specific value in a JSON document + (GenericDocument). It can simplify coding of DOM tree manipulation, because it + can access multiple-level depth of DOM tree with single API call. + + After it parses a string representation (e.g. "/foo/0" or URI fragment + representation (e.g. "#/foo/0") into its internal representation (tokens), + it can be used to resolve a specific value in multiple documents, or sub-tree + of documents. + + Contrary to GenericValue, Pointer can be copy constructed and copy assigned. + Apart from assignment, a Pointer cannot be modified after construction. + + Although Pointer is very convenient, please aware that constructing Pointer + involves parsing and dynamic memory allocation. A special constructor with user- + supplied tokens eliminates these. + + GenericPointer depends on GenericDocument and GenericValue. + + \tparam ValueType The value type of the DOM tree. E.g. GenericValue > + \tparam Allocator The allocator type for allocating memory for internal representation. + + \note GenericPointer uses same encoding of ValueType. + However, Allocator of GenericPointer is independent of Allocator of Value. +*/ +template +class GenericPointer { +public: + typedef typename ValueType::EncodingType EncodingType; //!< Encoding type from Value + typedef typename ValueType::Ch Ch; //!< Character type from Value + + //! A token is the basic units of internal representation. + /*! + A JSON pointer string representation "/foo/123" is parsed to two tokens: + "foo" and 123. 123 will be represented in both numeric form and string form. + They are resolved according to the actual value type (object or array). + + For token that are not numbers, or the numeric value is out of bound + (greater than limits of SizeType), they are only treated as string form + (i.e. the token's index will be equal to kPointerInvalidIndex). + + This struct is public so that user can create a Pointer without parsing and + allocation, using a special constructor. + */ + struct Token { + const Ch* name; //!< Name of the token. It has null character at the end but it can contain null character. + SizeType length; //!< Length of the name. + SizeType index; //!< A valid array index, if it is not equal to kPointerInvalidIndex. + }; + + //!@name Constructors and destructor. + //@{ + + //! Default constructor. + GenericPointer(Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {} + + //! Constructor that parses a string or URI fragment representation. + /*! + \param source A null-terminated, string or URI fragment representation of JSON pointer. + \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one. + */ + explicit GenericPointer(const Ch* source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { + Parse(source, internal::StrLen(source)); + } + +#if RAPIDJSON_HAS_STDSTRING + //! Constructor that parses a string or URI fragment representation. + /*! + \param source A string or URI fragment representation of JSON pointer. + \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one. + \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. + */ + explicit GenericPointer(const std::basic_string& source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { + Parse(source.c_str(), source.size()); + } +#endif + + //! Constructor that parses a string or URI fragment representation, with length of the source string. + /*! + \param source A string or URI fragment representation of JSON pointer. + \param length Length of source. + \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one. + \note Slightly faster than the overload without length. + */ + GenericPointer(const Ch* source, size_t length, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { + Parse(source, length); + } + + //! Constructor with user-supplied tokens. + /*! + This constructor let user supplies const array of tokens. + This prevents the parsing process and eliminates allocation. + This is preferred for memory constrained environments. + + \param tokens An constant array of tokens representing the JSON pointer. + \param tokenCount Number of tokens. + + \b Example + \code + #define NAME(s) { s, sizeof(s) / sizeof(s[0]) - 1, kPointerInvalidIndex } + #define INDEX(i) { #i, sizeof(#i) - 1, i } + + static const Pointer::Token kTokens[] = { NAME("foo"), INDEX(123) }; + static const Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0])); + // Equivalent to static const Pointer p("/foo/123"); + + #undef NAME + #undef INDEX + \endcode + */ + GenericPointer(const Token* tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {} + + //! Copy constructor. + GenericPointer(const GenericPointer& rhs) : allocator_(rhs.allocator_), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { + *this = rhs; + } + + //! Copy constructor. + GenericPointer(const GenericPointer& rhs, Allocator* allocator) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { + *this = rhs; + } + + //! Destructor. + ~GenericPointer() { + if (nameBuffer_) // If user-supplied tokens constructor is used, nameBuffer_ is nullptr and tokens_ are not deallocated. + Allocator::Free(tokens_); + RAPIDJSON_DELETE(ownAllocator_); + } + + //! Assignment operator. + GenericPointer& operator=(const GenericPointer& rhs) { + if (this != &rhs) { + // Do not delete ownAllcator + if (nameBuffer_) + Allocator::Free(tokens_); + + tokenCount_ = rhs.tokenCount_; + parseErrorOffset_ = rhs.parseErrorOffset_; + parseErrorCode_ = rhs.parseErrorCode_; + + if (rhs.nameBuffer_) + CopyFromRaw(rhs); // Normally parsed tokens. + else { + tokens_ = rhs.tokens_; // User supplied const tokens. + nameBuffer_ = 0; + } + } + return *this; + } + + //! Swap the content of this pointer with an other. + /*! + \param other The pointer to swap with. + \note Constant complexity. + */ + GenericPointer& Swap(GenericPointer& other) RAPIDJSON_NOEXCEPT { + internal::Swap(allocator_, other.allocator_); + internal::Swap(ownAllocator_, other.ownAllocator_); + internal::Swap(nameBuffer_, other.nameBuffer_); + internal::Swap(tokens_, other.tokens_); + internal::Swap(tokenCount_, other.tokenCount_); + internal::Swap(parseErrorOffset_, other.parseErrorOffset_); + internal::Swap(parseErrorCode_, other.parseErrorCode_); + return *this; + } + + //! free-standing swap function helper + /*! + Helper function to enable support for common swap implementation pattern based on \c std::swap: + \code + void swap(MyClass& a, MyClass& b) { + using std::swap; + swap(a.pointer, b.pointer); + // ... + } + \endcode + \see Swap() + */ + friend inline void swap(GenericPointer& a, GenericPointer& b) RAPIDJSON_NOEXCEPT { a.Swap(b); } + + //@} + + //!@name Append token + //@{ + + //! Append a token and return a new Pointer + /*! + \param token Token to be appended. + \param allocator Allocator for the newly return Pointer. + \return A new Pointer with appended token. + */ + GenericPointer Append(const Token& token, Allocator* allocator = 0) const { + GenericPointer r; + r.allocator_ = allocator; + Ch *p = r.CopyFromRaw(*this, 1, token.length + 1); + std::memcpy(p, token.name, (token.length + 1) * sizeof(Ch)); + r.tokens_[tokenCount_].name = p; + r.tokens_[tokenCount_].length = token.length; + r.tokens_[tokenCount_].index = token.index; + return r; + } + + //! Append a name token with length, and return a new Pointer + /*! + \param name Name to be appended. + \param length Length of name. + \param allocator Allocator for the newly return Pointer. + \return A new Pointer with appended token. + */ + GenericPointer Append(const Ch* name, SizeType length, Allocator* allocator = 0) const { + Token token = { name, length, kPointerInvalidIndex }; + return Append(token, allocator); + } + + //! Append a name token without length, and return a new Pointer + /*! + \param name Name (const Ch*) to be appended. + \param allocator Allocator for the newly return Pointer. + \return A new Pointer with appended token. + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >), (GenericPointer)) + Append(T* name, Allocator* allocator = 0) const { + return Append(name, internal::StrLen(name), allocator); + } + +#if RAPIDJSON_HAS_STDSTRING + //! Append a name token, and return a new Pointer + /*! + \param name Name to be appended. + \param allocator Allocator for the newly return Pointer. + \return A new Pointer with appended token. + */ + GenericPointer Append(const std::basic_string& name, Allocator* allocator = 0) const { + return Append(name.c_str(), static_cast(name.size()), allocator); + } +#endif + + //! Append a index token, and return a new Pointer + /*! + \param index Index to be appended. + \param allocator Allocator for the newly return Pointer. + \return A new Pointer with appended token. + */ + GenericPointer Append(SizeType index, Allocator* allocator = 0) const { + char buffer[21]; + char* end = sizeof(SizeType) == 4 ? internal::u32toa(index, buffer) : internal::u64toa(index, buffer); + SizeType length = static_cast(end - buffer); + buffer[length] = '\0'; + + if (sizeof(Ch) == 1) { + Token token = { reinterpret_cast(buffer), length, index }; + return Append(token, allocator); + } + else { + Ch name[21]; + for (size_t i = 0; i <= length; i++) + name[i] = static_cast(buffer[i]); + Token token = { name, length, index }; + return Append(token, allocator); + } + } + + //! Append a token by value, and return a new Pointer + /*! + \param token token to be appended. + \param allocator Allocator for the newly return Pointer. + \return A new Pointer with appended token. + */ + GenericPointer Append(const ValueType& token, Allocator* allocator = 0) const { + if (token.IsString()) + return Append(token.GetString(), token.GetStringLength(), allocator); + else { + RAPIDJSON_ASSERT(token.IsUint64()); + RAPIDJSON_ASSERT(token.GetUint64() <= SizeType(~0)); + return Append(static_cast(token.GetUint64()), allocator); + } + } + + //!@name Handling Parse Error + //@{ + + //! Check whether this is a valid pointer. + bool IsValid() const { return parseErrorCode_ == kPointerParseErrorNone; } + + //! Get the parsing error offset in code unit. + size_t GetParseErrorOffset() const { return parseErrorOffset_; } + + //! Get the parsing error code. + PointerParseErrorCode GetParseErrorCode() const { return parseErrorCode_; } + + //@} + + //! Get the allocator of this pointer. + Allocator& GetAllocator() { return *allocator_; } + + //!@name Tokens + //@{ + + //! Get the token array (const version only). + const Token* GetTokens() const { return tokens_; } + + //! Get the number of tokens. + size_t GetTokenCount() const { return tokenCount_; } + + //@} + + //!@name Equality/inequality operators + //@{ + + //! Equality operator. + /*! + \note When any pointers are invalid, always returns false. + */ + bool operator==(const GenericPointer& rhs) const { + if (!IsValid() || !rhs.IsValid() || tokenCount_ != rhs.tokenCount_) + return false; + + for (size_t i = 0; i < tokenCount_; i++) { + if (tokens_[i].index != rhs.tokens_[i].index || + tokens_[i].length != rhs.tokens_[i].length || + (tokens_[i].length != 0 && std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch)* tokens_[i].length) != 0)) + { + return false; + } + } + + return true; + } + + //! Inequality operator. + /*! + \note When any pointers are invalid, always returns true. + */ + bool operator!=(const GenericPointer& rhs) const { return !(*this == rhs); } + + //! Less than operator. + /*! + \note Invalid pointers are always greater than valid ones. + */ + bool operator<(const GenericPointer& rhs) const { + if (!IsValid()) + return false; + if (!rhs.IsValid()) + return true; + + if (tokenCount_ != rhs.tokenCount_) + return tokenCount_ < rhs.tokenCount_; + + for (size_t i = 0; i < tokenCount_; i++) { + if (tokens_[i].index != rhs.tokens_[i].index) + return tokens_[i].index < rhs.tokens_[i].index; + + if (tokens_[i].length != rhs.tokens_[i].length) + return tokens_[i].length < rhs.tokens_[i].length; + + if (int cmp = std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch) * tokens_[i].length)) + return cmp < 0; + } + + return false; + } + + //@} + + //!@name Stringify + //@{ + + //! Stringify the pointer into string representation. + /*! + \tparam OutputStream Type of output stream. + \param os The output stream. + */ + template + bool Stringify(OutputStream& os) const { + return Stringify(os); + } + + //! Stringify the pointer into URI fragment representation. + /*! + \tparam OutputStream Type of output stream. + \param os The output stream. + */ + template + bool StringifyUriFragment(OutputStream& os) const { + return Stringify(os); + } + + //@} + + //!@name Create value + //@{ + + //! Create a value in a subtree. + /*! + If the value is not exist, it creates all parent values and a JSON Null value. + So it always succeed and return the newly created or existing value. + + Remind that it may change types of parents according to tokens, so it + potentially removes previously stored values. For example, if a document + was an array, and "/foo" is used to create a value, then the document + will be changed to an object, and all existing array elements are lost. + + \param root Root value of a DOM subtree to be resolved. It can be any value other than document root. + \param allocator Allocator for creating the values if the specified value or its parents are not exist. + \param alreadyExist If non-null, it stores whether the resolved value is already exist. + \return The resolved newly created (a JSON Null value), or already exists value. + */ + ValueType& Create(ValueType& root, typename ValueType::AllocatorType& allocator, bool* alreadyExist = 0) const { + RAPIDJSON_ASSERT(IsValid()); + ValueType* v = &root; + bool exist = true; + for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { + if (v->IsArray() && t->name[0] == '-' && t->length == 1) { + v->PushBack(ValueType().Move(), allocator); + v = &((*v)[v->Size() - 1]); + exist = false; + } + else { + if (t->index == kPointerInvalidIndex) { // must be object name + if (!v->IsObject()) + v->SetObject(); // Change to Object + } + else { // object name or array index + if (!v->IsArray() && !v->IsObject()) + v->SetArray(); // Change to Array + } + + if (v->IsArray()) { + if (t->index >= v->Size()) { + v->Reserve(t->index + 1, allocator); + while (t->index >= v->Size()) + v->PushBack(ValueType().Move(), allocator); + exist = false; + } + v = &((*v)[t->index]); + } + else { + typename ValueType::MemberIterator m = v->FindMember(GenericValue(GenericStringRef(t->name, t->length))); + if (m == v->MemberEnd()) { + v->AddMember(ValueType(t->name, t->length, allocator).Move(), ValueType().Move(), allocator); + m = v->MemberEnd(); + v = &(--m)->value; // Assumes AddMember() appends at the end + exist = false; + } + else + v = &m->value; + } + } + } + + if (alreadyExist) + *alreadyExist = exist; + + return *v; + } + + //! Creates a value in a document. + /*! + \param document A document to be resolved. + \param alreadyExist If non-null, it stores whether the resolved value is already exist. + \return The resolved newly created, or already exists value. + */ + template + ValueType& Create(GenericDocument& document, bool* alreadyExist = 0) const { + return Create(document, document.GetAllocator(), alreadyExist); + } + + //@} + + //!@name Query value + //@{ + + //! Query a value in a subtree. + /*! + \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. + \param unresolvedTokenIndex If the pointer cannot resolve a token in the pointer, this parameter can obtain the index of unresolved token. + \return Pointer to the value if it can be resolved. Otherwise null. + + \note + There are only 3 situations when a value cannot be resolved: + 1. A value in the path is not an array nor object. + 2. An object value does not contain the token. + 3. A token is out of range of an array value. + + Use unresolvedTokenIndex to retrieve the token index. + */ + ValueType* Get(ValueType& root, size_t* unresolvedTokenIndex = 0) const { + RAPIDJSON_ASSERT(IsValid()); + ValueType* v = &root; + for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { + switch (v->GetType()) { + case kObjectType: + { + typename ValueType::MemberIterator m = v->FindMember(GenericValue(GenericStringRef(t->name, t->length))); + if (m == v->MemberEnd()) + break; + v = &m->value; + } + continue; + case kArrayType: + if (t->index == kPointerInvalidIndex || t->index >= v->Size()) + break; + v = &((*v)[t->index]); + continue; + default: + break; + } + + // Error: unresolved token + if (unresolvedTokenIndex) + *unresolvedTokenIndex = static_cast(t - tokens_); + return 0; + } + return v; + } + + //! Query a const value in a const subtree. + /*! + \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. + \return Pointer to the value if it can be resolved. Otherwise null. + */ + const ValueType* Get(const ValueType& root, size_t* unresolvedTokenIndex = 0) const { + return Get(const_cast(root), unresolvedTokenIndex); + } + + //@} + + //!@name Query a value with default + //@{ + + //! Query a value in a subtree with default value. + /*! + Similar to Get(), but if the specified value do not exists, it creates all parents and clone the default value. + So that this function always succeed. + + \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. + \param defaultValue Default value to be cloned if the value was not exists. + \param allocator Allocator for creating the values if the specified value or its parents are not exist. + \see Create() + */ + ValueType& GetWithDefault(ValueType& root, const ValueType& defaultValue, typename ValueType::AllocatorType& allocator) const { + bool alreadyExist; + ValueType& v = Create(root, allocator, &alreadyExist); + return alreadyExist ? v : v.CopyFrom(defaultValue, allocator); + } + + //! Query a value in a subtree with default null-terminated string. + ValueType& GetWithDefault(ValueType& root, const Ch* defaultValue, typename ValueType::AllocatorType& allocator) const { + bool alreadyExist; + ValueType& v = Create(root, allocator, &alreadyExist); + return alreadyExist ? v : v.SetString(defaultValue, allocator); + } + +#if RAPIDJSON_HAS_STDSTRING + //! Query a value in a subtree with default std::basic_string. + ValueType& GetWithDefault(ValueType& root, const std::basic_string& defaultValue, typename ValueType::AllocatorType& allocator) const { + bool alreadyExist; + ValueType& v = Create(root, allocator, &alreadyExist); + return alreadyExist ? v : v.SetString(defaultValue, allocator); + } +#endif + + //! Query a value in a subtree with default primitive value. + /*! + \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) + GetWithDefault(ValueType& root, T defaultValue, typename ValueType::AllocatorType& allocator) const { + return GetWithDefault(root, ValueType(defaultValue).Move(), allocator); + } + + //! Query a value in a document with default value. + template + ValueType& GetWithDefault(GenericDocument& document, const ValueType& defaultValue) const { + return GetWithDefault(document, defaultValue, document.GetAllocator()); + } + + //! Query a value in a document with default null-terminated string. + template + ValueType& GetWithDefault(GenericDocument& document, const Ch* defaultValue) const { + return GetWithDefault(document, defaultValue, document.GetAllocator()); + } + +#if RAPIDJSON_HAS_STDSTRING + //! Query a value in a document with default std::basic_string. + template + ValueType& GetWithDefault(GenericDocument& document, const std::basic_string& defaultValue) const { + return GetWithDefault(document, defaultValue, document.GetAllocator()); + } +#endif + + //! Query a value in a document with default primitive value. + /*! + \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) + GetWithDefault(GenericDocument& document, T defaultValue) const { + return GetWithDefault(document, defaultValue, document.GetAllocator()); + } + + //@} + + //!@name Set a value + //@{ + + //! Set a value in a subtree, with move semantics. + /*! + It creates all parents if they are not exist or types are different to the tokens. + So this function always succeeds but potentially remove existing values. + + \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. + \param value Value to be set. + \param allocator Allocator for creating the values if the specified value or its parents are not exist. + \see Create() + */ + ValueType& Set(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const { + return Create(root, allocator) = value; + } + + //! Set a value in a subtree, with copy semantics. + ValueType& Set(ValueType& root, const ValueType& value, typename ValueType::AllocatorType& allocator) const { + return Create(root, allocator).CopyFrom(value, allocator); + } + + //! Set a null-terminated string in a subtree. + ValueType& Set(ValueType& root, const Ch* value, typename ValueType::AllocatorType& allocator) const { + return Create(root, allocator) = ValueType(value, allocator).Move(); + } + +#if RAPIDJSON_HAS_STDSTRING + //! Set a std::basic_string in a subtree. + ValueType& Set(ValueType& root, const std::basic_string& value, typename ValueType::AllocatorType& allocator) const { + return Create(root, allocator) = ValueType(value, allocator).Move(); + } +#endif + + //! Set a primitive value in a subtree. + /*! + \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) + Set(ValueType& root, T value, typename ValueType::AllocatorType& allocator) const { + return Create(root, allocator) = ValueType(value).Move(); + } + + //! Set a value in a document, with move semantics. + template + ValueType& Set(GenericDocument& document, ValueType& value) const { + return Create(document) = value; + } + + //! Set a value in a document, with copy semantics. + template + ValueType& Set(GenericDocument& document, const ValueType& value) const { + return Create(document).CopyFrom(value, document.GetAllocator()); + } + + //! Set a null-terminated string in a document. + template + ValueType& Set(GenericDocument& document, const Ch* value) const { + return Create(document) = ValueType(value, document.GetAllocator()).Move(); + } + +#if RAPIDJSON_HAS_STDSTRING + //! Sets a std::basic_string in a document. + template + ValueType& Set(GenericDocument& document, const std::basic_string& value) const { + return Create(document) = ValueType(value, document.GetAllocator()).Move(); + } +#endif + + //! Set a primitive value in a document. + /*! + \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) + Set(GenericDocument& document, T value) const { + return Create(document) = value; + } + + //@} + + //!@name Swap a value + //@{ + + //! Swap a value with a value in a subtree. + /*! + It creates all parents if they are not exist or types are different to the tokens. + So this function always succeeds but potentially remove existing values. + + \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. + \param value Value to be swapped. + \param allocator Allocator for creating the values if the specified value or its parents are not exist. + \see Create() + */ + ValueType& Swap(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const { + return Create(root, allocator).Swap(value); + } + + //! Swap a value with a value in a document. + template + ValueType& Swap(GenericDocument& document, ValueType& value) const { + return Create(document).Swap(value); + } + + //@} + + //! Erase a value in a subtree. + /*! + \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. + \return Whether the resolved value is found and erased. + + \note Erasing with an empty pointer \c Pointer(""), i.e. the root, always fail and return false. + */ + bool Erase(ValueType& root) const { + RAPIDJSON_ASSERT(IsValid()); + if (tokenCount_ == 0) // Cannot erase the root + return false; + + ValueType* v = &root; + const Token* last = tokens_ + (tokenCount_ - 1); + for (const Token *t = tokens_; t != last; ++t) { + switch (v->GetType()) { + case kObjectType: + { + typename ValueType::MemberIterator m = v->FindMember(GenericValue(GenericStringRef(t->name, t->length))); + if (m == v->MemberEnd()) + return false; + v = &m->value; + } + break; + case kArrayType: + if (t->index == kPointerInvalidIndex || t->index >= v->Size()) + return false; + v = &((*v)[t->index]); + break; + default: + return false; + } + } + + switch (v->GetType()) { + case kObjectType: + return v->EraseMember(GenericStringRef(last->name, last->length)); + case kArrayType: + if (last->index == kPointerInvalidIndex || last->index >= v->Size()) + return false; + v->Erase(v->Begin() + last->index); + return true; + default: + return false; + } + } + +private: + //! Clone the content from rhs to this. + /*! + \param rhs Source pointer. + \param extraToken Extra tokens to be allocated. + \param extraNameBufferSize Extra name buffer size (in number of Ch) to be allocated. + \return Start of non-occupied name buffer, for storing extra names. + */ + Ch* CopyFromRaw(const GenericPointer& rhs, size_t extraToken = 0, size_t extraNameBufferSize = 0) { + if (!allocator_) // allocator is independently owned. + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); + + size_t nameBufferSize = rhs.tokenCount_; // null terminators for tokens + for (Token *t = rhs.tokens_; t != rhs.tokens_ + rhs.tokenCount_; ++t) + nameBufferSize += t->length; + + tokenCount_ = rhs.tokenCount_ + extraToken; + tokens_ = static_cast(allocator_->Malloc(tokenCount_ * sizeof(Token) + (nameBufferSize + extraNameBufferSize) * sizeof(Ch))); + nameBuffer_ = reinterpret_cast(tokens_ + tokenCount_); + if (rhs.tokenCount_ > 0) { + std::memcpy(tokens_, rhs.tokens_, rhs.tokenCount_ * sizeof(Token)); + } + if (nameBufferSize > 0) { + std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch)); + } + + // Adjust pointers to name buffer + std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_; + for (Token *t = tokens_; t != tokens_ + rhs.tokenCount_; ++t) + t->name += diff; + + return nameBuffer_ + nameBufferSize; + } + + //! Check whether a character should be percent-encoded. + /*! + According to RFC 3986 2.3 Unreserved Characters. + \param c The character (code unit) to be tested. + */ + bool NeedPercentEncode(Ch c) const { + return !((c >= '0' && c <= '9') || (c >= 'A' && c <='Z') || (c >= 'a' && c <= 'z') || c == '-' || c == '.' || c == '_' || c =='~'); + } + + //! Parse a JSON String or its URI fragment representation into tokens. +#ifndef __clang__ // -Wdocumentation + /*! + \param source Either a JSON Pointer string, or its URI fragment representation. Not need to be null terminated. + \param length Length of the source string. + \note Source cannot be JSON String Representation of JSON Pointer, e.g. In "/\u0000", \u0000 will not be unescaped. + */ +#endif + void Parse(const Ch* source, size_t length) { + RAPIDJSON_ASSERT(source != NULL); + RAPIDJSON_ASSERT(nameBuffer_ == 0); + RAPIDJSON_ASSERT(tokens_ == 0); + + // Create own allocator if user did not supply. + if (!allocator_) + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); + + // Count number of '/' as tokenCount + tokenCount_ = 0; + for (const Ch* s = source; s != source + length; s++) + if (*s == '/') + tokenCount_++; + + Token* token = tokens_ = static_cast(allocator_->Malloc(tokenCount_ * sizeof(Token) + length * sizeof(Ch))); + Ch* name = nameBuffer_ = reinterpret_cast(tokens_ + tokenCount_); + size_t i = 0; + + // Detect if it is a URI fragment + bool uriFragment = false; + if (source[i] == '#') { + uriFragment = true; + i++; + } + + if (i != length && source[i] != '/') { + parseErrorCode_ = kPointerParseErrorTokenMustBeginWithSolidus; + goto error; + } + + while (i < length) { + RAPIDJSON_ASSERT(source[i] == '/'); + i++; // consumes '/' + + token->name = name; + bool isNumber = true; + + while (i < length && source[i] != '/') { + Ch c = source[i]; + if (uriFragment) { + // Decoding percent-encoding for URI fragment + if (c == '%') { + PercentDecodeStream is(&source[i], source + length); + GenericInsituStringStream os(name); + Ch* begin = os.PutBegin(); + if (!Transcoder, EncodingType>().Validate(is, os) || !is.IsValid()) { + parseErrorCode_ = kPointerParseErrorInvalidPercentEncoding; + goto error; + } + size_t len = os.PutEnd(begin); + i += is.Tell() - 1; + if (len == 1) + c = *name; + else { + name += len; + isNumber = false; + i++; + continue; + } + } + else if (NeedPercentEncode(c)) { + parseErrorCode_ = kPointerParseErrorCharacterMustPercentEncode; + goto error; + } + } + + i++; + + // Escaping "~0" -> '~', "~1" -> '/' + if (c == '~') { + if (i < length) { + c = source[i]; + if (c == '0') c = '~'; + else if (c == '1') c = '/'; + else { + parseErrorCode_ = kPointerParseErrorInvalidEscape; + goto error; + } + i++; + } + else { + parseErrorCode_ = kPointerParseErrorInvalidEscape; + goto error; + } + } + + // First check for index: all of characters are digit + if (c < '0' || c > '9') + isNumber = false; + + *name++ = c; + } + token->length = static_cast(name - token->name); + if (token->length == 0) + isNumber = false; + *name++ = '\0'; // Null terminator + + // Second check for index: more than one digit cannot have leading zero + if (isNumber && token->length > 1 && token->name[0] == '0') + isNumber = false; + + // String to SizeType conversion + SizeType n = 0; + if (isNumber) { + for (size_t j = 0; j < token->length; j++) { + SizeType m = n * 10 + static_cast(token->name[j] - '0'); + if (m < n) { // overflow detection + isNumber = false; + break; + } + n = m; + } + } + + token->index = isNumber ? n : kPointerInvalidIndex; + token++; + } + + RAPIDJSON_ASSERT(name <= nameBuffer_ + length); // Should not overflow buffer + parseErrorCode_ = kPointerParseErrorNone; + return; + + error: + Allocator::Free(tokens_); + nameBuffer_ = 0; + tokens_ = 0; + tokenCount_ = 0; + parseErrorOffset_ = i; + return; + } + + //! Stringify to string or URI fragment representation. + /*! + \tparam uriFragment True for stringifying to URI fragment representation. False for string representation. + \tparam OutputStream type of output stream. + \param os The output stream. + */ + template + bool Stringify(OutputStream& os) const { + RAPIDJSON_ASSERT(IsValid()); + + if (uriFragment) + os.Put('#'); + + for (Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { + os.Put('/'); + for (size_t j = 0; j < t->length; j++) { + Ch c = t->name[j]; + if (c == '~') { + os.Put('~'); + os.Put('0'); + } + else if (c == '/') { + os.Put('~'); + os.Put('1'); + } + else if (uriFragment && NeedPercentEncode(c)) { + // Transcode to UTF8 sequence + GenericStringStream source(&t->name[j]); + PercentEncodeStream target(os); + if (!Transcoder >().Validate(source, target)) + return false; + j += source.Tell() - 1; + } + else + os.Put(c); + } + } + return true; + } + + //! A helper stream for decoding a percent-encoded sequence into code unit. + /*! + This stream decodes %XY triplet into code unit (0-255). + If it encounters invalid characters, it sets output code unit as 0 and + mark invalid, and to be checked by IsValid(). + */ + class PercentDecodeStream { + public: + typedef typename ValueType::Ch Ch; + + //! Constructor + /*! + \param source Start of the stream + \param end Past-the-end of the stream. + */ + PercentDecodeStream(const Ch* source, const Ch* end) : src_(source), head_(source), end_(end), valid_(true) {} + + Ch Take() { + if (*src_ != '%' || src_ + 3 > end_) { // %XY triplet + valid_ = false; + return 0; + } + src_++; + Ch c = 0; + for (int j = 0; j < 2; j++) { + c = static_cast(c << 4); + Ch h = *src_; + if (h >= '0' && h <= '9') c = static_cast(c + h - '0'); + else if (h >= 'A' && h <= 'F') c = static_cast(c + h - 'A' + 10); + else if (h >= 'a' && h <= 'f') c = static_cast(c + h - 'a' + 10); + else { + valid_ = false; + return 0; + } + src_++; + } + return c; + } + + size_t Tell() const { return static_cast(src_ - head_); } + bool IsValid() const { return valid_; } + + private: + const Ch* src_; //!< Current read position. + const Ch* head_; //!< Original head of the string. + const Ch* end_; //!< Past-the-end position. + bool valid_; //!< Whether the parsing is valid. + }; + + //! A helper stream to encode character (UTF-8 code unit) into percent-encoded sequence. + template + class PercentEncodeStream { + public: + PercentEncodeStream(OutputStream& os) : os_(os) {} + void Put(char c) { // UTF-8 must be byte + unsigned char u = static_cast(c); + static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + os_.Put('%'); + os_.Put(static_cast(hexDigits[u >> 4])); + os_.Put(static_cast(hexDigits[u & 15])); + } + private: + OutputStream& os_; + }; + + Allocator* allocator_; //!< The current allocator. It is either user-supplied or equal to ownAllocator_. + Allocator* ownAllocator_; //!< Allocator owned by this Pointer. + Ch* nameBuffer_; //!< A buffer containing all names in tokens. + Token* tokens_; //!< A list of tokens. + size_t tokenCount_; //!< Number of tokens in tokens_. + size_t parseErrorOffset_; //!< Offset in code unit when parsing fail. + PointerParseErrorCode parseErrorCode_; //!< Parsing error code. +}; + +//! GenericPointer for Value (UTF-8, default allocator). +typedef GenericPointer Pointer; + +//!@name Helper functions for GenericPointer +//@{ + +////////////////////////////////////////////////////////////////////////////// + +template +typename T::ValueType& CreateValueByPointer(T& root, const GenericPointer& pointer, typename T::AllocatorType& a) { + return pointer.Create(root, a); +} + +template +typename T::ValueType& CreateValueByPointer(T& root, const CharType(&source)[N], typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).Create(root, a); +} + +// No allocator parameter + +template +typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const GenericPointer& pointer) { + return pointer.Create(document); +} + +template +typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const CharType(&source)[N]) { + return GenericPointer(source, N - 1).Create(document); +} + +////////////////////////////////////////////////////////////////////////////// + +template +typename T::ValueType* GetValueByPointer(T& root, const GenericPointer& pointer, size_t* unresolvedTokenIndex = 0) { + return pointer.Get(root, unresolvedTokenIndex); +} + +template +const typename T::ValueType* GetValueByPointer(const T& root, const GenericPointer& pointer, size_t* unresolvedTokenIndex = 0) { + return pointer.Get(root, unresolvedTokenIndex); +} + +template +typename T::ValueType* GetValueByPointer(T& root, const CharType (&source)[N], size_t* unresolvedTokenIndex = 0) { + return GenericPointer(source, N - 1).Get(root, unresolvedTokenIndex); +} + +template +const typename T::ValueType* GetValueByPointer(const T& root, const CharType(&source)[N], size_t* unresolvedTokenIndex = 0) { + return GenericPointer(source, N - 1).Get(root, unresolvedTokenIndex); +} + +////////////////////////////////////////////////////////////////////////////// + +template +typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer& pointer, const typename T::ValueType& defaultValue, typename T::AllocatorType& a) { + return pointer.GetWithDefault(root, defaultValue, a); +} + +template +typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer& pointer, const typename T::Ch* defaultValue, typename T::AllocatorType& a) { + return pointer.GetWithDefault(root, defaultValue, a); +} + +#if RAPIDJSON_HAS_STDSTRING +template +typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer& pointer, const std::basic_string& defaultValue, typename T::AllocatorType& a) { + return pointer.GetWithDefault(root, defaultValue, a); +} +#endif + +template +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) +GetValueByPointerWithDefault(T& root, const GenericPointer& pointer, T2 defaultValue, typename T::AllocatorType& a) { + return pointer.GetWithDefault(root, defaultValue, a); +} + +template +typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::ValueType& defaultValue, typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); +} + +template +typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::Ch* defaultValue, typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); +} + +#if RAPIDJSON_HAS_STDSTRING +template +typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const std::basic_string& defaultValue, typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); +} +#endif + +template +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) +GetValueByPointerWithDefault(T& root, const CharType(&source)[N], T2 defaultValue, typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); +} + +// No allocator parameter + +template +typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, const typename DocumentType::ValueType& defaultValue) { + return pointer.GetWithDefault(document, defaultValue); +} + +template +typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, const typename DocumentType::Ch* defaultValue) { + return pointer.GetWithDefault(document, defaultValue); +} + +#if RAPIDJSON_HAS_STDSTRING +template +typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, const std::basic_string& defaultValue) { + return pointer.GetWithDefault(document, defaultValue); +} +#endif + +template +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) +GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, T2 defaultValue) { + return pointer.GetWithDefault(document, defaultValue); +} + +template +typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& defaultValue) { + return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); +} + +template +typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* defaultValue) { + return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); +} + +#if RAPIDJSON_HAS_STDSTRING +template +typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const std::basic_string& defaultValue) { + return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); +} +#endif + +template +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) +GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], T2 defaultValue) { + return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); +} + +////////////////////////////////////////////////////////////////////////////// + +template +typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, typename T::ValueType& value, typename T::AllocatorType& a) { + return pointer.Set(root, value, a); +} + +template +typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, const typename T::ValueType& value, typename T::AllocatorType& a) { + return pointer.Set(root, value, a); +} + +template +typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, const typename T::Ch* value, typename T::AllocatorType& a) { + return pointer.Set(root, value, a); +} + +#if RAPIDJSON_HAS_STDSTRING +template +typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, const std::basic_string& value, typename T::AllocatorType& a) { + return pointer.Set(root, value, a); +} +#endif + +template +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) +SetValueByPointer(T& root, const GenericPointer& pointer, T2 value, typename T::AllocatorType& a) { + return pointer.Set(root, value, a); +} + +template +typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).Set(root, value, a); +} + +template +typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::ValueType& value, typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).Set(root, value, a); +} + +template +typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::Ch* value, typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).Set(root, value, a); +} + +#if RAPIDJSON_HAS_STDSTRING +template +typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const std::basic_string& value, typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).Set(root, value, a); +} +#endif + +template +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) +SetValueByPointer(T& root, const CharType(&source)[N], T2 value, typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).Set(root, value, a); +} + +// No allocator parameter + +template +typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, typename DocumentType::ValueType& value) { + return pointer.Set(document, value); +} + +template +typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, const typename DocumentType::ValueType& value) { + return pointer.Set(document, value); +} + +template +typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, const typename DocumentType::Ch* value) { + return pointer.Set(document, value); +} + +#if RAPIDJSON_HAS_STDSTRING +template +typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, const std::basic_string& value) { + return pointer.Set(document, value); +} +#endif + +template +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) +SetValueByPointer(DocumentType& document, const GenericPointer& pointer, T2 value) { + return pointer.Set(document, value); +} + +template +typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) { + return GenericPointer(source, N - 1).Set(document, value); +} + +template +typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& value) { + return GenericPointer(source, N - 1).Set(document, value); +} + +template +typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* value) { + return GenericPointer(source, N - 1).Set(document, value); +} + +#if RAPIDJSON_HAS_STDSTRING +template +typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const std::basic_string& value) { + return GenericPointer(source, N - 1).Set(document, value); +} +#endif + +template +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) +SetValueByPointer(DocumentType& document, const CharType(&source)[N], T2 value) { + return GenericPointer(source, N - 1).Set(document, value); +} + +////////////////////////////////////////////////////////////////////////////// + +template +typename T::ValueType& SwapValueByPointer(T& root, const GenericPointer& pointer, typename T::ValueType& value, typename T::AllocatorType& a) { + return pointer.Swap(root, value, a); +} + +template +typename T::ValueType& SwapValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).Swap(root, value, a); +} + +template +typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const GenericPointer& pointer, typename DocumentType::ValueType& value) { + return pointer.Swap(document, value); +} + +template +typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) { + return GenericPointer(source, N - 1).Swap(document, value); +} + +////////////////////////////////////////////////////////////////////////////// + +template +bool EraseValueByPointer(T& root, const GenericPointer& pointer) { + return pointer.Erase(root); +} + +template +bool EraseValueByPointer(T& root, const CharType(&source)[N]) { + return GenericPointer(source, N - 1).Erase(root); +} + +//@} + +RAPIDJSON_NAMESPACE_END + +#if defined(__clang__) || defined(_MSC_VER) +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_POINTER_H_ diff --git a/src/include/rapidjson/prettywriter.h b/src/include/rapidjson/prettywriter.h new file mode 100755 index 0000000..94eeb69 --- /dev/null +++ b/src/include/rapidjson/prettywriter.h @@ -0,0 +1,277 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_PRETTYWRITER_H_ +#define RAPIDJSON_PRETTYWRITER_H_ + +#include "writer.h" + +#ifdef __GNUC__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#endif + +#if defined(__clang__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(c++98-compat) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! Combination of PrettyWriter format flags. +/*! \see PrettyWriter::SetFormatOptions + */ +enum PrettyFormatOptions { + kFormatDefault = 0, //!< Default pretty formatting. + kFormatSingleLineArray = 1 //!< Format arrays on a single line. +}; + +//! Writer with indentation and spacing. +/*! + \tparam OutputStream Type of output os. + \tparam SourceEncoding Encoding of source string. + \tparam TargetEncoding Encoding of output stream. + \tparam StackAllocator Type of allocator for allocating memory of stack. +*/ +template, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags> +class PrettyWriter : public Writer { +public: + typedef Writer Base; + typedef typename Base::Ch Ch; + + //! Constructor + /*! \param os Output stream. + \param allocator User supplied allocator. If it is null, it will create a private one. + \param levelDepth Initial capacity of stack. + */ + explicit PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : + Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {} + + + explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : + Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {} + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + PrettyWriter(PrettyWriter&& rhs) : + Base(std::forward(rhs)), indentChar_(rhs.indentChar_), indentCharCount_(rhs.indentCharCount_), formatOptions_(rhs.formatOptions_) {} +#endif + + //! Set custom indentation. + /*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r'). + \param indentCharCount Number of indent characters for each indentation level. + \note The default indentation is 4 spaces. + */ + PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) { + RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r'); + indentChar_ = indentChar; + indentCharCount_ = indentCharCount; + return *this; + } + + //! Set pretty writer formatting options. + /*! \param options Formatting options. + */ + PrettyWriter& SetFormatOptions(PrettyFormatOptions options) { + formatOptions_ = options; + return *this; + } + + /*! @name Implementation of Handler + \see Handler + */ + //@{ + + bool Null() { PrettyPrefix(kNullType); return Base::EndValue(Base::WriteNull()); } + bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::EndValue(Base::WriteBool(b)); } + bool Int(int i) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteInt(i)); } + bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteUint(u)); } + bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteInt64(i64)); } + bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteUint64(u64)); } + bool Double(double d) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteDouble(d)); } + + bool RawNumber(const Ch* str, SizeType length, bool copy = false) { + RAPIDJSON_ASSERT(str != 0); + (void)copy; + PrettyPrefix(kNumberType); + return Base::EndValue(Base::WriteString(str, length)); + } + + bool String(const Ch* str, SizeType length, bool copy = false) { + RAPIDJSON_ASSERT(str != 0); + (void)copy; + PrettyPrefix(kStringType); + return Base::EndValue(Base::WriteString(str, length)); + } + +#if RAPIDJSON_HAS_STDSTRING + bool String(const std::basic_string& str) { + return String(str.data(), SizeType(str.size())); + } +#endif + + bool StartObject() { + PrettyPrefix(kObjectType); + new (Base::level_stack_.template Push()) typename Base::Level(false); + return Base::WriteStartObject(); + } + + bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } + +#if RAPIDJSON_HAS_STDSTRING + bool Key(const std::basic_string& str) { + return Key(str.data(), SizeType(str.size())); + } +#endif + + bool EndObject(SizeType memberCount = 0) { + (void)memberCount; + RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); // not inside an Object + RAPIDJSON_ASSERT(!Base::level_stack_.template Top()->inArray); // currently inside an Array, not Object + RAPIDJSON_ASSERT(0 == Base::level_stack_.template Top()->valueCount % 2); // Object has a Key without a Value + + bool empty = Base::level_stack_.template Pop(1)->valueCount == 0; + + if (!empty) { + Base::os_->Put('\n'); + WriteIndent(); + } + bool ret = Base::EndValue(Base::WriteEndObject()); + (void)ret; + RAPIDJSON_ASSERT(ret == true); + if (Base::level_stack_.Empty()) // end of json text + Base::Flush(); + return true; + } + + bool StartArray() { + PrettyPrefix(kArrayType); + new (Base::level_stack_.template Push()) typename Base::Level(true); + return Base::WriteStartArray(); + } + + bool EndArray(SizeType memberCount = 0) { + (void)memberCount; + RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); + RAPIDJSON_ASSERT(Base::level_stack_.template Top()->inArray); + bool empty = Base::level_stack_.template Pop(1)->valueCount == 0; + + if (!empty && !(formatOptions_ & kFormatSingleLineArray)) { + Base::os_->Put('\n'); + WriteIndent(); + } + bool ret = Base::EndValue(Base::WriteEndArray()); + (void)ret; + RAPIDJSON_ASSERT(ret == true); + if (Base::level_stack_.Empty()) // end of json text + Base::Flush(); + return true; + } + + //@} + + /*! @name Convenience extensions */ + //@{ + + //! Simpler but slower overload. + bool String(const Ch* str) { return String(str, internal::StrLen(str)); } + bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); } + + //@} + + //! Write a raw JSON value. + /*! + For user to write a stringified JSON as a value. + + \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range. + \param length Length of the json. + \param type Type of the root of json. + \note When using PrettyWriter::RawValue(), the result json may not be indented correctly. + */ + bool RawValue(const Ch* json, size_t length, Type type) { + RAPIDJSON_ASSERT(json != 0); + PrettyPrefix(type); + return Base::EndValue(Base::WriteRawValue(json, length)); + } + +protected: + void PrettyPrefix(Type type) { + (void)type; + if (Base::level_stack_.GetSize() != 0) { // this value is not at root + typename Base::Level* level = Base::level_stack_.template Top(); + + if (level->inArray) { + if (level->valueCount > 0) { + Base::os_->Put(','); // add comma if it is not the first element in array + if (formatOptions_ & kFormatSingleLineArray) + Base::os_->Put(' '); + } + + if (!(formatOptions_ & kFormatSingleLineArray)) { + Base::os_->Put('\n'); + WriteIndent(); + } + } + else { // in object + if (level->valueCount > 0) { + if (level->valueCount % 2 == 0) { + Base::os_->Put(','); + Base::os_->Put('\n'); + } + else { + Base::os_->Put(':'); + Base::os_->Put(' '); + } + } + else + Base::os_->Put('\n'); + + if (level->valueCount % 2 == 0) + WriteIndent(); + } + if (!level->inArray && level->valueCount % 2 == 0) + RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name + level->valueCount++; + } + else { + RAPIDJSON_ASSERT(!Base::hasRoot_); // Should only has one and only one root. + Base::hasRoot_ = true; + } + } + + void WriteIndent() { + size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_; + PutN(*Base::os_, static_cast(indentChar_), count); + } + + Ch indentChar_; + unsigned indentCharCount_; + PrettyFormatOptions formatOptions_; + +private: + // Prohibit copy constructor & assignment operator. + PrettyWriter(const PrettyWriter&); + PrettyWriter& operator=(const PrettyWriter&); +}; + +RAPIDJSON_NAMESPACE_END + +#if defined(__clang__) +RAPIDJSON_DIAG_POP +#endif + +#ifdef __GNUC__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_RAPIDJSON_H_ diff --git a/src/include/rapidjson/rapidjson.h b/src/include/rapidjson/rapidjson.h new file mode 100755 index 0000000..329ce92 --- /dev/null +++ b/src/include/rapidjson/rapidjson.h @@ -0,0 +1,676 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_RAPIDJSON_H_ +#define RAPIDJSON_RAPIDJSON_H_ + +/*!\file rapidjson.h + \brief common definitions and configuration + + \see RAPIDJSON_CONFIG + */ + +/*! \defgroup RAPIDJSON_CONFIG RapidJSON configuration + \brief Configuration macros for library features + + Some RapidJSON features are configurable to adapt the library to a wide + variety of platforms, environments and usage scenarios. Most of the + features can be configured in terms of overridden or predefined + preprocessor macros at compile-time. + + Some additional customization is available in the \ref RAPIDJSON_ERRORS APIs. + + \note These macros should be given on the compiler command-line + (where applicable) to avoid inconsistent values when compiling + different translation units of a single application. + */ + +#include // malloc(), realloc(), free(), size_t +#include // memset(), memcpy(), memmove(), memcmp() + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_VERSION_STRING +// +// ALWAYS synchronize the following 3 macros with corresponding variables in /CMakeLists.txt. +// + +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN +// token stringification +#define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x) +#define RAPIDJSON_DO_STRINGIFY(x) #x + +// token concatenation +#define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y) +#define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y) +#define RAPIDJSON_DO_JOIN2(X, Y) X##Y +//!@endcond + +/*! \def RAPIDJSON_MAJOR_VERSION + \ingroup RAPIDJSON_CONFIG + \brief Major version of RapidJSON in integer. +*/ +/*! \def RAPIDJSON_MINOR_VERSION + \ingroup RAPIDJSON_CONFIG + \brief Minor version of RapidJSON in integer. +*/ +/*! \def RAPIDJSON_PATCH_VERSION + \ingroup RAPIDJSON_CONFIG + \brief Patch version of RapidJSON in integer. +*/ +/*! \def RAPIDJSON_VERSION_STRING + \ingroup RAPIDJSON_CONFIG + \brief Version of RapidJSON in ".." string format. +*/ +#define RAPIDJSON_MAJOR_VERSION 1 +#define RAPIDJSON_MINOR_VERSION 1 +#define RAPIDJSON_PATCH_VERSION 0 +#define RAPIDJSON_VERSION_STRING \ + RAPIDJSON_STRINGIFY(RAPIDJSON_MAJOR_VERSION.RAPIDJSON_MINOR_VERSION.RAPIDJSON_PATCH_VERSION) + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_NAMESPACE_(BEGIN|END) +/*! \def RAPIDJSON_NAMESPACE + \ingroup RAPIDJSON_CONFIG + \brief provide custom rapidjson namespace + + In order to avoid symbol clashes and/or "One Definition Rule" errors + between multiple inclusions of (different versions of) RapidJSON in + a single binary, users can customize the name of the main RapidJSON + namespace. + + In case of a single nesting level, defining \c RAPIDJSON_NAMESPACE + to a custom name (e.g. \c MyRapidJSON) is sufficient. If multiple + levels are needed, both \ref RAPIDJSON_NAMESPACE_BEGIN and \ref + RAPIDJSON_NAMESPACE_END need to be defined as well: + + \code + // in some .cpp file + #define RAPIDJSON_NAMESPACE my::rapidjson + #define RAPIDJSON_NAMESPACE_BEGIN namespace my { namespace rapidjson { + #define RAPIDJSON_NAMESPACE_END } } + #include "rapidjson/..." + \endcode + + \see rapidjson + */ +/*! \def RAPIDJSON_NAMESPACE_BEGIN + \ingroup RAPIDJSON_CONFIG + \brief provide custom rapidjson namespace (opening expression) + \see RAPIDJSON_NAMESPACE +*/ +/*! \def RAPIDJSON_NAMESPACE_END + \ingroup RAPIDJSON_CONFIG + \brief provide custom rapidjson namespace (closing expression) + \see RAPIDJSON_NAMESPACE +*/ +#ifndef RAPIDJSON_NAMESPACE +#define RAPIDJSON_NAMESPACE rapidjson +#endif +#ifndef RAPIDJSON_NAMESPACE_BEGIN +#define RAPIDJSON_NAMESPACE_BEGIN namespace RAPIDJSON_NAMESPACE { +#endif +#ifndef RAPIDJSON_NAMESPACE_END +#define RAPIDJSON_NAMESPACE_END } +#endif + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_HAS_STDSTRING + +#ifndef RAPIDJSON_HAS_STDSTRING +#ifdef RAPIDJSON_DOXYGEN_RUNNING +#define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation +#else +#define RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default +#endif +/*! \def RAPIDJSON_HAS_STDSTRING + \ingroup RAPIDJSON_CONFIG + \brief Enable RapidJSON support for \c std::string + + By defining this preprocessor symbol to \c 1, several convenience functions for using + \ref rapidjson::GenericValue with \c std::string are enabled, especially + for construction and comparison. + + \hideinitializer +*/ +#endif // !defined(RAPIDJSON_HAS_STDSTRING) + +#if RAPIDJSON_HAS_STDSTRING +#include +#endif // RAPIDJSON_HAS_STDSTRING + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_NO_INT64DEFINE + +/*! \def RAPIDJSON_NO_INT64DEFINE + \ingroup RAPIDJSON_CONFIG + \brief Use external 64-bit integer types. + + RapidJSON requires the 64-bit integer types \c int64_t and \c uint64_t types + to be available at global scope. + + If users have their own definition, define RAPIDJSON_NO_INT64DEFINE to + prevent RapidJSON from defining its own types. +*/ +#ifndef RAPIDJSON_NO_INT64DEFINE +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN +#if defined(_MSC_VER) && (_MSC_VER < 1800) // Visual Studio 2013 +#include "msinttypes/stdint.h" +#include "msinttypes/inttypes.h" +#else +// Other compilers should have this. +#include +#include +#endif +//!@endcond +#ifdef RAPIDJSON_DOXYGEN_RUNNING +#define RAPIDJSON_NO_INT64DEFINE +#endif +#endif // RAPIDJSON_NO_INT64TYPEDEF + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_FORCEINLINE + +#ifndef RAPIDJSON_FORCEINLINE +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN +#if defined(_MSC_VER) && defined(NDEBUG) +#define RAPIDJSON_FORCEINLINE __forceinline +#elif defined(__GNUC__) && __GNUC__ >= 4 && defined(NDEBUG) +#define RAPIDJSON_FORCEINLINE __attribute__((always_inline)) +#else +#define RAPIDJSON_FORCEINLINE +#endif +//!@endcond +#endif // RAPIDJSON_FORCEINLINE + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_ENDIAN +#define RAPIDJSON_LITTLEENDIAN 0 //!< Little endian machine +#define RAPIDJSON_BIGENDIAN 1 //!< Big endian machine + +//! Endianness of the machine. +/*! + \def RAPIDJSON_ENDIAN + \ingroup RAPIDJSON_CONFIG + + GCC 4.6 provided macro for detecting endianness of the target machine. But other + compilers may not have this. User can define RAPIDJSON_ENDIAN to either + \ref RAPIDJSON_LITTLEENDIAN or \ref RAPIDJSON_BIGENDIAN. + + Default detection implemented with reference to + \li https://gcc.gnu.org/onlinedocs/gcc-4.6.0/cpp/Common-Predefined-Macros.html + \li http://www.boost.org/doc/libs/1_42_0/boost/detail/endian.hpp +*/ +#ifndef RAPIDJSON_ENDIAN +// Detect with GCC 4.6's macro +# ifdef __BYTE_ORDER__ +# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN +# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN +# else +# error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN. +# endif // __BYTE_ORDER__ +// Detect with GLIBC's endian.h +# elif defined(__GLIBC__) +# include +# if (__BYTE_ORDER == __LITTLE_ENDIAN) +# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN +# elif (__BYTE_ORDER == __BIG_ENDIAN) +# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN +# else +# error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN. +# endif // __GLIBC__ +// Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro +# elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN) +# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN +# elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN) +# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN +// Detect with architecture macros +# elif defined(__sparc) || defined(__sparc__) || defined(_POWER) || defined(__powerpc__) || defined(__ppc__) || defined(__hpux) || defined(__hppa) || defined(_MIPSEB) || defined(_POWER) || defined(__s390__) +# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN +# elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__) +# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN +# elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64)) +# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN +# elif defined(RAPIDJSON_DOXYGEN_RUNNING) +# define RAPIDJSON_ENDIAN +# else +# error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN. +# endif +#endif // RAPIDJSON_ENDIAN + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_64BIT + +//! Whether using 64-bit architecture +#ifndef RAPIDJSON_64BIT +#if defined(__LP64__) || (defined(__x86_64__) && defined(__ILP32__)) || defined(_WIN64) || defined(__EMSCRIPTEN__) +#define RAPIDJSON_64BIT 1 +#else +#define RAPIDJSON_64BIT 0 +#endif +#endif // RAPIDJSON_64BIT + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_ALIGN + +//! Data alignment of the machine. +/*! \ingroup RAPIDJSON_CONFIG + \param x pointer to align + + Some machines require strict data alignment. The default is 8 bytes. + User can customize by defining the RAPIDJSON_ALIGN function macro. +*/ +#ifndef RAPIDJSON_ALIGN +#define RAPIDJSON_ALIGN(x) (((x) + static_cast(7u)) & ~static_cast(7u)) +#endif + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_UINT64_C2 + +//! Construct a 64-bit literal by a pair of 32-bit integer. +/*! + 64-bit literal with or without ULL suffix is prone to compiler warnings. + UINT64_C() is C macro which cause compilation problems. + Use this macro to define 64-bit constants by a pair of 32-bit integer. +*/ +#ifndef RAPIDJSON_UINT64_C2 +#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast(high32) << 32) | static_cast(low32)) +#endif + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_48BITPOINTER_OPTIMIZATION + +//! Use only lower 48-bit address for some pointers. +/*! + \ingroup RAPIDJSON_CONFIG + + This optimization uses the fact that current X86-64 architecture only implement lower 48-bit virtual address. + The higher 16-bit can be used for storing other data. + \c GenericValue uses this optimization to reduce its size form 24 bytes to 16 bytes in 64-bit architecture. +*/ +#ifndef RAPIDJSON_48BITPOINTER_OPTIMIZATION +#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64) +#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 1 +#else +#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 0 +#endif +#endif // RAPIDJSON_48BITPOINTER_OPTIMIZATION + +#if RAPIDJSON_48BITPOINTER_OPTIMIZATION == 1 +#if RAPIDJSON_64BIT != 1 +#error RAPIDJSON_48BITPOINTER_OPTIMIZATION can only be set to 1 when RAPIDJSON_64BIT=1 +#endif +#define RAPIDJSON_SETPOINTER(type, p, x) (p = reinterpret_cast((reinterpret_cast(p) & static_cast(RAPIDJSON_UINT64_C2(0xFFFF0000, 0x00000000))) | reinterpret_cast(reinterpret_cast(x)))) +#define RAPIDJSON_GETPOINTER(type, p) (reinterpret_cast(reinterpret_cast(p) & static_cast(RAPIDJSON_UINT64_C2(0x0000FFFF, 0xFFFFFFFF)))) +#else +#define RAPIDJSON_SETPOINTER(type, p, x) (p = (x)) +#define RAPIDJSON_GETPOINTER(type, p) (p) +#endif + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_NEON/RAPIDJSON_SIMD + +/*! \def RAPIDJSON_SIMD + \ingroup RAPIDJSON_CONFIG + \brief Enable SSE2/SSE4.2/Neon optimization. + + RapidJSON supports optimized implementations for some parsing operations + based on the SSE2, SSE4.2 or NEon SIMD extensions on modern Intel + or ARM compatible processors. + + To enable these optimizations, three different symbols can be defined; + \code + // Enable SSE2 optimization. + #define RAPIDJSON_SSE2 + + // Enable SSE4.2 optimization. + #define RAPIDJSON_SSE42 + \endcode + + // Enable ARM Neon optimization. + #define RAPIDJSON_NEON + \endcode + + \c RAPIDJSON_SSE42 takes precedence over SSE2, if both are defined. + + If any of these symbols is defined, RapidJSON defines the macro + \c RAPIDJSON_SIMD to indicate the availability of the optimized code. +*/ +#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) \ + || defined(RAPIDJSON_NEON) || defined(RAPIDJSON_DOXYGEN_RUNNING) +#define RAPIDJSON_SIMD +#endif + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_NO_SIZETYPEDEFINE + +#ifndef RAPIDJSON_NO_SIZETYPEDEFINE +/*! \def RAPIDJSON_NO_SIZETYPEDEFINE + \ingroup RAPIDJSON_CONFIG + \brief User-provided \c SizeType definition. + + In order to avoid using 32-bit size types for indexing strings and arrays, + define this preprocessor symbol and provide the type rapidjson::SizeType + before including RapidJSON: + \code + #define RAPIDJSON_NO_SIZETYPEDEFINE + namespace rapidjson { typedef ::std::size_t SizeType; } + #include "rapidjson/..." + \endcode + + \see rapidjson::SizeType +*/ +#ifdef RAPIDJSON_DOXYGEN_RUNNING +#define RAPIDJSON_NO_SIZETYPEDEFINE +#endif +RAPIDJSON_NAMESPACE_BEGIN +//! Size type (for string lengths, array sizes, etc.) +/*! RapidJSON uses 32-bit array/string indices even on 64-bit platforms, + instead of using \c size_t. Users may override the SizeType by defining + \ref RAPIDJSON_NO_SIZETYPEDEFINE. +*/ +typedef unsigned SizeType; +RAPIDJSON_NAMESPACE_END +#endif + +// always import std::size_t to rapidjson namespace +RAPIDJSON_NAMESPACE_BEGIN +using std::size_t; +RAPIDJSON_NAMESPACE_END + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_ASSERT + +//! Assertion. +/*! \ingroup RAPIDJSON_CONFIG + By default, rapidjson uses C \c assert() for internal assertions. + User can override it by defining RAPIDJSON_ASSERT(x) macro. + + \note Parsing errors are handled and can be customized by the + \ref RAPIDJSON_ERRORS APIs. +*/ +#ifndef RAPIDJSON_ASSERT +#include +#define RAPIDJSON_ASSERT(x) assert(x) +#endif // RAPIDJSON_ASSERT + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_STATIC_ASSERT + +// Prefer C++11 static_assert, if available +#ifndef RAPIDJSON_STATIC_ASSERT +#if __cplusplus >= 201103L || ( defined(_MSC_VER) && _MSC_VER >= 1800 ) +#define RAPIDJSON_STATIC_ASSERT(x) \ + static_assert(x, RAPIDJSON_STRINGIFY(x)) +#endif // C++11 +#endif // RAPIDJSON_STATIC_ASSERT + +// Adopt C++03 implementation from boost +#ifndef RAPIDJSON_STATIC_ASSERT +#ifndef __clang__ +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN +#endif +RAPIDJSON_NAMESPACE_BEGIN +template struct STATIC_ASSERTION_FAILURE; +template <> struct STATIC_ASSERTION_FAILURE { enum { value = 1 }; }; +template struct StaticAssertTest {}; +RAPIDJSON_NAMESPACE_END + +#if defined(__GNUC__) || defined(__clang__) +#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused)) +#else +#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE +#endif +#ifndef __clang__ +//!@endcond +#endif + +/*! \def RAPIDJSON_STATIC_ASSERT + \brief (Internal) macro to check for conditions at compile-time + \param x compile-time condition + \hideinitializer + */ +#define RAPIDJSON_STATIC_ASSERT(x) \ + typedef ::RAPIDJSON_NAMESPACE::StaticAssertTest< \ + sizeof(::RAPIDJSON_NAMESPACE::STATIC_ASSERTION_FAILURE)> \ + RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE +#endif // RAPIDJSON_STATIC_ASSERT + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_LIKELY, RAPIDJSON_UNLIKELY + +//! Compiler branching hint for expression with high probability to be true. +/*! + \ingroup RAPIDJSON_CONFIG + \param x Boolean expression likely to be true. +*/ +#ifndef RAPIDJSON_LIKELY +#if defined(__GNUC__) || defined(__clang__) +#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1) +#else +#define RAPIDJSON_LIKELY(x) (x) +#endif +#endif + +//! Compiler branching hint for expression with low probability to be true. +/*! + \ingroup RAPIDJSON_CONFIG + \param x Boolean expression unlikely to be true. +*/ +#ifndef RAPIDJSON_UNLIKELY +#if defined(__GNUC__) || defined(__clang__) +#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0) +#else +#define RAPIDJSON_UNLIKELY(x) (x) +#endif +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Helpers + +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN + +#define RAPIDJSON_MULTILINEMACRO_BEGIN do { +#define RAPIDJSON_MULTILINEMACRO_END \ +} while((void)0, 0) + +// adopted from Boost +#define RAPIDJSON_VERSION_CODE(x,y,z) \ + (((x)*100000) + ((y)*100) + (z)) + +#if defined(__has_builtin) +#define RAPIDJSON_HAS_BUILTIN(x) __has_builtin(x) +#else +#define RAPIDJSON_HAS_BUILTIN(x) 0 +#endif + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF + +#if defined(__GNUC__) +#define RAPIDJSON_GNUC \ + RAPIDJSON_VERSION_CODE(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__) +#endif + +#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,2,0)) + +#define RAPIDJSON_PRAGMA(x) _Pragma(RAPIDJSON_STRINGIFY(x)) +#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(GCC diagnostic x) +#define RAPIDJSON_DIAG_OFF(x) \ + RAPIDJSON_DIAG_PRAGMA(ignored RAPIDJSON_STRINGIFY(RAPIDJSON_JOIN(-W,x))) + +// push/pop support in Clang and GCC>=4.6 +#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) +#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push) +#define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop) +#else // GCC >= 4.2, < 4.6 +#define RAPIDJSON_DIAG_PUSH /* ignored */ +#define RAPIDJSON_DIAG_POP /* ignored */ +#endif + +#elif defined(_MSC_VER) + +// pragma (MSVC specific) +#define RAPIDJSON_PRAGMA(x) __pragma(x) +#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(warning(x)) + +#define RAPIDJSON_DIAG_OFF(x) RAPIDJSON_DIAG_PRAGMA(disable: x) +#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push) +#define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop) + +#else + +#define RAPIDJSON_DIAG_OFF(x) /* ignored */ +#define RAPIDJSON_DIAG_PUSH /* ignored */ +#define RAPIDJSON_DIAG_POP /* ignored */ + +#endif // RAPIDJSON_DIAG_* + +/////////////////////////////////////////////////////////////////////////////// +// C++11 features + +#ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS +#if defined(__clang__) +#if __has_feature(cxx_rvalue_references) && \ + (defined(_MSC_VER) || defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306) +#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 +#else +#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0 +#endif +#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ + (defined(_MSC_VER) && _MSC_VER >= 1600) || \ + (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__)) + +#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 +#else +#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0 +#endif +#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS + +#ifndef RAPIDJSON_HAS_CXX11_NOEXCEPT +#if defined(__clang__) +#define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept) +#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ + (defined(_MSC_VER) && _MSC_VER >= 1900) || \ + (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__)) +#define RAPIDJSON_HAS_CXX11_NOEXCEPT 1 +#else +#define RAPIDJSON_HAS_CXX11_NOEXCEPT 0 +#endif +#endif +#if RAPIDJSON_HAS_CXX11_NOEXCEPT +#define RAPIDJSON_NOEXCEPT noexcept +#else +#define RAPIDJSON_NOEXCEPT /* noexcept */ +#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT + +// no automatic detection, yet +#ifndef RAPIDJSON_HAS_CXX11_TYPETRAITS +#if (defined(_MSC_VER) && _MSC_VER >= 1700) +#define RAPIDJSON_HAS_CXX11_TYPETRAITS 1 +#else +#define RAPIDJSON_HAS_CXX11_TYPETRAITS 0 +#endif +#endif + +#ifndef RAPIDJSON_HAS_CXX11_RANGE_FOR +#if defined(__clang__) +#define RAPIDJSON_HAS_CXX11_RANGE_FOR __has_feature(cxx_range_for) +#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ + (defined(_MSC_VER) && _MSC_VER >= 1700) || \ + (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__)) +#define RAPIDJSON_HAS_CXX11_RANGE_FOR 1 +#else +#define RAPIDJSON_HAS_CXX11_RANGE_FOR 0 +#endif +#endif // RAPIDJSON_HAS_CXX11_RANGE_FOR + +/////////////////////////////////////////////////////////////////////////////// +// C++17 features + +#if defined(__has_cpp_attribute) +# if __has_cpp_attribute(fallthrough) +# define RAPIDJSON_DELIBERATE_FALLTHROUGH [[fallthrough]] +# else +# define RAPIDJSON_DELIBERATE_FALLTHROUGH +# endif +#else +# define RAPIDJSON_DELIBERATE_FALLTHROUGH +#endif + +//!@endcond + +//! Assertion (in non-throwing contexts). + /*! \ingroup RAPIDJSON_CONFIG + Some functions provide a \c noexcept guarantee, if the compiler supports it. + In these cases, the \ref RAPIDJSON_ASSERT macro cannot be overridden to + throw an exception. This macro adds a separate customization point for + such cases. + + Defaults to C \c assert() (as \ref RAPIDJSON_ASSERT), if \c noexcept is + supported, and to \ref RAPIDJSON_ASSERT otherwise. + */ + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_NOEXCEPT_ASSERT + +#ifndef RAPIDJSON_NOEXCEPT_ASSERT +#ifdef RAPIDJSON_ASSERT_THROWS +#if RAPIDJSON_HAS_CXX11_NOEXCEPT +#define RAPIDJSON_NOEXCEPT_ASSERT(x) +#else +#include +#define RAPIDJSON_NOEXCEPT_ASSERT(x) assert(x) +#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT +#else +#define RAPIDJSON_NOEXCEPT_ASSERT(x) RAPIDJSON_ASSERT(x) +#endif // RAPIDJSON_ASSERT_THROWS +#endif // RAPIDJSON_NOEXCEPT_ASSERT + +/////////////////////////////////////////////////////////////////////////////// +// new/delete + +#ifndef RAPIDJSON_NEW +///! customization point for global \c new +#define RAPIDJSON_NEW(TypeName) new TypeName +#endif +#ifndef RAPIDJSON_DELETE +///! customization point for global \c delete +#define RAPIDJSON_DELETE(x) delete x +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Type + +/*! \namespace rapidjson + \brief main RapidJSON namespace + \see RAPIDJSON_NAMESPACE +*/ +RAPIDJSON_NAMESPACE_BEGIN + +//! Type of JSON value +enum Type { + kNullType = 0, //!< null + kFalseType = 1, //!< false + kTrueType = 2, //!< true + kObjectType = 3, //!< object + kArrayType = 4, //!< array + kStringType = 5, //!< string + kNumberType = 6 //!< number +}; + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_RAPIDJSON_H_ diff --git a/src/include/rapidjson/reader.h b/src/include/rapidjson/reader.h new file mode 100755 index 0000000..0f85032 --- /dev/null +++ b/src/include/rapidjson/reader.h @@ -0,0 +1,2236 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_READER_H_ +#define RAPIDJSON_READER_H_ + +/*! \file reader.h */ + +#include "allocators.h" +#include "stream.h" +#include "encodedstream.h" +#include "internal/clzll.h" +#include "internal/meta.h" +#include "internal/stack.h" +#include "internal/strtod.h" +#include + +#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER) +#include +#pragma intrinsic(_BitScanForward) +#endif +#ifdef RAPIDJSON_SSE42 +#include +#elif defined(RAPIDJSON_SSE2) +#include +#elif defined(RAPIDJSON_NEON) +#include +#endif + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(old-style-cast) +RAPIDJSON_DIAG_OFF(padded) +RAPIDJSON_DIAG_OFF(switch-enum) +#elif defined(_MSC_VER) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant +RAPIDJSON_DIAG_OFF(4702) // unreachable code +#endif + +#ifdef __GNUC__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#endif + +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN +#define RAPIDJSON_NOTHING /* deliberately empty */ +#ifndef RAPIDJSON_PARSE_ERROR_EARLY_RETURN +#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN(value) \ + RAPIDJSON_MULTILINEMACRO_BEGIN \ + if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \ + RAPIDJSON_MULTILINEMACRO_END +#endif +#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID \ + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING) +//!@endcond + +/*! \def RAPIDJSON_PARSE_ERROR_NORETURN + \ingroup RAPIDJSON_ERRORS + \brief Macro to indicate a parse error. + \param parseErrorCode \ref rapidjson::ParseErrorCode of the error + \param offset position of the error in JSON input (\c size_t) + + This macros can be used as a customization point for the internal + error handling mechanism of RapidJSON. + + A common usage model is to throw an exception instead of requiring the + caller to explicitly check the \ref rapidjson::GenericReader::Parse's + return value: + + \code + #define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode,offset) \ + throw ParseException(parseErrorCode, #parseErrorCode, offset) + + #include // std::runtime_error + #include "rapidjson/error/error.h" // rapidjson::ParseResult + + struct ParseException : std::runtime_error, rapidjson::ParseResult { + ParseException(rapidjson::ParseErrorCode code, const char* msg, size_t offset) + : std::runtime_error(msg), ParseResult(code, offset) {} + }; + + #include "rapidjson/reader.h" + \endcode + + \see RAPIDJSON_PARSE_ERROR, rapidjson::GenericReader::Parse + */ +#ifndef RAPIDJSON_PARSE_ERROR_NORETURN +#define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset) \ + RAPIDJSON_MULTILINEMACRO_BEGIN \ + RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \ + SetParseError(parseErrorCode, offset); \ + RAPIDJSON_MULTILINEMACRO_END +#endif + +/*! \def RAPIDJSON_PARSE_ERROR + \ingroup RAPIDJSON_ERRORS + \brief (Internal) macro to indicate and handle a parse error. + \param parseErrorCode \ref rapidjson::ParseErrorCode of the error + \param offset position of the error in JSON input (\c size_t) + + Invokes RAPIDJSON_PARSE_ERROR_NORETURN and stops the parsing. + + \see RAPIDJSON_PARSE_ERROR_NORETURN + \hideinitializer + */ +#ifndef RAPIDJSON_PARSE_ERROR +#define RAPIDJSON_PARSE_ERROR(parseErrorCode, offset) \ + RAPIDJSON_MULTILINEMACRO_BEGIN \ + RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \ + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \ + RAPIDJSON_MULTILINEMACRO_END +#endif + +#include "error/error.h" // ParseErrorCode, ParseResult + +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// ParseFlag + +/*! \def RAPIDJSON_PARSE_DEFAULT_FLAGS + \ingroup RAPIDJSON_CONFIG + \brief User-defined kParseDefaultFlags definition. + + User can define this as any \c ParseFlag combinations. +*/ +#ifndef RAPIDJSON_PARSE_DEFAULT_FLAGS +#define RAPIDJSON_PARSE_DEFAULT_FLAGS kParseNoFlags +#endif + +//! Combination of parseFlags +/*! \see Reader::Parse, Document::Parse, Document::ParseInsitu, Document::ParseStream + */ +enum ParseFlag { + kParseNoFlags = 0, //!< No flags are set. + kParseInsituFlag = 1, //!< In-situ(destructive) parsing. + kParseValidateEncodingFlag = 2, //!< Validate encoding of JSON strings. + kParseIterativeFlag = 4, //!< Iterative(constant complexity in terms of function call stack size) parsing. + kParseStopWhenDoneFlag = 8, //!< After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate kParseErrorDocumentRootNotSingular error. + kParseFullPrecisionFlag = 16, //!< Parse number in full precision (but slower). + kParseCommentsFlag = 32, //!< Allow one-line (//) and multi-line (/**/) comments. + kParseNumbersAsStringsFlag = 64, //!< Parse all numbers (ints/doubles) as strings. + kParseTrailingCommasFlag = 128, //!< Allow trailing commas at the end of objects and arrays. + kParseNanAndInfFlag = 256, //!< Allow parsing NaN, Inf, Infinity, -Inf and -Infinity as doubles. + kParseEscapedApostropheFlag = 512, //!< Allow escaped apostrophe in strings. + kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS +}; + +/////////////////////////////////////////////////////////////////////////////// +// Handler + +/*! \class rapidjson::Handler + \brief Concept for receiving events from GenericReader upon parsing. + The functions return true if no error occurs. If they return false, + the event publisher should terminate the process. +\code +concept Handler { + typename Ch; + + bool Null(); + bool Bool(bool b); + bool Int(int i); + bool Uint(unsigned i); + bool Int64(int64_t i); + bool Uint64(uint64_t i); + bool Double(double d); + /// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (use length) + bool RawNumber(const Ch* str, SizeType length, bool copy); + bool String(const Ch* str, SizeType length, bool copy); + bool StartObject(); + bool Key(const Ch* str, SizeType length, bool copy); + bool EndObject(SizeType memberCount); + bool StartArray(); + bool EndArray(SizeType elementCount); +}; +\endcode +*/ +/////////////////////////////////////////////////////////////////////////////// +// BaseReaderHandler + +//! Default implementation of Handler. +/*! This can be used as base class of any reader handler. + \note implements Handler concept +*/ +template, typename Derived = void> +struct BaseReaderHandler { + typedef typename Encoding::Ch Ch; + + typedef typename internal::SelectIf, BaseReaderHandler, Derived>::Type Override; + + bool Default() { return true; } + bool Null() { return static_cast(*this).Default(); } + bool Bool(bool) { return static_cast(*this).Default(); } + bool Int(int) { return static_cast(*this).Default(); } + bool Uint(unsigned) { return static_cast(*this).Default(); } + bool Int64(int64_t) { return static_cast(*this).Default(); } + bool Uint64(uint64_t) { return static_cast(*this).Default(); } + bool Double(double) { return static_cast(*this).Default(); } + /// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (use length) + bool RawNumber(const Ch* str, SizeType len, bool copy) { return static_cast(*this).String(str, len, copy); } + bool String(const Ch*, SizeType, bool) { return static_cast(*this).Default(); } + bool StartObject() { return static_cast(*this).Default(); } + bool Key(const Ch* str, SizeType len, bool copy) { return static_cast(*this).String(str, len, copy); } + bool EndObject(SizeType) { return static_cast(*this).Default(); } + bool StartArray() { return static_cast(*this).Default(); } + bool EndArray(SizeType) { return static_cast(*this).Default(); } +}; + +/////////////////////////////////////////////////////////////////////////////// +// StreamLocalCopy + +namespace internal { + +template::copyOptimization> +class StreamLocalCopy; + +//! Do copy optimization. +template +class StreamLocalCopy { +public: + StreamLocalCopy(Stream& original) : s(original), original_(original) {} + ~StreamLocalCopy() { original_ = s; } + + Stream s; + +private: + StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */; + + Stream& original_; +}; + +//! Keep reference. +template +class StreamLocalCopy { +public: + StreamLocalCopy(Stream& original) : s(original) {} + + Stream& s; + +private: + StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */; +}; + +} // namespace internal + +/////////////////////////////////////////////////////////////////////////////// +// SkipWhitespace + +//! Skip the JSON white spaces in a stream. +/*! \param is A input stream for skipping white spaces. + \note This function has SSE2/SSE4.2 specialization. +*/ +template +void SkipWhitespace(InputStream& is) { + internal::StreamLocalCopy copy(is); + InputStream& s(copy.s); + + typename InputStream::Ch c; + while ((c = s.Peek()) == ' ' || c == '\n' || c == '\r' || c == '\t') + s.Take(); +} + +inline const char* SkipWhitespace(const char* p, const char* end) { + while (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) + ++p; + return p; +} + +#ifdef RAPIDJSON_SSE42 +//! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once. +inline const char *SkipWhitespace_SIMD(const char* p) { + // Fast return for single non-whitespace + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') + ++p; + else + return p; + + // 16-byte align to the next boundary + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + while (p != nextAligned) + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') + ++p; + else + return p; + + // The rest of string using SIMD + static const char whitespace[16] = " \n\r\t"; + const __m128i w = _mm_loadu_si128(reinterpret_cast(&whitespace[0])); + + for (;; p += 16) { + const __m128i s = _mm_load_si128(reinterpret_cast(p)); + const int r = _mm_cmpistri(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT | _SIDD_NEGATIVE_POLARITY); + if (r != 16) // some of characters is non-whitespace + return p + r; + } +} + +inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { + // Fast return for single non-whitespace + if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) + ++p; + else + return p; + + // The middle of string using SIMD + static const char whitespace[16] = " \n\r\t"; + const __m128i w = _mm_loadu_si128(reinterpret_cast(&whitespace[0])); + + for (; p <= end - 16; p += 16) { + const __m128i s = _mm_loadu_si128(reinterpret_cast(p)); + const int r = _mm_cmpistri(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT | _SIDD_NEGATIVE_POLARITY); + if (r != 16) // some of characters is non-whitespace + return p + r; + } + + return SkipWhitespace(p, end); +} + +#elif defined(RAPIDJSON_SSE2) + +//! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once. +inline const char *SkipWhitespace_SIMD(const char* p) { + // Fast return for single non-whitespace + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') + ++p; + else + return p; + + // 16-byte align to the next boundary + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + while (p != nextAligned) + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') + ++p; + else + return p; + + // The rest of string + #define C16(c) { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c } + static const char whitespaces[4][16] = { C16(' '), C16('\n'), C16('\r'), C16('\t') }; + #undef C16 + + const __m128i w0 = _mm_loadu_si128(reinterpret_cast(&whitespaces[0][0])); + const __m128i w1 = _mm_loadu_si128(reinterpret_cast(&whitespaces[1][0])); + const __m128i w2 = _mm_loadu_si128(reinterpret_cast(&whitespaces[2][0])); + const __m128i w3 = _mm_loadu_si128(reinterpret_cast(&whitespaces[3][0])); + + for (;; p += 16) { + const __m128i s = _mm_load_si128(reinterpret_cast(p)); + __m128i x = _mm_cmpeq_epi8(s, w0); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1)); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2)); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3)); + unsigned short r = static_cast(~_mm_movemask_epi8(x)); + if (r != 0) { // some of characters may be non-whitespace +#ifdef _MSC_VER // Find the index of first non-whitespace + unsigned long offset; + _BitScanForward(&offset, r); + return p + offset; +#else + return p + __builtin_ffs(r) - 1; +#endif + } + } +} + +inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { + // Fast return for single non-whitespace + if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) + ++p; + else + return p; + + // The rest of string + #define C16(c) { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c } + static const char whitespaces[4][16] = { C16(' '), C16('\n'), C16('\r'), C16('\t') }; + #undef C16 + + const __m128i w0 = _mm_loadu_si128(reinterpret_cast(&whitespaces[0][0])); + const __m128i w1 = _mm_loadu_si128(reinterpret_cast(&whitespaces[1][0])); + const __m128i w2 = _mm_loadu_si128(reinterpret_cast(&whitespaces[2][0])); + const __m128i w3 = _mm_loadu_si128(reinterpret_cast(&whitespaces[3][0])); + + for (; p <= end - 16; p += 16) { + const __m128i s = _mm_loadu_si128(reinterpret_cast(p)); + __m128i x = _mm_cmpeq_epi8(s, w0); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1)); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2)); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3)); + unsigned short r = static_cast(~_mm_movemask_epi8(x)); + if (r != 0) { // some of characters may be non-whitespace +#ifdef _MSC_VER // Find the index of first non-whitespace + unsigned long offset; + _BitScanForward(&offset, r); + return p + offset; +#else + return p + __builtin_ffs(r) - 1; +#endif + } + } + + return SkipWhitespace(p, end); +} + +#elif defined(RAPIDJSON_NEON) + +//! Skip whitespace with ARM Neon instructions, testing 16 8-byte characters at once. +inline const char *SkipWhitespace_SIMD(const char* p) { + // Fast return for single non-whitespace + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') + ++p; + else + return p; + + // 16-byte align to the next boundary + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + while (p != nextAligned) + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') + ++p; + else + return p; + + const uint8x16_t w0 = vmovq_n_u8(' '); + const uint8x16_t w1 = vmovq_n_u8('\n'); + const uint8x16_t w2 = vmovq_n_u8('\r'); + const uint8x16_t w3 = vmovq_n_u8('\t'); + + for (;; p += 16) { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, w0); + x = vorrq_u8(x, vceqq_u8(s, w1)); + x = vorrq_u8(x, vceqq_u8(s, w2)); + x = vorrq_u8(x, vceqq_u8(s, w3)); + + x = vmvnq_u8(x); // Negate + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract + uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract + + if (low == 0) { + if (high != 0) { + uint32_t lz = internal::clzll(high); + return p + 8 + (lz >> 3); + } + } else { + uint32_t lz = internal::clzll(low); + return p + (lz >> 3); + } + } +} + +inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { + // Fast return for single non-whitespace + if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) + ++p; + else + return p; + + const uint8x16_t w0 = vmovq_n_u8(' '); + const uint8x16_t w1 = vmovq_n_u8('\n'); + const uint8x16_t w2 = vmovq_n_u8('\r'); + const uint8x16_t w3 = vmovq_n_u8('\t'); + + for (; p <= end - 16; p += 16) { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, w0); + x = vorrq_u8(x, vceqq_u8(s, w1)); + x = vorrq_u8(x, vceqq_u8(s, w2)); + x = vorrq_u8(x, vceqq_u8(s, w3)); + + x = vmvnq_u8(x); // Negate + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract + uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract + + if (low == 0) { + if (high != 0) { + uint32_t lz = internal::clzll(high); + return p + 8 + (lz >> 3); + } + } else { + uint32_t lz = internal::clzll(low); + return p + (lz >> 3); + } + } + + return SkipWhitespace(p, end); +} + +#endif // RAPIDJSON_NEON + +#ifdef RAPIDJSON_SIMD +//! Template function specialization for InsituStringStream +template<> inline void SkipWhitespace(InsituStringStream& is) { + is.src_ = const_cast(SkipWhitespace_SIMD(is.src_)); +} + +//! Template function specialization for StringStream +template<> inline void SkipWhitespace(StringStream& is) { + is.src_ = SkipWhitespace_SIMD(is.src_); +} + +template<> inline void SkipWhitespace(EncodedInputStream, MemoryStream>& is) { + is.is_.src_ = SkipWhitespace_SIMD(is.is_.src_, is.is_.end_); +} +#endif // RAPIDJSON_SIMD + +/////////////////////////////////////////////////////////////////////////////// +// GenericReader + +//! SAX-style JSON parser. Use \ref Reader for UTF8 encoding and default allocator. +/*! GenericReader parses JSON text from a stream, and send events synchronously to an + object implementing Handler concept. + + It needs to allocate a stack for storing a single decoded string during + non-destructive parsing. + + For in-situ parsing, the decoded string is directly written to the source + text string, no temporary buffer is required. + + A GenericReader object can be reused for parsing multiple JSON text. + + \tparam SourceEncoding Encoding of the input stream. + \tparam TargetEncoding Encoding of the parse output. + \tparam StackAllocator Allocator type for stack. +*/ +template +class GenericReader { +public: + typedef typename SourceEncoding::Ch Ch; //!< SourceEncoding character type + + //! Constructor. + /*! \param stackAllocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing) + \param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing) + */ + GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) : + stack_(stackAllocator, stackCapacity), parseResult_(), state_(IterativeParsingStartState) {} + + //! Parse JSON text. + /*! \tparam parseFlags Combination of \ref ParseFlag. + \tparam InputStream Type of input stream, implementing Stream concept. + \tparam Handler Type of handler, implementing Handler concept. + \param is Input stream to be parsed. + \param handler The handler to receive events. + \return Whether the parsing is successful. + */ + template + ParseResult Parse(InputStream& is, Handler& handler) { + if (parseFlags & kParseIterativeFlag) + return IterativeParse(is, handler); + + parseResult_.Clear(); + + ClearStackOnExit scope(*this); + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + + if (RAPIDJSON_UNLIKELY(is.Peek() == '\0')) { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell()); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + } + else { + ParseValue(is, handler); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + + if (!(parseFlags & kParseStopWhenDoneFlag)) { + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + + if (RAPIDJSON_UNLIKELY(is.Peek() != '\0')) { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell()); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + } + } + } + + return parseResult_; + } + + //! Parse JSON text (with \ref kParseDefaultFlags) + /*! \tparam InputStream Type of input stream, implementing Stream concept + \tparam Handler Type of handler, implementing Handler concept. + \param is Input stream to be parsed. + \param handler The handler to receive events. + \return Whether the parsing is successful. + */ + template + ParseResult Parse(InputStream& is, Handler& handler) { + return Parse(is, handler); + } + + //! Initialize JSON text token-by-token parsing + /*! + */ + void IterativeParseInit() { + parseResult_.Clear(); + state_ = IterativeParsingStartState; + } + + //! Parse one token from JSON text + /*! \tparam InputStream Type of input stream, implementing Stream concept + \tparam Handler Type of handler, implementing Handler concept. + \param is Input stream to be parsed. + \param handler The handler to receive events. + \return Whether the parsing is successful. + */ + template + bool IterativeParseNext(InputStream& is, Handler& handler) { + while (RAPIDJSON_LIKELY(is.Peek() != '\0')) { + SkipWhitespaceAndComments(is); + + Token t = Tokenize(is.Peek()); + IterativeParsingState n = Predict(state_, t); + IterativeParsingState d = Transit(state_, t, n, is, handler); + + // If we've finished or hit an error... + if (RAPIDJSON_UNLIKELY(IsIterativeParsingCompleteState(d))) { + // Report errors. + if (d == IterativeParsingErrorState) { + HandleError(state_, is); + return false; + } + + // Transition to the finish state. + RAPIDJSON_ASSERT(d == IterativeParsingFinishState); + state_ = d; + + // If StopWhenDone is not set... + if (!(parseFlags & kParseStopWhenDoneFlag)) { + // ... and extra non-whitespace data is found... + SkipWhitespaceAndComments(is); + if (is.Peek() != '\0') { + // ... this is considered an error. + HandleError(state_, is); + return false; + } + } + + // Success! We are done! + return true; + } + + // Transition to the new state. + state_ = d; + + // If we parsed anything other than a delimiter, we invoked the handler, so we can return true now. + if (!IsIterativeParsingDelimiterState(n)) + return true; + } + + // We reached the end of file. + stack_.Clear(); + + if (state_ != IterativeParsingFinishState) { + HandleError(state_, is); + return false; + } + + return true; + } + + //! Check if token-by-token parsing JSON text is complete + /*! \return Whether the JSON has been fully decoded. + */ + RAPIDJSON_FORCEINLINE bool IterativeParseComplete() const { + return IsIterativeParsingCompleteState(state_); + } + + //! Whether a parse error has occurred in the last parsing. + bool HasParseError() const { return parseResult_.IsError(); } + + //! Get the \ref ParseErrorCode of last parsing. + ParseErrorCode GetParseErrorCode() const { return parseResult_.Code(); } + + //! Get the position of last parsing error in input, 0 otherwise. + size_t GetErrorOffset() const { return parseResult_.Offset(); } + +protected: + void SetParseError(ParseErrorCode code, size_t offset) { parseResult_.Set(code, offset); } + +private: + // Prohibit copy constructor & assignment operator. + GenericReader(const GenericReader&); + GenericReader& operator=(const GenericReader&); + + void ClearStack() { stack_.Clear(); } + + // clear stack on any exit from ParseStream, e.g. due to exception + struct ClearStackOnExit { + explicit ClearStackOnExit(GenericReader& r) : r_(r) {} + ~ClearStackOnExit() { r_.ClearStack(); } + private: + GenericReader& r_; + ClearStackOnExit(const ClearStackOnExit&); + ClearStackOnExit& operator=(const ClearStackOnExit&); + }; + + template + void SkipWhitespaceAndComments(InputStream& is) { + SkipWhitespace(is); + + if (parseFlags & kParseCommentsFlag) { + while (RAPIDJSON_UNLIKELY(Consume(is, '/'))) { + if (Consume(is, '*')) { + while (true) { + if (RAPIDJSON_UNLIKELY(is.Peek() == '\0')) + RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); + else if (Consume(is, '*')) { + if (Consume(is, '/')) + break; + } + else + is.Take(); + } + } + else if (RAPIDJSON_LIKELY(Consume(is, '/'))) + while (is.Peek() != '\0' && is.Take() != '\n') {} + else + RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); + + SkipWhitespace(is); + } + } + } + + // Parse object: { string : value, ... } + template + void ParseObject(InputStream& is, Handler& handler) { + RAPIDJSON_ASSERT(is.Peek() == '{'); + is.Take(); // Skip '{' + + if (RAPIDJSON_UNLIKELY(!handler.StartObject())) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + if (Consume(is, '}')) { + if (RAPIDJSON_UNLIKELY(!handler.EndObject(0))) // empty object + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + return; + } + + for (SizeType memberCount = 0;;) { + if (RAPIDJSON_UNLIKELY(is.Peek() != '"')) + RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); + + ParseString(is, handler, true); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + if (RAPIDJSON_UNLIKELY(!Consume(is, ':'))) + RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + ParseValue(is, handler); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + ++memberCount; + + switch (is.Peek()) { + case ',': + is.Take(); + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + break; + case '}': + is.Take(); + if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount))) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + return; + default: + RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); break; // This useless break is only for making warning and coverage happy + } + + if (parseFlags & kParseTrailingCommasFlag) { + if (is.Peek() == '}') { + if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount))) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + is.Take(); + return; + } + } + } + } + + // Parse array: [ value, ... ] + template + void ParseArray(InputStream& is, Handler& handler) { + RAPIDJSON_ASSERT(is.Peek() == '['); + is.Take(); // Skip '[' + + if (RAPIDJSON_UNLIKELY(!handler.StartArray())) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + if (Consume(is, ']')) { + if (RAPIDJSON_UNLIKELY(!handler.EndArray(0))) // empty array + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + return; + } + + for (SizeType elementCount = 0;;) { + ParseValue(is, handler); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + ++elementCount; + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + if (Consume(is, ',')) { + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + } + else if (Consume(is, ']')) { + if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount))) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + return; + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); + + if (parseFlags & kParseTrailingCommasFlag) { + if (is.Peek() == ']') { + if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount))) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + is.Take(); + return; + } + } + } + } + + template + void ParseNull(InputStream& is, Handler& handler) { + RAPIDJSON_ASSERT(is.Peek() == 'n'); + is.Take(); + + if (RAPIDJSON_LIKELY(Consume(is, 'u') && Consume(is, 'l') && Consume(is, 'l'))) { + if (RAPIDJSON_UNLIKELY(!handler.Null())) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); + } + + template + void ParseTrue(InputStream& is, Handler& handler) { + RAPIDJSON_ASSERT(is.Peek() == 't'); + is.Take(); + + if (RAPIDJSON_LIKELY(Consume(is, 'r') && Consume(is, 'u') && Consume(is, 'e'))) { + if (RAPIDJSON_UNLIKELY(!handler.Bool(true))) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); + } + + template + void ParseFalse(InputStream& is, Handler& handler) { + RAPIDJSON_ASSERT(is.Peek() == 'f'); + is.Take(); + + if (RAPIDJSON_LIKELY(Consume(is, 'a') && Consume(is, 'l') && Consume(is, 's') && Consume(is, 'e'))) { + if (RAPIDJSON_UNLIKELY(!handler.Bool(false))) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); + } + + template + RAPIDJSON_FORCEINLINE static bool Consume(InputStream& is, typename InputStream::Ch expect) { + if (RAPIDJSON_LIKELY(is.Peek() == expect)) { + is.Take(); + return true; + } + else + return false; + } + + // Helper function to parse four hexadecimal digits in \uXXXX in ParseString(). + template + unsigned ParseHex4(InputStream& is, size_t escapeOffset) { + unsigned codepoint = 0; + for (int i = 0; i < 4; i++) { + Ch c = is.Peek(); + codepoint <<= 4; + codepoint += static_cast(c); + if (c >= '0' && c <= '9') + codepoint -= '0'; + else if (c >= 'A' && c <= 'F') + codepoint -= 'A' - 10; + else if (c >= 'a' && c <= 'f') + codepoint -= 'a' - 10; + else { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex, escapeOffset); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(0); + } + is.Take(); + } + return codepoint; + } + + template + class StackStream { + public: + typedef CharType Ch; + + StackStream(internal::Stack& stack) : stack_(stack), length_(0) {} + RAPIDJSON_FORCEINLINE void Put(Ch c) { + *stack_.template Push() = c; + ++length_; + } + + RAPIDJSON_FORCEINLINE void* Push(SizeType count) { + length_ += count; + return stack_.template Push(count); + } + + size_t Length() const { return length_; } + + Ch* Pop() { + return stack_.template Pop(length_); + } + + private: + StackStream(const StackStream&); + StackStream& operator=(const StackStream&); + + internal::Stack& stack_; + SizeType length_; + }; + + // Parse string and generate String event. Different code paths for kParseInsituFlag. + template + void ParseString(InputStream& is, Handler& handler, bool isKey = false) { + internal::StreamLocalCopy copy(is); + InputStream& s(copy.s); + + RAPIDJSON_ASSERT(s.Peek() == '\"'); + s.Take(); // Skip '\"' + + bool success = false; + if (parseFlags & kParseInsituFlag) { + typename InputStream::Ch *head = s.PutBegin(); + ParseStringToStream(s, s); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + size_t length = s.PutEnd(head) - 1; + RAPIDJSON_ASSERT(length <= 0xFFFFFFFF); + const typename TargetEncoding::Ch* const str = reinterpret_cast(head); + success = (isKey ? handler.Key(str, SizeType(length), false) : handler.String(str, SizeType(length), false)); + } + else { + StackStream stackStream(stack_); + ParseStringToStream(s, stackStream); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + SizeType length = static_cast(stackStream.Length()) - 1; + const typename TargetEncoding::Ch* const str = stackStream.Pop(); + success = (isKey ? handler.Key(str, length, true) : handler.String(str, length, true)); + } + if (RAPIDJSON_UNLIKELY(!success)) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell()); + } + + // Parse string to an output is + // This function handles the prefix/suffix double quotes, escaping, and optional encoding validation. + template + RAPIDJSON_FORCEINLINE void ParseStringToStream(InputStream& is, OutputStream& os) { +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN +#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + static const char escape[256] = { + Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '/', + Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, + 0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0, + 0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 + }; +#undef Z16 +//!@endcond + + for (;;) { + // Scan and copy string before "\\\"" or < 0x20. This is an optional optimzation. + if (!(parseFlags & kParseValidateEncodingFlag)) + ScanCopyUnescapedString(is, os); + + Ch c = is.Peek(); + if (RAPIDJSON_UNLIKELY(c == '\\')) { // Escape + size_t escapeOffset = is.Tell(); // For invalid escaping, report the initial '\\' as error offset + is.Take(); + Ch e = is.Peek(); + if ((sizeof(Ch) == 1 || unsigned(e) < 256) && RAPIDJSON_LIKELY(escape[static_cast(e)])) { + is.Take(); + os.Put(static_cast(escape[static_cast(e)])); + } + else if ((parseFlags & kParseEscapedApostropheFlag) && RAPIDJSON_LIKELY(e == '\'')) { // Allow escaped apostrophe + is.Take(); + os.Put('\''); + } + else if (RAPIDJSON_LIKELY(e == 'u')) { // Unicode + is.Take(); + unsigned codepoint = ParseHex4(is, escapeOffset); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDBFF)) { + // Handle UTF-16 surrogate pair + if (RAPIDJSON_UNLIKELY(!Consume(is, '\\') || !Consume(is, 'u'))) + RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset); + unsigned codepoint2 = ParseHex4(is, escapeOffset); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + if (RAPIDJSON_UNLIKELY(codepoint2 < 0xDC00 || codepoint2 > 0xDFFF)) + RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset); + codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000; + } + TEncoding::Encode(os, codepoint); + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, escapeOffset); + } + else if (RAPIDJSON_UNLIKELY(c == '"')) { // Closing double quote + is.Take(); + os.Put('\0'); // null-terminate the string + return; + } + else if (RAPIDJSON_UNLIKELY(static_cast(c) < 0x20)) { // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF + if (c == '\0') + RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell()); + else + RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, is.Tell()); + } + else { + size_t offset = is.Tell(); + if (RAPIDJSON_UNLIKELY((parseFlags & kParseValidateEncodingFlag ? + !Transcoder::Validate(is, os) : + !Transcoder::Transcode(is, os)))) + RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, offset); + } + } + } + + template + static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InputStream&, OutputStream&) { + // Do nothing for generic version + } + +#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) + // StringStream -> StackStream + static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream& os) { + const char* p = is.src_; + + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + while (p != nextAligned) + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { + is.src_ = p; + return; + } + else + os.Put(*p++); + + // The rest of string using SIMD + static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; + static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; + static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; + const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); + const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); + const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); + + for (;; p += 16) { + const __m128i s = _mm_load_si128(reinterpret_cast(p)); + const __m128i t1 = _mm_cmpeq_epi8(s, dq); + const __m128i t2 = _mm_cmpeq_epi8(s, bs); + const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F + const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); + unsigned short r = static_cast(_mm_movemask_epi8(x)); + if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped + SizeType length; + #ifdef _MSC_VER // Find the index of first escaped + unsigned long offset; + _BitScanForward(&offset, r); + length = offset; + #else + length = static_cast(__builtin_ffs(r) - 1); + #endif + if (length != 0) { + char* q = reinterpret_cast(os.Push(length)); + for (size_t i = 0; i < length; i++) + q[i] = p[i]; + + p += length; + } + break; + } + _mm_storeu_si128(reinterpret_cast<__m128i *>(os.Push(16)), s); + } + + is.src_ = p; + } + + // InsituStringStream -> InsituStringStream + static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InsituStringStream& is, InsituStringStream& os) { + RAPIDJSON_ASSERT(&is == &os); + (void)os; + + if (is.src_ == is.dst_) { + SkipUnescapedString(is); + return; + } + + char* p = is.src_; + char *q = is.dst_; + + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + while (p != nextAligned) + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { + is.src_ = p; + is.dst_ = q; + return; + } + else + *q++ = *p++; + + // The rest of string using SIMD + static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; + static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; + static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; + const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); + const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); + const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); + + for (;; p += 16, q += 16) { + const __m128i s = _mm_load_si128(reinterpret_cast(p)); + const __m128i t1 = _mm_cmpeq_epi8(s, dq); + const __m128i t2 = _mm_cmpeq_epi8(s, bs); + const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F + const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); + unsigned short r = static_cast(_mm_movemask_epi8(x)); + if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped + size_t length; +#ifdef _MSC_VER // Find the index of first escaped + unsigned long offset; + _BitScanForward(&offset, r); + length = offset; +#else + length = static_cast(__builtin_ffs(r) - 1); +#endif + for (const char* pend = p + length; p != pend; ) + *q++ = *p++; + break; + } + _mm_storeu_si128(reinterpret_cast<__m128i *>(q), s); + } + + is.src_ = p; + is.dst_ = q; + } + + // When read/write pointers are the same for insitu stream, just skip unescaped characters + static RAPIDJSON_FORCEINLINE void SkipUnescapedString(InsituStringStream& is) { + RAPIDJSON_ASSERT(is.src_ == is.dst_); + char* p = is.src_; + + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + for (; p != nextAligned; p++) + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { + is.src_ = is.dst_ = p; + return; + } + + // The rest of string using SIMD + static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; + static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; + static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; + const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); + const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); + const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); + + for (;; p += 16) { + const __m128i s = _mm_load_si128(reinterpret_cast(p)); + const __m128i t1 = _mm_cmpeq_epi8(s, dq); + const __m128i t2 = _mm_cmpeq_epi8(s, bs); + const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F + const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); + unsigned short r = static_cast(_mm_movemask_epi8(x)); + if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped + size_t length; +#ifdef _MSC_VER // Find the index of first escaped + unsigned long offset; + _BitScanForward(&offset, r); + length = offset; +#else + length = static_cast(__builtin_ffs(r) - 1); +#endif + p += length; + break; + } + } + + is.src_ = is.dst_ = p; + } +#elif defined(RAPIDJSON_NEON) + // StringStream -> StackStream + static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream& os) { + const char* p = is.src_; + + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + while (p != nextAligned) + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { + is.src_ = p; + return; + } + else + os.Put(*p++); + + // The rest of string using SIMD + const uint8x16_t s0 = vmovq_n_u8('"'); + const uint8x16_t s1 = vmovq_n_u8('\\'); + const uint8x16_t s2 = vmovq_n_u8('\b'); + const uint8x16_t s3 = vmovq_n_u8(32); + + for (;; p += 16) { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, s0); + x = vorrq_u8(x, vceqq_u8(s, s1)); + x = vorrq_u8(x, vceqq_u8(s, s2)); + x = vorrq_u8(x, vcltq_u8(s, s3)); + + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract + uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract + + SizeType length = 0; + bool escaped = false; + if (low == 0) { + if (high != 0) { + uint32_t lz = internal::clzll(high); + length = 8 + (lz >> 3); + escaped = true; + } + } else { + uint32_t lz = internal::clzll(low); + length = lz >> 3; + escaped = true; + } + if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped + if (length != 0) { + char* q = reinterpret_cast(os.Push(length)); + for (size_t i = 0; i < length; i++) + q[i] = p[i]; + + p += length; + } + break; + } + vst1q_u8(reinterpret_cast(os.Push(16)), s); + } + + is.src_ = p; + } + + // InsituStringStream -> InsituStringStream + static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InsituStringStream& is, InsituStringStream& os) { + RAPIDJSON_ASSERT(&is == &os); + (void)os; + + if (is.src_ == is.dst_) { + SkipUnescapedString(is); + return; + } + + char* p = is.src_; + char *q = is.dst_; + + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + while (p != nextAligned) + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { + is.src_ = p; + is.dst_ = q; + return; + } + else + *q++ = *p++; + + // The rest of string using SIMD + const uint8x16_t s0 = vmovq_n_u8('"'); + const uint8x16_t s1 = vmovq_n_u8('\\'); + const uint8x16_t s2 = vmovq_n_u8('\b'); + const uint8x16_t s3 = vmovq_n_u8(32); + + for (;; p += 16, q += 16) { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, s0); + x = vorrq_u8(x, vceqq_u8(s, s1)); + x = vorrq_u8(x, vceqq_u8(s, s2)); + x = vorrq_u8(x, vcltq_u8(s, s3)); + + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract + uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract + + SizeType length = 0; + bool escaped = false; + if (low == 0) { + if (high != 0) { + uint32_t lz = internal::clzll(high); + length = 8 + (lz >> 3); + escaped = true; + } + } else { + uint32_t lz = internal::clzll(low); + length = lz >> 3; + escaped = true; + } + if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped + for (const char* pend = p + length; p != pend; ) { + *q++ = *p++; + } + break; + } + vst1q_u8(reinterpret_cast(q), s); + } + + is.src_ = p; + is.dst_ = q; + } + + // When read/write pointers are the same for insitu stream, just skip unescaped characters + static RAPIDJSON_FORCEINLINE void SkipUnescapedString(InsituStringStream& is) { + RAPIDJSON_ASSERT(is.src_ == is.dst_); + char* p = is.src_; + + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + for (; p != nextAligned; p++) + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { + is.src_ = is.dst_ = p; + return; + } + + // The rest of string using SIMD + const uint8x16_t s0 = vmovq_n_u8('"'); + const uint8x16_t s1 = vmovq_n_u8('\\'); + const uint8x16_t s2 = vmovq_n_u8('\b'); + const uint8x16_t s3 = vmovq_n_u8(32); + + for (;; p += 16) { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, s0); + x = vorrq_u8(x, vceqq_u8(s, s1)); + x = vorrq_u8(x, vceqq_u8(s, s2)); + x = vorrq_u8(x, vcltq_u8(s, s3)); + + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract + uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract + + if (low == 0) { + if (high != 0) { + uint32_t lz = internal::clzll(high); + p += 8 + (lz >> 3); + break; + } + } else { + uint32_t lz = internal::clzll(low); + p += lz >> 3; + break; + } + } + + is.src_ = is.dst_ = p; + } +#endif // RAPIDJSON_NEON + + template + class NumberStream; + + template + class NumberStream { + public: + typedef typename InputStream::Ch Ch; + + NumberStream(GenericReader& reader, InputStream& s) : is(s) { (void)reader; } + + RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); } + RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); } + RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); } + RAPIDJSON_FORCEINLINE void Push(char) {} + + size_t Tell() { return is.Tell(); } + size_t Length() { return 0; } + const char* Pop() { return 0; } + + protected: + NumberStream& operator=(const NumberStream&); + + InputStream& is; + }; + + template + class NumberStream : public NumberStream { + typedef NumberStream Base; + public: + NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is), stackStream(reader.stack_) {} + + RAPIDJSON_FORCEINLINE Ch TakePush() { + stackStream.Put(static_cast(Base::is.Peek())); + return Base::is.Take(); + } + + RAPIDJSON_FORCEINLINE void Push(char c) { + stackStream.Put(c); + } + + size_t Length() { return stackStream.Length(); } + + const char* Pop() { + stackStream.Put('\0'); + return stackStream.Pop(); + } + + private: + StackStream stackStream; + }; + + template + class NumberStream : public NumberStream { + typedef NumberStream Base; + public: + NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is) {} + + RAPIDJSON_FORCEINLINE Ch Take() { return Base::TakePush(); } + }; + + template + void ParseNumber(InputStream& is, Handler& handler) { + internal::StreamLocalCopy copy(is); + NumberStream s(*this, copy.s); + + size_t startOffset = s.Tell(); + double d = 0.0; + bool useNanOrInf = false; + + // Parse minus + bool minus = Consume(s, '-'); + + // Parse int: zero / ( digit1-9 *DIGIT ) + unsigned i = 0; + uint64_t i64 = 0; + bool use64bit = false; + int significandDigit = 0; + if (RAPIDJSON_UNLIKELY(s.Peek() == '0')) { + i = 0; + s.TakePush(); + } + else if (RAPIDJSON_LIKELY(s.Peek() >= '1' && s.Peek() <= '9')) { + i = static_cast(s.TakePush() - '0'); + + if (minus) + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + if (RAPIDJSON_UNLIKELY(i >= 214748364)) { // 2^31 = 2147483648 + if (RAPIDJSON_LIKELY(i != 214748364 || s.Peek() > '8')) { + i64 = i; + use64bit = true; + break; + } + } + i = i * 10 + static_cast(s.TakePush() - '0'); + significandDigit++; + } + else + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + if (RAPIDJSON_UNLIKELY(i >= 429496729)) { // 2^32 - 1 = 4294967295 + if (RAPIDJSON_LIKELY(i != 429496729 || s.Peek() > '5')) { + i64 = i; + use64bit = true; + break; + } + } + i = i * 10 + static_cast(s.TakePush() - '0'); + significandDigit++; + } + } + // Parse NaN or Infinity here + else if ((parseFlags & kParseNanAndInfFlag) && RAPIDJSON_LIKELY((s.Peek() == 'I' || s.Peek() == 'N'))) { + if (Consume(s, 'N')) { + if (Consume(s, 'a') && Consume(s, 'N')) { + d = std::numeric_limits::quiet_NaN(); + useNanOrInf = true; + } + } + else if (RAPIDJSON_LIKELY(Consume(s, 'I'))) { + if (Consume(s, 'n') && Consume(s, 'f')) { + d = (minus ? -std::numeric_limits::infinity() : std::numeric_limits::infinity()); + useNanOrInf = true; + + if (RAPIDJSON_UNLIKELY(s.Peek() == 'i' && !(Consume(s, 'i') && Consume(s, 'n') + && Consume(s, 'i') && Consume(s, 't') && Consume(s, 'y')))) { + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); + } + } + } + + if (RAPIDJSON_UNLIKELY(!useNanOrInf)) { + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); + } + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); + + // Parse 64bit int + bool useDouble = false; + if (use64bit) { + if (minus) + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC))) // 2^63 = 9223372036854775808 + if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8')) { + d = static_cast(i64); + useDouble = true; + break; + } + i64 = i64 * 10 + static_cast(s.TakePush() - '0'); + significandDigit++; + } + else + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999))) // 2^64 - 1 = 18446744073709551615 + if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || s.Peek() > '5')) { + d = static_cast(i64); + useDouble = true; + break; + } + i64 = i64 * 10 + static_cast(s.TakePush() - '0'); + significandDigit++; + } + } + + // Force double for big integer + if (useDouble) { + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + d = d * 10 + (s.TakePush() - '0'); + } + } + + // Parse frac = decimal-point 1*DIGIT + int expFrac = 0; + size_t decimalPosition; + if (Consume(s, '.')) { + decimalPosition = s.Length(); + + if (RAPIDJSON_UNLIKELY(!(s.Peek() >= '0' && s.Peek() <= '9'))) + RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell()); + + if (!useDouble) { +#if RAPIDJSON_64BIT + // Use i64 to store significand in 64-bit architecture + if (!use64bit) + i64 = i; + + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) // 2^53 - 1 for fast path + break; + else { + i64 = i64 * 10 + static_cast(s.TakePush() - '0'); + --expFrac; + if (i64 != 0) + significandDigit++; + } + } + + d = static_cast(i64); +#else + // Use double to store significand in 32-bit architecture + d = static_cast(use64bit ? i64 : i); +#endif + useDouble = true; + } + + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + if (significandDigit < 17) { + d = d * 10.0 + (s.TakePush() - '0'); + --expFrac; + if (RAPIDJSON_LIKELY(d > 0.0)) + significandDigit++; + } + else + s.TakePush(); + } + } + else + decimalPosition = s.Length(); // decimal position at the end of integer. + + // Parse exp = e [ minus / plus ] 1*DIGIT + int exp = 0; + if (Consume(s, 'e') || Consume(s, 'E')) { + if (!useDouble) { + d = static_cast(use64bit ? i64 : i); + useDouble = true; + } + + bool expMinus = false; + if (Consume(s, '+')) + ; + else if (Consume(s, '-')) + expMinus = true; + + if (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + exp = static_cast(s.Take() - '0'); + if (expMinus) { + // (exp + expFrac) must not underflow int => we're detecting when -exp gets + // dangerously close to INT_MIN (a pessimistic next digit 9 would push it into + // underflow territory): + // + // -(exp * 10 + 9) + expFrac >= INT_MIN + // <=> exp <= (expFrac - INT_MIN - 9) / 10 + RAPIDJSON_ASSERT(expFrac <= 0); + int maxExp = (expFrac + 2147483639) / 10; + + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + exp = exp * 10 + static_cast(s.Take() - '0'); + if (RAPIDJSON_UNLIKELY(exp > maxExp)) { + while (RAPIDJSON_UNLIKELY(s.Peek() >= '0' && s.Peek() <= '9')) // Consume the rest of exponent + s.Take(); + } + } + } + else { // positive exp + int maxExp = 308 - expFrac; + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + exp = exp * 10 + static_cast(s.Take() - '0'); + if (RAPIDJSON_UNLIKELY(exp > maxExp)) + RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset); + } + } + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissExponent, s.Tell()); + + if (expMinus) + exp = -exp; + } + + // Finish parsing, call event according to the type of number. + bool cont = true; + + if (parseFlags & kParseNumbersAsStringsFlag) { + if (parseFlags & kParseInsituFlag) { + s.Pop(); // Pop stack no matter if it will be used or not. + typename InputStream::Ch* head = is.PutBegin(); + const size_t length = s.Tell() - startOffset; + RAPIDJSON_ASSERT(length <= 0xFFFFFFFF); + // unable to insert the \0 character here, it will erase the comma after this number + const typename TargetEncoding::Ch* const str = reinterpret_cast(head); + cont = handler.RawNumber(str, SizeType(length), false); + } + else { + SizeType numCharsToCopy = static_cast(s.Length()); + StringStream srcStream(s.Pop()); + StackStream dstStream(stack_); + while (numCharsToCopy--) { + Transcoder, TargetEncoding>::Transcode(srcStream, dstStream); + } + dstStream.Put('\0'); + const typename TargetEncoding::Ch* str = dstStream.Pop(); + const SizeType length = static_cast(dstStream.Length()) - 1; + cont = handler.RawNumber(str, SizeType(length), true); + } + } + else { + size_t length = s.Length(); + const char* decimal = s.Pop(); // Pop stack no matter if it will be used or not. + + if (useDouble) { + int p = exp + expFrac; + if (parseFlags & kParseFullPrecisionFlag) + d = internal::StrtodFullPrecision(d, p, decimal, length, decimalPosition, exp); + else + d = internal::StrtodNormalPrecision(d, p); + + // Use > max, instead of == inf, to fix bogus warning -Wfloat-equal + if (d > (std::numeric_limits::max)()) { + // Overflow + // TODO: internal::StrtodX should report overflow (or underflow) + RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset); + } + + cont = handler.Double(minus ? -d : d); + } + else if (useNanOrInf) { + cont = handler.Double(d); + } + else { + if (use64bit) { + if (minus) + cont = handler.Int64(static_cast(~i64 + 1)); + else + cont = handler.Uint64(i64); + } + else { + if (minus) + cont = handler.Int(static_cast(~i + 1)); + else + cont = handler.Uint(i); + } + } + } + if (RAPIDJSON_UNLIKELY(!cont)) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, startOffset); + } + + // Parse any JSON value + template + void ParseValue(InputStream& is, Handler& handler) { + switch (is.Peek()) { + case 'n': ParseNull (is, handler); break; + case 't': ParseTrue (is, handler); break; + case 'f': ParseFalse (is, handler); break; + case '"': ParseString(is, handler); break; + case '{': ParseObject(is, handler); break; + case '[': ParseArray (is, handler); break; + default : + ParseNumber(is, handler); + break; + + } + } + + // Iterative Parsing + + // States + enum IterativeParsingState { + IterativeParsingFinishState = 0, // sink states at top + IterativeParsingErrorState, // sink states at top + IterativeParsingStartState, + + // Object states + IterativeParsingObjectInitialState, + IterativeParsingMemberKeyState, + IterativeParsingMemberValueState, + IterativeParsingObjectFinishState, + + // Array states + IterativeParsingArrayInitialState, + IterativeParsingElementState, + IterativeParsingArrayFinishState, + + // Single value state + IterativeParsingValueState, + + // Delimiter states (at bottom) + IterativeParsingElementDelimiterState, + IterativeParsingMemberDelimiterState, + IterativeParsingKeyValueDelimiterState, + + cIterativeParsingStateCount + }; + + // Tokens + enum Token { + LeftBracketToken = 0, + RightBracketToken, + + LeftCurlyBracketToken, + RightCurlyBracketToken, + + CommaToken, + ColonToken, + + StringToken, + FalseToken, + TrueToken, + NullToken, + NumberToken, + + kTokenCount + }; + + RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) const { + +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN +#define N NumberToken +#define N16 N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N + // Maps from ASCII to Token + static const unsigned char tokenMap[256] = { + N16, // 00~0F + N16, // 10~1F + N, N, StringToken, N, N, N, N, N, N, N, N, N, CommaToken, N, N, N, // 20~2F + N, N, N, N, N, N, N, N, N, N, ColonToken, N, N, N, N, N, // 30~3F + N16, // 40~4F + N, N, N, N, N, N, N, N, N, N, N, LeftBracketToken, N, RightBracketToken, N, N, // 50~5F + N, N, N, N, N, N, FalseToken, N, N, N, N, N, N, N, NullToken, N, // 60~6F + N, N, N, N, TrueToken, N, N, N, N, N, N, LeftCurlyBracketToken, N, RightCurlyBracketToken, N, N, // 70~7F + N16, N16, N16, N16, N16, N16, N16, N16 // 80~FF + }; +#undef N +#undef N16 +//!@endcond + + if (sizeof(Ch) == 1 || static_cast(c) < 256) + return static_cast(tokenMap[static_cast(c)]); + else + return NumberToken; + } + + RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) const { + // current state x one lookahead token -> new state + static const char G[cIterativeParsingStateCount][kTokenCount] = { + // Finish(sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + }, + // Error(sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + }, + // Start + { + IterativeParsingArrayInitialState, // Left bracket + IterativeParsingErrorState, // Right bracket + IterativeParsingObjectInitialState, // Left curly bracket + IterativeParsingErrorState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingValueState, // String + IterativeParsingValueState, // False + IterativeParsingValueState, // True + IterativeParsingValueState, // Null + IterativeParsingValueState // Number + }, + // ObjectInitial + { + IterativeParsingErrorState, // Left bracket + IterativeParsingErrorState, // Right bracket + IterativeParsingErrorState, // Left curly bracket + IterativeParsingObjectFinishState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingMemberKeyState, // String + IterativeParsingErrorState, // False + IterativeParsingErrorState, // True + IterativeParsingErrorState, // Null + IterativeParsingErrorState // Number + }, + // MemberKey + { + IterativeParsingErrorState, // Left bracket + IterativeParsingErrorState, // Right bracket + IterativeParsingErrorState, // Left curly bracket + IterativeParsingErrorState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingKeyValueDelimiterState, // Colon + IterativeParsingErrorState, // String + IterativeParsingErrorState, // False + IterativeParsingErrorState, // True + IterativeParsingErrorState, // Null + IterativeParsingErrorState // Number + }, + // MemberValue + { + IterativeParsingErrorState, // Left bracket + IterativeParsingErrorState, // Right bracket + IterativeParsingErrorState, // Left curly bracket + IterativeParsingObjectFinishState, // Right curly bracket + IterativeParsingMemberDelimiterState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingErrorState, // String + IterativeParsingErrorState, // False + IterativeParsingErrorState, // True + IterativeParsingErrorState, // Null + IterativeParsingErrorState // Number + }, + // ObjectFinish(sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + }, + // ArrayInitial + { + IterativeParsingArrayInitialState, // Left bracket(push Element state) + IterativeParsingArrayFinishState, // Right bracket + IterativeParsingObjectInitialState, // Left curly bracket(push Element state) + IterativeParsingErrorState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingElementState, // String + IterativeParsingElementState, // False + IterativeParsingElementState, // True + IterativeParsingElementState, // Null + IterativeParsingElementState // Number + }, + // Element + { + IterativeParsingErrorState, // Left bracket + IterativeParsingArrayFinishState, // Right bracket + IterativeParsingErrorState, // Left curly bracket + IterativeParsingErrorState, // Right curly bracket + IterativeParsingElementDelimiterState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingErrorState, // String + IterativeParsingErrorState, // False + IterativeParsingErrorState, // True + IterativeParsingErrorState, // Null + IterativeParsingErrorState // Number + }, + // ArrayFinish(sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + }, + // Single Value (sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + }, + // ElementDelimiter + { + IterativeParsingArrayInitialState, // Left bracket(push Element state) + IterativeParsingArrayFinishState, // Right bracket + IterativeParsingObjectInitialState, // Left curly bracket(push Element state) + IterativeParsingErrorState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingElementState, // String + IterativeParsingElementState, // False + IterativeParsingElementState, // True + IterativeParsingElementState, // Null + IterativeParsingElementState // Number + }, + // MemberDelimiter + { + IterativeParsingErrorState, // Left bracket + IterativeParsingErrorState, // Right bracket + IterativeParsingErrorState, // Left curly bracket + IterativeParsingObjectFinishState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingMemberKeyState, // String + IterativeParsingErrorState, // False + IterativeParsingErrorState, // True + IterativeParsingErrorState, // Null + IterativeParsingErrorState // Number + }, + // KeyValueDelimiter + { + IterativeParsingArrayInitialState, // Left bracket(push MemberValue state) + IterativeParsingErrorState, // Right bracket + IterativeParsingObjectInitialState, // Left curly bracket(push MemberValue state) + IterativeParsingErrorState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingMemberValueState, // String + IterativeParsingMemberValueState, // False + IterativeParsingMemberValueState, // True + IterativeParsingMemberValueState, // Null + IterativeParsingMemberValueState // Number + }, + }; // End of G + + return static_cast(G[state][token]); + } + + // Make an advance in the token stream and state based on the candidate destination state which was returned by Transit(). + // May return a new state on state pop. + template + RAPIDJSON_FORCEINLINE IterativeParsingState Transit(IterativeParsingState src, Token token, IterativeParsingState dst, InputStream& is, Handler& handler) { + (void)token; + + switch (dst) { + case IterativeParsingErrorState: + return dst; + + case IterativeParsingObjectInitialState: + case IterativeParsingArrayInitialState: + { + // Push the state(Element or MemeberValue) if we are nested in another array or value of member. + // In this way we can get the correct state on ObjectFinish or ArrayFinish by frame pop. + IterativeParsingState n = src; + if (src == IterativeParsingArrayInitialState || src == IterativeParsingElementDelimiterState) + n = IterativeParsingElementState; + else if (src == IterativeParsingKeyValueDelimiterState) + n = IterativeParsingMemberValueState; + // Push current state. + *stack_.template Push(1) = n; + // Initialize and push the member/element count. + *stack_.template Push(1) = 0; + // Call handler + bool hr = (dst == IterativeParsingObjectInitialState) ? handler.StartObject() : handler.StartArray(); + // On handler short circuits the parsing. + if (!hr) { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); + return IterativeParsingErrorState; + } + else { + is.Take(); + return dst; + } + } + + case IterativeParsingMemberKeyState: + ParseString(is, handler, true); + if (HasParseError()) + return IterativeParsingErrorState; + else + return dst; + + case IterativeParsingKeyValueDelimiterState: + RAPIDJSON_ASSERT(token == ColonToken); + is.Take(); + return dst; + + case IterativeParsingMemberValueState: + // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. + ParseValue(is, handler); + if (HasParseError()) { + return IterativeParsingErrorState; + } + return dst; + + case IterativeParsingElementState: + // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. + ParseValue(is, handler); + if (HasParseError()) { + return IterativeParsingErrorState; + } + return dst; + + case IterativeParsingMemberDelimiterState: + case IterativeParsingElementDelimiterState: + is.Take(); + // Update member/element count. + *stack_.template Top() = *stack_.template Top() + 1; + return dst; + + case IterativeParsingObjectFinishState: + { + // Transit from delimiter is only allowed when trailing commas are enabled + if (!(parseFlags & kParseTrailingCommasFlag) && src == IterativeParsingMemberDelimiterState) { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorObjectMissName, is.Tell()); + return IterativeParsingErrorState; + } + // Get member count. + SizeType c = *stack_.template Pop(1); + // If the object is not empty, count the last member. + if (src == IterativeParsingMemberValueState) + ++c; + // Restore the state. + IterativeParsingState n = static_cast(*stack_.template Pop(1)); + // Transit to Finish state if this is the topmost scope. + if (n == IterativeParsingStartState) + n = IterativeParsingFinishState; + // Call handler + bool hr = handler.EndObject(c); + // On handler short circuits the parsing. + if (!hr) { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); + return IterativeParsingErrorState; + } + else { + is.Take(); + return n; + } + } + + case IterativeParsingArrayFinishState: + { + // Transit from delimiter is only allowed when trailing commas are enabled + if (!(parseFlags & kParseTrailingCommasFlag) && src == IterativeParsingElementDelimiterState) { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorValueInvalid, is.Tell()); + return IterativeParsingErrorState; + } + // Get element count. + SizeType c = *stack_.template Pop(1); + // If the array is not empty, count the last element. + if (src == IterativeParsingElementState) + ++c; + // Restore the state. + IterativeParsingState n = static_cast(*stack_.template Pop(1)); + // Transit to Finish state if this is the topmost scope. + if (n == IterativeParsingStartState) + n = IterativeParsingFinishState; + // Call handler + bool hr = handler.EndArray(c); + // On handler short circuits the parsing. + if (!hr) { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); + return IterativeParsingErrorState; + } + else { + is.Take(); + return n; + } + } + + default: + // This branch is for IterativeParsingValueState actually. + // Use `default:` rather than + // `case IterativeParsingValueState:` is for code coverage. + + // The IterativeParsingStartState is not enumerated in this switch-case. + // It is impossible for that case. And it can be caught by following assertion. + + // The IterativeParsingFinishState is not enumerated in this switch-case either. + // It is a "derivative" state which cannot triggered from Predict() directly. + // Therefore it cannot happen here. And it can be caught by following assertion. + RAPIDJSON_ASSERT(dst == IterativeParsingValueState); + + // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. + ParseValue(is, handler); + if (HasParseError()) { + return IterativeParsingErrorState; + } + return IterativeParsingFinishState; + } + } + + template + void HandleError(IterativeParsingState src, InputStream& is) { + if (HasParseError()) { + // Error flag has been set. + return; + } + + switch (src) { + case IterativeParsingStartState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell()); return; + case IterativeParsingFinishState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell()); return; + case IterativeParsingObjectInitialState: + case IterativeParsingMemberDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); return; + case IterativeParsingMemberKeyState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); return; + case IterativeParsingMemberValueState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); return; + case IterativeParsingKeyValueDelimiterState: + case IterativeParsingArrayInitialState: + case IterativeParsingElementDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); return; + default: RAPIDJSON_ASSERT(src == IterativeParsingElementState); RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return; + } + } + + RAPIDJSON_FORCEINLINE bool IsIterativeParsingDelimiterState(IterativeParsingState s) const { + return s >= IterativeParsingElementDelimiterState; + } + + RAPIDJSON_FORCEINLINE bool IsIterativeParsingCompleteState(IterativeParsingState s) const { + return s <= IterativeParsingErrorState; + } + + template + ParseResult IterativeParse(InputStream& is, Handler& handler) { + parseResult_.Clear(); + ClearStackOnExit scope(*this); + IterativeParsingState state = IterativeParsingStartState; + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + while (is.Peek() != '\0') { + Token t = Tokenize(is.Peek()); + IterativeParsingState n = Predict(state, t); + IterativeParsingState d = Transit(state, t, n, is, handler); + + if (d == IterativeParsingErrorState) { + HandleError(state, is); + break; + } + + state = d; + + // Do not further consume streams if a root JSON has been parsed. + if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState) + break; + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + } + + // Handle the end of file. + if (state != IterativeParsingFinishState) + HandleError(state, is); + + return parseResult_; + } + + static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string. + internal::Stack stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing. + ParseResult parseResult_; + IterativeParsingState state_; +}; // class GenericReader + +//! Reader with UTF8 encoding and default allocator. +typedef GenericReader, UTF8<> > Reader; + +RAPIDJSON_NAMESPACE_END + +#if defined(__clang__) || defined(_MSC_VER) +RAPIDJSON_DIAG_POP +#endif + + +#ifdef __GNUC__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_READER_H_ diff --git a/src/include/rapidjson/schema.h b/src/include/rapidjson/schema.h new file mode 100755 index 0000000..fc39d06 --- /dev/null +++ b/src/include/rapidjson/schema.h @@ -0,0 +1,2496 @@ +// Tencent is pleased to support the open source community by making RapidJSON available-> +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip-> All rights reserved-> +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License-> You may obtain a copy of the License at +// +// http://opensource->org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied-> See the License for the +// specific language governing permissions and limitations under the License-> + +#ifndef RAPIDJSON_SCHEMA_H_ +#define RAPIDJSON_SCHEMA_H_ + +#include "document.h" +#include "pointer.h" +#include "stringbuffer.h" +#include // abs, floor + +#if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX) +#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1 +#else +#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0 +#endif + +#if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800)) +#define RAPIDJSON_SCHEMA_USE_STDREGEX 1 +#else +#define RAPIDJSON_SCHEMA_USE_STDREGEX 0 +#endif + +#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX +#include "internal/regex.h" +#elif RAPIDJSON_SCHEMA_USE_STDREGEX +#include +#endif + +#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX || RAPIDJSON_SCHEMA_USE_STDREGEX +#define RAPIDJSON_SCHEMA_HAS_REGEX 1 +#else +#define RAPIDJSON_SCHEMA_HAS_REGEX 0 +#endif + +#ifndef RAPIDJSON_SCHEMA_VERBOSE +#define RAPIDJSON_SCHEMA_VERBOSE 0 +#endif + +#if RAPIDJSON_SCHEMA_VERBOSE +#include "stringbuffer.h" +#endif + +RAPIDJSON_DIAG_PUSH + +#if defined(__GNUC__) +RAPIDJSON_DIAG_OFF(effc++) +#endif + +#ifdef __clang__ +RAPIDJSON_DIAG_OFF(weak-vtables) +RAPIDJSON_DIAG_OFF(exit-time-destructors) +RAPIDJSON_DIAG_OFF(c++98-compat-pedantic) +RAPIDJSON_DIAG_OFF(variadic-macros) +#elif defined(_MSC_VER) +RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// Verbose Utilities + +#if RAPIDJSON_SCHEMA_VERBOSE + +namespace internal { + +inline void PrintInvalidKeyword(const char* keyword) { + printf("Fail keyword: %s\n", keyword); +} + +inline void PrintInvalidKeyword(const wchar_t* keyword) { + wprintf(L"Fail keyword: %ls\n", keyword); +} + +inline void PrintInvalidDocument(const char* document) { + printf("Fail document: %s\n\n", document); +} + +inline void PrintInvalidDocument(const wchar_t* document) { + wprintf(L"Fail document: %ls\n\n", document); +} + +inline void PrintValidatorPointers(unsigned depth, const char* s, const char* d) { + printf("S: %*s%s\nD: %*s%s\n\n", depth * 4, " ", s, depth * 4, " ", d); +} + +inline void PrintValidatorPointers(unsigned depth, const wchar_t* s, const wchar_t* d) { + wprintf(L"S: %*ls%ls\nD: %*ls%ls\n\n", depth * 4, L" ", s, depth * 4, L" ", d); +} + +} // namespace internal + +#endif // RAPIDJSON_SCHEMA_VERBOSE + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_INVALID_KEYWORD_RETURN + +#if RAPIDJSON_SCHEMA_VERBOSE +#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) internal::PrintInvalidKeyword(keyword) +#else +#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) +#endif + +#define RAPIDJSON_INVALID_KEYWORD_RETURN(keyword)\ +RAPIDJSON_MULTILINEMACRO_BEGIN\ + context.invalidKeyword = keyword.GetString();\ + RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword.GetString());\ + return false;\ +RAPIDJSON_MULTILINEMACRO_END + +/////////////////////////////////////////////////////////////////////////////// +// Forward declarations + +template +class GenericSchemaDocument; + +namespace internal { + +template +class Schema; + +/////////////////////////////////////////////////////////////////////////////// +// ISchemaValidator + +class ISchemaValidator { +public: + virtual ~ISchemaValidator() {} + virtual bool IsValid() const = 0; +}; + +/////////////////////////////////////////////////////////////////////////////// +// ISchemaStateFactory + +template +class ISchemaStateFactory { +public: + virtual ~ISchemaStateFactory() {} + virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&) = 0; + virtual void DestroySchemaValidator(ISchemaValidator* validator) = 0; + virtual void* CreateHasher() = 0; + virtual uint64_t GetHashCode(void* hasher) = 0; + virtual void DestroryHasher(void* hasher) = 0; + virtual void* MallocState(size_t size) = 0; + virtual void FreeState(void* p) = 0; +}; + +/////////////////////////////////////////////////////////////////////////////// +// IValidationErrorHandler + +template +class IValidationErrorHandler { +public: + typedef typename SchemaType::Ch Ch; + typedef typename SchemaType::SValue SValue; + + virtual ~IValidationErrorHandler() {} + + virtual void NotMultipleOf(int64_t actual, const SValue& expected) = 0; + virtual void NotMultipleOf(uint64_t actual, const SValue& expected) = 0; + virtual void NotMultipleOf(double actual, const SValue& expected) = 0; + virtual void AboveMaximum(int64_t actual, const SValue& expected, bool exclusive) = 0; + virtual void AboveMaximum(uint64_t actual, const SValue& expected, bool exclusive) = 0; + virtual void AboveMaximum(double actual, const SValue& expected, bool exclusive) = 0; + virtual void BelowMinimum(int64_t actual, const SValue& expected, bool exclusive) = 0; + virtual void BelowMinimum(uint64_t actual, const SValue& expected, bool exclusive) = 0; + virtual void BelowMinimum(double actual, const SValue& expected, bool exclusive) = 0; + + virtual void TooLong(const Ch* str, SizeType length, SizeType expected) = 0; + virtual void TooShort(const Ch* str, SizeType length, SizeType expected) = 0; + virtual void DoesNotMatch(const Ch* str, SizeType length) = 0; + + virtual void DisallowedItem(SizeType index) = 0; + virtual void TooFewItems(SizeType actualCount, SizeType expectedCount) = 0; + virtual void TooManyItems(SizeType actualCount, SizeType expectedCount) = 0; + virtual void DuplicateItems(SizeType index1, SizeType index2) = 0; + + virtual void TooManyProperties(SizeType actualCount, SizeType expectedCount) = 0; + virtual void TooFewProperties(SizeType actualCount, SizeType expectedCount) = 0; + virtual void StartMissingProperties() = 0; + virtual void AddMissingProperty(const SValue& name) = 0; + virtual bool EndMissingProperties() = 0; + virtual void PropertyViolations(ISchemaValidator** subvalidators, SizeType count) = 0; + virtual void DisallowedProperty(const Ch* name, SizeType length) = 0; + + virtual void StartDependencyErrors() = 0; + virtual void StartMissingDependentProperties() = 0; + virtual void AddMissingDependentProperty(const SValue& targetName) = 0; + virtual void EndMissingDependentProperties(const SValue& sourceName) = 0; + virtual void AddDependencySchemaError(const SValue& souceName, ISchemaValidator* subvalidator) = 0; + virtual bool EndDependencyErrors() = 0; + + virtual void DisallowedValue() = 0; + virtual void StartDisallowedType() = 0; + virtual void AddExpectedType(const typename SchemaType::ValueType& expectedType) = 0; + virtual void EndDisallowedType(const typename SchemaType::ValueType& actualType) = 0; + virtual void NotAllOf(ISchemaValidator** subvalidators, SizeType count) = 0; + virtual void NoneOf(ISchemaValidator** subvalidators, SizeType count) = 0; + virtual void NotOneOf(ISchemaValidator** subvalidators, SizeType count) = 0; + virtual void Disallowed() = 0; +}; + + +/////////////////////////////////////////////////////////////////////////////// +// Hasher + +// For comparison of compound value +template +class Hasher { +public: + typedef typename Encoding::Ch Ch; + + Hasher(Allocator* allocator = 0, size_t stackCapacity = kDefaultSize) : stack_(allocator, stackCapacity) {} + + bool Null() { return WriteType(kNullType); } + bool Bool(bool b) { return WriteType(b ? kTrueType : kFalseType); } + bool Int(int i) { Number n; n.u.i = i; n.d = static_cast(i); return WriteNumber(n); } + bool Uint(unsigned u) { Number n; n.u.u = u; n.d = static_cast(u); return WriteNumber(n); } + bool Int64(int64_t i) { Number n; n.u.i = i; n.d = static_cast(i); return WriteNumber(n); } + bool Uint64(uint64_t u) { Number n; n.u.u = u; n.d = static_cast(u); return WriteNumber(n); } + bool Double(double d) { + Number n; + if (d < 0) n.u.i = static_cast(d); + else n.u.u = static_cast(d); + n.d = d; + return WriteNumber(n); + } + + bool RawNumber(const Ch* str, SizeType len, bool) { + WriteBuffer(kNumberType, str, len * sizeof(Ch)); + return true; + } + + bool String(const Ch* str, SizeType len, bool) { + WriteBuffer(kStringType, str, len * sizeof(Ch)); + return true; + } + + bool StartObject() { return true; } + bool Key(const Ch* str, SizeType len, bool copy) { return String(str, len, copy); } + bool EndObject(SizeType memberCount) { + uint64_t h = Hash(0, kObjectType); + uint64_t* kv = stack_.template Pop(memberCount * 2); + for (SizeType i = 0; i < memberCount; i++) + h ^= Hash(kv[i * 2], kv[i * 2 + 1]); // Use xor to achieve member order insensitive + *stack_.template Push() = h; + return true; + } + + bool StartArray() { return true; } + bool EndArray(SizeType elementCount) { + uint64_t h = Hash(0, kArrayType); + uint64_t* e = stack_.template Pop(elementCount); + for (SizeType i = 0; i < elementCount; i++) + h = Hash(h, e[i]); // Use hash to achieve element order sensitive + *stack_.template Push() = h; + return true; + } + + bool IsValid() const { return stack_.GetSize() == sizeof(uint64_t); } + + uint64_t GetHashCode() const { + RAPIDJSON_ASSERT(IsValid()); + return *stack_.template Top(); + } + +private: + static const size_t kDefaultSize = 256; + struct Number { + union U { + uint64_t u; + int64_t i; + }u; + double d; + }; + + bool WriteType(Type type) { return WriteBuffer(type, 0, 0); } + + bool WriteNumber(const Number& n) { return WriteBuffer(kNumberType, &n, sizeof(n)); } + + bool WriteBuffer(Type type, const void* data, size_t len) { + // FNV-1a from http://isthe.com/chongo/tech/comp/fnv/ + uint64_t h = Hash(RAPIDJSON_UINT64_C2(0x84222325, 0xcbf29ce4), type); + const unsigned char* d = static_cast(data); + for (size_t i = 0; i < len; i++) + h = Hash(h, d[i]); + *stack_.template Push() = h; + return true; + } + + static uint64_t Hash(uint64_t h, uint64_t d) { + static const uint64_t kPrime = RAPIDJSON_UINT64_C2(0x00000100, 0x000001b3); + h ^= d; + h *= kPrime; + return h; + } + + Stack stack_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// SchemaValidationContext + +template +struct SchemaValidationContext { + typedef Schema SchemaType; + typedef ISchemaStateFactory SchemaValidatorFactoryType; + typedef IValidationErrorHandler ErrorHandlerType; + typedef typename SchemaType::ValueType ValueType; + typedef typename ValueType::Ch Ch; + + enum PatternValidatorType { + kPatternValidatorOnly, + kPatternValidatorWithProperty, + kPatternValidatorWithAdditionalProperty + }; + + SchemaValidationContext(SchemaValidatorFactoryType& f, ErrorHandlerType& eh, const SchemaType* s) : + factory(f), + error_handler(eh), + schema(s), + valueSchema(), + invalidKeyword(), + hasher(), + arrayElementHashCodes(), + validators(), + validatorCount(), + patternPropertiesValidators(), + patternPropertiesValidatorCount(), + patternPropertiesSchemas(), + patternPropertiesSchemaCount(), + valuePatternValidatorType(kPatternValidatorOnly), + propertyExist(), + inArray(false), + valueUniqueness(false), + arrayUniqueness(false) + { + } + + ~SchemaValidationContext() { + if (hasher) + factory.DestroryHasher(hasher); + if (validators) { + for (SizeType i = 0; i < validatorCount; i++) + factory.DestroySchemaValidator(validators[i]); + factory.FreeState(validators); + } + if (patternPropertiesValidators) { + for (SizeType i = 0; i < patternPropertiesValidatorCount; i++) + factory.DestroySchemaValidator(patternPropertiesValidators[i]); + factory.FreeState(patternPropertiesValidators); + } + if (patternPropertiesSchemas) + factory.FreeState(patternPropertiesSchemas); + if (propertyExist) + factory.FreeState(propertyExist); + } + + SchemaValidatorFactoryType& factory; + ErrorHandlerType& error_handler; + const SchemaType* schema; + const SchemaType* valueSchema; + const Ch* invalidKeyword; + void* hasher; // Only validator access + void* arrayElementHashCodes; // Only validator access this + ISchemaValidator** validators; + SizeType validatorCount; + ISchemaValidator** patternPropertiesValidators; + SizeType patternPropertiesValidatorCount; + const SchemaType** patternPropertiesSchemas; + SizeType patternPropertiesSchemaCount; + PatternValidatorType valuePatternValidatorType; + PatternValidatorType objectPatternValidatorType; + SizeType arrayElementIndex; + bool* propertyExist; + bool inArray; + bool valueUniqueness; + bool arrayUniqueness; +}; + +/////////////////////////////////////////////////////////////////////////////// +// Schema + +template +class Schema { +public: + typedef typename SchemaDocumentType::ValueType ValueType; + typedef typename SchemaDocumentType::AllocatorType AllocatorType; + typedef typename SchemaDocumentType::PointerType PointerType; + typedef typename ValueType::EncodingType EncodingType; + typedef typename EncodingType::Ch Ch; + typedef SchemaValidationContext Context; + typedef Schema SchemaType; + typedef GenericValue SValue; + typedef IValidationErrorHandler ErrorHandler; + friend class GenericSchemaDocument; + + Schema(SchemaDocumentType* schemaDocument, const PointerType& p, const ValueType& value, const ValueType& document, AllocatorType* allocator) : + allocator_(allocator), + uri_(schemaDocument->GetURI(), *allocator), + pointer_(p, allocator), + typeless_(schemaDocument->GetTypeless()), + enum_(), + enumCount_(), + not_(), + type_((1 << kTotalSchemaType) - 1), // typeless + validatorCount_(), + notValidatorIndex_(), + properties_(), + additionalPropertiesSchema_(), + patternProperties_(), + patternPropertyCount_(), + propertyCount_(), + minProperties_(), + maxProperties_(SizeType(~0)), + additionalProperties_(true), + hasDependencies_(), + hasRequired_(), + hasSchemaDependencies_(), + additionalItemsSchema_(), + itemsList_(), + itemsTuple_(), + itemsTupleCount_(), + minItems_(), + maxItems_(SizeType(~0)), + additionalItems_(true), + uniqueItems_(false), + pattern_(), + minLength_(0), + maxLength_(~SizeType(0)), + exclusiveMinimum_(false), + exclusiveMaximum_(false), + defaultValueLength_(0) + { + typedef typename ValueType::ConstValueIterator ConstValueIterator; + typedef typename ValueType::ConstMemberIterator ConstMemberIterator; + + if (!value.IsObject()) + return; + + if (const ValueType* v = GetMember(value, GetTypeString())) { + type_ = 0; + if (v->IsString()) + AddType(*v); + else if (v->IsArray()) + for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) + AddType(*itr); + } + + if (const ValueType* v = GetMember(value, GetEnumString())) + if (v->IsArray() && v->Size() > 0) { + enum_ = static_cast(allocator_->Malloc(sizeof(uint64_t) * v->Size())); + for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) { + typedef Hasher > EnumHasherType; + char buffer[256u + 24]; + MemoryPoolAllocator<> hasherAllocator(buffer, sizeof(buffer)); + EnumHasherType h(&hasherAllocator, 256); + itr->Accept(h); + enum_[enumCount_++] = h.GetHashCode(); + } + } + + if (schemaDocument) { + AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document); + AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document); + AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document); + } + + if (const ValueType* v = GetMember(value, GetNotString())) { + schemaDocument->CreateSchema(¬_, p.Append(GetNotString(), allocator_), *v, document); + notValidatorIndex_ = validatorCount_; + validatorCount_++; + } + + // Object + + const ValueType* properties = GetMember(value, GetPropertiesString()); + const ValueType* required = GetMember(value, GetRequiredString()); + const ValueType* dependencies = GetMember(value, GetDependenciesString()); + { + // Gather properties from properties/required/dependencies + SValue allProperties(kArrayType); + + if (properties && properties->IsObject()) + for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) + AddUniqueElement(allProperties, itr->name); + + if (required && required->IsArray()) + for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr) + if (itr->IsString()) + AddUniqueElement(allProperties, *itr); + + if (dependencies && dependencies->IsObject()) + for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) { + AddUniqueElement(allProperties, itr->name); + if (itr->value.IsArray()) + for (ConstValueIterator i = itr->value.Begin(); i != itr->value.End(); ++i) + if (i->IsString()) + AddUniqueElement(allProperties, *i); + } + + if (allProperties.Size() > 0) { + propertyCount_ = allProperties.Size(); + properties_ = static_cast(allocator_->Malloc(sizeof(Property) * propertyCount_)); + for (SizeType i = 0; i < propertyCount_; i++) { + new (&properties_[i]) Property(); + properties_[i].name = allProperties[i]; + properties_[i].schema = typeless_; + } + } + } + + if (properties && properties->IsObject()) { + PointerType q = p.Append(GetPropertiesString(), allocator_); + for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) { + SizeType index; + if (FindPropertyIndex(itr->name, &index)) + schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document); + } + } + + if (const ValueType* v = GetMember(value, GetPatternPropertiesString())) { + PointerType q = p.Append(GetPatternPropertiesString(), allocator_); + patternProperties_ = static_cast(allocator_->Malloc(sizeof(PatternProperty) * v->MemberCount())); + patternPropertyCount_ = 0; + + for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) { + new (&patternProperties_[patternPropertyCount_]) PatternProperty(); + patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name); + schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, q.Append(itr->name, allocator_), itr->value, document); + patternPropertyCount_++; + } + } + + if (required && required->IsArray()) + for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr) + if (itr->IsString()) { + SizeType index; + if (FindPropertyIndex(*itr, &index)) { + properties_[index].required = true; + hasRequired_ = true; + } + } + + if (dependencies && dependencies->IsObject()) { + PointerType q = p.Append(GetDependenciesString(), allocator_); + hasDependencies_ = true; + for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) { + SizeType sourceIndex; + if (FindPropertyIndex(itr->name, &sourceIndex)) { + if (itr->value.IsArray()) { + properties_[sourceIndex].dependencies = static_cast(allocator_->Malloc(sizeof(bool) * propertyCount_)); + std::memset(properties_[sourceIndex].dependencies, 0, sizeof(bool)* propertyCount_); + for (ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) { + SizeType targetIndex; + if (FindPropertyIndex(*targetItr, &targetIndex)) + properties_[sourceIndex].dependencies[targetIndex] = true; + } + } + else if (itr->value.IsObject()) { + hasSchemaDependencies_ = true; + schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document); + properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_; + validatorCount_++; + } + } + } + } + + if (const ValueType* v = GetMember(value, GetAdditionalPropertiesString())) { + if (v->IsBool()) + additionalProperties_ = v->GetBool(); + else if (v->IsObject()) + schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document); + } + + AssignIfExist(minProperties_, value, GetMinPropertiesString()); + AssignIfExist(maxProperties_, value, GetMaxPropertiesString()); + + // Array + if (const ValueType* v = GetMember(value, GetItemsString())) { + PointerType q = p.Append(GetItemsString(), allocator_); + if (v->IsObject()) // List validation + schemaDocument->CreateSchema(&itemsList_, q, *v, document); + else if (v->IsArray()) { // Tuple validation + itemsTuple_ = static_cast(allocator_->Malloc(sizeof(const Schema*) * v->Size())); + SizeType index = 0; + for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++) + schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document); + } + } + + AssignIfExist(minItems_, value, GetMinItemsString()); + AssignIfExist(maxItems_, value, GetMaxItemsString()); + + if (const ValueType* v = GetMember(value, GetAdditionalItemsString())) { + if (v->IsBool()) + additionalItems_ = v->GetBool(); + else if (v->IsObject()) + schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document); + } + + AssignIfExist(uniqueItems_, value, GetUniqueItemsString()); + + // String + AssignIfExist(minLength_, value, GetMinLengthString()); + AssignIfExist(maxLength_, value, GetMaxLengthString()); + + if (const ValueType* v = GetMember(value, GetPatternString())) + pattern_ = CreatePattern(*v); + + // Number + if (const ValueType* v = GetMember(value, GetMinimumString())) + if (v->IsNumber()) + minimum_.CopyFrom(*v, *allocator_); + + if (const ValueType* v = GetMember(value, GetMaximumString())) + if (v->IsNumber()) + maximum_.CopyFrom(*v, *allocator_); + + AssignIfExist(exclusiveMinimum_, value, GetExclusiveMinimumString()); + AssignIfExist(exclusiveMaximum_, value, GetExclusiveMaximumString()); + + if (const ValueType* v = GetMember(value, GetMultipleOfString())) + if (v->IsNumber() && v->GetDouble() > 0.0) + multipleOf_.CopyFrom(*v, *allocator_); + + // Default + if (const ValueType* v = GetMember(value, GetDefaultValueString())) + if (v->IsString()) + defaultValueLength_ = v->GetStringLength(); + + } + + ~Schema() { + AllocatorType::Free(enum_); + if (properties_) { + for (SizeType i = 0; i < propertyCount_; i++) + properties_[i].~Property(); + AllocatorType::Free(properties_); + } + if (patternProperties_) { + for (SizeType i = 0; i < patternPropertyCount_; i++) + patternProperties_[i].~PatternProperty(); + AllocatorType::Free(patternProperties_); + } + AllocatorType::Free(itemsTuple_); +#if RAPIDJSON_SCHEMA_HAS_REGEX + if (pattern_) { + pattern_->~RegexType(); + AllocatorType::Free(pattern_); + } +#endif + } + + const SValue& GetURI() const { + return uri_; + } + + const PointerType& GetPointer() const { + return pointer_; + } + + bool BeginValue(Context& context) const { + if (context.inArray) { + if (uniqueItems_) + context.valueUniqueness = true; + + if (itemsList_) + context.valueSchema = itemsList_; + else if (itemsTuple_) { + if (context.arrayElementIndex < itemsTupleCount_) + context.valueSchema = itemsTuple_[context.arrayElementIndex]; + else if (additionalItemsSchema_) + context.valueSchema = additionalItemsSchema_; + else if (additionalItems_) + context.valueSchema = typeless_; + else { + context.error_handler.DisallowedItem(context.arrayElementIndex); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetItemsString()); + } + } + else + context.valueSchema = typeless_; + + context.arrayElementIndex++; + } + return true; + } + + RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const { + if (context.patternPropertiesValidatorCount > 0) { + bool otherValid = false; + SizeType count = context.patternPropertiesValidatorCount; + if (context.objectPatternValidatorType != Context::kPatternValidatorOnly) + otherValid = context.patternPropertiesValidators[--count]->IsValid(); + + bool patternValid = true; + for (SizeType i = 0; i < count; i++) + if (!context.patternPropertiesValidators[i]->IsValid()) { + patternValid = false; + break; + } + + if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) { + if (!patternValid) { + context.error_handler.PropertyViolations(context.patternPropertiesValidators, count); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); + } + } + else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) { + if (!patternValid || !otherValid) { + context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); + } + } + else if (!patternValid && !otherValid) { // kPatternValidatorWithAdditionalProperty) + context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); + } + } + + if (enum_) { + const uint64_t h = context.factory.GetHashCode(context.hasher); + for (SizeType i = 0; i < enumCount_; i++) + if (enum_[i] == h) + goto foundEnum; + context.error_handler.DisallowedValue(); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetEnumString()); + foundEnum:; + } + + if (allOf_.schemas) + for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++) + if (!context.validators[i]->IsValid()) { + context.error_handler.NotAllOf(&context.validators[allOf_.begin], allOf_.count); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetAllOfString()); + } + + if (anyOf_.schemas) { + for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++) + if (context.validators[i]->IsValid()) + goto foundAny; + context.error_handler.NoneOf(&context.validators[anyOf_.begin], anyOf_.count); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetAnyOfString()); + foundAny:; + } + + if (oneOf_.schemas) { + bool oneValid = false; + for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++) + if (context.validators[i]->IsValid()) { + if (oneValid) { + context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString()); + } else + oneValid = true; + } + if (!oneValid) { + context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString()); + } + } + + if (not_ && context.validators[notValidatorIndex_]->IsValid()) { + context.error_handler.Disallowed(); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetNotString()); + } + + return true; + } + + bool Null(Context& context) const { + if (!(type_ & (1 << kNullSchemaType))) { + DisallowedType(context, GetNullString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + } + return CreateParallelValidator(context); + } + + bool Bool(Context& context, bool) const { + if (!(type_ & (1 << kBooleanSchemaType))) { + DisallowedType(context, GetBooleanString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + } + return CreateParallelValidator(context); + } + + bool Int(Context& context, int i) const { + if (!CheckInt(context, i)) + return false; + return CreateParallelValidator(context); + } + + bool Uint(Context& context, unsigned u) const { + if (!CheckUint(context, u)) + return false; + return CreateParallelValidator(context); + } + + bool Int64(Context& context, int64_t i) const { + if (!CheckInt(context, i)) + return false; + return CreateParallelValidator(context); + } + + bool Uint64(Context& context, uint64_t u) const { + if (!CheckUint(context, u)) + return false; + return CreateParallelValidator(context); + } + + bool Double(Context& context, double d) const { + if (!(type_ & (1 << kNumberSchemaType))) { + DisallowedType(context, GetNumberString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + } + + if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d)) + return false; + + if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d)) + return false; + + if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d)) + return false; + + return CreateParallelValidator(context); + } + + bool String(Context& context, const Ch* str, SizeType length, bool) const { + if (!(type_ & (1 << kStringSchemaType))) { + DisallowedType(context, GetStringString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + } + + if (minLength_ != 0 || maxLength_ != SizeType(~0)) { + SizeType count; + if (internal::CountStringCodePoint(str, length, &count)) { + if (count < minLength_) { + context.error_handler.TooShort(str, length, minLength_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinLengthString()); + } + if (count > maxLength_) { + context.error_handler.TooLong(str, length, maxLength_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxLengthString()); + } + } + } + + if (pattern_ && !IsPatternMatch(pattern_, str, length)) { + context.error_handler.DoesNotMatch(str, length); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternString()); + } + + return CreateParallelValidator(context); + } + + bool StartObject(Context& context) const { + if (!(type_ & (1 << kObjectSchemaType))) { + DisallowedType(context, GetObjectString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + } + + if (hasDependencies_ || hasRequired_) { + context.propertyExist = static_cast(context.factory.MallocState(sizeof(bool) * propertyCount_)); + std::memset(context.propertyExist, 0, sizeof(bool) * propertyCount_); + } + + if (patternProperties_) { // pre-allocate schema array + SizeType count = patternPropertyCount_ + 1; // extra for valuePatternValidatorType + context.patternPropertiesSchemas = static_cast(context.factory.MallocState(sizeof(const SchemaType*) * count)); + context.patternPropertiesSchemaCount = 0; + std::memset(context.patternPropertiesSchemas, 0, sizeof(SchemaType*) * count); + } + + return CreateParallelValidator(context); + } + + bool Key(Context& context, const Ch* str, SizeType len, bool) const { + if (patternProperties_) { + context.patternPropertiesSchemaCount = 0; + for (SizeType i = 0; i < patternPropertyCount_; i++) + if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len)) { + context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema; + context.valueSchema = typeless_; + } + } + + SizeType index = 0; + if (FindPropertyIndex(ValueType(str, len).Move(), &index)) { + if (context.patternPropertiesSchemaCount > 0) { + context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema; + context.valueSchema = typeless_; + context.valuePatternValidatorType = Context::kPatternValidatorWithProperty; + } + else + context.valueSchema = properties_[index].schema; + + if (context.propertyExist) + context.propertyExist[index] = true; + + return true; + } + + if (additionalPropertiesSchema_) { + if (additionalPropertiesSchema_ && context.patternPropertiesSchemaCount > 0) { + context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_; + context.valueSchema = typeless_; + context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty; + } + else + context.valueSchema = additionalPropertiesSchema_; + return true; + } + else if (additionalProperties_) { + context.valueSchema = typeless_; + return true; + } + + if (context.patternPropertiesSchemaCount == 0) { // patternProperties are not additional properties + context.error_handler.DisallowedProperty(str, len); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetAdditionalPropertiesString()); + } + + return true; + } + + bool EndObject(Context& context, SizeType memberCount) const { + if (hasRequired_) { + context.error_handler.StartMissingProperties(); + for (SizeType index = 0; index < propertyCount_; index++) + if (properties_[index].required && !context.propertyExist[index]) + if (properties_[index].schema->defaultValueLength_ == 0 ) + context.error_handler.AddMissingProperty(properties_[index].name); + if (context.error_handler.EndMissingProperties()) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString()); + } + + if (memberCount < minProperties_) { + context.error_handler.TooFewProperties(memberCount, minProperties_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString()); + } + + if (memberCount > maxProperties_) { + context.error_handler.TooManyProperties(memberCount, maxProperties_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxPropertiesString()); + } + + if (hasDependencies_) { + context.error_handler.StartDependencyErrors(); + for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++) { + const Property& source = properties_[sourceIndex]; + if (context.propertyExist[sourceIndex]) { + if (source.dependencies) { + context.error_handler.StartMissingDependentProperties(); + for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++) + if (source.dependencies[targetIndex] && !context.propertyExist[targetIndex]) + context.error_handler.AddMissingDependentProperty(properties_[targetIndex].name); + context.error_handler.EndMissingDependentProperties(source.name); + } + else if (source.dependenciesSchema) { + ISchemaValidator* dependenciesValidator = context.validators[source.dependenciesValidatorIndex]; + if (!dependenciesValidator->IsValid()) + context.error_handler.AddDependencySchemaError(source.name, dependenciesValidator); + } + } + } + if (context.error_handler.EndDependencyErrors()) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString()); + } + + return true; + } + + bool StartArray(Context& context) const { + if (!(type_ & (1 << kArraySchemaType))) { + DisallowedType(context, GetArrayString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + } + + context.arrayElementIndex = 0; + context.inArray = true; + + return CreateParallelValidator(context); + } + + bool EndArray(Context& context, SizeType elementCount) const { + context.inArray = false; + + if (elementCount < minItems_) { + context.error_handler.TooFewItems(elementCount, minItems_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinItemsString()); + } + + if (elementCount > maxItems_) { + context.error_handler.TooManyItems(elementCount, maxItems_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxItemsString()); + } + + return true; + } + + // Generate functions for string literal according to Ch +#define RAPIDJSON_STRING_(name, ...) \ + static const ValueType& Get##name##String() {\ + static const Ch s[] = { __VA_ARGS__, '\0' };\ + static const ValueType v(s, static_cast(sizeof(s) / sizeof(Ch) - 1));\ + return v;\ + } + + RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l') + RAPIDJSON_STRING_(Boolean, 'b', 'o', 'o', 'l', 'e', 'a', 'n') + RAPIDJSON_STRING_(Object, 'o', 'b', 'j', 'e', 'c', 't') + RAPIDJSON_STRING_(Array, 'a', 'r', 'r', 'a', 'y') + RAPIDJSON_STRING_(String, 's', 't', 'r', 'i', 'n', 'g') + RAPIDJSON_STRING_(Number, 'n', 'u', 'm', 'b', 'e', 'r') + RAPIDJSON_STRING_(Integer, 'i', 'n', 't', 'e', 'g', 'e', 'r') + RAPIDJSON_STRING_(Type, 't', 'y', 'p', 'e') + RAPIDJSON_STRING_(Enum, 'e', 'n', 'u', 'm') + RAPIDJSON_STRING_(AllOf, 'a', 'l', 'l', 'O', 'f') + RAPIDJSON_STRING_(AnyOf, 'a', 'n', 'y', 'O', 'f') + RAPIDJSON_STRING_(OneOf, 'o', 'n', 'e', 'O', 'f') + RAPIDJSON_STRING_(Not, 'n', 'o', 't') + RAPIDJSON_STRING_(Properties, 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') + RAPIDJSON_STRING_(Required, 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'd') + RAPIDJSON_STRING_(Dependencies, 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'i', 'e', 's') + RAPIDJSON_STRING_(PatternProperties, 'p', 'a', 't', 't', 'e', 'r', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') + RAPIDJSON_STRING_(AdditionalProperties, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') + RAPIDJSON_STRING_(MinProperties, 'm', 'i', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') + RAPIDJSON_STRING_(MaxProperties, 'm', 'a', 'x', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') + RAPIDJSON_STRING_(Items, 'i', 't', 'e', 'm', 's') + RAPIDJSON_STRING_(MinItems, 'm', 'i', 'n', 'I', 't', 'e', 'm', 's') + RAPIDJSON_STRING_(MaxItems, 'm', 'a', 'x', 'I', 't', 'e', 'm', 's') + RAPIDJSON_STRING_(AdditionalItems, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'I', 't', 'e', 'm', 's') + RAPIDJSON_STRING_(UniqueItems, 'u', 'n', 'i', 'q', 'u', 'e', 'I', 't', 'e', 'm', 's') + RAPIDJSON_STRING_(MinLength, 'm', 'i', 'n', 'L', 'e', 'n', 'g', 't', 'h') + RAPIDJSON_STRING_(MaxLength, 'm', 'a', 'x', 'L', 'e', 'n', 'g', 't', 'h') + RAPIDJSON_STRING_(Pattern, 'p', 'a', 't', 't', 'e', 'r', 'n') + RAPIDJSON_STRING_(Minimum, 'm', 'i', 'n', 'i', 'm', 'u', 'm') + RAPIDJSON_STRING_(Maximum, 'm', 'a', 'x', 'i', 'm', 'u', 'm') + RAPIDJSON_STRING_(ExclusiveMinimum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'i', 'n', 'i', 'm', 'u', 'm') + RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm') + RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f') + RAPIDJSON_STRING_(DefaultValue, 'd', 'e', 'f', 'a', 'u', 'l', 't') + +#undef RAPIDJSON_STRING_ + +private: + enum SchemaValueType { + kNullSchemaType, + kBooleanSchemaType, + kObjectSchemaType, + kArraySchemaType, + kStringSchemaType, + kNumberSchemaType, + kIntegerSchemaType, + kTotalSchemaType + }; + +#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX + typedef internal::GenericRegex RegexType; +#elif RAPIDJSON_SCHEMA_USE_STDREGEX + typedef std::basic_regex RegexType; +#else + typedef char RegexType; +#endif + + struct SchemaArray { + SchemaArray() : schemas(), count() {} + ~SchemaArray() { AllocatorType::Free(schemas); } + const SchemaType** schemas; + SizeType begin; // begin index of context.validators + SizeType count; + }; + + template + void AddUniqueElement(V1& a, const V2& v) { + for (typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr) + if (*itr == v) + return; + V1 c(v, *allocator_); + a.PushBack(c, *allocator_); + } + + static const ValueType* GetMember(const ValueType& value, const ValueType& name) { + typename ValueType::ConstMemberIterator itr = value.FindMember(name); + return itr != value.MemberEnd() ? &(itr->value) : 0; + } + + static void AssignIfExist(bool& out, const ValueType& value, const ValueType& name) { + if (const ValueType* v = GetMember(value, name)) + if (v->IsBool()) + out = v->GetBool(); + } + + static void AssignIfExist(SizeType& out, const ValueType& value, const ValueType& name) { + if (const ValueType* v = GetMember(value, name)) + if (v->IsUint64() && v->GetUint64() <= SizeType(~0)) + out = static_cast(v->GetUint64()); + } + + void AssignIfExist(SchemaArray& out, SchemaDocumentType& schemaDocument, const PointerType& p, const ValueType& value, const ValueType& name, const ValueType& document) { + if (const ValueType* v = GetMember(value, name)) { + if (v->IsArray() && v->Size() > 0) { + PointerType q = p.Append(name, allocator_); + out.count = v->Size(); + out.schemas = static_cast(allocator_->Malloc(out.count * sizeof(const Schema*))); + memset(out.schemas, 0, sizeof(Schema*)* out.count); + for (SizeType i = 0; i < out.count; i++) + schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document); + out.begin = validatorCount_; + validatorCount_ += out.count; + } + } + } + +#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX + template + RegexType* CreatePattern(const ValueType& value) { + if (value.IsString()) { + RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), allocator_); + if (!r->IsValid()) { + r->~RegexType(); + AllocatorType::Free(r); + r = 0; + } + return r; + } + return 0; + } + + static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType) { + GenericRegexSearch rs(*pattern); + return rs.Search(str); + } +#elif RAPIDJSON_SCHEMA_USE_STDREGEX + template + RegexType* CreatePattern(const ValueType& value) { + if (value.IsString()) { + RegexType *r = static_cast(allocator_->Malloc(sizeof(RegexType))); + try { + return new (r) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript); + } + catch (const std::regex_error&) { + AllocatorType::Free(r); + } + } + return 0; + } + + static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType length) { + std::match_results r; + return std::regex_search(str, str + length, r, *pattern); + } +#else + template + RegexType* CreatePattern(const ValueType&) { return 0; } + + static bool IsPatternMatch(const RegexType*, const Ch *, SizeType) { return true; } +#endif // RAPIDJSON_SCHEMA_USE_STDREGEX + + void AddType(const ValueType& type) { + if (type == GetNullString() ) type_ |= 1 << kNullSchemaType; + else if (type == GetBooleanString()) type_ |= 1 << kBooleanSchemaType; + else if (type == GetObjectString() ) type_ |= 1 << kObjectSchemaType; + else if (type == GetArrayString() ) type_ |= 1 << kArraySchemaType; + else if (type == GetStringString() ) type_ |= 1 << kStringSchemaType; + else if (type == GetIntegerString()) type_ |= 1 << kIntegerSchemaType; + else if (type == GetNumberString() ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType); + } + + bool CreateParallelValidator(Context& context) const { + if (enum_ || context.arrayUniqueness) + context.hasher = context.factory.CreateHasher(); + + if (validatorCount_) { + RAPIDJSON_ASSERT(context.validators == 0); + context.validators = static_cast(context.factory.MallocState(sizeof(ISchemaValidator*) * validatorCount_)); + context.validatorCount = validatorCount_; + + if (allOf_.schemas) + CreateSchemaValidators(context, allOf_); + + if (anyOf_.schemas) + CreateSchemaValidators(context, anyOf_); + + if (oneOf_.schemas) + CreateSchemaValidators(context, oneOf_); + + if (not_) + context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_); + + if (hasSchemaDependencies_) { + for (SizeType i = 0; i < propertyCount_; i++) + if (properties_[i].dependenciesSchema) + context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema); + } + } + + return true; + } + + void CreateSchemaValidators(Context& context, const SchemaArray& schemas) const { + for (SizeType i = 0; i < schemas.count; i++) + context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i]); + } + + // O(n) + bool FindPropertyIndex(const ValueType& name, SizeType* outIndex) const { + SizeType len = name.GetStringLength(); + const Ch* str = name.GetString(); + for (SizeType index = 0; index < propertyCount_; index++) + if (properties_[index].name.GetStringLength() == len && + (std::memcmp(properties_[index].name.GetString(), str, sizeof(Ch) * len) == 0)) + { + *outIndex = index; + return true; + } + return false; + } + + bool CheckInt(Context& context, int64_t i) const { + if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) { + DisallowedType(context, GetIntegerString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + } + + if (!minimum_.IsNull()) { + if (minimum_.IsInt64()) { + if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64()) { + context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); + } + } + else if (minimum_.IsUint64()) { + context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); // i <= max(int64_t) < minimum.GetUint64() + } + else if (!CheckDoubleMinimum(context, static_cast(i))) + return false; + } + + if (!maximum_.IsNull()) { + if (maximum_.IsInt64()) { + if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) { + context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); + } + } + else if (maximum_.IsUint64()) { } + /* do nothing */ // i <= max(int64_t) < maximum_.GetUint64() + else if (!CheckDoubleMaximum(context, static_cast(i))) + return false; + } + + if (!multipleOf_.IsNull()) { + if (multipleOf_.IsUint64()) { + if (static_cast(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0) { + context.error_handler.NotMultipleOf(i, multipleOf_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); + } + } + else if (!CheckDoubleMultipleOf(context, static_cast(i))) + return false; + } + + return true; + } + + bool CheckUint(Context& context, uint64_t i) const { + if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) { + DisallowedType(context, GetIntegerString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + } + + if (!minimum_.IsNull()) { + if (minimum_.IsUint64()) { + if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64()) { + context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); + } + } + else if (minimum_.IsInt64()) + /* do nothing */; // i >= 0 > minimum.Getint64() + else if (!CheckDoubleMinimum(context, static_cast(i))) + return false; + } + + if (!maximum_.IsNull()) { + if (maximum_.IsUint64()) { + if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64()) { + context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); + } + } + else if (maximum_.IsInt64()) { + context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); // i >= 0 > maximum_ + } + else if (!CheckDoubleMaximum(context, static_cast(i))) + return false; + } + + if (!multipleOf_.IsNull()) { + if (multipleOf_.IsUint64()) { + if (i % multipleOf_.GetUint64() != 0) { + context.error_handler.NotMultipleOf(i, multipleOf_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); + } + } + else if (!CheckDoubleMultipleOf(context, static_cast(i))) + return false; + } + + return true; + } + + bool CheckDoubleMinimum(Context& context, double d) const { + if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble()) { + context.error_handler.BelowMinimum(d, minimum_, exclusiveMinimum_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); + } + return true; + } + + bool CheckDoubleMaximum(Context& context, double d) const { + if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble()) { + context.error_handler.AboveMaximum(d, maximum_, exclusiveMaximum_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); + } + return true; + } + + bool CheckDoubleMultipleOf(Context& context, double d) const { + double a = std::abs(d), b = std::abs(multipleOf_.GetDouble()); + double q = std::floor(a / b); + double r = a - q * b; + if (r > 0.0) { + context.error_handler.NotMultipleOf(d, multipleOf_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); + } + return true; + } + + void DisallowedType(Context& context, const ValueType& actualType) const { + ErrorHandler& eh = context.error_handler; + eh.StartDisallowedType(); + + if (type_ & (1 << kNullSchemaType)) eh.AddExpectedType(GetNullString()); + if (type_ & (1 << kBooleanSchemaType)) eh.AddExpectedType(GetBooleanString()); + if (type_ & (1 << kObjectSchemaType)) eh.AddExpectedType(GetObjectString()); + if (type_ & (1 << kArraySchemaType)) eh.AddExpectedType(GetArrayString()); + if (type_ & (1 << kStringSchemaType)) eh.AddExpectedType(GetStringString()); + + if (type_ & (1 << kNumberSchemaType)) eh.AddExpectedType(GetNumberString()); + else if (type_ & (1 << kIntegerSchemaType)) eh.AddExpectedType(GetIntegerString()); + + eh.EndDisallowedType(actualType); + } + + struct Property { + Property() : schema(), dependenciesSchema(), dependenciesValidatorIndex(), dependencies(), required(false) {} + ~Property() { AllocatorType::Free(dependencies); } + SValue name; + const SchemaType* schema; + const SchemaType* dependenciesSchema; + SizeType dependenciesValidatorIndex; + bool* dependencies; + bool required; + }; + + struct PatternProperty { + PatternProperty() : schema(), pattern() {} + ~PatternProperty() { + if (pattern) { + pattern->~RegexType(); + AllocatorType::Free(pattern); + } + } + const SchemaType* schema; + RegexType* pattern; + }; + + AllocatorType* allocator_; + SValue uri_; + PointerType pointer_; + const SchemaType* typeless_; + uint64_t* enum_; + SizeType enumCount_; + SchemaArray allOf_; + SchemaArray anyOf_; + SchemaArray oneOf_; + const SchemaType* not_; + unsigned type_; // bitmask of kSchemaType + SizeType validatorCount_; + SizeType notValidatorIndex_; + + Property* properties_; + const SchemaType* additionalPropertiesSchema_; + PatternProperty* patternProperties_; + SizeType patternPropertyCount_; + SizeType propertyCount_; + SizeType minProperties_; + SizeType maxProperties_; + bool additionalProperties_; + bool hasDependencies_; + bool hasRequired_; + bool hasSchemaDependencies_; + + const SchemaType* additionalItemsSchema_; + const SchemaType* itemsList_; + const SchemaType** itemsTuple_; + SizeType itemsTupleCount_; + SizeType minItems_; + SizeType maxItems_; + bool additionalItems_; + bool uniqueItems_; + + RegexType* pattern_; + SizeType minLength_; + SizeType maxLength_; + + SValue minimum_; + SValue maximum_; + SValue multipleOf_; + bool exclusiveMinimum_; + bool exclusiveMaximum_; + + SizeType defaultValueLength_; +}; + +template +struct TokenHelper { + RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) { + *documentStack.template Push() = '/'; + char buffer[21]; + size_t length = static_cast((sizeof(SizeType) == 4 ? u32toa(index, buffer) : u64toa(index, buffer)) - buffer); + for (size_t i = 0; i < length; i++) + *documentStack.template Push() = static_cast(buffer[i]); + } +}; + +// Partial specialized version for char to prevent buffer copying. +template +struct TokenHelper { + RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) { + if (sizeof(SizeType) == 4) { + char *buffer = documentStack.template Push(1 + 10); // '/' + uint + *buffer++ = '/'; + const char* end = internal::u32toa(index, buffer); + documentStack.template Pop(static_cast(10 - (end - buffer))); + } + else { + char *buffer = documentStack.template Push(1 + 20); // '/' + uint64 + *buffer++ = '/'; + const char* end = internal::u64toa(index, buffer); + documentStack.template Pop(static_cast(20 - (end - buffer))); + } + } +}; + +} // namespace internal + +/////////////////////////////////////////////////////////////////////////////// +// IGenericRemoteSchemaDocumentProvider + +template +class IGenericRemoteSchemaDocumentProvider { +public: + typedef typename SchemaDocumentType::Ch Ch; + + virtual ~IGenericRemoteSchemaDocumentProvider() {} + virtual const SchemaDocumentType* GetRemoteDocument(const Ch* uri, SizeType length) = 0; +}; + +/////////////////////////////////////////////////////////////////////////////// +// GenericSchemaDocument + +//! JSON schema document. +/*! + A JSON schema document is a compiled version of a JSON schema. + It is basically a tree of internal::Schema. + + \note This is an immutable class (i.e. its instance cannot be modified after construction). + \tparam ValueT Type of JSON value (e.g. \c Value ), which also determine the encoding. + \tparam Allocator Allocator type for allocating memory of this document. +*/ +template +class GenericSchemaDocument { +public: + typedef ValueT ValueType; + typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProviderType; + typedef Allocator AllocatorType; + typedef typename ValueType::EncodingType EncodingType; + typedef typename EncodingType::Ch Ch; + typedef internal::Schema SchemaType; + typedef GenericPointer PointerType; + typedef GenericValue URIType; + friend class internal::Schema; + template + friend class GenericSchemaValidator; + + //! Constructor. + /*! + Compile a JSON document into schema document. + + \param document A JSON document as source. + \param uri The base URI of this schema document for purposes of violation reporting. + \param uriLength Length of \c name, in code points. + \param remoteProvider An optional remote schema document provider for resolving remote reference. Can be null. + \param allocator An optional allocator instance for allocating memory. Can be null. + */ + explicit GenericSchemaDocument(const ValueType& document, const Ch* uri = 0, SizeType uriLength = 0, + IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) : + remoteProvider_(remoteProvider), + allocator_(allocator), + ownAllocator_(), + root_(), + typeless_(), + schemaMap_(allocator, kInitialSchemaMapSize), + schemaRef_(allocator, kInitialSchemaRefSize) + { + if (!allocator_) + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); + + Ch noUri[1] = {0}; + uri_.SetString(uri ? uri : noUri, uriLength, *allocator_); + + typeless_ = static_cast(allocator_->Malloc(sizeof(SchemaType))); + new (typeless_) SchemaType(this, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), allocator_); + + // Generate root schema, it will call CreateSchema() to create sub-schemas, + // And call AddRefSchema() if there are $ref. + CreateSchemaRecursive(&root_, PointerType(), document, document); + + // Resolve $ref + while (!schemaRef_.Empty()) { + SchemaRefEntry* refEntry = schemaRef_.template Pop(1); + if (const SchemaType* s = GetSchema(refEntry->target)) { + if (refEntry->schema) + *refEntry->schema = s; + + // Create entry in map if not exist + if (!GetSchema(refEntry->source)) { + new (schemaMap_.template Push()) SchemaEntry(refEntry->source, const_cast(s), false, allocator_); + } + } + else if (refEntry->schema) + *refEntry->schema = typeless_; + + refEntry->~SchemaRefEntry(); + } + + RAPIDJSON_ASSERT(root_ != 0); + + schemaRef_.ShrinkToFit(); // Deallocate all memory for ref + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + //! Move constructor in C++11 + GenericSchemaDocument(GenericSchemaDocument&& rhs) RAPIDJSON_NOEXCEPT : + remoteProvider_(rhs.remoteProvider_), + allocator_(rhs.allocator_), + ownAllocator_(rhs.ownAllocator_), + root_(rhs.root_), + typeless_(rhs.typeless_), + schemaMap_(std::move(rhs.schemaMap_)), + schemaRef_(std::move(rhs.schemaRef_)), + uri_(std::move(rhs.uri_)) + { + rhs.remoteProvider_ = 0; + rhs.allocator_ = 0; + rhs.ownAllocator_ = 0; + rhs.typeless_ = 0; + } +#endif + + //! Destructor + ~GenericSchemaDocument() { + while (!schemaMap_.Empty()) + schemaMap_.template Pop(1)->~SchemaEntry(); + + if (typeless_) { + typeless_->~SchemaType(); + Allocator::Free(typeless_); + } + + RAPIDJSON_DELETE(ownAllocator_); + } + + const URIType& GetURI() const { return uri_; } + + //! Get the root schema. + const SchemaType& GetRoot() const { return *root_; } + +private: + //! Prohibit copying + GenericSchemaDocument(const GenericSchemaDocument&); + //! Prohibit assignment + GenericSchemaDocument& operator=(const GenericSchemaDocument&); + + struct SchemaRefEntry { + SchemaRefEntry(const PointerType& s, const PointerType& t, const SchemaType** outSchema, Allocator *allocator) : source(s, allocator), target(t, allocator), schema(outSchema) {} + PointerType source; + PointerType target; + const SchemaType** schema; + }; + + struct SchemaEntry { + SchemaEntry(const PointerType& p, SchemaType* s, bool o, Allocator* allocator) : pointer(p, allocator), schema(s), owned(o) {} + ~SchemaEntry() { + if (owned) { + schema->~SchemaType(); + Allocator::Free(schema); + } + } + PointerType pointer; + SchemaType* schema; + bool owned; + }; + + void CreateSchemaRecursive(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) { + if (schema) + *schema = typeless_; + + if (v.GetType() == kObjectType) { + const SchemaType* s = GetSchema(pointer); + if (!s) + CreateSchema(schema, pointer, v, document); + + for (typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr) + CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document); + } + else if (v.GetType() == kArrayType) + for (SizeType i = 0; i < v.Size(); i++) + CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document); + } + + void CreateSchema(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) { + RAPIDJSON_ASSERT(pointer.IsValid()); + if (v.IsObject()) { + if (!HandleRefSchema(pointer, schema, v, document)) { + SchemaType* s = new (allocator_->Malloc(sizeof(SchemaType))) SchemaType(this, pointer, v, document, allocator_); + new (schemaMap_.template Push()) SchemaEntry(pointer, s, true, allocator_); + if (schema) + *schema = s; + } + } + } + + bool HandleRefSchema(const PointerType& source, const SchemaType** schema, const ValueType& v, const ValueType& document) { + static const Ch kRefString[] = { '$', 'r', 'e', 'f', '\0' }; + static const ValueType kRefValue(kRefString, 4); + + typename ValueType::ConstMemberIterator itr = v.FindMember(kRefValue); + if (itr == v.MemberEnd()) + return false; + + if (itr->value.IsString()) { + SizeType len = itr->value.GetStringLength(); + if (len > 0) { + const Ch* s = itr->value.GetString(); + SizeType i = 0; + while (i < len && s[i] != '#') // Find the first # + i++; + + if (i > 0) { // Remote reference, resolve immediately + if (remoteProvider_) { + if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i)) { + PointerType pointer(&s[i], len - i, allocator_); + if (pointer.IsValid()) { + if (const SchemaType* sc = remoteDocument->GetSchema(pointer)) { + if (schema) + *schema = sc; + new (schemaMap_.template Push()) SchemaEntry(source, const_cast(sc), false, allocator_); + return true; + } + } + } + } + } + else if (s[i] == '#') { // Local reference, defer resolution + PointerType pointer(&s[i], len - i, allocator_); + if (pointer.IsValid()) { + if (const ValueType* nv = pointer.Get(document)) + if (HandleRefSchema(source, schema, *nv, document)) + return true; + + new (schemaRef_.template Push()) SchemaRefEntry(source, pointer, schema, allocator_); + return true; + } + } + } + } + return false; + } + + const SchemaType* GetSchema(const PointerType& pointer) const { + for (const SchemaEntry* target = schemaMap_.template Bottom(); target != schemaMap_.template End(); ++target) + if (pointer == target->pointer) + return target->schema; + return 0; + } + + PointerType GetPointer(const SchemaType* schema) const { + for (const SchemaEntry* target = schemaMap_.template Bottom(); target != schemaMap_.template End(); ++target) + if (schema == target->schema) + return target->pointer; + return PointerType(); + } + + const SchemaType* GetTypeless() const { return typeless_; } + + static const size_t kInitialSchemaMapSize = 64; + static const size_t kInitialSchemaRefSize = 64; + + IRemoteSchemaDocumentProviderType* remoteProvider_; + Allocator *allocator_; + Allocator *ownAllocator_; + const SchemaType* root_; //!< Root schema. + SchemaType* typeless_; + internal::Stack schemaMap_; // Stores created Pointer -> Schemas + internal::Stack schemaRef_; // Stores Pointer from $ref and schema which holds the $ref + URIType uri_; +}; + +//! GenericSchemaDocument using Value type. +typedef GenericSchemaDocument SchemaDocument; +//! IGenericRemoteSchemaDocumentProvider using SchemaDocument. +typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProvider; + +/////////////////////////////////////////////////////////////////////////////// +// GenericSchemaValidator + +//! JSON Schema Validator. +/*! + A SAX style JSON schema validator. + It uses a \c GenericSchemaDocument to validate SAX events. + It delegates the incoming SAX events to an output handler. + The default output handler does nothing. + It can be reused multiple times by calling \c Reset(). + + \tparam SchemaDocumentType Type of schema document. + \tparam OutputHandler Type of output handler. Default handler does nothing. + \tparam StateAllocator Allocator for storing the internal validation states. +*/ +template < + typename SchemaDocumentType, + typename OutputHandler = BaseReaderHandler, + typename StateAllocator = CrtAllocator> +class GenericSchemaValidator : + public internal::ISchemaStateFactory, + public internal::ISchemaValidator, + public internal::IValidationErrorHandler +{ +public: + typedef typename SchemaDocumentType::SchemaType SchemaType; + typedef typename SchemaDocumentType::PointerType PointerType; + typedef typename SchemaType::EncodingType EncodingType; + typedef typename SchemaType::SValue SValue; + typedef typename EncodingType::Ch Ch; + typedef GenericStringRef StringRefType; + typedef GenericValue ValueType; + + //! Constructor without output handler. + /*! + \param schemaDocument The schema document to conform to. + \param allocator Optional allocator for storing internal validation states. + \param schemaStackCapacity Optional initial capacity of schema path stack. + \param documentStackCapacity Optional initial capacity of document path stack. + */ + GenericSchemaValidator( + const SchemaDocumentType& schemaDocument, + StateAllocator* allocator = 0, + size_t schemaStackCapacity = kDefaultSchemaStackCapacity, + size_t documentStackCapacity = kDefaultDocumentStackCapacity) + : + schemaDocument_(&schemaDocument), + root_(schemaDocument.GetRoot()), + stateAllocator_(allocator), + ownStateAllocator_(0), + schemaStack_(allocator, schemaStackCapacity), + documentStack_(allocator, documentStackCapacity), + outputHandler_(0), + error_(kObjectType), + currentError_(), + missingDependents_(), + valid_(true) +#if RAPIDJSON_SCHEMA_VERBOSE + , depth_(0) +#endif + { + } + + //! Constructor with output handler. + /*! + \param schemaDocument The schema document to conform to. + \param allocator Optional allocator for storing internal validation states. + \param schemaStackCapacity Optional initial capacity of schema path stack. + \param documentStackCapacity Optional initial capacity of document path stack. + */ + GenericSchemaValidator( + const SchemaDocumentType& schemaDocument, + OutputHandler& outputHandler, + StateAllocator* allocator = 0, + size_t schemaStackCapacity = kDefaultSchemaStackCapacity, + size_t documentStackCapacity = kDefaultDocumentStackCapacity) + : + schemaDocument_(&schemaDocument), + root_(schemaDocument.GetRoot()), + stateAllocator_(allocator), + ownStateAllocator_(0), + schemaStack_(allocator, schemaStackCapacity), + documentStack_(allocator, documentStackCapacity), + outputHandler_(&outputHandler), + error_(kObjectType), + currentError_(), + missingDependents_(), + valid_(true) +#if RAPIDJSON_SCHEMA_VERBOSE + , depth_(0) +#endif + { + } + + //! Destructor. + ~GenericSchemaValidator() { + Reset(); + RAPIDJSON_DELETE(ownStateAllocator_); + } + + //! Reset the internal states. + void Reset() { + while (!schemaStack_.Empty()) + PopSchema(); + documentStack_.Clear(); + error_.SetObject(); + currentError_.SetNull(); + missingDependents_.SetNull(); + valid_ = true; + } + + //! Checks whether the current state is valid. + // Implementation of ISchemaValidator + virtual bool IsValid() const { return valid_; } + + //! Gets the error object. + ValueType& GetError() { return error_; } + const ValueType& GetError() const { return error_; } + + //! Gets the JSON pointer pointed to the invalid schema. + PointerType GetInvalidSchemaPointer() const { + return schemaStack_.Empty() ? PointerType() : CurrentSchema().GetPointer(); + } + + //! Gets the keyword of invalid schema. + const Ch* GetInvalidSchemaKeyword() const { + return schemaStack_.Empty() ? 0 : CurrentContext().invalidKeyword; + } + + //! Gets the JSON pointer pointed to the invalid value. + PointerType GetInvalidDocumentPointer() const { + if (documentStack_.Empty()) { + return PointerType(); + } + else { + return PointerType(documentStack_.template Bottom(), documentStack_.GetSize() / sizeof(Ch)); + } + } + + void NotMultipleOf(int64_t actual, const SValue& expected) { + AddNumberError(SchemaType::GetMultipleOfString(), ValueType(actual).Move(), expected); + } + void NotMultipleOf(uint64_t actual, const SValue& expected) { + AddNumberError(SchemaType::GetMultipleOfString(), ValueType(actual).Move(), expected); + } + void NotMultipleOf(double actual, const SValue& expected) { + AddNumberError(SchemaType::GetMultipleOfString(), ValueType(actual).Move(), expected); + } + void AboveMaximum(int64_t actual, const SValue& expected, bool exclusive) { + AddNumberError(SchemaType::GetMaximumString(), ValueType(actual).Move(), expected, + exclusive ? &SchemaType::GetExclusiveMaximumString : 0); + } + void AboveMaximum(uint64_t actual, const SValue& expected, bool exclusive) { + AddNumberError(SchemaType::GetMaximumString(), ValueType(actual).Move(), expected, + exclusive ? &SchemaType::GetExclusiveMaximumString : 0); + } + void AboveMaximum(double actual, const SValue& expected, bool exclusive) { + AddNumberError(SchemaType::GetMaximumString(), ValueType(actual).Move(), expected, + exclusive ? &SchemaType::GetExclusiveMaximumString : 0); + } + void BelowMinimum(int64_t actual, const SValue& expected, bool exclusive) { + AddNumberError(SchemaType::GetMinimumString(), ValueType(actual).Move(), expected, + exclusive ? &SchemaType::GetExclusiveMinimumString : 0); + } + void BelowMinimum(uint64_t actual, const SValue& expected, bool exclusive) { + AddNumberError(SchemaType::GetMinimumString(), ValueType(actual).Move(), expected, + exclusive ? &SchemaType::GetExclusiveMinimumString : 0); + } + void BelowMinimum(double actual, const SValue& expected, bool exclusive) { + AddNumberError(SchemaType::GetMinimumString(), ValueType(actual).Move(), expected, + exclusive ? &SchemaType::GetExclusiveMinimumString : 0); + } + + void TooLong(const Ch* str, SizeType length, SizeType expected) { + AddNumberError(SchemaType::GetMaxLengthString(), + ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move()); + } + void TooShort(const Ch* str, SizeType length, SizeType expected) { + AddNumberError(SchemaType::GetMinLengthString(), + ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move()); + } + void DoesNotMatch(const Ch* str, SizeType length) { + currentError_.SetObject(); + currentError_.AddMember(GetActualString(), ValueType(str, length, GetStateAllocator()).Move(), GetStateAllocator()); + AddCurrentError(SchemaType::GetPatternString()); + } + + void DisallowedItem(SizeType index) { + currentError_.SetObject(); + currentError_.AddMember(GetDisallowedString(), ValueType(index).Move(), GetStateAllocator()); + AddCurrentError(SchemaType::GetAdditionalItemsString(), true); + } + void TooFewItems(SizeType actualCount, SizeType expectedCount) { + AddNumberError(SchemaType::GetMinItemsString(), + ValueType(actualCount).Move(), SValue(expectedCount).Move()); + } + void TooManyItems(SizeType actualCount, SizeType expectedCount) { + AddNumberError(SchemaType::GetMaxItemsString(), + ValueType(actualCount).Move(), SValue(expectedCount).Move()); + } + void DuplicateItems(SizeType index1, SizeType index2) { + ValueType duplicates(kArrayType); + duplicates.PushBack(index1, GetStateAllocator()); + duplicates.PushBack(index2, GetStateAllocator()); + currentError_.SetObject(); + currentError_.AddMember(GetDuplicatesString(), duplicates, GetStateAllocator()); + AddCurrentError(SchemaType::GetUniqueItemsString(), true); + } + + void TooManyProperties(SizeType actualCount, SizeType expectedCount) { + AddNumberError(SchemaType::GetMaxPropertiesString(), + ValueType(actualCount).Move(), SValue(expectedCount).Move()); + } + void TooFewProperties(SizeType actualCount, SizeType expectedCount) { + AddNumberError(SchemaType::GetMinPropertiesString(), + ValueType(actualCount).Move(), SValue(expectedCount).Move()); + } + void StartMissingProperties() { + currentError_.SetArray(); + } + void AddMissingProperty(const SValue& name) { + currentError_.PushBack(ValueType(name, GetStateAllocator()).Move(), GetStateAllocator()); + } + bool EndMissingProperties() { + if (currentError_.Empty()) + return false; + ValueType error(kObjectType); + error.AddMember(GetMissingString(), currentError_, GetStateAllocator()); + currentError_ = error; + AddCurrentError(SchemaType::GetRequiredString()); + return true; + } + void PropertyViolations(ISchemaValidator** subvalidators, SizeType count) { + for (SizeType i = 0; i < count; ++i) + MergeError(static_cast(subvalidators[i])->GetError()); + } + void DisallowedProperty(const Ch* name, SizeType length) { + currentError_.SetObject(); + currentError_.AddMember(GetDisallowedString(), ValueType(name, length, GetStateAllocator()).Move(), GetStateAllocator()); + AddCurrentError(SchemaType::GetAdditionalPropertiesString(), true); + } + + void StartDependencyErrors() { + currentError_.SetObject(); + } + void StartMissingDependentProperties() { + missingDependents_.SetArray(); + } + void AddMissingDependentProperty(const SValue& targetName) { + missingDependents_.PushBack(ValueType(targetName, GetStateAllocator()).Move(), GetStateAllocator()); + } + void EndMissingDependentProperties(const SValue& sourceName) { + if (!missingDependents_.Empty()) + currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(), + missingDependents_, GetStateAllocator()); + } + void AddDependencySchemaError(const SValue& sourceName, ISchemaValidator* subvalidator) { + currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(), + static_cast(subvalidator)->GetError(), GetStateAllocator()); + } + bool EndDependencyErrors() { + if (currentError_.ObjectEmpty()) + return false; + ValueType error(kObjectType); + error.AddMember(GetErrorsString(), currentError_, GetStateAllocator()); + currentError_ = error; + AddCurrentError(SchemaType::GetDependenciesString()); + return true; + } + + void DisallowedValue() { + currentError_.SetObject(); + AddCurrentError(SchemaType::GetEnumString()); + } + void StartDisallowedType() { + currentError_.SetArray(); + } + void AddExpectedType(const typename SchemaType::ValueType& expectedType) { + currentError_.PushBack(ValueType(expectedType, GetStateAllocator()).Move(), GetStateAllocator()); + } + void EndDisallowedType(const typename SchemaType::ValueType& actualType) { + ValueType error(kObjectType); + error.AddMember(GetExpectedString(), currentError_, GetStateAllocator()); + error.AddMember(GetActualString(), ValueType(actualType, GetStateAllocator()).Move(), GetStateAllocator()); + currentError_ = error; + AddCurrentError(SchemaType::GetTypeString()); + } + void NotAllOf(ISchemaValidator** subvalidators, SizeType count) { + for (SizeType i = 0; i < count; ++i) { + MergeError(static_cast(subvalidators[i])->GetError()); + } + } + void NoneOf(ISchemaValidator** subvalidators, SizeType count) { + AddErrorArray(SchemaType::GetAnyOfString(), subvalidators, count); + } + void NotOneOf(ISchemaValidator** subvalidators, SizeType count) { + AddErrorArray(SchemaType::GetOneOfString(), subvalidators, count); + } + void Disallowed() { + currentError_.SetObject(); + AddCurrentError(SchemaType::GetNotString()); + } + +#define RAPIDJSON_STRING_(name, ...) \ + static const StringRefType& Get##name##String() {\ + static const Ch s[] = { __VA_ARGS__, '\0' };\ + static const StringRefType v(s, static_cast(sizeof(s) / sizeof(Ch) - 1)); \ + return v;\ + } + + RAPIDJSON_STRING_(InstanceRef, 'i', 'n', 's', 't', 'a', 'n', 'c', 'e', 'R', 'e', 'f') + RAPIDJSON_STRING_(SchemaRef, 's', 'c', 'h', 'e', 'm', 'a', 'R', 'e', 'f') + RAPIDJSON_STRING_(Expected, 'e', 'x', 'p', 'e', 'c', 't', 'e', 'd') + RAPIDJSON_STRING_(Actual, 'a', 'c', 't', 'u', 'a', 'l') + RAPIDJSON_STRING_(Disallowed, 'd', 'i', 's', 'a', 'l', 'l', 'o', 'w', 'e', 'd') + RAPIDJSON_STRING_(Missing, 'm', 'i', 's', 's', 'i', 'n', 'g') + RAPIDJSON_STRING_(Errors, 'e', 'r', 'r', 'o', 'r', 's') + RAPIDJSON_STRING_(Duplicates, 'd', 'u', 'p', 'l', 'i', 'c', 'a', 't', 'e', 's') + +#undef RAPIDJSON_STRING_ + +#if RAPIDJSON_SCHEMA_VERBOSE +#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() \ +RAPIDJSON_MULTILINEMACRO_BEGIN\ + *documentStack_.template Push() = '\0';\ + documentStack_.template Pop(1);\ + internal::PrintInvalidDocument(documentStack_.template Bottom());\ +RAPIDJSON_MULTILINEMACRO_END +#else +#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() +#endif + +#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\ + if (!valid_) return false; \ + if (!BeginValue() || !CurrentSchema().method arg1) {\ + RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_();\ + return valid_ = false;\ + } + +#define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\ + for (Context* context = schemaStack_.template Bottom(); context != schemaStack_.template End(); context++) {\ + if (context->hasher)\ + static_cast(context->hasher)->method arg2;\ + if (context->validators)\ + for (SizeType i_ = 0; i_ < context->validatorCount; i_++)\ + static_cast(context->validators[i_])->method arg2;\ + if (context->patternPropertiesValidators)\ + for (SizeType i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++)\ + static_cast(context->patternPropertiesValidators[i_])->method arg2;\ + } + +#define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\ + return valid_ = EndValue() && (!outputHandler_ || outputHandler_->method arg2) + +#define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \ + RAPIDJSON_SCHEMA_HANDLE_BEGIN_ (method, arg1);\ + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\ + RAPIDJSON_SCHEMA_HANDLE_END_ (method, arg2) + + bool Null() { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext()), ( )); } + bool Bool(bool b) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool, (CurrentContext(), b), (b)); } + bool Int(int i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int, (CurrentContext(), i), (i)); } + bool Uint(unsigned u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint, (CurrentContext(), u), (u)); } + bool Int64(int64_t i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), i), (i)); } + bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); } + bool Double(double d) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); } + bool RawNumber(const Ch* str, SizeType length, bool copy) + { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); } + bool String(const Ch* str, SizeType length, bool copy) + { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); } + + bool StartObject() { + RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext())); + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ()); + return valid_ = !outputHandler_ || outputHandler_->StartObject(); + } + + bool Key(const Ch* str, SizeType len, bool copy) { + if (!valid_) return false; + AppendToken(str, len); + if (!CurrentSchema().Key(CurrentContext(), str, len, copy)) return valid_ = false; + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy)); + return valid_ = !outputHandler_ || outputHandler_->Key(str, len, copy); + } + + bool EndObject(SizeType memberCount) { + if (!valid_) return false; + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount)); + if (!CurrentSchema().EndObject(CurrentContext(), memberCount)) return valid_ = false; + RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount)); + } + + bool StartArray() { + RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext())); + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ()); + return valid_ = !outputHandler_ || outputHandler_->StartArray(); + } + + bool EndArray(SizeType elementCount) { + if (!valid_) return false; + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount)); + if (!CurrentSchema().EndArray(CurrentContext(), elementCount)) return valid_ = false; + RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount)); + } + +#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_ +#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_ +#undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_ +#undef RAPIDJSON_SCHEMA_HANDLE_VALUE_ + + // Implementation of ISchemaStateFactory + virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root) { + return new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root, documentStack_.template Bottom(), documentStack_.GetSize(), +#if RAPIDJSON_SCHEMA_VERBOSE + depth_ + 1, +#endif + &GetStateAllocator()); + } + + virtual void DestroySchemaValidator(ISchemaValidator* validator) { + GenericSchemaValidator* v = static_cast(validator); + v->~GenericSchemaValidator(); + StateAllocator::Free(v); + } + + virtual void* CreateHasher() { + return new (GetStateAllocator().Malloc(sizeof(HasherType))) HasherType(&GetStateAllocator()); + } + + virtual uint64_t GetHashCode(void* hasher) { + return static_cast(hasher)->GetHashCode(); + } + + virtual void DestroryHasher(void* hasher) { + HasherType* h = static_cast(hasher); + h->~HasherType(); + StateAllocator::Free(h); + } + + virtual void* MallocState(size_t size) { + return GetStateAllocator().Malloc(size); + } + + virtual void FreeState(void* p) { + StateAllocator::Free(p); + } + +private: + typedef typename SchemaType::Context Context; + typedef GenericValue, StateAllocator> HashCodeArray; + typedef internal::Hasher HasherType; + + GenericSchemaValidator( + const SchemaDocumentType& schemaDocument, + const SchemaType& root, + const char* basePath, size_t basePathSize, +#if RAPIDJSON_SCHEMA_VERBOSE + unsigned depth, +#endif + StateAllocator* allocator = 0, + size_t schemaStackCapacity = kDefaultSchemaStackCapacity, + size_t documentStackCapacity = kDefaultDocumentStackCapacity) + : + schemaDocument_(&schemaDocument), + root_(root), + stateAllocator_(allocator), + ownStateAllocator_(0), + schemaStack_(allocator, schemaStackCapacity), + documentStack_(allocator, documentStackCapacity), + outputHandler_(0), + error_(kObjectType), + currentError_(), + missingDependents_(), + valid_(true) +#if RAPIDJSON_SCHEMA_VERBOSE + , depth_(depth) +#endif + { + if (basePath && basePathSize) + memcpy(documentStack_.template Push(basePathSize), basePath, basePathSize); + } + + StateAllocator& GetStateAllocator() { + if (!stateAllocator_) + stateAllocator_ = ownStateAllocator_ = RAPIDJSON_NEW(StateAllocator)(); + return *stateAllocator_; + } + + bool BeginValue() { + if (schemaStack_.Empty()) + PushSchema(root_); + else { + if (CurrentContext().inArray) + internal::TokenHelper, Ch>::AppendIndexToken(documentStack_, CurrentContext().arrayElementIndex); + + if (!CurrentSchema().BeginValue(CurrentContext())) + return false; + + SizeType count = CurrentContext().patternPropertiesSchemaCount; + const SchemaType** sa = CurrentContext().patternPropertiesSchemas; + typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType; + bool valueUniqueness = CurrentContext().valueUniqueness; + RAPIDJSON_ASSERT(CurrentContext().valueSchema); + PushSchema(*CurrentContext().valueSchema); + + if (count > 0) { + CurrentContext().objectPatternValidatorType = patternValidatorType; + ISchemaValidator**& va = CurrentContext().patternPropertiesValidators; + SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount; + va = static_cast(MallocState(sizeof(ISchemaValidator*) * count)); + for (SizeType i = 0; i < count; i++) + va[validatorCount++] = CreateSchemaValidator(*sa[i]); + } + + CurrentContext().arrayUniqueness = valueUniqueness; + } + return true; + } + + bool EndValue() { + if (!CurrentSchema().EndValue(CurrentContext())) + return false; + +#if RAPIDJSON_SCHEMA_VERBOSE + GenericStringBuffer sb; + schemaDocument_->GetPointer(&CurrentSchema()).Stringify(sb); + + *documentStack_.template Push() = '\0'; + documentStack_.template Pop(1); + internal::PrintValidatorPointers(depth_, sb.GetString(), documentStack_.template Bottom()); +#endif + + uint64_t h = CurrentContext().arrayUniqueness ? static_cast(CurrentContext().hasher)->GetHashCode() : 0; + + PopSchema(); + + if (!schemaStack_.Empty()) { + Context& context = CurrentContext(); + if (context.valueUniqueness) { + HashCodeArray* a = static_cast(context.arrayElementHashCodes); + if (!a) + CurrentContext().arrayElementHashCodes = a = new (GetStateAllocator().Malloc(sizeof(HashCodeArray))) HashCodeArray(kArrayType); + for (typename HashCodeArray::ConstValueIterator itr = a->Begin(); itr != a->End(); ++itr) + if (itr->GetUint64() == h) { + DuplicateItems(static_cast(itr - a->Begin()), a->Size()); + RAPIDJSON_INVALID_KEYWORD_RETURN(SchemaType::GetUniqueItemsString()); + } + a->PushBack(h, GetStateAllocator()); + } + } + + // Remove the last token of document pointer + while (!documentStack_.Empty() && *documentStack_.template Pop(1) != '/') + ; + + return true; + } + + void AppendToken(const Ch* str, SizeType len) { + documentStack_.template Reserve(1 + len * 2); // worst case all characters are escaped as two characters + *documentStack_.template PushUnsafe() = '/'; + for (SizeType i = 0; i < len; i++) { + if (str[i] == '~') { + *documentStack_.template PushUnsafe() = '~'; + *documentStack_.template PushUnsafe() = '0'; + } + else if (str[i] == '/') { + *documentStack_.template PushUnsafe() = '~'; + *documentStack_.template PushUnsafe() = '1'; + } + else + *documentStack_.template PushUnsafe() = str[i]; + } + } + + RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push()) Context(*this, *this, &schema); } + + RAPIDJSON_FORCEINLINE void PopSchema() { + Context* c = schemaStack_.template Pop(1); + if (HashCodeArray* a = static_cast(c->arrayElementHashCodes)) { + a->~HashCodeArray(); + StateAllocator::Free(a); + } + c->~Context(); + } + + void AddErrorLocation(ValueType& result, bool parent) { + GenericStringBuffer sb; + PointerType instancePointer = GetInvalidDocumentPointer(); + ((parent && instancePointer.GetTokenCount() > 0) + ? PointerType(instancePointer.GetTokens(), instancePointer.GetTokenCount() - 1) + : instancePointer).StringifyUriFragment(sb); + ValueType instanceRef(sb.GetString(), static_cast(sb.GetSize() / sizeof(Ch)), + GetStateAllocator()); + result.AddMember(GetInstanceRefString(), instanceRef, GetStateAllocator()); + sb.Clear(); + memcpy(sb.Push(CurrentSchema().GetURI().GetStringLength()), + CurrentSchema().GetURI().GetString(), + CurrentSchema().GetURI().GetStringLength() * sizeof(Ch)); + GetInvalidSchemaPointer().StringifyUriFragment(sb); + ValueType schemaRef(sb.GetString(), static_cast(sb.GetSize() / sizeof(Ch)), + GetStateAllocator()); + result.AddMember(GetSchemaRefString(), schemaRef, GetStateAllocator()); + } + + void AddError(ValueType& keyword, ValueType& error) { + typename ValueType::MemberIterator member = error_.FindMember(keyword); + if (member == error_.MemberEnd()) + error_.AddMember(keyword, error, GetStateAllocator()); + else { + if (member->value.IsObject()) { + ValueType errors(kArrayType); + errors.PushBack(member->value, GetStateAllocator()); + member->value = errors; + } + member->value.PushBack(error, GetStateAllocator()); + } + } + + void AddCurrentError(const typename SchemaType::ValueType& keyword, bool parent = false) { + AddErrorLocation(currentError_, parent); + AddError(ValueType(keyword, GetStateAllocator(), false).Move(), currentError_); + } + + void MergeError(ValueType& other) { + for (typename ValueType::MemberIterator it = other.MemberBegin(), end = other.MemberEnd(); it != end; ++it) { + AddError(it->name, it->value); + } + } + + void AddNumberError(const typename SchemaType::ValueType& keyword, ValueType& actual, const SValue& expected, + const typename SchemaType::ValueType& (*exclusive)() = 0) { + currentError_.SetObject(); + currentError_.AddMember(GetActualString(), actual, GetStateAllocator()); + currentError_.AddMember(GetExpectedString(), ValueType(expected, GetStateAllocator()).Move(), GetStateAllocator()); + if (exclusive) + currentError_.AddMember(ValueType(exclusive(), GetStateAllocator()).Move(), true, GetStateAllocator()); + AddCurrentError(keyword); + } + + void AddErrorArray(const typename SchemaType::ValueType& keyword, + ISchemaValidator** subvalidators, SizeType count) { + ValueType errors(kArrayType); + for (SizeType i = 0; i < count; ++i) + errors.PushBack(static_cast(subvalidators[i])->GetError(), GetStateAllocator()); + currentError_.SetObject(); + currentError_.AddMember(GetErrorsString(), errors, GetStateAllocator()); + AddCurrentError(keyword); + } + + const SchemaType& CurrentSchema() const { return *schemaStack_.template Top()->schema; } + Context& CurrentContext() { return *schemaStack_.template Top(); } + const Context& CurrentContext() const { return *schemaStack_.template Top(); } + + static const size_t kDefaultSchemaStackCapacity = 1024; + static const size_t kDefaultDocumentStackCapacity = 256; + const SchemaDocumentType* schemaDocument_; + const SchemaType& root_; + StateAllocator* stateAllocator_; + StateAllocator* ownStateAllocator_; + internal::Stack schemaStack_; //!< stack to store the current path of schema (BaseSchemaType *) + internal::Stack documentStack_; //!< stack to store the current path of validating document (Ch) + OutputHandler* outputHandler_; + ValueType error_; + ValueType currentError_; + ValueType missingDependents_; + bool valid_; +#if RAPIDJSON_SCHEMA_VERBOSE + unsigned depth_; +#endif +}; + +typedef GenericSchemaValidator SchemaValidator; + +/////////////////////////////////////////////////////////////////////////////// +// SchemaValidatingReader + +//! A helper class for parsing with validation. +/*! + This helper class is a functor, designed as a parameter of \ref GenericDocument::Populate(). + + \tparam parseFlags Combination of \ref ParseFlag. + \tparam InputStream Type of input stream, implementing Stream concept. + \tparam SourceEncoding Encoding of the input stream. + \tparam SchemaDocumentType Type of schema document. + \tparam StackAllocator Allocator type for stack. +*/ +template < + unsigned parseFlags, + typename InputStream, + typename SourceEncoding, + typename SchemaDocumentType = SchemaDocument, + typename StackAllocator = CrtAllocator> +class SchemaValidatingReader { +public: + typedef typename SchemaDocumentType::PointerType PointerType; + typedef typename InputStream::Ch Ch; + typedef GenericValue ValueType; + + //! Constructor + /*! + \param is Input stream. + \param sd Schema document. + */ + SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), error_(kObjectType), isValid_(true) {} + + template + bool operator()(Handler& handler) { + GenericReader reader; + GenericSchemaValidator validator(sd_, handler); + parseResult_ = reader.template Parse(is_, validator); + + isValid_ = validator.IsValid(); + if (isValid_) { + invalidSchemaPointer_ = PointerType(); + invalidSchemaKeyword_ = 0; + invalidDocumentPointer_ = PointerType(); + error_.SetObject(); + } + else { + invalidSchemaPointer_ = validator.GetInvalidSchemaPointer(); + invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword(); + invalidDocumentPointer_ = validator.GetInvalidDocumentPointer(); + error_.CopyFrom(validator.GetError(), allocator_); + } + + return parseResult_; + } + + const ParseResult& GetParseResult() const { return parseResult_; } + bool IsValid() const { return isValid_; } + const PointerType& GetInvalidSchemaPointer() const { return invalidSchemaPointer_; } + const Ch* GetInvalidSchemaKeyword() const { return invalidSchemaKeyword_; } + const PointerType& GetInvalidDocumentPointer() const { return invalidDocumentPointer_; } + const ValueType& GetError() const { return error_; } + +private: + InputStream& is_; + const SchemaDocumentType& sd_; + + ParseResult parseResult_; + PointerType invalidSchemaPointer_; + const Ch* invalidSchemaKeyword_; + PointerType invalidDocumentPointer_; + StackAllocator allocator_; + ValueType error_; + bool isValid_; +}; + +RAPIDJSON_NAMESPACE_END +RAPIDJSON_DIAG_POP + +#endif // RAPIDJSON_SCHEMA_H_ diff --git a/src/include/rapidjson/stream.h b/src/include/rapidjson/stream.h new file mode 100755 index 0000000..7f2643e --- /dev/null +++ b/src/include/rapidjson/stream.h @@ -0,0 +1,223 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#include "rapidjson.h" + +#ifndef RAPIDJSON_STREAM_H_ +#define RAPIDJSON_STREAM_H_ + +#include "encodings.h" + +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// Stream + +/*! \class rapidjson::Stream + \brief Concept for reading and writing characters. + + For read-only stream, no need to implement PutBegin(), Put(), Flush() and PutEnd(). + + For write-only stream, only need to implement Put() and Flush(). + +\code +concept Stream { + typename Ch; //!< Character type of the stream. + + //! Read the current character from stream without moving the read cursor. + Ch Peek() const; + + //! Read the current character from stream and moving the read cursor to next character. + Ch Take(); + + //! Get the current read cursor. + //! \return Number of characters read from start. + size_t Tell(); + + //! Begin writing operation at the current read pointer. + //! \return The begin writer pointer. + Ch* PutBegin(); + + //! Write a character. + void Put(Ch c); + + //! Flush the buffer. + void Flush(); + + //! End the writing operation. + //! \param begin The begin write pointer returned by PutBegin(). + //! \return Number of characters written. + size_t PutEnd(Ch* begin); +} +\endcode +*/ + +//! Provides additional information for stream. +/*! + By using traits pattern, this type provides a default configuration for stream. + For custom stream, this type can be specialized for other configuration. + See TEST(Reader, CustomStringStream) in readertest.cpp for example. +*/ +template +struct StreamTraits { + //! Whether to make local copy of stream for optimization during parsing. + /*! + By default, for safety, streams do not use local copy optimization. + Stream that can be copied fast should specialize this, like StreamTraits. + */ + enum { copyOptimization = 0 }; +}; + +//! Reserve n characters for writing to a stream. +template +inline void PutReserve(Stream& stream, size_t count) { + (void)stream; + (void)count; +} + +//! Write character to a stream, presuming buffer is reserved. +template +inline void PutUnsafe(Stream& stream, typename Stream::Ch c) { + stream.Put(c); +} + +//! Put N copies of a character to a stream. +template +inline void PutN(Stream& stream, Ch c, size_t n) { + PutReserve(stream, n); + for (size_t i = 0; i < n; i++) + PutUnsafe(stream, c); +} + +/////////////////////////////////////////////////////////////////////////////// +// GenericStreamWrapper + +//! A Stream Wrapper +/*! \tThis string stream is a wrapper for any stream by just forwarding any + \treceived message to the origin stream. + \note implements Stream concept +*/ + +#if defined(_MSC_VER) && _MSC_VER <= 1800 +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4702) // unreachable code +RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated +#endif + +template > +class GenericStreamWrapper { +public: + typedef typename Encoding::Ch Ch; + GenericStreamWrapper(InputStream& is): is_(is) {} + + Ch Peek() const { return is_.Peek(); } + Ch Take() { return is_.Take(); } + size_t Tell() { return is_.Tell(); } + Ch* PutBegin() { return is_.PutBegin(); } + void Put(Ch ch) { is_.Put(ch); } + void Flush() { is_.Flush(); } + size_t PutEnd(Ch* ch) { return is_.PutEnd(ch); } + + // wrapper for MemoryStream + const Ch* Peek4() const { return is_.Peek4(); } + + // wrapper for AutoUTFInputStream + UTFType GetType() const { return is_.GetType(); } + bool HasBOM() const { return is_.HasBOM(); } + +protected: + InputStream& is_; +}; + +#if defined(_MSC_VER) && _MSC_VER <= 1800 +RAPIDJSON_DIAG_POP +#endif + +/////////////////////////////////////////////////////////////////////////////// +// StringStream + +//! Read-only string stream. +/*! \note implements Stream concept +*/ +template +struct GenericStringStream { + typedef typename Encoding::Ch Ch; + + GenericStringStream(const Ch *src) : src_(src), head_(src) {} + + Ch Peek() const { return *src_; } + Ch Take() { return *src_++; } + size_t Tell() const { return static_cast(src_ - head_); } + + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + void Put(Ch) { RAPIDJSON_ASSERT(false); } + void Flush() { RAPIDJSON_ASSERT(false); } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + + const Ch* src_; //!< Current read position. + const Ch* head_; //!< Original head of the string. +}; + +template +struct StreamTraits > { + enum { copyOptimization = 1 }; +}; + +//! String stream with UTF8 encoding. +typedef GenericStringStream > StringStream; + +/////////////////////////////////////////////////////////////////////////////// +// InsituStringStream + +//! A read-write string stream. +/*! This string stream is particularly designed for in-situ parsing. + \note implements Stream concept +*/ +template +struct GenericInsituStringStream { + typedef typename Encoding::Ch Ch; + + GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {} + + // Read + Ch Peek() { return *src_; } + Ch Take() { return *src_++; } + size_t Tell() { return static_cast(src_ - head_); } + + // Write + void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; } + + Ch* PutBegin() { return dst_ = src_; } + size_t PutEnd(Ch* begin) { return static_cast(dst_ - begin); } + void Flush() {} + + Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; } + void Pop(size_t count) { dst_ -= count; } + + Ch* src_; + Ch* dst_; + Ch* head_; +}; + +template +struct StreamTraits > { + enum { copyOptimization = 1 }; +}; + +//! Insitu string stream with UTF8 encoding. +typedef GenericInsituStringStream > InsituStringStream; + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_STREAM_H_ diff --git a/src/include/rapidjson/stringbuffer.h b/src/include/rapidjson/stringbuffer.h new file mode 100755 index 0000000..4e38b82 --- /dev/null +++ b/src/include/rapidjson/stringbuffer.h @@ -0,0 +1,121 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_STRINGBUFFER_H_ +#define RAPIDJSON_STRINGBUFFER_H_ + +#include "stream.h" +#include "internal/stack.h" + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS +#include // std::move +#endif + +#include "internal/stack.h" + +#if defined(__clang__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(c++98-compat) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! Represents an in-memory output stream. +/*! + \tparam Encoding Encoding of the stream. + \tparam Allocator type for allocating memory buffer. + \note implements Stream concept +*/ +template +class GenericStringBuffer { +public: + typedef typename Encoding::Ch Ch; + + GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {} + GenericStringBuffer& operator=(GenericStringBuffer&& rhs) { + if (&rhs != this) + stack_ = std::move(rhs.stack_); + return *this; + } +#endif + + void Put(Ch c) { *stack_.template Push() = c; } + void PutUnsafe(Ch c) { *stack_.template PushUnsafe() = c; } + void Flush() {} + + void Clear() { stack_.Clear(); } + void ShrinkToFit() { + // Push and pop a null terminator. This is safe. + *stack_.template Push() = '\0'; + stack_.ShrinkToFit(); + stack_.template Pop(1); + } + + void Reserve(size_t count) { stack_.template Reserve(count); } + Ch* Push(size_t count) { return stack_.template Push(count); } + Ch* PushUnsafe(size_t count) { return stack_.template PushUnsafe(count); } + void Pop(size_t count) { stack_.template Pop(count); } + + const Ch* GetString() const { + // Push and pop a null terminator. This is safe. + *stack_.template Push() = '\0'; + stack_.template Pop(1); + + return stack_.template Bottom(); + } + + //! Get the size of string in bytes in the string buffer. + size_t GetSize() const { return stack_.GetSize(); } + + //! Get the length of string in Ch in the string buffer. + size_t GetLength() const { return stack_.GetSize() / sizeof(Ch); } + + static const size_t kDefaultCapacity = 256; + mutable internal::Stack stack_; + +private: + // Prohibit copy constructor & assignment operator. + GenericStringBuffer(const GenericStringBuffer&); + GenericStringBuffer& operator=(const GenericStringBuffer&); +}; + +//! String buffer with UTF8 encoding +typedef GenericStringBuffer > StringBuffer; + +template +inline void PutReserve(GenericStringBuffer& stream, size_t count) { + stream.Reserve(count); +} + +template +inline void PutUnsafe(GenericStringBuffer& stream, typename Encoding::Ch c) { + stream.PutUnsafe(c); +} + +//! Implement specialized version of PutN() with memset() for better performance. +template<> +inline void PutN(GenericStringBuffer >& stream, char c, size_t n) { + std::memset(stream.stack_.Push(n), c, n * sizeof(c)); +} + +RAPIDJSON_NAMESPACE_END + +#if defined(__clang__) +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_STRINGBUFFER_H_ diff --git a/src/include/rapidjson/writer.h b/src/include/rapidjson/writer.h new file mode 100755 index 0000000..e7fb873 --- /dev/null +++ b/src/include/rapidjson/writer.h @@ -0,0 +1,710 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_WRITER_H_ +#define RAPIDJSON_WRITER_H_ + +#include "stream.h" +#include "internal/clzll.h" +#include "internal/meta.h" +#include "internal/stack.h" +#include "internal/strfunc.h" +#include "internal/dtoa.h" +#include "internal/itoa.h" +#include "stringbuffer.h" +#include // placement new + +#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER) +#include +#pragma intrinsic(_BitScanForward) +#endif +#ifdef RAPIDJSON_SSE42 +#include +#elif defined(RAPIDJSON_SSE2) +#include +#elif defined(RAPIDJSON_NEON) +#include +#endif + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +RAPIDJSON_DIAG_OFF(unreachable-code) +RAPIDJSON_DIAG_OFF(c++98-compat) +#elif defined(_MSC_VER) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// WriteFlag + +/*! \def RAPIDJSON_WRITE_DEFAULT_FLAGS + \ingroup RAPIDJSON_CONFIG + \brief User-defined kWriteDefaultFlags definition. + + User can define this as any \c WriteFlag combinations. +*/ +#ifndef RAPIDJSON_WRITE_DEFAULT_FLAGS +#define RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNoFlags +#endif + +//! Combination of writeFlags +enum WriteFlag { + kWriteNoFlags = 0, //!< No flags are set. + kWriteValidateEncodingFlag = 1, //!< Validate encoding of JSON strings. + kWriteNanAndInfFlag = 2, //!< Allow writing of Infinity, -Infinity and NaN. + kWriteDefaultFlags = RAPIDJSON_WRITE_DEFAULT_FLAGS //!< Default write flags. Can be customized by defining RAPIDJSON_WRITE_DEFAULT_FLAGS +}; + +//! JSON writer +/*! Writer implements the concept Handler. + It generates JSON text by events to an output os. + + User may programmatically calls the functions of a writer to generate JSON text. + + On the other side, a writer can also be passed to objects that generates events, + + for example Reader::Parse() and Document::Accept(). + + \tparam OutputStream Type of output stream. + \tparam SourceEncoding Encoding of source string. + \tparam TargetEncoding Encoding of output stream. + \tparam StackAllocator Type of allocator for allocating memory of stack. + \note implements Handler concept +*/ +template, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags> +class Writer { +public: + typedef typename SourceEncoding::Ch Ch; + + static const int kDefaultMaxDecimalPlaces = 324; + + //! Constructor + /*! \param os Output stream. + \param stackAllocator User supplied allocator. If it is null, it will create a private one. + \param levelDepth Initial capacity of stack. + */ + explicit + Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) : + os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {} + + explicit + Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) : + os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {} + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + Writer(Writer&& rhs) : + os_(rhs.os_), level_stack_(std::move(rhs.level_stack_)), maxDecimalPlaces_(rhs.maxDecimalPlaces_), hasRoot_(rhs.hasRoot_) { + rhs.os_ = 0; + } +#endif + + //! Reset the writer with a new stream. + /*! + This function reset the writer with a new stream and default settings, + in order to make a Writer object reusable for output multiple JSONs. + + \param os New output stream. + \code + Writer writer(os1); + writer.StartObject(); + // ... + writer.EndObject(); + + writer.Reset(os2); + writer.StartObject(); + // ... + writer.EndObject(); + \endcode + */ + void Reset(OutputStream& os) { + os_ = &os; + hasRoot_ = false; + level_stack_.Clear(); + } + + //! Checks whether the output is a complete JSON. + /*! + A complete JSON has a complete root object or array. + */ + bool IsComplete() const { + return hasRoot_ && level_stack_.Empty(); + } + + int GetMaxDecimalPlaces() const { + return maxDecimalPlaces_; + } + + //! Sets the maximum number of decimal places for double output. + /*! + This setting truncates the output with specified number of decimal places. + + For example, + + \code + writer.SetMaxDecimalPlaces(3); + writer.StartArray(); + writer.Double(0.12345); // "0.123" + writer.Double(0.0001); // "0.0" + writer.Double(1.234567890123456e30); // "1.234567890123456e30" (do not truncate significand for positive exponent) + writer.Double(1.23e-4); // "0.0" (do truncate significand for negative exponent) + writer.EndArray(); + \endcode + + The default setting does not truncate any decimal places. You can restore to this setting by calling + \code + writer.SetMaxDecimalPlaces(Writer::kDefaultMaxDecimalPlaces); + \endcode + */ + void SetMaxDecimalPlaces(int maxDecimalPlaces) { + maxDecimalPlaces_ = maxDecimalPlaces; + } + + /*!@name Implementation of Handler + \see Handler + */ + //@{ + + bool Null() { Prefix(kNullType); return EndValue(WriteNull()); } + bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return EndValue(WriteBool(b)); } + bool Int(int i) { Prefix(kNumberType); return EndValue(WriteInt(i)); } + bool Uint(unsigned u) { Prefix(kNumberType); return EndValue(WriteUint(u)); } + bool Int64(int64_t i64) { Prefix(kNumberType); return EndValue(WriteInt64(i64)); } + bool Uint64(uint64_t u64) { Prefix(kNumberType); return EndValue(WriteUint64(u64)); } + + //! Writes the given \c double value to the stream + /*! + \param d The value to be written. + \return Whether it is succeed. + */ + bool Double(double d) { Prefix(kNumberType); return EndValue(WriteDouble(d)); } + + bool RawNumber(const Ch* str, SizeType length, bool copy = false) { + RAPIDJSON_ASSERT(str != 0); + (void)copy; + Prefix(kNumberType); + return EndValue(WriteString(str, length)); + } + + bool String(const Ch* str, SizeType length, bool copy = false) { + RAPIDJSON_ASSERT(str != 0); + (void)copy; + Prefix(kStringType); + return EndValue(WriteString(str, length)); + } + +#if RAPIDJSON_HAS_STDSTRING + bool String(const std::basic_string& str) { + return String(str.data(), SizeType(str.size())); + } +#endif + + bool StartObject() { + Prefix(kObjectType); + new (level_stack_.template Push()) Level(false); + return WriteStartObject(); + } + + bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } + +#if RAPIDJSON_HAS_STDSTRING + bool Key(const std::basic_string& str) + { + return Key(str.data(), SizeType(str.size())); + } +#endif + + bool EndObject(SizeType memberCount = 0) { + (void)memberCount; + RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); // not inside an Object + RAPIDJSON_ASSERT(!level_stack_.template Top()->inArray); // currently inside an Array, not Object + RAPIDJSON_ASSERT(0 == level_stack_.template Top()->valueCount % 2); // Object has a Key without a Value + level_stack_.template Pop(1); + return EndValue(WriteEndObject()); + } + + bool StartArray() { + Prefix(kArrayType); + new (level_stack_.template Push()) Level(true); + return WriteStartArray(); + } + + bool EndArray(SizeType elementCount = 0) { + (void)elementCount; + RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); + RAPIDJSON_ASSERT(level_stack_.template Top()->inArray); + level_stack_.template Pop(1); + return EndValue(WriteEndArray()); + } + //@} + + /*! @name Convenience extensions */ + //@{ + + //! Simpler but slower overload. + bool String(const Ch* const& str) { return String(str, internal::StrLen(str)); } + bool Key(const Ch* const& str) { return Key(str, internal::StrLen(str)); } + + //@} + + //! Write a raw JSON value. + /*! + For user to write a stringified JSON as a value. + + \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range. + \param length Length of the json. + \param type Type of the root of json. + */ + bool RawValue(const Ch* json, size_t length, Type type) { + RAPIDJSON_ASSERT(json != 0); + Prefix(type); + return EndValue(WriteRawValue(json, length)); + } + + //! Flush the output stream. + /*! + Allows the user to flush the output stream immediately. + */ + void Flush() { + os_->Flush(); + } + +protected: + //! Information for each nested level + struct Level { + Level(bool inArray_) : valueCount(0), inArray(inArray_) {} + size_t valueCount; //!< number of values in this level + bool inArray; //!< true if in array, otherwise in object + }; + + static const size_t kDefaultLevelDepth = 32; + + bool WriteNull() { + PutReserve(*os_, 4); + PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true; + } + + bool WriteBool(bool b) { + if (b) { + PutReserve(*os_, 4); + PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'r'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'e'); + } + else { + PutReserve(*os_, 5); + PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 's'); PutUnsafe(*os_, 'e'); + } + return true; + } + + bool WriteInt(int i) { + char buffer[11]; + const char* end = internal::i32toa(i, buffer); + PutReserve(*os_, static_cast(end - buffer)); + for (const char* p = buffer; p != end; ++p) + PutUnsafe(*os_, static_cast(*p)); + return true; + } + + bool WriteUint(unsigned u) { + char buffer[10]; + const char* end = internal::u32toa(u, buffer); + PutReserve(*os_, static_cast(end - buffer)); + for (const char* p = buffer; p != end; ++p) + PutUnsafe(*os_, static_cast(*p)); + return true; + } + + bool WriteInt64(int64_t i64) { + char buffer[21]; + const char* end = internal::i64toa(i64, buffer); + PutReserve(*os_, static_cast(end - buffer)); + for (const char* p = buffer; p != end; ++p) + PutUnsafe(*os_, static_cast(*p)); + return true; + } + + bool WriteUint64(uint64_t u64) { + char buffer[20]; + char* end = internal::u64toa(u64, buffer); + PutReserve(*os_, static_cast(end - buffer)); + for (char* p = buffer; p != end; ++p) + PutUnsafe(*os_, static_cast(*p)); + return true; + } + + bool WriteDouble(double d) { + if (internal::Double(d).IsNanOrInf()) { + if (!(writeFlags & kWriteNanAndInfFlag)) + return false; + if (internal::Double(d).IsNan()) { + PutReserve(*os_, 3); + PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N'); + return true; + } + if (internal::Double(d).Sign()) { + PutReserve(*os_, 9); + PutUnsafe(*os_, '-'); + } + else + PutReserve(*os_, 8); + PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f'); + PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y'); + return true; + } + + char buffer[25]; + char* end = internal::dtoa(d, buffer, maxDecimalPlaces_); + PutReserve(*os_, static_cast(end - buffer)); + for (char* p = buffer; p != end; ++p) + PutUnsafe(*os_, static_cast(*p)); + return true; + } + + bool WriteString(const Ch* str, SizeType length) { + static const typename OutputStream::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + static const char escape[256] = { +#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + //0 1 2 3 4 5 6 7 8 9 A B C D E F + 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00 + 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10 + 0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20 + Z16, Z16, // 30~4F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50 + Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF +#undef Z16 + }; + + if (TargetEncoding::supportUnicode) + PutReserve(*os_, 2 + length * 6); // "\uxxxx..." + else + PutReserve(*os_, 2 + length * 12); // "\uxxxx\uyyyy..." + + PutUnsafe(*os_, '\"'); + GenericStringStream is(str); + while (ScanWriteUnescapedString(is, length)) { + const Ch c = is.Peek(); + if (!TargetEncoding::supportUnicode && static_cast(c) >= 0x80) { + // Unicode escaping + unsigned codepoint; + if (RAPIDJSON_UNLIKELY(!SourceEncoding::Decode(is, &codepoint))) + return false; + PutUnsafe(*os_, '\\'); + PutUnsafe(*os_, 'u'); + if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) { + PutUnsafe(*os_, hexDigits[(codepoint >> 12) & 15]); + PutUnsafe(*os_, hexDigits[(codepoint >> 8) & 15]); + PutUnsafe(*os_, hexDigits[(codepoint >> 4) & 15]); + PutUnsafe(*os_, hexDigits[(codepoint ) & 15]); + } + else { + RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF); + // Surrogate pair + unsigned s = codepoint - 0x010000; + unsigned lead = (s >> 10) + 0xD800; + unsigned trail = (s & 0x3FF) + 0xDC00; + PutUnsafe(*os_, hexDigits[(lead >> 12) & 15]); + PutUnsafe(*os_, hexDigits[(lead >> 8) & 15]); + PutUnsafe(*os_, hexDigits[(lead >> 4) & 15]); + PutUnsafe(*os_, hexDigits[(lead ) & 15]); + PutUnsafe(*os_, '\\'); + PutUnsafe(*os_, 'u'); + PutUnsafe(*os_, hexDigits[(trail >> 12) & 15]); + PutUnsafe(*os_, hexDigits[(trail >> 8) & 15]); + PutUnsafe(*os_, hexDigits[(trail >> 4) & 15]); + PutUnsafe(*os_, hexDigits[(trail ) & 15]); + } + } + else if ((sizeof(Ch) == 1 || static_cast(c) < 256) && RAPIDJSON_UNLIKELY(escape[static_cast(c)])) { + is.Take(); + PutUnsafe(*os_, '\\'); + PutUnsafe(*os_, static_cast(escape[static_cast(c)])); + if (escape[static_cast(c)] == 'u') { + PutUnsafe(*os_, '0'); + PutUnsafe(*os_, '0'); + PutUnsafe(*os_, hexDigits[static_cast(c) >> 4]); + PutUnsafe(*os_, hexDigits[static_cast(c) & 0xF]); + } + } + else if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ? + Transcoder::Validate(is, *os_) : + Transcoder::TranscodeUnsafe(is, *os_)))) + return false; + } + PutUnsafe(*os_, '\"'); + return true; + } + + bool ScanWriteUnescapedString(GenericStringStream& is, size_t length) { + return RAPIDJSON_LIKELY(is.Tell() < length); + } + + bool WriteStartObject() { os_->Put('{'); return true; } + bool WriteEndObject() { os_->Put('}'); return true; } + bool WriteStartArray() { os_->Put('['); return true; } + bool WriteEndArray() { os_->Put(']'); return true; } + + bool WriteRawValue(const Ch* json, size_t length) { + PutReserve(*os_, length); + GenericStringStream is(json); + while (RAPIDJSON_LIKELY(is.Tell() < length)) { + RAPIDJSON_ASSERT(is.Peek() != '\0'); + if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ? + Transcoder::Validate(is, *os_) : + Transcoder::TranscodeUnsafe(is, *os_)))) + return false; + } + return true; + } + + void Prefix(Type type) { + (void)type; + if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is not at root + Level* level = level_stack_.template Top(); + if (level->valueCount > 0) { + if (level->inArray) + os_->Put(','); // add comma if it is not the first element in array + else // in object + os_->Put((level->valueCount % 2 == 0) ? ',' : ':'); + } + if (!level->inArray && level->valueCount % 2 == 0) + RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name + level->valueCount++; + } + else { + RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root. + hasRoot_ = true; + } + } + + // Flush the value if it is the top level one. + bool EndValue(bool ret) { + if (RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text + Flush(); + return ret; + } + + OutputStream* os_; + internal::Stack level_stack_; + int maxDecimalPlaces_; + bool hasRoot_; + +private: + // Prohibit copy constructor & assignment operator. + Writer(const Writer&); + Writer& operator=(const Writer&); +}; + +// Full specialization for StringStream to prevent memory copying + +template<> +inline bool Writer::WriteInt(int i) { + char *buffer = os_->Push(11); + const char* end = internal::i32toa(i, buffer); + os_->Pop(static_cast(11 - (end - buffer))); + return true; +} + +template<> +inline bool Writer::WriteUint(unsigned u) { + char *buffer = os_->Push(10); + const char* end = internal::u32toa(u, buffer); + os_->Pop(static_cast(10 - (end - buffer))); + return true; +} + +template<> +inline bool Writer::WriteInt64(int64_t i64) { + char *buffer = os_->Push(21); + const char* end = internal::i64toa(i64, buffer); + os_->Pop(static_cast(21 - (end - buffer))); + return true; +} + +template<> +inline bool Writer::WriteUint64(uint64_t u) { + char *buffer = os_->Push(20); + const char* end = internal::u64toa(u, buffer); + os_->Pop(static_cast(20 - (end - buffer))); + return true; +} + +template<> +inline bool Writer::WriteDouble(double d) { + if (internal::Double(d).IsNanOrInf()) { + // Note: This code path can only be reached if (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag). + if (!(kWriteDefaultFlags & kWriteNanAndInfFlag)) + return false; + if (internal::Double(d).IsNan()) { + PutReserve(*os_, 3); + PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N'); + return true; + } + if (internal::Double(d).Sign()) { + PutReserve(*os_, 9); + PutUnsafe(*os_, '-'); + } + else + PutReserve(*os_, 8); + PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f'); + PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y'); + return true; + } + + char *buffer = os_->Push(25); + char* end = internal::dtoa(d, buffer, maxDecimalPlaces_); + os_->Pop(static_cast(25 - (end - buffer))); + return true; +} + +#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) +template<> +inline bool Writer::ScanWriteUnescapedString(StringStream& is, size_t length) { + if (length < 16) + return RAPIDJSON_LIKELY(is.Tell() < length); + + if (!RAPIDJSON_LIKELY(is.Tell() < length)) + return false; + + const char* p = is.src_; + const char* end = is.head_ + length; + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + const char* endAligned = reinterpret_cast(reinterpret_cast(end) & static_cast(~15)); + if (nextAligned > end) + return true; + + while (p != nextAligned) + if (*p < 0x20 || *p == '\"' || *p == '\\') { + is.src_ = p; + return RAPIDJSON_LIKELY(is.Tell() < length); + } + else + os_->PutUnsafe(*p++); + + // The rest of string using SIMD + static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; + static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; + static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; + const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); + const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); + const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); + + for (; p != endAligned; p += 16) { + const __m128i s = _mm_load_si128(reinterpret_cast(p)); + const __m128i t1 = _mm_cmpeq_epi8(s, dq); + const __m128i t2 = _mm_cmpeq_epi8(s, bs); + const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F + const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); + unsigned short r = static_cast(_mm_movemask_epi8(x)); + if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped + SizeType len; +#ifdef _MSC_VER // Find the index of first escaped + unsigned long offset; + _BitScanForward(&offset, r); + len = offset; +#else + len = static_cast(__builtin_ffs(r) - 1); +#endif + char* q = reinterpret_cast(os_->PushUnsafe(len)); + for (size_t i = 0; i < len; i++) + q[i] = p[i]; + + p += len; + break; + } + _mm_storeu_si128(reinterpret_cast<__m128i *>(os_->PushUnsafe(16)), s); + } + + is.src_ = p; + return RAPIDJSON_LIKELY(is.Tell() < length); +} +#elif defined(RAPIDJSON_NEON) +template<> +inline bool Writer::ScanWriteUnescapedString(StringStream& is, size_t length) { + if (length < 16) + return RAPIDJSON_LIKELY(is.Tell() < length); + + if (!RAPIDJSON_LIKELY(is.Tell() < length)) + return false; + + const char* p = is.src_; + const char* end = is.head_ + length; + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + const char* endAligned = reinterpret_cast(reinterpret_cast(end) & static_cast(~15)); + if (nextAligned > end) + return true; + + while (p != nextAligned) + if (*p < 0x20 || *p == '\"' || *p == '\\') { + is.src_ = p; + return RAPIDJSON_LIKELY(is.Tell() < length); + } + else + os_->PutUnsafe(*p++); + + // The rest of string using SIMD + const uint8x16_t s0 = vmovq_n_u8('"'); + const uint8x16_t s1 = vmovq_n_u8('\\'); + const uint8x16_t s2 = vmovq_n_u8('\b'); + const uint8x16_t s3 = vmovq_n_u8(32); + + for (; p != endAligned; p += 16) { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, s0); + x = vorrq_u8(x, vceqq_u8(s, s1)); + x = vorrq_u8(x, vceqq_u8(s, s2)); + x = vorrq_u8(x, vcltq_u8(s, s3)); + + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract + uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract + + SizeType len = 0; + bool escaped = false; + if (low == 0) { + if (high != 0) { + uint32_t lz = internal::clzll(high); + len = 8 + (lz >> 3); + escaped = true; + } + } else { + uint32_t lz = internal::clzll(low); + len = lz >> 3; + escaped = true; + } + if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped + char* q = reinterpret_cast(os_->PushUnsafe(len)); + for (size_t i = 0; i < len; i++) + q[i] = p[i]; + + p += len; + break; + } + vst1q_u8(reinterpret_cast(os_->PushUnsafe(16)), s); + } + + is.src_ = p; + return RAPIDJSON_LIKELY(is.Tell() < length); +} +#endif // RAPIDJSON_NEON + +RAPIDJSON_NAMESPACE_END + +#if defined(_MSC_VER) || defined(__clang__) +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_RAPIDJSON_H_ diff --git a/src/proc/event.cpp b/src/proc/event.cpp index 6b6b4e0..486100f 100644 --- a/src/proc/event.cpp +++ b/src/proc/event.cpp @@ -7,10 +7,10 @@ namespace cjs { namespace event { void handle_bus_fire(int key_pass) { - cjs_str* key_str = cjs::str::receive(key_pass); - std::string key = key_str->to_str(); - delete key_str; - g_event_bus.fire(key); +// cjs_str* key_str = cjs::str::receive(key_pass); +// std::string key = key_str->to_str(); +// delete key_str; +// g_event_bus.fire(key); } } }