diff --git a/.travis.yml b/.travis.yml index df821a70..8f34664f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,18 @@ sudo: required -dist: trusty -group: edge +dist: xenial language: cpp cache: - ccache +addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - cmake + - valgrind + - clang-8 env: global: - USE_CCACHE=1 @@ -14,41 +21,60 @@ env: - CCACHE_MAXSIZE=100M - ARCH_FLAGS_x86='-m32' # #266: don't use SSE on 32-bit - ARCH_FLAGS_x86_64='-msse4.2' # use SSE4.2 on 64-bit + - ARCH_FLAGS_aarch64='-march=armv8-a' - GITHUB_REPO='Tencent/rapidjson' - secure: "HrsaCb+N66EG1HR+LWH1u51SjaJyRwJEDzqJGYMB7LJ/bfqb9mWKF1fLvZGk46W5t7TVaXRDD5KHFx9DPWvKn4gRUVkwTHEy262ah5ORh8M6n/6VVVajeV/AYt2C0sswdkDBDO4Xq+xy5gdw3G8s1A4Inbm73pUh+6vx+7ltBbk=" -before_install: - - sudo apt-add-repository -y ppa:ubuntu-toolchain-r/test - - sudo apt-get update -qq - - sudo apt-get install -y cmake valgrind g++-multilib libc6-dbg:i386 - matrix: include: # gcc - env: CONF=release ARCH=x86 CXX11=ON compiler: gcc + arch: amd64 - env: CONF=release ARCH=x86_64 CXX11=ON compiler: gcc + arch: amd64 - env: CONF=debug ARCH=x86 CXX11=OFF compiler: gcc + arch: amd64 - env: CONF=debug ARCH=x86_64 CXX11=OFF compiler: gcc + arch: amd64 + - env: CONF=release ARCH=aarch64 CXX11=ON + compiler: gcc + arch: arm64 + - env: CONF=debug ARCH=aarch64 CXX11=OFF + compiler: gcc + arch: arm64 # clang - env: CONF=debug ARCH=x86 CXX11=ON CCACHE_CPP2=yes compiler: clang + arch: amd64 - env: CONF=debug ARCH=x86_64 CXX11=ON CCACHE_CPP2=yes compiler: clang + arch: amd64 - env: CONF=debug ARCH=x86 CXX11=OFF CCACHE_CPP2=yes compiler: clang + arch: amd64 - env: CONF=debug ARCH=x86_64 CXX11=OFF CCACHE_CPP2=yes compiler: clang + arch: amd64 - env: CONF=release ARCH=x86 CXX11=ON CCACHE_CPP2=yes compiler: clang + arch: amd64 - env: CONF=release ARCH=x86_64 CXX11=ON CCACHE_CPP2=yes compiler: clang + arch: amd64 + - env: CONF=debug ARCH=aarch64 CXX11=ON CCACHE_CPP2=yes + compiler: clang + arch: arm64 + - env: CONF=debug ARCH=aarch64 CXX11=OFF CCACHE_CPP2=yes + compiler: clang + arch: arm64 # coverage report - env: CONF=debug ARCH=x86 CXX11=ON GCOV_FLAGS='--coverage' compiler: gcc + arch: amd64 cache: - ccache - pip @@ -57,6 +83,16 @@ matrix: - coveralls -r .. --gcov-options '\-lp' -e thirdparty -e example -e test -e build/CMakeFiles -e include/rapidjson/msinttypes -e include/rapidjson/internal/meta.h -e include/rapidjson/error/en.h - env: CONF=debug ARCH=x86_64 GCOV_FLAGS='--coverage' compiler: gcc + arch: amd64 + cache: + - ccache + - pip + after_success: + - pip install --user cpp-coveralls + - coveralls -r .. --gcov-options '\-lp' -e thirdparty -e example -e test -e build/CMakeFiles -e include/rapidjson/msinttypes -e include/rapidjson/internal/meta.h -e include/rapidjson/error/en.h + - env: CONF=debug ARCH=aarch64 GCOV_FLAGS='--coverage' + compiler: gcc + arch: arm64 cache: - ccache - pip @@ -73,13 +109,24 @@ matrix: packages: - doxygen +before_install: + - if [ "x86_64" = "$(arch)" ]; then sudo apt-get install -y g++-multilib libc6-dbg:i386 --allow-unauthenticated; fi + before_script: - - ccache -s - # hack to avoid Valgrind bug (https://bugs.kde.org/show_bug.cgi?id=326469), - # exposed by merging PR#163 (using -march=native) - # TODO: Since this bug is already fixed. Remove this when valgrind can be upgraded. - - sed -i "s/-march=native//" CMakeLists.txt - - mkdir build + # travis provides clang-7 for amd64 and clang-3.8 for arm64 + # here use clang-8 to all architectures as clang-7 is not available for arm64 + - if [ -f /usr/bin/clang++-8 ]; then + sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-8 1000; + sudo update-alternatives --config clang++; + export PATH=/usr/bin:$PATH; + fi + - if [ "$CXX" = "clang++" ]; then export CCACHE_CPP2=yes; fi + - ccache -s + # hack to avoid Valgrind bug (https://bugs.kde.org/show_bug.cgi?id=326469), + # exposed by merging PR#163 (using -march=native) + # TODO: Since this bug is already fixed. Remove this when valgrind can be upgraded. + - sed -i "s/-march=native//" CMakeLists.txt + - mkdir build script: - if [ "$CXX" = "clang++" ]; then export CXXFLAGS="-stdlib=libc++ ${CXXFLAGS}"; fi diff --git a/CMakeLists.txt b/CMakeLists.txt index 0275672e..3b9ac512 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,13 +9,18 @@ endif() SET(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules) -PROJECT(RapidJSON CXX) - set(LIB_MAJOR_VERSION "1") set(LIB_MINOR_VERSION "1") set(LIB_PATCH_VERSION "0") set(LIB_VERSION_STRING "${LIB_MAJOR_VERSION}.${LIB_MINOR_VERSION}.${LIB_PATCH_VERSION}") +if (CMAKE_VERSION VERSION_LESS 3.0) + PROJECT(RapidJSON CXX) +else() + cmake_policy(SET CMP0048 NEW) + PROJECT(RapidJSON VERSION "${LIB_VERSION_STRING}" LANGUAGES CXX) +endif() + # compile in release with debug info mode by default if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE) diff --git a/RapidJSONConfig.cmake.in b/RapidJSONConfig.cmake.in index e3c65a54..c25d3125 100644 --- a/RapidJSONConfig.cmake.in +++ b/RapidJSONConfig.cmake.in @@ -1,3 +1,7 @@ +################################################################################ +# CMake minimum version required +cmake_minimum_required(VERSION 3.0) + ################################################################################ # RapidJSON source dir set( RapidJSON_SOURCE_DIR "@CONFIG_SOURCE_DIR@") @@ -13,3 +17,9 @@ get_filename_component(RapidJSON_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) set( RapidJSON_INCLUDE_DIR "@RapidJSON_INCLUDE_DIR@" ) set( RapidJSON_INCLUDE_DIRS "@RapidJSON_INCLUDE_DIR@" ) message(STATUS "RapidJSON found. Headers: ${RapidJSON_INCLUDE_DIRS}") + +if(NOT TARGET rapidjson) + add_library(rapidjson INTERFACE IMPORTED) + set_property(TARGET rapidjson PROPERTY + INTERFACE_INCLUDE_DIRECTORIES ${RapidJSON_INCLUDE_DIRS}) +endif() diff --git a/contrib/natvis/rapidjson.natvis b/contrib/natvis/rapidjson.natvis index a804b7bf..e7bd44b6 100644 --- a/contrib/natvis/rapidjson.natvis +++ b/contrib/natvis/rapidjson.natvis @@ -5,8 +5,8 @@ null true false - {data_.ss.str} - {(const char*)((size_t)data_.s.str & 0x0000FFFFFFFFFFFF)} + {(const Ch*)data_.ss.str,na} + {(const Ch*)((size_t)data_.s.str & 0x0000FFFFFFFFFFFF),na} {data_.n.i.i} {data_.n.u.u} {data_.n.i64} diff --git a/doc/dom.md b/doc/dom.md index 0079b64b..6992e77d 100644 --- a/doc/dom.md +++ b/doc/dom.md @@ -119,6 +119,7 @@ Parse flags | Meaning `kParseNumbersAsStringsFlag` | Parse numerical type values as strings. `kParseTrailingCommasFlag` | Allow trailing commas at the end of objects and arrays (relaxed JSON syntax). `kParseNanAndInfFlag` | Allow parsing `NaN`, `Inf`, `Infinity`, `-Inf` and `-Infinity` as `double` values (relaxed JSON syntax). +`kParseEscapedApostropheFlag` | Allow escaped apostrophe `\'` in strings (relaxed JSON syntax). By using a non-type template parameter, instead of a function parameter, C++ compiler can generate code which is optimized for specified combinations, improving speed, and reducing code size (if only using a single specialization). The downside is the flags needed to be determined in compile-time. diff --git a/doc/dom.zh-cn.md b/doc/dom.zh-cn.md index 9743b7ac..8fcd5387 100644 --- a/doc/dom.zh-cn.md +++ b/doc/dom.zh-cn.md @@ -119,6 +119,7 @@ GenericDocument& GenericDocument::Parse(const Ch* str); `kParseNumbersAsStringsFlag` | 把数字类型解析成字符串。 `kParseTrailingCommasFlag` | 容许在对象和数组结束前含有逗号(放宽的 JSON 语法)。 `kParseNanAndInfFlag` | 容许 `NaN`、`Inf`、`Infinity`、`-Inf` 及 `-Infinity` 作为 `double` 值(放宽的 JSON 语法)。 +`kParseEscapedApostropheFlag` | 容许字符串中转义单引号 `\'` (放宽的 JSON 语法)。 由于使用了非类型模板参数,而不是函数参数,C++ 编译器能为个别组合生成代码,以改善性能及减少代码尺寸(当只用单种特化)。缺点是需要在编译期决定标志。 diff --git a/doc/faq.md b/doc/faq.md index 9abfdf1c..55fa2af8 100644 --- a/doc/faq.md +++ b/doc/faq.md @@ -64,11 +64,11 @@ JSON are commonly used in web applications for transferring structured data. It is also used as a file format for data persistence. -2. Does RapidJSON conform to the JSON standard? +3. Does RapidJSON conform to the JSON standard? Yes. RapidJSON is fully compliance with [RFC7159](http://www.ietf.org/rfc/rfc7159.txt) and [ECMA-404](http://www.ecma-international.org/publications/standards/Ecma-404.htm). It can handle corner cases, such as supporting null character and surrogate pairs in JSON strings. -3. Does RapidJSON support relaxed syntax? +4. Does RapidJSON support relaxed syntax? Currently no. RapidJSON only support the strict standardized format. Support on related syntax is under discussion in this [issue](https://github.com/Tencent/rapidjson/issues/36). diff --git a/doc/faq.zh-cn.md b/doc/faq.zh-cn.md index bdacfcee..cf1124d8 100644 --- a/doc/faq.zh-cn.md +++ b/doc/faq.zh-cn.md @@ -18,7 +18,7 @@ 4. RapidJSON 是免费的么? - 是的,它在 MIT 特許條款下免费。它可用于商业软件。详情请参看 [license.txt](https://github.com/Tencent/rapidjson/blob/master/license.txt)。 + 是的,它在 MIT 协议下免费。它可用于商业软件。详情请参看 [license.txt](https://github.com/Tencent/rapidjson/blob/master/license.txt)。 5. RapidJSON 很小么?它有何依赖? @@ -64,13 +64,13 @@ JSON 常用于网页应用程序,以传送结构化数据。它也可作为文件格式用于数据持久化。 -2. RapidJSON 是否符合 JSON 标准? +3. RapidJSON 是否符合 JSON 标准? 是。RapidJSON 完全符合 [RFC7159](http://www.ietf.org/rfc/rfc7159.txt) 及 [ECMA-404](http://www.ecma-international.org/publications/standards/Ecma-404.htm)。它能处理一些特殊情况,例如支持 JSON 字符串中含有空字符及代理对(surrogate pair)。 -3. RapidJSON 是否支持宽松的语法? +4. RapidJSON 是否支持宽松的语法? - 现时不支持。RapidJSON 只支持严格的标准格式。宽松语法现时在这 [issue](https://github.com/Tencent/rapidjson/issues/36) 中进行讨论。 + 目前不支持。RapidJSON 只支持严格的标准格式。宽松语法可以在这个 [issue](https://github.com/Tencent/rapidjson/issues/36) 中进行讨论。 ## DOM 与 SAX @@ -271,7 +271,7 @@ 有些应用程序需要处理非常大的 JSON 文件。而有些后台应用程序需要处理大量的 JSON。达到高性能同时改善延时及吞吐量。更广义来说,这也可以节省能源。 -## 八挂 +## 八卦 1. 谁是 RapidJSON 的开发者? @@ -279,11 +279,11 @@ 2. 为何你要开发 RapidJSON? - 在 2011 年开始这项目是,它仅一个兴趣项目。Milo Yip 是一个游戏程序员,他在那时候认识到 JSON 并希望在未来的项目中使用。由于 JSON 好像很简单,他希望写一个仅有头文件并且快速的程序库。 + 在 2011 年开始这项目时,它只是一个兴趣项目。Milo Yip 是一个游戏程序员,他在那时候认识到 JSON 并希望在未来的项目中使用。由于 JSON 好像很简单,他希望写一个快速的仅有头文件的程序库。 3. 为什么开发中段有一段长期空档? - 主要是个人因素,例如加入新家庭成员。另外,Milo Yip 也花了许多业馀时间去翻译 Jason Gregory 的《Game Engine Architecture》至中文版《游戏引擎架构》。 + 主要是个人因素,例如加入新家庭成员。另外,Milo Yip 也花了许多业余时间去翻译 Jason Gregory 的《Game Engine Architecture》至中文版《游戏引擎架构》。 4. 为什么这个项目从 Google Code 搬到 GitHub? diff --git a/doc/internals.md b/doc/internals.md index 706f98cb..81fe9c16 100644 --- a/doc/internals.md +++ b/doc/internals.md @@ -79,7 +79,7 @@ The following tables show the data layout of each type. The 32-bit/64-bit column | `unsigned u` | 32-bit unsigned integer |4 |4 | | (zero padding) | 0 |4 |4 | | (unused) | |4 |8 | -| `unsigned flags_` | `kNumberType kNumberFlag kUIntFlag kUInt64Flag ...` |4 |4 | +| `unsigned flags_` | `kNumberType kNumberFlag kUintFlag kUint64Flag ...` |4 |4 | | Number (Int64) | |32-bit|64-bit| |---------------------|-------------------------------------|:----:|:----:| diff --git a/doc/internals.zh-cn.md b/doc/internals.zh-cn.md index ca3d297a..d414fc14 100644 --- a/doc/internals.zh-cn.md +++ b/doc/internals.zh-cn.md @@ -79,7 +79,7 @@ SAX 和 DOM API 都依赖于3个额外的概念:`Allocator`、`Encoding` 和 ` | `unsigned u` | 32位无符号整数 |4 |4 | | (零填充) | 0 |4 |4 | | (未使用) | |4 |8 | -| `unsigned flags_` | `kNumberType kNumberFlag kUIntFlag kUInt64Flag ...` |4 |4 | +| `unsigned flags_` | `kNumberType kNumberFlag kUintFlag kUint64Flag ...` |4 |4 | | Number (Int64) | | 32位 | 64位 | |---------------------|-------------------------------------|:----:|:----:| @@ -248,7 +248,7 @@ void SkipWhitespace(InputStream& is) { ## 整数到字符串的转换 {#itoa} -整数到字符串转换的朴素算法需要对每一个十进制位进行一次处罚。我们实现了若干版本并在 [itoa-benchmark](https://github.com/miloyip/itoa-benchmark) 中对它们进行了评估。 +整数到字符串转换的朴素算法需要对每一个十进制位进行一次除法。我们实现了若干版本并在 [itoa-benchmark](https://github.com/miloyip/itoa-benchmark) 中对它们进行了评估。 虽然 SSE2 版本是最快的,但它和第二快的 `branchlut` 差距不大。而且 `branchlut` 是纯C++实现,所以我们在 RapidJSON 中使用了 `branchlut`。 diff --git a/doc/pointer.zh-cn.md b/doc/pointer.zh-cn.md index f58f55f3..239569d4 100644 --- a/doc/pointer.zh-cn.md +++ b/doc/pointer.zh-cn.md @@ -181,7 +181,7 @@ private: `Pointer` 在其建构函数里会解译源字符串。若有解析错误,`Pointer::IsValid()` 返回 `false`。你可使用 `Pointer::GetParseErrorCode()` 和 `GetParseErrorOffset()` 去获取错信息。 -要注意的是,所有解析函数都假设 pointer 是合法的。对一个非法 pointer 解析会做成断言失败。 +要注意的是,所有解析函数都假设 pointer 是合法的。对一个非法 pointer 解析会造成断言失败。 # URI 片段表示方式 {#URIFragment} diff --git a/doc/sax.md b/doc/sax.md index 874361ff..d42d0438 100644 --- a/doc/sax.md +++ b/doc/sax.md @@ -37,7 +37,7 @@ Bool(false) Key("n", 1, true) Null() Key("i") -UInt(123) +Uint(123) Key("pi") Double(3.1416) Key("a") diff --git a/doc/sax.zh-cn.md b/doc/sax.zh-cn.md index 740c339f..9b11e768 100644 --- a/doc/sax.zh-cn.md +++ b/doc/sax.zh-cn.md @@ -37,7 +37,7 @@ Bool(false) Key("n", 1, true) Null() Key("i") -UInt(123) +Uint(123) Key("pi") Double(3.1416) Key("a") @@ -91,7 +91,7 @@ void main() { } ~~~~~~~~~~ -注意 RapidJSON 使用模板去静态挷定 `Reader` 类型及处理器的类形,而不是使用含虚函数的类。这个范式可以通过把函数内联而改善性能。 +注意 RapidJSON 使用模板去静态挷定 `Reader` 类型及处理器的类型,而不是使用含虚函数的类。这个范式可以通过把函数内联而改善性能。 ## 处理器 {#Handler} diff --git a/doc/stream.md b/doc/stream.md index d95de142..04c865c7 100644 --- a/doc/stream.md +++ b/doc/stream.md @@ -127,7 +127,7 @@ Due to users' requests, RapidJSON provided official wrappers for `std::basic_ist ## IStreamWrapper {#IStreamWrapper} -`IStreamWrapper` wraps any class drived from `std::istream`, such as `std::istringstream`, `std::stringstream`, `std::ifstream`, `std::fstream`, into RapidJSON's input stream. +`IStreamWrapper` wraps any class derived from `std::istream`, such as `std::istringstream`, `std::stringstream`, `std::ifstream`, `std::fstream`, into RapidJSON's input stream. ~~~cpp #include diff --git a/doc/tutorial.md b/doc/tutorial.md index 3fa63c93..4bde2faf 100644 --- a/doc/tutorial.md +++ b/doc/tutorial.md @@ -82,7 +82,7 @@ JSON number type represents all numeric values. However, C++ needs more specific ~~~~~~~~~~cpp assert(document["i"].IsNumber()); -// In this case, IsUint()/IsInt64()/IsUInt64() also return true. +// In this case, IsUint()/IsInt64()/IsUint64() also return true. assert(document["i"].IsInt()); printf("i = %d\n", document["i"].GetInt()); // Alternative (int)document["i"] diff --git a/doc/tutorial.zh-cn.md b/doc/tutorial.zh-cn.md index 77608bf0..8b24ff11 100644 --- a/doc/tutorial.zh-cn.md +++ b/doc/tutorial.zh-cn.md @@ -82,7 +82,7 @@ JSON Number 类型表示所有数值。然而,C++ 需要使用更专门的类 ~~~~~~~~~~cpp assert(document["i"].IsNumber()); -// 在此情况下,IsUint()/IsInt64()/IsUInt64() 也会返回 true +// 在此情况下,IsUint()/IsInt64()/IsUint64() 也会返回 true assert(document["i"].IsInt()); printf("i = %d\n", document["i"].GetInt()); // 另一种用法: (int)document["i"] @@ -250,7 +250,7 @@ string(const char* s, size_t count); ~~~~~~~~~~cpp if (document["hello"] == document["n"]) /*...*/; // 比较两个值 -if (document["hello"] == "world") /*...*/; // 与字符串家面量作比较 +if (document["hello"] == "world") /*...*/; // 与字符串字面量作比较 if (document["i"] != 123) /*...*/; // 与整数作比较 if (document["pi"] != 3.14) /*...*/; // 与 double 作比较 ~~~~~~~~~~ @@ -388,7 +388,7 @@ allocator 参数。对于字符串字面量(或字符数组常量),只需 ~~~~~~~~~~cpp Value s; -s.SetString("rapidjson"); // 可包含空字符,长度在编译萁推导 +s.SetString("rapidjson"); // 可包含空字符,长度在编译期推导 s = "rapidjson"; // 上行的缩写 ~~~~~~~~~~ @@ -447,7 +447,7 @@ contact.PushBack(val, document.GetAllocator()); ~~~~~~~~~~ ## 修改 Object {#ModifyObject} -Object 是键值对的集合。每个键必须为 String。要修改 Object,方法是增加或移除成员。以下的 API 用来增加城员: +Object 是键值对的集合。每个键必须为 String。要修改 Object,方法是增加或移除成员。以下的 API 用来增加成员: * `Value& AddMember(Value&, Value&, Allocator& allocator)` * `Value& AddMember(StringRefType, Value&, Allocator&)` diff --git a/example/sortkeys/sortkeys.cpp b/example/sortkeys/sortkeys.cpp index 72a64102..7ede9fb9 100644 --- a/example/sortkeys/sortkeys.cpp +++ b/example/sortkeys/sortkeys.cpp @@ -42,7 +42,12 @@ int main() { } */ +// C++11 supports std::move() of Value so it always have no problem for std::sort(). +// Some C++03 implementations of std::sort() requires copy constructor which causes compilation error. +// Needs a sorting function only depends on std::swap() instead. +#if __cplusplus >= 201103L || (!defined(__GLIBCXX__) && (!defined(_MSC_VER) || _MSC_VER >= 1900)) std::sort(d.MemberBegin(), d.MemberEnd(), NameComparator()); + printIt(d); /* @@ -53,4 +58,5 @@ int main() { "zeta": false } */ +#endif } diff --git a/example/tutorial/tutorial.cpp b/example/tutorial/tutorial.cpp index c8bfcc14..d6021c66 100644 --- a/example/tutorial/tutorial.cpp +++ b/example/tutorial/tutorial.cpp @@ -57,7 +57,7 @@ int main(int, char*[]) { printf("n = %s\n", document["n"].IsNull() ? "null" : "?"); assert(document["i"].IsNumber()); // Number is a JSON type, but C++ needs more specific type. - assert(document["i"].IsInt()); // In this case, IsUint()/IsInt64()/IsUInt64() also return true. + assert(document["i"].IsInt()); // In this case, IsUint()/IsInt64()/IsUint64() also return true. printf("i = %d\n", document["i"].GetInt()); // Alternative (int)document["i"] assert(document["pi"].IsNumber()); diff --git a/include/rapidjson/allocators.h b/include/rapidjson/allocators.h index b196c94e..0b8f5e14 100644 --- a/include/rapidjson/allocators.h +++ b/include/rapidjson/allocators.h @@ -53,7 +53,7 @@ concept Allocator { */ -/*! \def RAPIDJSON_ALLOCATOR_DEFUALT_CHUNK_CAPACITY +/*! \def RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY \ingroup RAPIDJSON_CONFIG \brief User-defined kDefaultChunkCapacity definition. diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index d1b90eb0..68aaae7e 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -24,6 +24,9 @@ #include "encodedstream.h" #include // placement new #include +#ifdef __cpp_lib_three_way_comparison +#include +#endif RAPIDJSON_DIAG_PUSH #ifdef __clang__ @@ -56,6 +59,48 @@ 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. @@ -63,15 +108,45 @@ class GenericDocument; https://code.google.com/p/rapidjson/issues/detail?id=64 */ template -struct GenericMember { +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); }; /////////////////////////////////////////////////////////////////////////////// @@ -175,12 +250,16 @@ public: //! @name relations //@{ - bool operator==(ConstIterator that) const { return ptr_ == that.ptr_; } - bool operator!=(ConstIterator that) const { return ptr_ != that.ptr_; } - bool operator<=(ConstIterator that) const { return ptr_ <= that.ptr_; } - bool operator>=(ConstIterator that) const { return ptr_ >= that.ptr_; } - bool operator< (ConstIterator that) const { return ptr_ < that.ptr_; } - bool operator> (ConstIterator 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_; } + 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 @@ -205,17 +284,17 @@ private: // class-based member iterator implementation disabled, use plain pointers template -struct GenericMemberIterator; +class GenericMemberIterator; //! non-const GenericMemberIterator template -struct GenericMemberIterator { +class GenericMemberIterator { //! use plain pointer as iterator type typedef GenericMember* Iterator; }; //! const GenericMemberIterator template -struct GenericMemberIterator { +class GenericMemberIterator { //! use plain const pointer as iterator type typedef const GenericMember* Iterator; }; @@ -574,7 +653,7 @@ template class GenericObject; \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 > +template class GenericValue { public: //! Name-value pair in an object. @@ -1939,8 +2018,8 @@ private: kTypeMask = 0x07 }; - static const SizeType kDefaultArrayCapacity = 16; - static const SizeType kDefaultObjectCapacity = 16; + static const SizeType kDefaultArrayCapacity = RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY; + static const SizeType kDefaultObjectCapacity = RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY; struct Flag { #if RAPIDJSON_48BITPOINTER_OPTIMIZATION @@ -2120,7 +2199,7 @@ typedef GenericValue > Value; \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 , typename StackAllocator = CrtAllocator> +template class GenericDocument : public GenericValue { public: typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. @@ -2505,6 +2584,7 @@ private: //! 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(). diff --git a/include/rapidjson/fwd.h b/include/rapidjson/fwd.h index e8104e84..b74a2b81 100644 --- a/include/rapidjson/fwd.h +++ b/include/rapidjson/fwd.h @@ -102,7 +102,7 @@ class PrettyWriter; // document.h template -struct GenericMember; +class GenericMember; template class GenericMemberIterator; diff --git a/include/rapidjson/internal/biginteger.h b/include/rapidjson/internal/biginteger.h index a31c8a88..8eb87c7c 100644 --- a/include/rapidjson/internal/biginteger.h +++ b/include/rapidjson/internal/biginteger.h @@ -17,7 +17,7 @@ #include "../rapidjson.h" -#if defined(_MSC_VER) && !__INTEL_COMPILER && defined(_M_AMD64) +#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && defined(_M_AMD64) #include // for _umul128 #pragma intrinsic(_umul128) #endif diff --git a/include/rapidjson/internal/clzll.h b/include/rapidjson/internal/clzll.h new file mode 100644 index 00000000..6cd79234 --- /dev/null +++ b/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/include/rapidjson/internal/diyfp.h b/include/rapidjson/internal/diyfp.h index b6c2cf56..8f7d853a 100644 --- a/include/rapidjson/internal/diyfp.h +++ b/include/rapidjson/internal/diyfp.h @@ -20,11 +20,11 @@ #define RAPIDJSON_DIYFP_H_ #include "../rapidjson.h" +#include "clzll.h" #include #if defined(_MSC_VER) && defined(_M_AMD64) && !defined(__INTEL_COMPILER) #include -#pragma intrinsic(_BitScanReverse64) #pragma intrinsic(_umul128) #endif @@ -100,22 +100,8 @@ struct DiyFp { } DiyFp Normalize() const { - RAPIDJSON_ASSERT(f != 0); // https://stackoverflow.com/a/26809183/291737 -#if defined(_MSC_VER) && defined(_M_AMD64) - unsigned long index; - _BitScanReverse64(&index, f); - return DiyFp(f << (63 - index), e - (63 - index)); -#elif defined(__GNUC__) && __GNUC__ >= 4 - int s = __builtin_clzll(f); + int s = static_cast(clzll(f)); return DiyFp(f << s, e - s); -#else - DiyFp res = *this; - while (!(res.f & (static_cast(1) << 63))) { - res.f <<= 1; - res.e--; - } - return res; -#endif } DiyFp NormalizeBoundary() const { diff --git a/include/rapidjson/internal/regex.h b/include/rapidjson/internal/regex.h index 16e35592..af7e06de 100644 --- a/include/rapidjson/internal/regex.h +++ b/include/rapidjson/internal/regex.h @@ -23,7 +23,6 @@ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(switch-enum) -RAPIDJSON_DIAG_OFF(implicit-fallthrough) #elif defined(_MSC_VER) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated @@ -32,9 +31,6 @@ RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated #ifdef __GNUC__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) -#if __GNUC__ >= 7 -RAPIDJSON_DIAG_OFF(implicit-fallthrough) -#endif #endif #ifndef RAPIDJSON_REGEX_VERBOSE @@ -291,6 +287,7 @@ private: if (!CharacterEscape(ds, &codepoint)) return; // Unsupported escape character // fall through to default + RAPIDJSON_DELIBERATE_FALLTHROUGH; default: // Pattern character PushOperand(operandStack, codepoint); @@ -520,6 +517,7 @@ private: else if (!CharacterEscape(ds, &codepoint)) return false; // fall through to default + RAPIDJSON_DELIBERATE_FALLTHROUGH; default: switch (step) { @@ -529,6 +527,7 @@ private: break; } // fall through to step 0 for other characters + RAPIDJSON_DELIBERATE_FALLTHROUGH; case 0: { diff --git a/include/rapidjson/internal/stack.h b/include/rapidjson/internal/stack.h index 89558d0d..45dca6a8 100644 --- a/include/rapidjson/internal/stack.h +++ b/include/rapidjson/internal/stack.h @@ -17,6 +17,7 @@ #include "../allocators.h" #include "swap.h" +#include #if defined(__clang__) RAPIDJSON_DIAG_PUSH @@ -114,7 +115,7 @@ public: template RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) { // Expand the stack if needed - if (RAPIDJSON_UNLIKELY(stackTop_ + sizeof(T) * count > stackEnd_)) + if (RAPIDJSON_UNLIKELY(static_cast(sizeof(T) * count) > (stackEnd_ - stackTop_))) Expand(count); } @@ -127,7 +128,7 @@ public: template RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) { RAPIDJSON_ASSERT(stackTop_); - RAPIDJSON_ASSERT(stackTop_ + sizeof(T) * count <= stackEnd_); + RAPIDJSON_ASSERT(static_cast(sizeof(T) * count) <= (stackEnd_ - stackTop_)); T* ret = reinterpret_cast(stackTop_); stackTop_ += sizeof(T) * count; return ret; diff --git a/include/rapidjson/istreamwrapper.h b/include/rapidjson/istreamwrapper.h index f304fb03..c4950b9d 100644 --- a/include/rapidjson/istreamwrapper.h +++ b/include/rapidjson/istreamwrapper.h @@ -17,6 +17,7 @@ #include "stream.h" #include +#include #ifdef __clang__ RAPIDJSON_DIAG_PUSH diff --git a/include/rapidjson/pointer.h b/include/rapidjson/pointer.h index 063abab9..b8143b63 100644 --- a/include/rapidjson/pointer.h +++ b/include/rapidjson/pointer.h @@ -488,10 +488,11 @@ public: v = &((*v)[t->index]); } else { - typename ValueType::MemberIterator m = v->FindMember(GenericStringRef(t->name, t->length)); + 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); - v = &(--v->MemberEnd())->value; // Assumes AddMember() appends at the end + m = v->MemberEnd(); + v = &(--m)->value; // Assumes AddMember() appends at the end exist = false; } else @@ -543,7 +544,7 @@ public: switch (v->GetType()) { case kObjectType: { - typename ValueType::MemberIterator m = v->FindMember(GenericStringRef(t->name, t->length)); + typename ValueType::MemberIterator m = v->FindMember(GenericValue(GenericStringRef(t->name, t->length))); if (m == v->MemberEnd()) break; v = &m->value; @@ -779,7 +780,7 @@ public: switch (v->GetType()) { case kObjectType: { - typename ValueType::MemberIterator m = v->FindMember(GenericStringRef(t->name, t->length)); + typename ValueType::MemberIterator m = v->FindMember(GenericValue(GenericStringRef(t->name, t->length))); if (m == v->MemberEnd()) return false; v = &m->value; diff --git a/include/rapidjson/prettywriter.h b/include/rapidjson/prettywriter.h index 45afb694..94eeb69d 100644 --- a/include/rapidjson/prettywriter.h +++ b/include/rapidjson/prettywriter.h @@ -60,7 +60,7 @@ public: explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : - Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {} + Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {} #if RAPIDJSON_HAS_CXX11_RVALUE_REFS PrettyWriter(PrettyWriter&& rhs) : diff --git a/include/rapidjson/rapidjson.h b/include/rapidjson/rapidjson.h index 99e8b838..c5f4d65f 100644 --- a/include/rapidjson/rapidjson.h +++ b/include/rapidjson/rapidjson.h @@ -490,6 +490,12 @@ RAPIDJSON_NAMESPACE_END #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 @@ -591,6 +597,19 @@ RAPIDJSON_NAMESPACE_END #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). @@ -607,15 +626,18 @@ RAPIDJSON_NAMESPACE_END /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_NOEXCEPT_ASSERT +#ifndef RAPIDJSON_NOEXCEPT_ASSERT #ifdef RAPIDJSON_ASSERT_THROWS #if RAPIDJSON_HAS_CXX11_NOEXCEPT #define RAPIDJSON_NOEXCEPT_ASSERT(x) #else -#define RAPIDJSON_NOEXCEPT_ASSERT(x) RAPIDJSON_ASSERT(x) +#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 /////////////////////////////////////////////////////////////////////////////// // malloc/realloc/free diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 44a6bcd3..0f85032a 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -20,6 +20,7 @@ #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" @@ -153,6 +154,7 @@ enum ParseFlag { 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 }; @@ -443,16 +445,16 @@ inline const char *SkipWhitespace_SIMD(const char* p) { x = vmvnq_u8(x); // Negate x = vrev64q_u8(x); // Rev in 64 - uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract - uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + 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) { - int lz =__builtin_clzll(high);; + uint32_t lz = internal::clzll(high); return p + 8 + (lz >> 3); } } else { - int lz = __builtin_clzll(low);; + uint32_t lz = internal::clzll(low); return p + (lz >> 3); } } @@ -479,16 +481,16 @@ inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { x = vmvnq_u8(x); // Negate x = vrev64q_u8(x); // Rev in 64 - uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract - uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + 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) { - int lz = __builtin_clzll(high); + uint32_t lz = internal::clzll(high); return p + 8 + (lz >> 3); } } else { - int lz = __builtin_clzll(low); + uint32_t lz = internal::clzll(low); return p + (lz >> 3); } } @@ -990,7 +992,7 @@ private: //!@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, '/', 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, @@ -1013,6 +1015,10 @@ private: 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); @@ -1244,19 +1250,19 @@ private: x = vorrq_u8(x, vcltq_u8(s, s3)); x = vrev64q_u8(x); // Rev in 64 - uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract - uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + 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) { - unsigned lz = (unsigned)__builtin_clzll(high);; + uint32_t lz = internal::clzll(high); length = 8 + (lz >> 3); escaped = true; } } else { - unsigned lz = (unsigned)__builtin_clzll(low);; + uint32_t lz = internal::clzll(low); length = lz >> 3; escaped = true; } @@ -1314,19 +1320,19 @@ private: x = vorrq_u8(x, vcltq_u8(s, s3)); x = vrev64q_u8(x); // Rev in 64 - uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract - uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + 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) { - unsigned lz = (unsigned)__builtin_clzll(high); + uint32_t lz = internal::clzll(high); length = 8 + (lz >> 3); escaped = true; } } else { - unsigned lz = (unsigned)__builtin_clzll(low); + uint32_t lz = internal::clzll(low); length = lz >> 3; escaped = true; } @@ -1370,17 +1376,17 @@ private: x = vorrq_u8(x, vcltq_u8(s, s3)); x = vrev64q_u8(x); // Rev in 64 - uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract - uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + 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) { - int lz = __builtin_clzll(high); + uint32_t lz = internal::clzll(high); p += 8 + (lz >> 3); break; } } else { - int lz = __builtin_clzll(low); + uint32_t lz = internal::clzll(low); p += lz >> 3; break; } @@ -1403,7 +1409,7 @@ private: 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) {} + RAPIDJSON_FORCEINLINE void Push(char) {} size_t Tell() { return is.Tell(); } size_t Length() { return 0; } diff --git a/include/rapidjson/schema.h b/include/rapidjson/schema.h index 5b622f78..fc39d06c 100644 --- a/include/rapidjson/schema.h +++ b/include/rapidjson/schema.h @@ -443,7 +443,6 @@ public: exclusiveMaximum_(false), defaultValueLength_(0) { - typedef typename SchemaDocumentType::ValueType ValueType; typedef typename ValueType::ConstValueIterator ConstValueIterator; typedef typename ValueType::ConstMemberIterator ConstMemberIterator; @@ -899,7 +898,7 @@ public: } } - SizeType index; + SizeType index = 0; if (FindPropertyIndex(ValueType(str, len).Move(), &index)) { if (context.patternPropertiesSchemaCount > 0) { context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema; @@ -1149,7 +1148,7 @@ private: #elif RAPIDJSON_SCHEMA_USE_STDREGEX template RegexType* CreatePattern(const ValueType& value) { - if (value.IsString()) + 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); @@ -1157,6 +1156,7 @@ private: catch (const std::regex_error&) { AllocatorType::Free(r); } + } return 0; } diff --git a/include/rapidjson/writer.h b/include/rapidjson/writer.h index 6f5b6903..51dd86d5 100644 --- a/include/rapidjson/writer.h +++ b/include/rapidjson/writer.h @@ -16,6 +16,7 @@ #define RAPIDJSON_WRITER_H_ #include "stream.h" +#include "internal/clzll.h" #include "internal/meta.h" #include "internal/stack.h" #include "internal/strfunc.h" @@ -226,7 +227,7 @@ public: 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 @@ -282,6 +283,8 @@ public: os_->Flush(); } + static const size_t kDefaultLevelDepth = 32; + protected: //! Information for each nested level struct Level { @@ -290,8 +293,6 @@ protected: 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; @@ -668,19 +669,19 @@ inline bool Writer::ScanWriteUnescapedString(StringStream& is, siz x = vorrq_u8(x, vcltq_u8(s, s3)); x = vrev64q_u8(x); // Rev in 64 - uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract - uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + 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) { - unsigned lz = (unsigned)__builtin_clzll(high); + uint32_t lz = internal::clzll(high); len = 8 + (lz >> 3); escaped = true; } } else { - unsigned lz = (unsigned)__builtin_clzll(low); + uint32_t lz = internal::clzll(low); len = lz >> 3; escaped = true; } diff --git a/readme.md b/readme.md index 78c9540d..fdb34228 100644 --- a/readme.md +++ b/readme.md @@ -72,6 +72,9 @@ Users can build and run the unit tests on their platform/compiler. RapidJSON is a header-only C++ library. Just copy the `include/rapidjson` folder to system or project's include path. +Alternatively, if you are using the [vcpkg](https://github.com/Microsoft/vcpkg/) dependency manager you can download and install rapidjson with CMake integration in a single command: +* vcpkg install rapidjson + RapidJSON uses following software as its dependencies: * [CMake](https://cmake.org/) as a general build tool * (optional) [Doxygen](http://www.doxygen.org) to build documentation @@ -158,3 +161,50 @@ More [examples](https://github.com/Tencent/rapidjson/tree/master/example) are av * [parsebyparts](https://github.com/Tencent/rapidjson/blob/master/example/parsebyparts/parsebyparts.cpp): Implements an `AsyncDocumentParser` which can parse JSON in parts, using C++11 thread. * [filterkey](https://github.com/Tencent/rapidjson/blob/master/example/filterkey/filterkey.cpp): A command line tool to remove all values with user-specified key. * [filterkeydom](https://github.com/Tencent/rapidjson/blob/master/example/filterkeydom/filterkeydom.cpp): Same tool as above, but it demonstrates how to use a generator to populate a `Document`. + +## Contributing + +RapidJSON welcomes contributions. When contributing, please follow the code below. + +### Issues + +Feel free to submit issues and enhancement requests. + +Please help us by providing **minimal reproducible examples**, because source code is easier to let other people understand what happens. +For crash problems on certain platforms, please bring stack dump content with the detail of the OS, compiler, etc. + +Please try breakpoint debugging first, tell us what you found, see if we can start exploring based on more information been prepared. + +### Workflow + +In general, we follow the "fork-and-pull" Git workflow. + + 1. **Fork** the repo on GitHub + 2. **Clone** the project to your own machine + 3. **Checkout** a new branch on your fork, start developing on the branch + 4. **Test** the change before commit, Make sure the changes pass all the tests, including `unittest` and `preftest`, please add test case for each new feature or bug-fix if needed. + 5. **Commit** changes to your own branch + 6. **Push** your work back up to your fork + 7. Submit a **Pull request** so that we can review your changes + +NOTE: Be sure to merge the latest from "upstream" before making a pull request! + +### Copyright and Licensing + +You can copy and paste the license summary from below. + +``` +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. +``` \ No newline at end of file diff --git a/test/unittest/pointertest.cpp b/test/unittest/pointertest.cpp index 858fd2ae..4629f766 100644 --- a/test/unittest/pointertest.cpp +++ b/test/unittest/pointertest.cpp @@ -674,6 +674,9 @@ TEST(Pointer, Get) { EXPECT_EQ(2u, unresolvedTokenIndex); EXPECT_TRUE(Pointer("/foo/0/a").Get(d, &unresolvedTokenIndex) == 0); // "/foo/0" is an string, cannot further query EXPECT_EQ(2u, unresolvedTokenIndex); + + Pointer::Token tokens[] = { { "foo ...", 3, kPointerInvalidIndex } }; + EXPECT_EQ(&d["foo"], Pointer(tokens, 1).Get(d)); } TEST(Pointer, GetWithDefault) { diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp index e3d51481..2795766c 100644 --- a/test/unittest/readertest.cpp +++ b/test/unittest/readertest.cpp @@ -2198,4 +2198,28 @@ TEST(Reader, ParseNanAndInfinity) { #undef TEST_NAN_INF } +TEST(Reader, EscapedApostrophe) { + const char json[] = " { \"foo\": \"bar\\'buzz\" } "; + + BaseReaderHandler<> h; + + { + StringStream s(json); + Reader reader; + ParseResult r = reader.Parse(s, h); + EXPECT_TRUE(reader.HasParseError()); + EXPECT_EQ(kParseErrorStringEscapeInvalid, r.Code()); + EXPECT_EQ(14u, r.Offset()); + } + + { + StringStream s(json); + Reader reader; + ParseResult r = reader.Parse(s, h); + EXPECT_FALSE(reader.HasParseError()); + EXPECT_EQ(kParseErrorNone, r.Code()); + EXPECT_EQ(0u, r.Offset()); + } +} + RAPIDJSON_DIAG_POP diff --git a/test/unittest/unittest.h b/test/unittest/unittest.h index 84c1b734..0afac09c 100644 --- a/test/unittest/unittest.h +++ b/test/unittest/unittest.h @@ -122,6 +122,9 @@ public: #ifndef RAPIDJSON_ASSERT #define RAPIDJSON_ASSERT(x) (!(x) ? throw AssertException(RAPIDJSON_STRINGIFY(x)) : (void)0u) +#ifndef RAPIDJSON_ASSERT_THROWS +#define RAPIDJSON_ASSERT_THROWS +#endif #endif class Random { diff --git a/travis-doxygen.sh b/travis-doxygen.sh index 33ec6ab3..cf18dc34 100755 --- a/travis-doxygen.sh +++ b/travis-doxygen.sh @@ -4,9 +4,8 @@ set -e -DOXYGEN_VER=doxygen-1.8.13 -DOXYGEN_TAR=${DOXYGEN_VER}.linux.bin.tar.gz -DOXYGEN_URL="http://ftp.stack.nl/pub/users/dimitri/${DOXYGEN_TAR}" +DOXYGEN_VER=1_8_16 +DOXYGEN_URL="https://codeload.github.com/doxygen/doxygen/tar.gz/Release_${DOXYGEN_VER}" : ${GITHUB_REPO:="Tencent/rapidjson"} GITHUB_HOST="github.com" @@ -47,9 +46,17 @@ abort() { # install doxygen binary distribution doxygen_install() { - wget -O - "${DOXYGEN_URL}" | \ - tar xz -C ${TMPDIR-/tmp} ${DOXYGEN_VER}/bin/doxygen - export PATH="${TMPDIR-/tmp}/${DOXYGEN_VER}/bin:$PATH" + cd ${TMPDIR-/tmp} + curl ${DOXYGEN_URL} -o doxygen.tar.gz + tar zxvf doxygen.tar.gz + mkdir doxygen_build + cd doxygen_build + cmake ../doxygen-Release_${DOXYGEN_VER}/ + make + + export PATH="${TMPDIR-/tmp}/doxygen_build/bin:$PATH" + + cd ../../ } doxygen_run()