diff --git a/CMakeLists.txt b/CMakeLists.txt index 060a316..cc2f8e9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,12 +1,13 @@ -cmake_minimum_required (VERSION 2.8.4) -project (ngen) +cmake_minimum_required(VERSION 2.8.4) +project(ngen) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -Wno-terminate") -set (CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD 11) include_directories(external) include_directories(core/include/attachments) add_subdirectory(core) add_subdirectory(attachments) +add_subdirectory(docker) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b9540ab..43f125c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,7 +1,8 @@ # Welcome to open-appsec's Open Sources Contributing Guide -We welcome everyone that wishes to share their expetise in improving open-appsec. +Thank you for investing your time to consider a contribution to our project! +Various open source repositories were released as part of Check Point's platform for distributing and deploying security applications for a variety of environments. We welcome everyone that wishes to share their knowledge and expertise to enhance and expand both our platform, and our ability to secure more environments. -Please ead our [Code of Conduct](./CODE_OF_CONDUCT.md) to keep our community approachable and respectable. +Read our [Code of Conduct](./CODE_OF_CONDUCT.md) to keep our community approachable and respectable. In this guide we will provide an overview of the various contribution options' guidelines - from reporting or fixing a bug, to suggesting an enhancement. @@ -15,7 +16,7 @@ An internal process will be activated upon determining the validity of a reporte **Important - If the bug you wish to report regards a suspicion of a security vulnerability, please refer to the "Reporting security vulnerability" section** -To report a bug, you can either open a new issue using a relevant [issue form](https://github.com/github/docs/issues/new/choose), or, alternatively, contact us using [this email](mailto:opensource@openappsec.io). +To report a bug, you can either open a new issue using a relevant [issue form](https://github.com/github/docs/issues/new/choose), or, alternatively, [contact us via our open-appsec open source distribution list](mailto:opensource@openappsec.io). Be sure to include a **title and clear description**, as much relevant information as possible, and a **code sample** or an **executable test case** demonstrating the expected behavior that is not occurring. @@ -30,3 +31,10 @@ Please [suggest your change via our open-appsec open source distribution list](m ## Open Source documentation issues For reporting or suggesting a change, of any issue detected in the documentation files of our open source repositories, please use the same guidelines as bug reports/fixes. + +# Final Thanks +We value all users that use our open source files. +We value all efforts to read, suggest changes and/or contribute to our open source files. +Thank you for it. + +The open-appsec Team diff --git a/README.md b/README.md index d7383c5..87b9d53 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@
-

openappsec/attachment

+

openappsec/attachement

## About -open-appsec (https://www.openappsec.io) is a machine learning security engine that preemptively and automatically prevent threats against Web Application & APIs. +open-appsec is a machine learning security engine that preemptively and automatically prevent threats against Web Application & APIs. open-appsec Attachments connect between processes that provide HTTP data and the open-appsec Agent security logic. @@ -18,44 +18,78 @@ This repository will host Attachment for different platforms. The first one is t ## open-appsec NGINX attachment compilation instructions -### Compiling the attachment code +The attchment can be compiled to support an existing alpine based nginx server or an nginx/ingress-nginx alpine based docker. + +Your compilation environment must be alpine based and contain git, docker, cmake and g++. + +Before compiling, ensure the latest development versions of the following libraries: + +* PCRE +* libxml2 +* zlib +* OpenSSL +* Geoip + +```bash + $ apk update + $ apk add pcre-dev libxml2-dev zlib-dev openssl-dev geoip-dev +``` + +### Compiling the attachment code for an existing nginx server + +On your existing nginx server: +1. Run command to extract nginx compilation flags to a file + +```bash + $ nginx -V &> /tmp/nginx.ver +``` + +On your compilation environment: 1. Clone this repository -2. Run CMake command -3. Run make install command +2. Copy the file created on your nginx server (the previous section) to your compilation environment to the path /tmp/nginx.ver +3. Run Configuration script +4. Run CMake command +5. Run make command ```bash $ git clone https://github.com/openappsec/attachment.git - $ cd attachment/ + $ ./attachments/nginx/ngx_module/nginx_version_configuration.sh --conf /tmp/nginx.ver build_out $ cmake -DCMAKE_INSTALL_PREFIX=build_out . $ make install ``` -### NGINX plugin - -NGINX Plugins are built per specific version. -1. Get nginx source code from [nginx.org](http://nginx.org/), e.g. version 1.23.0 (see [nginx compatibility](http://nginx.org/en/docs/njs/compatibility.html)) -2. Run make modules - -```bash - $ module_path=//attachment - - $ wget 'https://nginx.org/download/nginx-1.23.0.tar.gz' - $ sha256sum nginx-1.23.0.tar.gz - 820acaa35b9272be9e9e72f6defa4a5f2921824709f8aa4772c78ab31ed94cd1 nginx-1.23.0.tar.gz - - $ tar -xzvf nginx-1.23.0.tar.gz - $ cd nginx-1.23.0/ - - $ ./configure --add-dynamic-module=$module_path --with-cc-opt="-I $module_path/core/include/attachments" - - $ make modules -``` - #### NGINX plugin associated libraries The NGINX plugin uses these libraries: shmem_ipc, compression_utils, and nginx_attachment_util. They can be found under the `lib` directory in the `` given to the CMake. +#### Deploying the attachment on an existing alpine nginx server + +1. Copy the associated libraries to /usr/lib on your existing nginx server +2. Copy the nginx attachment file lib/libngx_module.so to the following path on your existing nginx server: /usr/lib/nginx/modules/ +3. Load the attachment on your nginx by adding the following command to the main nginx.conf file: + load_module /usr/lib/nginx/modules/libngx_module.so; +4. Restart your nginx server. + +### Compiling the attachment code and create a docker image for an existing nginx/ingres-nginx alpine docker + +This step requires Docker to be installed on your comilation environment + +1. Clone this repository +3. Run Configuration script with the required docker image name and tag +4. Run CMake command +5. Run make command + +```bash + $ git clone https://github.com/openappsec/attachment.git + $ ./attachments/nginx/ngx_module/nginx_version_configuration.sh --docker build_out + $ cmake -DCMAKE_INSTALL_PREFIX=build_out -DOUTPUT_DOCKER_IMAGE= . + $ make install + $ make docker +``` + +Later on, you can push the image to your own registry in use it as needed. + ## License open-appsec/attachment is open source and available under the Apache 2.0 license. diff --git a/attachments/nginx/CMakeLists.txt b/attachments/nginx/CMakeLists.txt index ef815f9..196e407 100644 --- a/attachments/nginx/CMakeLists.txt +++ b/attachments/nginx/CMakeLists.txt @@ -1 +1,2 @@ add_subdirectory(nginx_attachment_util) +add_subdirectory(ngx_module) diff --git a/attachments/nginx/nginx_attachment_util/CMakeLists.txt b/attachments/nginx/nginx_attachment_util/CMakeLists.txt index ba3aa76..5a8e158 100644 --- a/attachments/nginx/nginx_attachment_util/CMakeLists.txt +++ b/attachments/nginx/nginx_attachment_util/CMakeLists.txt @@ -1,5 +1,6 @@ add_definitions(-DUSERSPACE) add_library(osrc_nginx_attachment_util SHARED nginx_attachment_util.cc) +target_link_libraries(osrc_nginx_attachment_util http_configuration) install(TARGETS osrc_nginx_attachment_util DESTINATION lib) diff --git a/attachments/nginx/nginx_attachment_util/nginx_attachment_util.cc b/attachments/nginx/nginx_attachment_util/nginx_attachment_util.cc index df2edcb..32e66cd 100644 --- a/attachments/nginx/nginx_attachment_util/nginx_attachment_util.cc +++ b/attachments/nginx/nginx_attachment_util/nginx_attachment_util.cc @@ -83,6 +83,18 @@ getFailOpenTimeout() return conf_data.getNumericalValue("fail_open_timeout"); } +int +isFailOpenHoldMode() +{ + return conf_data.getNumericalValue("is_fail_open_mode_hold_enabled"); +} + +unsigned int +getFailOpenHoldTimeout() +{ + return conf_data.getNumericalValue("fail_open_hold_timeout"); +} + unsigned int getMaxSessionsPerMinute() { @@ -137,6 +149,12 @@ getResBodyThreadTimeout() return conf_data.getNumericalValue("res_body_thread_timeout_msec"); } +unsigned int +getWaitingForVerdictThreadTimeout() +{ + return conf_data.getNumericalValue("waiting_for_verdict_thread_timeout_msec"); +} + int isIPAddress(c_str ip_str) { diff --git a/attachments/nginx/ngx_module/CMakeLists.txt b/attachments/nginx/ngx_module/CMakeLists.txt new file mode 100644 index 0000000..5b08a97 --- /dev/null +++ b/attachments/nginx/ngx_module/CMakeLists.txt @@ -0,0 +1,48 @@ +MACRO(CREATE_INCLUDE_LIST result) + file(READ ${CMAKE_INSTALL_PREFIX}/nginx-src/include_paths.mk relative_includes) + STRING(REGEX REPLACE "\n" ";" relative_includes "${relative_includes}") + set(inclist "") + FOREACH(include ${relative_includes}) + if(NOT include MATCHES "^/") + set(inclist ${inclist} "${CMAKE_INSTALL_PREFIX}/nginx-src/${include}") + else() + set(inclist ${inclist} "${include}") + endif() + ENDFOREACH() + set(${result} ${inclist}) +ENDMACRO() + +MACRO(READ_COMPILE_FLAGS result) + file(READ ${CMAKE_INSTALL_PREFIX}/nginx-src/cc_flags.mk CC_FLAGS) + string(REGEX REPLACE "\n" "" CC_FLAGS "${CC_FLAGS}") + set(flag_list "") + FOREACH(flag ${CC_FLAGS}) + if (flag MATCHES "-fstack-clash-protection" OR flag MATCHES "-fcf-protection" OR flag MATCHES "-Wno-cast-function-type") + continue() + endif() + + set(flag_list ${flag_list} "${flag}") + ENDFOREACH() + separate_arguments(flag_list) + set(${result} ${flag_list}) +ENDMACRO() + +add_library( + ngx_module + SHARED + ngx_http_cp_attachment_module.c ngx_cp_thread.c ngx_cp_hook_threads.c ngx_cp_hooks.c ngx_cp_utils.c + ngx_cp_initializer.c ngx_cp_io.c ngx_cp_static_content.c ngx_cp_custom_response.c ngx_modules.c + ngx_cp_compression.c ngx_cp_http_parser.c ngx_cp_failing_state.c ngx_cp_metric.c +) + +add_dependencies(ngx_module osrc_shmem_ipc osrc_nginx_attachment_util osrc_compression_utils) + +target_link_libraries(ngx_module osrc_shmem_ipc osrc_nginx_attachment_util osrc_compression_utils) + +CREATE_INCLUDE_LIST(NGX_INCLUDES) +READ_COMPILE_FLAGS(CC_FLAG_LIST) + +target_include_directories(ngx_module PRIVATE ${NGX_INCLUDES}) +target_compile_options(ngx_module PRIVATE ${CC_FLAG_LIST}) + +install(TARGETS ngx_module DESTINATION lib) diff --git a/attachments/nginx/ngx_module/nginx_version_configuration.sh b/attachments/nginx/ngx_module/nginx_version_configuration.sh new file mode 100755 index 0000000..0db4951 --- /dev/null +++ b/attachments/nginx/ngx_module/nginx_version_configuration.sh @@ -0,0 +1,66 @@ +#!/bin/bash + +NGINX_VERSION_CONF_INPUT_PATH=/tmp/nginx.sourcefile.ver +if [ "${1}" == "--docker" ]; then + docker run -it ${2} nginx -V > ${NGINX_VERSION_CONF_INPUT_PATH} +elif [ "${1}" == "--conf" ]; then + cp ${2} ${NGINX_VERSION_CONF_INPUT_PATH} +else + echo "Usage: ${0} [--conf | --docker ] " + exit 1 +fi +NGINX_VERSION_CONF_OUTPUT_PATH=/tmp/nginx.sourcefile.conf +$(dirname $0)/nginx_version_extractor.sh -i ${NGINX_VERSION_CONF_INPUT_PATH} -o ${NGINX_VERSION_CONF_OUTPUT_PATH} +BUILD_OUTPUT_DIR=${3} + +if [[ ${BUILD_OUTPUT_DIR} != /* ]]; then + BUILD_OUTPUT_DIR=$(pwd)/${BUILD_OUTPUT_DIR} +fi + +source ${NGINX_VERSION_CONF_OUTPUT_PATH} + +CURRENT_PWD=$(pwd) + +mkdir -p ${BUILD_OUTPUT_DIR} +cd ${BUILD_OUTPUT_DIR} + +wget --no-check-certificate https://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz + +tar -xzvf nginx-${NGINX_VERSION}.tar.gz + +rm nginx-${NGINX_VERSION}.tar.gz + +mv nginx-${NGINX_VERSION} nginx-src +cd nginx-src + +if test ! -f configured.ok; then + echo "Configuring nginx compiler: ./configure ${CONFIGURE_OPT} --with-cc-opt=\"${EXTRA_CC_OPT} ${LOCAL_CC_OPT}\" && touch configured.ok" + ./configure ${CONFIGURE_OPT} --with-cc-opt="${EXTRA_CC_OPT} ${LOCAL_CC_OPT}" && touch configured.ok +else + echo "Nginx compiler already Configured...\n" +fi + +make && echo "${EXTRA_CC_OPT}" > cc_flags.mk + + +OUTPUT_FILE_NAME=include_paths.mk + +ALL_INCS=$(cat objs/Makefile|grep -v \$\(ALL_INCS\) | awk '/ALL_INCS/' RS="\n\n" ORS="\n\n" | tr '\\' ' ') +ALL_INCS=${ALL_INCS/ALL_INCS =/} +ALL_INCS=$(sed "s/-I//g" <<< "${ALL_INCS}") + +echo > include_paths.mk +for include in ${ALL_INCS}; do + echo $include >> include_paths.mk +done + +cd ${CURRENT_PWD} + +if [ "${1}" == "--docker" ]; then + cp -f $(dirname $0)/../../../docker/Dockerfile ${BUILD_OUTPUT_DIR}/Dockerfile + sed -i "s||${2}|g" ${BUILD_OUTPUT_DIR}/Dockerfile + docker run -it ${2} whoami > /tmp/usertouse + USER_NAME="$(cat /tmp/usertouse)" + rm /tmp/usertouse + sed -i "s||${USER_NAME}|g" ${BUILD_OUTPUT_DIR}/Dockerfile +fi diff --git a/attachments/nginx/ngx_module/nginx_version_extractor.sh b/attachments/nginx/ngx_module/nginx_version_extractor.sh new file mode 100755 index 0000000..9f19850 --- /dev/null +++ b/attachments/nginx/ngx_module/nginx_version_extractor.sh @@ -0,0 +1,347 @@ +#!/bin/bash + +initializeEnviroment() +{ + CURRENT_TIME="" + PACKAGE_VERSION="" + CUR_NGINX_ALREADY_SUPPORTED=false + NUMBER_OF_CONFIGURATION_FLAGS=0 + TMP_NGINX_UNPARSED_CONFIGURATION="/tmp/nginx_unparsed_tmp_conf.txt" + TMP_NGINX_PARSED_CONFIGURATION_FLAGS="/tmp/nginx_parsed_conf_flags.txt" + TMP_DECODED_FILE_PATH="/tmp/decoded_file.txt" + IS_ALPINE=false + if [ ! -z "$(cat /etc/*release | grep alpine)" ]; then + IS_ALPINE=true + fi +} + +usage() +{ + local IS_ERROR=$1 + local option=$2 + if [[ ${IS_ERROR} == true ]]; then + echo "Error: unsupported option '${option}'" + fi + + echo "Usage:" + line_padding=" " + local debug_print_option="-h, --help" + printf "%s %s Print (this) help message\n" "$debug_print_option" "${line_padding:${#debug_print_option}}" + debug_print_option="-d, --debug" + printf "%s %s Enable debug mode\n" "$debug_print_option" "${line_padding:${#debug_print_option}}" + debug_print_option="-v, --verbose" + printf "%s %s show version and configure options\n" "$debug_print_option" "${line_padding:${#debug_print_option}}" + debug_print_option="-o, --output" + printf "%s %s change output file name into '${option}'\n" "$debug_print_option" "${line_padding:${#debug_print_option}}" + debug_print_option="-f, --force" + printf "%s %s force creation of makefile'\n" "$debug_print_option" "${line_padding:${#debug_print_option}}" + + if [[ ${IS_ERROR} == true ]]; then + exit -1 + else + exit 1 + fi +} + +debug() +{ + local debug_message=$1 + if [[ $IS_DEBUG_MODE_ACTIVE == true ]]; then + echo -e $debug_message + fi +} + +check_flags_options() +{ + local argc=$# + + for (( i = 1; i <= $argc; i++ )); do + local option=${!i} + local IS_ERROR=false + if [[ "$option" == "--debug" || "$option" == "-d" ]]; then + IS_DEBUG_MODE_ACTIVE=true + elif [[ "$option" == "--verbose" || "$option" == "-v" ]]; then + IS_VERBOSE_MODE_ACTIVE=true + elif [[ "$option" == "--force" || "$option" == "-f" ]]; then + IS_FORCE_OUTPUT=true + elif [[ "$option" == "--output" || "$option" == "-o" ]]; then + IS_OUTPUT_NAME_MODE_ACTIVE=true + i=$((i+1)) + FILE_NAME=${!i} + if [[ -z ${FILE_NAME} ]]; then + echo "Error: No file name was given for ${option} option." + exit -1 + fi + elif [[ "$option" == "--input" || "$option" == "-i" ]]; then + i=$((i+1)) + if [[ -z ${!i} ]]; then + echo "Error: No file name was given for ${option} option." + exit -1 + fi + cp -f ${!i} ${TMP_NGINX_UNPARSED_CONFIGURATION} + IS_INPUT_NAME_MODE_ACTIVE=true + elif [[ "$option" == "--help" || "$option" == "-h" ]]; then + usage ${IS_ERROR} ${option} + elif [[ ! -z $option ]]; then + IS_ERROR=true + usage ${IS_ERROR} ${option} + fi + done +} + +_main() +{ + echo "Starting verification of Check Point support with local nginx server" + initializeEnviroment + + if [[ ${IS_INPUT_NAME_MODE_ACTIVE} != true ]]; then + nginx -V &> "$TMP_NGINX_UNPARSED_CONFIGURATION" + fi + getNginxVersion + + if [[ $IS_VERBOSE_MODE_ACTIVE == true ]]; then + echo "" + cat ${TMP_NGINX_UNPARSED_CONFIGURATION} + echo "" + fi + + while IFS= read -ra UNPARSED_CONFIGURATION_LINE <&3; do + if [[ ${UNPARSED_CONFIGURATION_LINE} =~ ^"nginx version:" ]]; then + openFile + elif [[ ${UNPARSED_CONFIGURATION_LINE} =~ ^"built by gcc" ]]; then + addBuiltConfiguration "${UNPARSED_CONFIGURATION_LINE}" + elif [[ ${UNPARSED_CONFIGURATION_LINE} =~ ^"configure arguments:" ]]; then + IFS="'" + addAndCutOptionalFlags ${UNPARSED_CONFIGURATION_LINE} + IFS=" " + addRequiredFlags ${CONFIGURATION_FLAGES_NEED_TO_BE_PARSED} + fi + done 3<"$TMP_NGINX_UNPARSED_CONFIGURATION" + + PARSED_CONFIGURATION="CONFIGURE_OPT=\"${COMBINED_CONFIGURATION_FLAGS}\"\n\n" + NUMBER_OF_CONFIGURATION_FLAGS=$((NUMBER_OF_CONFIGURATION_FLAGS-1)) + local local_pwd=$(pwd) + if [[ ${local_pwd:0:2} == "//" ]]; then + local_pwd=${local_pwd:1} + fi + debug "Moving parsed configuration to target ${local_pwd}/${FILE_NAME} configuration file" + echo -e ${PARSED_CONFIGURATION} > ${FILE_NAME} + echo -e ${CC_OPTIONAL_FLAGS} >> ${FILE_NAME} + add_nginx_and_release_versions + if [[ $CUR_NGINX_ALREADY_SUPPORTED == true ]]; then + tearDown + echo -e "Check Point Nano Agent already supported on this environment" + else + tearDown + echo -e "Extracted environment data to $(pwd)/${FILE_NAME} \nPlease send file to nano-agent-attachments-support@checkpoint.com" + fi +} + +tearDown() +{ + rm -f ${TMP_NGINX_UNPARSED_CONFIGURATION} + rm -f ${TMP_NGINX_PARSED_CONFIGURATION_FLAGS} + rm -f ${TMP_DECODED_FILE_PATH} + rm -f ${TMP_NGINX_VERSION_FILE} +} + +getNginxVersion() +{ + TMP_NGINX_VERSION_FILE="/tmp/nginx_version_file.txt" + cat ${TMP_NGINX_UNPARSED_CONFIGURATION} | grep "nginx version:" &> "$TMP_NGINX_VERSION_FILE" + if [[ $IS_ALPINE == true ]]; then + NGINX_VERSION=`cat ${TMP_NGINX_VERSION_FILE} | grep -oE [0-9]+.[0-9]+.[0-9]+` + else + NGINX_VERSION=`cat ${TMP_NGINX_VERSION_FILE} | grep -oP [0-9]+.[0-9]+.[0-9]+` + fi +} + +openFile() +{ + if [[ ${IS_OUTPUT_NAME_MODE_ACTIVE} != true ]]; then + FILE_NAME="${NGINX_VERSION}.mk" + debug "Trying to create an empty ${NGINX_VERSION} file" + FILE_NAME_PATH="$(pwd)/${FILE_NAME}" + + if [[ -z ${FILE_NAME_PATH} || ! ( ${FILE_NAME} =~ [0-9]+.[0-9]+.[0-9]+.mk ) ]]; then + echo "ERROR: can't find nginx version." + exit -1 + fi + + if [[ -f "${FILE_NAME_PATH}" ]]; then + echo "The output file: ${FILE_NAME} already exists. Do you want to overwrite this file? [y/N]" + read answer + if [[ ${answer} != "y" ]]; then + echo -e "Stopping after the operation was cancelled.\nIf you wish to use other output file name you can use option -o or --output" + exit -1 + fi + fi + else + debug "Trying to create an empty ${FILE_NAME} file" + FILE_NAME_PATH="${FILE_NAME}" + fi + + touch ${FILE_NAME_PATH} &> /dev/null + if [ ! -e ${FILE_NAME_PATH} ];then + echo "Failed to create ${FILE_NAME_PATH}" + exit -1 + fi + debug "Created an empty ${FILE_NAME} file" +} + +checkAllDBLineFlags() +{ + local argc=$# + local argv=("$@") + local number_of_db_line_flags=$((argc-3)) + local gcc_version_prefix="--with-cc=" + + if [[ ${number_of_db_line_flags} == ${NUMBER_OF_CONFIGURATION_FLAGS} ]]; then + for ((i = 3; i < ${argc}; i++)); do + if [[ ${argv[i]} =~ ^"${gcc_version_prefix}"* ]]; then + continue + fi + checkFlag ${argv[i]} + if [[ ${found_equal_flag} == false ]]; then + EQUAL_FLAGS=false + return + fi + done + else return + fi + + EQUAL_FLAGS=true +} + +checkFlag() +{ + found_equal_flag=false + db_flag=$1 + while IFS='\' read -ra flag; do + if [[ "${flag}" == "${db_flag}" ]] || [[ "${flag} " == "${db_flag}" ]]; then + found_equal_flag=true + break + fi + done < ${TMP_NGINX_PARSED_CONFIGURATION_FLAGS} +} + +addBuiltConfiguration() +{ + BUILT_BY_GCC_FLAG_PREFIX="--with-cc=/usr/bin/" + if [[ $IS_ALPINE == true ]]; then + GCC_VERSION=`echo "$1" | grep -oE "gcc "[0-9]+ | tr ' ' '-'` + else + GCC_VERSION=`echo "$1" | grep -oP "gcc "[0-9]+ | tr ' ' '-'` + fi + if [[ "$GCC_VERSION" == "gcc-4" ]]; then + GCC_VERSION=gcc-5 + elif [[ "$GCC_VERSION" == "gcc-10" ]] || [[ "$GCC_VERSION" == "gcc-11" ]]; then + GCC_VERSION=gcc-8 + fi + BUILT_BY_GCC_FLAG=" \\\\\n${BUILT_BY_GCC_FLAG_PREFIX}${GCC_VERSION}" + NUMBER_OF_CONFIGURATION_FLAGS=$((NUMBER_OF_CONFIGURATION_FLAGS+1)) +} + +addAndCutOptionalFlags() +{ + debug "Parsing all nginx configuration flags" + CC_EXTRA_PREFIX="EXTRA_CC_OPT=" + CC_OPTIONAL_FLAG_PREFIX="--with-cc-opt=" + LD_OPTIONAL_FLAG_PREFIX="--with-ld-opt=" + local argc=$# + local argv=("$@") + for (( i = 0; i < $argc; i++ )); do + if [[ ${argv[i]} == *"${CC_OPTIONAL_FLAG_PREFIX}"* ]]; then + debug "Successfully added compilation flags" + CONFIGURATION_FLAGES_NEED_TO_BE_PARSED="${CONFIGURATION_FLAGES_NEED_TO_BE_PARSED}${argv[i]}" + i=$((i+1)) + IFS=" " + addCCFlagsWithoutSpecsLocalFlag ${argv[i]} + CC_OPTIONAL_FLAGS="${CC_EXTRA_PREFIX}\"${CC_OPTIONAL_FLAGS}\"" + elif [[ ${argv[i]} == *"${LD_OPTIONAL_FLAG_PREFIX}"* ]]; then + CONFIGURATION_FLAGES_NEED_TO_BE_PARSED="${CONFIGURATION_FLAGES_NEED_TO_BE_PARSED}${argv[i]}" + i=$((i+1)) + else + CONFIGURATION_FLAGES_NEED_TO_BE_PARSED="${CONFIGURATION_FLAGES_NEED_TO_BE_PARSED}${argv[i]}" + fi + done + debug "Successfully finished adding optional flags" + } + +addCCFlagsWithoutSpecsLocalFlag() +{ + local argc=$# + local argv=("$@") + SPECS_FLAG_PREFIX="-specs=" + NO_ERROR_PREFIX="-Wno-error=" + FCF_PROTECTION_PREFIX="-fcf-protection" + FSTACK_PREFIX="-fstack-clash-protection" + + for (( j = 0; j < $argc; j++ )); do + if [[ ! ${argv[j]} =~ ^${SPECS_FLAG_PREFIX} ]] && \ + [[ ! ${argv[j]} =~ ^${NO_ERROR_PREFIX} ]] && \ + [[ ! ${argv[j]} =~ ^${FSTACK_PREFIX} ]] && \ + [[ ! ${argv[j]} =~ ^${FCF_PROTECTION_PREFIX} ]]; \ + then + CC_OPTIONAL_FLAGS="${CC_OPTIONAL_FLAGS} ${argv[j]}" + fi + done + CC_OPTIONAL_FLAGS=`echo $CC_OPTIONAL_FLAGS | grep ^"-"` +} + +addRequiredFlags() +{ + local argc=$# + local argv=("$@") + CC_OPTIONAL_FLAG_PREFIX="--with-cc-opt=" + LD_OPTIONAL_FLAG_PREFIX="--with-ld-opt=" + ADDITIONAL_MODULE_FLAG_PREFIX="--add-module=" + DYNAMIC_MODULE_FLAG_PREFIX="--add-dynamic-module=" + BUILD_FLAG_PREFIX="--build=" + OPENSSL_VERSION_PREFIX="--with-openssl=" + OPENSSL_OPT_PREFIX="--with-openssl-opt=" + HPACK_ENC_PREFIX="--with-http_v2_hpack_enc" + AUTH_JWT_PREFIX="--with-http_auth_jwt_module" + F4F_PREFIX="--with-http_f4f_module" + HLS_PREFIX="--with-http_hls_module" + SESSION_LOG_PREFIX="--with-http_session_log_module" + COMMON_PREFIX="--" + WITH_CC_PREFIX="--with-cc" + + for (( i = 1; i < $argc; i++ )); do + if [[ "${argv[i]}" =~ ^${COMMON_PREFIX} ]] && \ + [[ ! ("${argv[i]}" =~ ^${CC_OPTIONAL_FLAG_PREFIX}) ]] && \ + [[ ! ("${argv[i]}" =~ ^${LD_OPTIONAL_FLAG_PREFIX}) ]] && \ + [[ ! ("${argv[i]}" =~ ${ADDITIONAL_MODULE_FLAG_PREFIX}) ]] && \ + [[ ! ("${argv[i]}" =~ ${OPENSSL_VERSION_PREFIX}) ]] && \ + [[ ! ("${argv[i]}" =~ ${OPENSSL_OPT_PREFIX}) ]] && \ + [[ ! ("${argv[i]}" =~ ${DYNAMIC_MODULE_FLAG_PREFIX}) ]] && \ + [[ ! ("${argv[i]}" =~ ${BUILD_FLAG_PREFIX}) ]] && \ + [[ ! ("${argv[i]}" =~ ${AUTH_JWT_PREFIX}) ]] && \ + [[ ! ("${argv[i]}" =~ ${F4F_PREFIX}) ]] && \ + [[ ! ("${argv[i]}" =~ ${HLS_PREFIX}) ]] && \ + [[ ! ("${argv[i]}" =~ ${SESSION_LOG_PREFIX}) ]] && \ + [[ ! ("${argv[i]}" =~ ${WITH_CC_PREFIX}) ]] && \ + [[ ! ("${argv[i]}" =~ ${HPACK_ENC_PREFIX}) ]] ; \ + then + debug "Adding configuration flag: ${argv[i]}\n" + NUMBER_OF_CONFIGURATION_FLAGS=$((NUMBER_OF_CONFIGURATION_FLAGS+1)) + CONFIGURATION_FLAGS="${CONFIGURATION_FLAGS} \\\\\n${argv[i]}" + fi + done + COMBINED_CONFIGURATION_FLAGS="${CONFIGURATION_FLAGS}" + debug "Successfully added nginx configuration flags" +} + +add_nginx_and_release_versions() +{ + echo -e "NGINX_VERSION=\"${NGINX_VERSION}\"" >> ${FILE_NAME} + RELEASE_VERSION=`cat /etc/*-release | grep -i "PRETTY_NAME\|Gaia" | cut -d"\"" -f2` + echo -e "RELEASE_VERSION=\"${RELEASE_VERSION}\"" >> ${FILE_NAME} +} + +initializeEnviroment +echo -e "Open-appsec Nginx version extractor\n" +check_flags_options "$@" +_main + diff --git a/attachments/nginx/ngx_module/ngx_cp_compression.c b/attachments/nginx/ngx_module/ngx_cp_compression.c index 500e544..35c4d68 100644 --- a/attachments/nginx/ngx_module/ngx_cp_compression.c +++ b/attachments/nginx/ngx_module/ngx_cp_compression.c @@ -380,7 +380,11 @@ compression_chain_filter( } ngx_memcpy(curr_input_link->buf, output_buffer, sizeof(ngx_buf_t)); - curr_input_link->buf->memory = 1; + + // Empty buffer should not be marked as "in-memory" + if (curr_input_link->buf->last - curr_input_link->buf->pos != 0) { + curr_input_link->buf->memory = 1; + } } write_dbg(DBG_LEVEL_TRACE, "Successfully %s chain", should_compress ? "compressed" : "decompressed"); diff --git a/attachments/nginx/ngx_module/ngx_cp_custom_response.c b/attachments/nginx/ngx_module/ngx_cp_custom_response.c index 28d529f..cc5ba93 100644 --- a/attachments/nginx/ngx_module/ngx_cp_custom_response.c +++ b/attachments/nginx/ngx_module/ngx_cp_custom_response.c @@ -333,7 +333,7 @@ ngx_http_cp_finalize_rejected_request(ngx_http_request_t *request) } out_chain[0].buf->last_buf = 1; out_chain[0].next = NULL; - return ngx_http_output_filter(request, &out_chain[0]); + ngx_http_output_filter(request, &out_chain[0]); } CUSTOM_RES_OUT: diff --git a/attachments/nginx/ngx_module/ngx_cp_hook_threads.c b/attachments/nginx/ngx_module/ngx_cp_hook_threads.c index c8805ee..ce87e7e 100644 --- a/attachments/nginx/ngx_module/ngx_cp_hook_threads.c +++ b/attachments/nginx/ngx_module/ngx_cp_hook_threads.c @@ -86,8 +86,8 @@ init_thread_ctx( void * ngx_http_cp_registration_thread(void *_ctx) { - struct ngx_http_cp_event_thread_ctx_t *ctx = (struct ngx_http_cp_event_thread_ctx_t*)_ctx; - ngx_int_t res = ngx_cp_attachment_init_process(); + struct ngx_http_cp_event_thread_ctx_t *ctx = (struct ngx_http_cp_event_thread_ctx_t *)_ctx; + ngx_int_t res = ngx_cp_attachment_init_process(ctx->request); if (res == NGX_ABORT && already_registered) { already_registered = 0; disconnect_communication(); @@ -141,7 +141,8 @@ end_req_header_handler( &session_data_p->verdict, session_data_p->session_id, request, - modifications + modifications, + REQUEST_END ); } @@ -154,7 +155,7 @@ does_contain_body(ngx_http_headers_in_t *headers) void * ngx_http_cp_req_header_handler_thread(void *_ctx) { - struct ngx_http_cp_event_thread_ctx_t *ctx = (struct ngx_http_cp_event_thread_ctx_t*)_ctx; + struct ngx_http_cp_event_thread_ctx_t *ctx = (struct ngx_http_cp_event_thread_ctx_t *)_ctx; ngx_http_request_t *request = ctx->request; ngx_http_cp_session_data *session_data_p = ctx->session_data_p; ngx_int_t send_meta_data_result; @@ -218,7 +219,7 @@ ngx_http_cp_req_header_handler_thread(void *_ctx) void * ngx_http_cp_req_body_filter_thread(void *_ctx) { - struct ngx_http_cp_event_thread_ctx_t *ctx = (struct ngx_http_cp_event_thread_ctx_t*)_ctx; + struct ngx_http_cp_event_thread_ctx_t *ctx = (struct ngx_http_cp_event_thread_ctx_t *)_ctx; ngx_http_request_t *request = ctx->request; ngx_http_cp_session_data *session_data_p = ctx->session_data_p; ngx_int_t is_last_part; @@ -248,31 +249,14 @@ ngx_http_cp_req_body_filter_thread(void *_ctx) } session_data_p->remaining_messages_to_reply += num_messages_sent; - num_messages_sent = 0; - if (is_last_part) { - // Signals the nano service that the transaction reached the end. - if (ngx_http_cp_end_transaction_sender(REQUEST_END, session_data_p->session_id, &num_messages_sent) != NGX_OK) { - write_dbg( - DBG_LEVEL_WARNING, - "Failed to send request end data to the nano service. Session ID: %d", - session_data_p->session_id - ); - handle_inspection_failure(inspection_failure_weight, fail_mode_verdict, session_data_p); - if (fail_mode_verdict == NGX_OK) { - THREAD_CTX_RETURN_NEXT_FILTER(); - } - THREAD_CTX_RETURN(NGX_ERROR); - } - session_data_p->remaining_messages_to_reply++; - } - // Fetch nano services' results. ctx->res = ngx_http_cp_reply_receiver( &session_data_p->remaining_messages_to_reply, &session_data_p->verdict, session_data_p->session_id, request, - &ctx->modifications + &ctx->modifications, + REQUEST_BODY ); if (is_last_part) session_data_p->was_request_fully_inspected = 1; @@ -280,10 +264,49 @@ ngx_http_cp_req_body_filter_thread(void *_ctx) return NULL; } +void * +ngx_http_cp_req_end_transaction_thread(void *_ctx) +{ + struct ngx_http_cp_event_thread_ctx_t *ctx = (struct ngx_http_cp_event_thread_ctx_t *)_ctx; + ngx_http_request_t *request = ctx->request; + ngx_http_cp_session_data *session_data_p = ctx->session_data_p; + ngx_uint_t num_messages_sent = 0; + + if (ngx_http_cp_end_transaction_sender(REQUEST_END, session_data_p->session_id, &num_messages_sent) != NGX_OK) { + write_dbg( + DBG_LEVEL_WARNING, + "Failed to send request end data to the nano service. Session ID: %d", + session_data_p->session_id + ); + handle_inspection_failure(inspection_failure_weight, fail_mode_verdict, session_data_p); + if (fail_mode_verdict == NGX_OK) { + THREAD_CTX_RETURN_NEXT_FILTER(); + } + THREAD_CTX_RETURN(NGX_ERROR); + } + + session_data_p->remaining_messages_to_reply += num_messages_sent; + + if (session_data_p->verdict != TRAFFIC_VERDICT_ACCEPT && + session_data_p->verdict != TRAFFIC_VERDICT_DROP) { + // Fetch nano services' results. + ctx->res = ngx_http_cp_reply_receiver( + &session_data_p->remaining_messages_to_reply, + &session_data_p->verdict, + session_data_p->session_id, + request, + &ctx->modifications, + REQUEST_END + ); + } + + return NULL; +} + void * ngx_http_cp_res_header_filter_thread(void *_ctx) { - struct ngx_http_cp_event_thread_ctx_t *ctx = (struct ngx_http_cp_event_thread_ctx_t*)_ctx; + struct ngx_http_cp_event_thread_ctx_t *ctx = (struct ngx_http_cp_event_thread_ctx_t *)_ctx; ngx_http_request_t *request = ctx->request; ngx_http_cp_session_data *session_data_p = ctx->session_data_p; ngx_int_t set_response_content_encoding_res; @@ -383,7 +406,8 @@ ngx_http_cp_res_header_filter_thread(void *_ctx) &session_data_p->verdict, session_data_p->session_id, request, - &ctx->modifications + &ctx->modifications, + RESPONSE_HEADER ); return NULL; @@ -392,7 +416,7 @@ ngx_http_cp_res_header_filter_thread(void *_ctx) void * ngx_http_cp_res_body_filter_thread(void *_ctx) { - struct ngx_http_cp_event_thread_ctx_t *ctx = (struct ngx_http_cp_event_thread_ctx_t*)_ctx; + struct ngx_http_cp_event_thread_ctx_t *ctx = (struct ngx_http_cp_event_thread_ctx_t *)_ctx; ngx_http_request_t *request = ctx->request; ngx_http_cp_session_data *session_data_p = ctx->session_data_p; ngx_int_t send_body_result; @@ -446,7 +470,50 @@ ngx_http_cp_res_body_filter_thread(void *_ctx) &session_data_p->verdict, session_data_p->session_id, request, - &ctx->modifications + &ctx->modifications, + RESPONSE_BODY + ); + + return NULL; +} + +void * +ngx_http_cp_hold_verdict_thread(void *_ctx) +{ + struct ngx_http_cp_event_thread_ctx_t *ctx = (struct ngx_http_cp_event_thread_ctx_t *)_ctx; + + ngx_http_request_t *request = ctx->request; + ngx_http_cp_session_data *session_data_p = ctx->session_data_p; + + ngx_uint_t num_messages_sent = 0; + + if (ngx_http_cp_wait_sender(session_data_p->session_id, &num_messages_sent) != NGX_OK) { + write_dbg( + DBG_LEVEL_WARNING, + "Failed to send inspect wait request to the nano service. Session ID: %d", + session_data_p->session_id + ); + handle_inspection_failure(inspection_failure_weight, fail_mode_hold_verdict, session_data_p); + if (fail_mode_hold_verdict == NGX_OK) { + THREAD_CTX_RETURN_NEXT_FILTER(); + } + THREAD_CTX_RETURN(NGX_ERROR); + } + session_data_p->remaining_messages_to_reply += num_messages_sent; + + ctx->res = ngx_http_cp_reply_receiver( + &session_data_p->remaining_messages_to_reply, + &session_data_p->verdict, + session_data_p->session_id, + request, + &ctx->modifications, + HOLD_DATA + ); + + write_dbg( + DBG_LEVEL_TRACE, + "Successfully receivied response to wait from the nano service. Session ID: %d", + session_data_p->session_id ); return NULL; diff --git a/attachments/nginx/ngx_module/ngx_cp_hook_threads.h b/attachments/nginx/ngx_module/ngx_cp_hook_threads.h index be23896..5619130 100644 --- a/attachments/nginx/ngx_module/ngx_cp_hook_threads.h +++ b/attachments/nginx/ngx_module/ngx_cp_hook_threads.h @@ -121,6 +121,19 @@ void * ngx_http_cp_req_header_handler_thread(void *_ctx); /// void * ngx_http_cp_req_body_filter_thread(void *_ctx); +/// +/// @brief Sends end request transmission to the attachment's service. +/// @details Communicates with the attachment service by sending request body to the attachment's service +/// and modifies _ctx by the received response. +/// @note _ctx needs to be properly initialized by init_thread_ctx() and ngx_chain_t needs of not NULL. +/// @param[in, out] _ctx is of type ngx_http_cp_event_thread_ctx_t. +/// Modifies _ctx res to the following values: +/// - #NGX_OK +/// - #NGX_ERROR +/// @return NULL. +/// +void * ngx_http_cp_req_end_transaction_thread(void *_ctx); + /// /// @brief Sends response headers to the attachment's service. /// @details Communicates with the attachment service by sending response headers to the attachment's service @@ -147,6 +160,21 @@ void * ngx_http_cp_res_header_filter_thread(void *_ctx); /// void * ngx_http_cp_res_body_filter_thread(void *_ctx); +/// +/// @brief Sends a request to the attachment's service to update the earlier provided "WAIT" verdict. +/// @details Communicates with the attachment service by sending a HOLD_DATA request to the attachment's service +/// and modifies _ctx by the received response. +/// @note _ctx needs to be properly initialized by init_thread_ctx() and +/// be called after another call returned wait verdict. +/// @param[in, out] _ctx is of type ngx_http_cp_event_thread_ctx_t. +/// Modifies _ctx res to the following values: +/// - #NGX_OK +/// - #NGX_ERROR +/// Modifies _ctx session data with an updated verdict. +/// @return NULL. +/// +void * ngx_http_cp_hold_verdict_thread(void *_ctx); + /// /// @brief Check if transaction contains headers. /// @param[in] headers ngx_http_headers_in_t struct. diff --git a/attachments/nginx/ngx_module/ngx_cp_hooks.c b/attachments/nginx/ngx_module/ngx_cp_hooks.c index 8014d11..3fcb882 100644 --- a/attachments/nginx/ngx_module/ngx_cp_hooks.c +++ b/attachments/nginx/ngx_module/ngx_cp_hooks.c @@ -144,6 +144,44 @@ was_transaction_timedout(ngx_http_cp_session_data *ctx) return 1; } +ngx_int_t +ngx_http_cp_hold_verdict(struct ngx_http_cp_event_thread_ctx_t *ctx) +{ + ngx_http_cp_session_data *session_data_p = ctx->session_data_p; + for (uint i = 0; i < 3; i++) { + sleep(1); + int res = ngx_cp_run_in_thread_timeout( + ngx_http_cp_hold_verdict_thread, + (void *)ctx, + waiting_for_verdict_thread_timeout_msec, + "ngx_http_cp_hold_verdict_thread" + ); + + if (!res) { + write_dbg( + DBG_LEVEL_DEBUG, + "ngx_http_cp_hold_verdict_thread failed at attempt number=%d", + i + ); + continue; + } + + if (session_data_p->verdict != TRAFFIC_VERDICT_WAIT) { + // Verdict was updated. + write_dbg( + DBG_LEVEL_DEBUG, + "finished ngx_http_cp_hold_verdict successfully. new verdict=%d", + session_data_p->verdict + ); + return 1; + } + } + write_dbg(DBG_LEVEL_TRACE, "Handling Failure with fail %s mode", fail_mode_hold_verdict == NGX_OK ? "open" : "close"); + handle_inspection_failure(inspection_failure_weight, fail_mode_hold_verdict, session_data_p); + session_data_p->verdict = fail_mode_hold_verdict == NGX_OK ? TRAFFIC_VERDICT_ACCEPT : TRAFFIC_VERDICT_DROP; + return 0; +} + ngx_http_cp_verdict_e enforce_sessions_rate() { @@ -498,6 +536,12 @@ ngx_http_cp_req_body_filter(ngx_http_request_t *request, ngx_chain_t *request_bo write_dbg(DBG_LEVEL_DEBUG, "spawn ngx_http_cp_req_body_filter_thread"); // Open threads while unprocessed chain elements still exist, up to num of elements in the chain iterations for (chain_elem = ctx.chain; chain_elem != NULL && ctx.chain; chain_elem = chain_elem->next) { + // Notify if zero-size buf is marked as "memory". This should never happen but if it does we want to know. + if (chain_elem->buf && chain_elem->buf->pos && + (chain_elem->buf->last - chain_elem->buf->pos == 0) && chain_elem->buf->memory == 1) { + write_dbg(DBG_LEVEL_WARNING, + "Warning: encountered request body chain element of size 0 with memory flag enabled"); + } clock_gettime(CLOCK_REALTIME, &hook_time_begin); res = ngx_cp_run_in_thread_timeout( ngx_http_cp_req_body_filter_thread, @@ -529,8 +573,45 @@ ngx_http_cp_req_body_filter(ngx_http_request_t *request, ngx_chain_t *request_bo ctx.res ); - calcProcessingTime(session_data_p, &hook_time_begin, 1); + if (session_data_p->verdict == TRAFFIC_VERDICT_WAIT) { + res = ngx_http_cp_hold_verdict(&ctx); + if (!res) { + session_data_p->verdict = fail_mode_hold_verdict == NGX_OK ? TRAFFIC_VERDICT_ACCEPT : TRAFFIC_VERDICT_DROP; + updateMetricField(HOLD_THREAD_TIMEOUT, 1); + return fail_mode_verdict == NGX_OK ? ngx_http_next_request_body_filter(request, request_body_chain) : NGX_ERROR; + } + } + if (session_data_p->was_request_fully_inspected) { + res = ngx_cp_run_in_thread_timeout( + ngx_http_cp_req_end_transaction_thread, + (void *)&ctx, + req_body_thread_timeout_msec, + "ngx_http_cp_req_end_transaction_thread" + ); + if (!res) { + // failed to execute thread task, or it timed out + session_data_p->verdict = fail_mode_verdict == NGX_OK ? TRAFFIC_VERDICT_ACCEPT : TRAFFIC_VERDICT_DROP; + write_dbg( + DBG_LEVEL_DEBUG, + "req_end_transaction thread failed, returning default fail mode verdict. Session id: %d, verdict: %s", + session_data_p->session_id, + session_data_p->verdict == TRAFFIC_VERDICT_ACCEPT ? "accept" : "drop" + ); + updateMetricField(REQ_BODY_THREAD_TIMEOUT, 1); + return fail_mode_verdict == NGX_OK ? ngx_http_next_request_body_filter(request, request_body_chain) : NGX_ERROR; + } + + write_dbg( + DBG_LEVEL_DEBUG, + "finished ngx_http_cp_req_end_transaction_thread successfully. return=%d next_filter=%d res=%d", + ctx.should_return, + ctx.should_return_next_filter, + ctx.res + ); + } + + calcProcessingTime(session_data_p, &hook_time_begin, 1); if (ctx.should_return_next_filter) { return ngx_http_next_request_body_filter(request, request_body_chain); } @@ -787,7 +868,7 @@ ngx_http_cp_res_body_filter(ngx_http_request_t *request, ngx_chain_t *body_chain if (session_data_p->verdict == TRAFFIC_VERDICT_DROP) request->keepalive = 0; return ngx_http_next_response_body_filter(request, body_chain); } - + session_data_p->response_data.num_body_chunk++; if (body_chain == NULL) { @@ -890,6 +971,12 @@ ngx_http_cp_res_body_filter(ngx_http_request_t *request, ngx_chain_t *body_chain write_dbg(DBG_LEVEL_DEBUG, "spawn ngx_http_cp_res_body_filter_thread"); // Open threads while unprocessed chain elements still exist, up to num of elements in the chain iterations for (chain_elem = ctx.chain; chain_elem != NULL && ctx.chain; chain_elem = chain_elem->next) { + // Notify if zero-size buf is marked as "memory". This should never happen but if it does we want to know. + if (chain_elem->buf && chain_elem->buf->pos && + (chain_elem->buf->last - chain_elem->buf->pos == 0) && chain_elem->buf->memory == 1) { + write_dbg(DBG_LEVEL_WARNING, + "Warning: encountered response body chain element of size 0 with memory flag enabled"); + } clock_gettime(CLOCK_REALTIME, &hook_time_begin); if (!ngx_cp_run_in_thread_timeout( ngx_http_cp_res_body_filter_thread, diff --git a/attachments/nginx/ngx_module/ngx_cp_hooks.h b/attachments/nginx/ngx_module/ngx_cp_hooks.h index 6ed097b..a8c5c00 100644 --- a/attachments/nginx/ngx_module/ngx_cp_hooks.h +++ b/attachments/nginx/ngx_module/ngx_cp_hooks.h @@ -25,6 +25,7 @@ #include "ngx_cp_http_parser.h" #include "nginx_attachment_common.h" +#include "ngx_cp_hook_threads.h" static const int registration_failure_weight = 2; ///< Registration failure weight. static const int inspection_failure_weight = 1; ///< Inspection failure weight. @@ -96,6 +97,16 @@ ngx_int_t ngx_http_cp_res_header_filter(ngx_http_request_t *request); /// ngx_int_t ngx_http_cp_req_header_handler(ngx_http_request_t *request); +/// +/// @brief Sends a request to the nano service to update the verdict. +/// @note Should be called after the nano service provided the verdict TRAFFIC_VERDICT_WAIT to get the updated verdict. +/// @param[in, out] request Event thread context to be updated. +/// @returns ngx_int_t +/// - #1 if request was properly communicated with the nano service and provided an updated response. +/// - #0 otherwise. +/// +ngx_int_t ngx_http_cp_hold_verdict(struct ngx_http_cp_event_thread_ctx_t *ctx); + /// /// @brief Checks if transaction was timed out. /// @param[in, out] ctx diff --git a/attachments/nginx/ngx_module/ngx_cp_initializer.h b/attachments/nginx/ngx_module/ngx_cp_initializer.h index 2c00b12..ed30a7e 100644 --- a/attachments/nginx/ngx_module/ngx_cp_initializer.h +++ b/attachments/nginx/ngx_module/ngx_cp_initializer.h @@ -32,7 +32,7 @@ typedef enum ngx_cp_comm_direction { /// - #NGX_ERROR /// - #NGX_ABORT /// -ngx_int_t ngx_cp_attachment_init_process(); +ngx_int_t ngx_cp_attachment_init_process(ngx_http_request_t *); /// /// @brief Preforms send\receive information to\from the service via a socket. diff --git a/attachments/nginx/ngx_module/ngx_cp_io.c b/attachments/nginx/ngx_module/ngx_cp_io.c index 5110807..c997164 100644 --- a/attachments/nginx/ngx_module/ngx_cp_io.c +++ b/attachments/nginx/ngx_module/ngx_cp_io.c @@ -81,6 +81,7 @@ ngx_http_cp_signal_to_service(uint32_t cur_session_id) /// /// @brief Signals and recieve signal to/from nano service about new session to inspect. /// @param[in] cur_session_id Session's Id. +/// @param[in] chunk_type Chunk type that the attachment is waiting for a response from nano service. /// @returns ngx_int_t /// - #NGX_OK /// - #NGX_ERROR @@ -88,7 +89,7 @@ ngx_http_cp_signal_to_service(uint32_t cur_session_id) /// - #NGX_AGAIN /// static ngx_int_t -ngx_http_cp_wait_for_service(uint32_t cur_session_id) +ngx_http_cp_wait_for_service(uint32_t cur_session_id, ngx_http_chunk_type_e chunk_type) { static int dbg_count = 0; static clock_t clock_start = (clock_t) 0; @@ -97,6 +98,7 @@ ngx_http_cp_wait_for_service(uint32_t cur_session_id) uint32_t reply_from_service; ngx_int_t retry; int is_fail_open_disabled = (inspection_mode != NON_BLOCKING_THREAD); + ngx_uint_t timeout = chunk_type == HOLD_DATA ? fail_open_hold_timeout : fail_open_timeout; res = ngx_http_cp_signal_to_service(cur_session_id); if (res != NGX_OK) return res; @@ -111,7 +113,7 @@ ngx_http_cp_wait_for_service(uint32_t cur_session_id) s_poll.fd = comm_socket; s_poll.events = POLLIN; s_poll.revents = 0; - res = poll(&s_poll, 1, is_fail_open_disabled ? 150 : fail_open_timeout); + res = poll(&s_poll, 1, is_fail_open_disabled ? 150 : timeout); if (res < 0) { // Polling from the nano service has failed. @@ -192,7 +194,9 @@ ngx_http_cp_send_data_to_service( const uint16_t *fragments_sizes, uint8_t num_of_data_elem, uint32_t cur_session_id, - int *was_waiting) + int *was_waiting, + ngx_http_chunk_type_e chunk_type +) { ngx_int_t max_retries; ngx_int_t res = NGX_OK; @@ -209,7 +213,7 @@ ngx_http_cp_send_data_to_service( *was_waiting = 1; } - res = ngx_http_cp_wait_for_service(cur_session_id); + res = ngx_http_cp_wait_for_service(cur_session_id, chunk_type); if (res != NGX_OK && res != NGX_AGAIN) return res; } @@ -428,7 +432,9 @@ ngx_http_cp_reply_receiver( ngx_http_cp_verdict_e *verdict, uint32_t cur_session_id, ngx_http_request_t *request, - ngx_http_cp_modification_list **modification_list) + ngx_http_cp_modification_list **modification_list, + ngx_http_chunk_type_e chunk_type +) { ngx_http_cp_reply_from_service_t *reply_p; ngx_http_cp_modification_list *new_modification = NULL; @@ -446,7 +452,7 @@ ngx_http_cp_reply_receiver( } do { - res = ngx_http_cp_wait_for_service(cur_session_id); + res = ngx_http_cp_wait_for_service(cur_session_id, chunk_type); } while (res == NGX_AGAIN); if (res != NGX_OK) return NGX_ERROR; @@ -554,10 +560,19 @@ ngx_http_cp_reply_receiver( break; } - case TRAFFIC_VERDICT_INSPECT: + case TRAFFIC_VERDICT_INSPECT: { // After an irrelevant verdict, ignore the verdict and continue to the next response. + write_dbg(DBG_LEVEL_TRACE, "Verdict inspect received from the nano service"); updateMetricField(INSPECT_VERDICTS_COUNT, 1); break; + } + + case TRAFFIC_VERDICT_WAIT: { + // After a wait verdict, query the nano agent again to get an updated verdict. + write_dbg(DBG_LEVEL_DEBUG, "Verdict wait received from the nano service"); + updateMetricField(HOLD_VERDICTS_COUNT, 1); + break; + } } free_data_from_service(); @@ -718,7 +733,7 @@ ngx_http_cp_meta_data_sender(ngx_http_request_t *request, uint32_t cur_request_i set_fragment_elem(fragments, fragments_sizes, &client_port, sizeof(client_port), CLIENT_PORT + 2); // Sends all the data to the nano service. - res = ngx_http_cp_send_data_to_service(fragments, fragments_sizes, META_DATA_COUNT + 2, cur_request_id, NULL); + res = ngx_http_cp_send_data_to_service(fragments, fragments_sizes, META_DATA_COUNT + 2, cur_request_id, NULL, fail_open_timeout); if (res != NGX_OK) { // Failed to send the metadata to nano service. if (res == NGX_ERROR && failure_count++ == 5) { @@ -764,7 +779,7 @@ ngx_http_cp_end_transaction_sender( set_fragments_identifiers(fragments, fragments_sizes, (uint16_t *)&end_transaction_type, &cur_request_id); - res = ngx_http_cp_send_data_to_service(fragments, fragments_sizes, end_transaction_num_fragments, cur_request_id, NULL); + res = ngx_http_cp_send_data_to_service(fragments, fragments_sizes, end_transaction_num_fragments, cur_request_id, NULL, fail_open_timeout); if (res != NGX_OK) { return NGX_ERROR; } @@ -773,6 +788,30 @@ ngx_http_cp_end_transaction_sender( return NGX_OK; } +ngx_int_t +ngx_http_cp_wait_sender(uint32_t cur_request_id, ngx_uint_t *num_messages_sent) +{ + static const ngx_uint_t end_transaction_num_fragments = 2; + + char *fragments[end_transaction_num_fragments]; + uint16_t fragments_sizes[end_transaction_num_fragments]; + ngx_http_chunk_type_e transaction_type = HOLD_DATA; + ngx_int_t res; + + set_fragments_identifiers(fragments, fragments_sizes, (uint16_t *)&transaction_type, &cur_request_id); + + write_dbg(DBG_LEVEL_TRACE, "Sending wait event flag for inspection"); + + res = ngx_http_cp_send_data_to_service(fragments, fragments_sizes, end_transaction_num_fragments, cur_request_id, NULL, fail_open_timeout); + if (res != NGX_OK) { + return NGX_ERROR; + } + + write_dbg(DBG_LEVEL_TRACE, "Successfully sent wait event"); + *num_messages_sent = 1; + return NGX_OK; +} + ngx_int_t ngx_http_cp_res_code_sender(uint16_t response_code, uint32_t cur_req_id, ngx_uint_t *num_messages_sent) { @@ -788,7 +827,7 @@ ngx_http_cp_res_code_sender(uint16_t response_code, uint32_t cur_req_id, ngx_uin set_fragments_identifiers(fragments, fragments_sizes, &chunck_type, &cur_req_id); set_fragment_elem(fragments, fragments_sizes, &response_code, sizeof(uint16_t), 2); - if (ngx_http_cp_send_data_to_service(fragments, fragments_sizes, res_code_num_fragments, cur_req_id, NULL) != NGX_OK) { + if (ngx_http_cp_send_data_to_service(fragments, fragments_sizes, res_code_num_fragments, cur_req_id, NULL, fail_open_hold_timeout) != NGX_OK) { return NGX_ERROR; } @@ -812,7 +851,7 @@ ngx_http_cp_content_length_sender(uint64_t content_length_n, uint32_t cur_req_id set_fragments_identifiers(fragments, fragments_sizes, &chunck_type, &cur_req_id); set_fragment_elem(fragments, fragments_sizes, &content_length_val, sizeof(content_length_val), 2); - if (ngx_http_cp_send_data_to_service(fragments, fragments_sizes, content_length_num_fragments, cur_req_id, NULL) != NGX_OK) { + if (ngx_http_cp_send_data_to_service(fragments, fragments_sizes, content_length_num_fragments, cur_req_id, NULL, fail_open_timeout) != NGX_OK) { return NGX_ERROR; } @@ -865,7 +904,7 @@ send_header_bulk( set_fragment_elem(data, data_sizes, &is_last_part, sizeof(is_last_part), 2); set_fragment_elem(data, data_sizes, &bulk_part_index, sizeof(bulk_part_index), 3); - res = ngx_http_cp_send_data_to_service(data, data_sizes, HEADER_DATA_COUNT * num_headers + 4, cur_request_id, NULL); + res = ngx_http_cp_send_data_to_service(data, data_sizes, HEADER_DATA_COUNT * num_headers + 4, cur_request_id, NULL, fail_open_timeout); if (res != NGX_OK) { write_dbg(DBG_LEVEL_TRACE, "Failed to send bulk of %iu headers", num_headers); return NGX_ERROR; @@ -1048,7 +1087,7 @@ ngx_http_cp_body_sender( } // Sending the data to the nano service. res = ngx_http_cp_send_data_to_service(fragments, fragments_sizes, num_body_chunk_fragments, session_data->session_id, - &was_waiting); + &was_waiting, fail_open_timeout); if (res != NGX_OK) { // Failed to send the fragments to the nano service. @@ -1091,7 +1130,7 @@ ngx_http_cp_metric_data_sender() fragments = (char *)&data_to_send; fragments_sizes = sizeof(ngx_http_cp_metric_data_t); - res = ngx_http_cp_send_data_to_service(&fragments, &fragments_sizes, 1, 0, NULL); + res = ngx_http_cp_send_data_to_service(&fragments, &fragments_sizes, 1, 0, NULL, fail_open_timeout); reset_metric_data(); return res; } diff --git a/attachments/nginx/ngx_module/ngx_cp_io.h b/attachments/nginx/ngx_module/ngx_cp_io.h index 8046c24..d662bfe 100644 --- a/attachments/nginx/ngx_module/ngx_cp_io.h +++ b/attachments/nginx/ngx_module/ngx_cp_io.h @@ -47,6 +47,7 @@ extern int comm_socket; ///< Communication socket. /// @param[in] cur_session_id Session's Id. /// @param[in, out] request NGINX request. /// @param[in] modification_list +/// @param[in] chunk_type Chunk type that the attachment is waiting for a response from nano service. /// @returns ngx_int_t /// - #NGX_OK /// - #NGX_HTTP_FORBIDDEN @@ -58,7 +59,8 @@ ngx_http_cp_reply_receiver( ngx_http_cp_verdict_e *verdict, uint32_t cur_session_id, ngx_http_request_t *request, - ngx_http_cp_modification_list **modification_list + ngx_http_cp_modification_list **modification_list, + ngx_http_chunk_type_e chunk_type ); /// @@ -170,6 +172,17 @@ ngx_http_cp_body_sender( ngx_chain_t **next_elem_to_inspect ); +/// +/// @brief Sends HOLD_DATA request to the nano service. +/// @details HOLD_DATA request is a request that asks the nano service to provide with an updated verdict. +/// @param[in] cur_request_id Request session's Id. +/// @param[in, out] num_messages_sent Number of messages sent will be saved onto this parameter. +/// - #NGX_OK +/// - #NGX_ERROR +/// +ngx_int_t +ngx_http_cp_wait_sender(uint32_t cur_request_id, ngx_uint_t *num_messages_sent); + /// /// @brief Checks if reconf is needed and reconfigs if necessary. /// @returns ngx_int_t diff --git a/attachments/nginx/ngx_module/ngx_cp_thread.c b/attachments/nginx/ngx_module/ngx_cp_thread.c index ec3d691..11c4ead 100644 --- a/attachments/nginx/ngx_module/ngx_cp_thread.c +++ b/attachments/nginx/ngx_module/ngx_cp_thread.c @@ -51,7 +51,7 @@ ngx_cp_run_in_thread_timeout(CpThreadRoutine thread_func, void *arg, int timeout void *res = NULL; pthread_t thread; struct timespec ts; - struct ngx_http_cp_event_thread_ctx_t *ctx = (struct ngx_http_cp_event_thread_ctx_t*)arg; + struct ngx_http_cp_event_thread_ctx_t *ctx = (struct ngx_http_cp_event_thread_ctx_t *)arg; if (inspection_mode == NO_THREAD) return ngx_cp_run_without_thread_timeout(thread_func, arg, func_name); diff --git a/attachments/nginx/ngx_module/ngx_cp_utils.c b/attachments/nginx/ngx_module/ngx_cp_utils.c index 81cbfc2..72f989a 100644 --- a/attachments/nginx/ngx_module/ngx_cp_utils.c +++ b/attachments/nginx/ngx_module/ngx_cp_utils.c @@ -81,9 +81,11 @@ ngx_http_cp_sessions_per_minute_limit sessions_per_minute_limit_info = { ngx_uint_t current_config_version = 0; ngx_int_t fail_mode_verdict = NGX_OK; ///< Fail open verdict incase of a timeout. +ngx_int_t fail_mode_hold_verdict = NGX_OK; ///< Fail open verdict incase of a timeout when waiting for wait verdict. ngx_int_t dbg_is_needed = 0; ///< Debug flag. ngx_int_t num_of_connection_attempts = 0; ///< Maximum number of attempted connections. ngx_uint_t fail_open_timeout = 50; ///< Fail open timeout in milliseconds. +ngx_uint_t fail_open_hold_timeout = 150; ///< Fail open wait timeout in milliseconds. ngx_http_cp_verdict_e sessions_per_minute_limit_verdict = TRAFFIC_VERDICT_ACCEPT; ngx_uint_t max_sessions_per_minute = 0; ///< Masimum session per minute. ngx_uint_t req_max_proccessing_ms_time = 3000; ///< Total Request processing timeout in milliseconds. @@ -93,6 +95,7 @@ ngx_uint_t req_header_thread_timeout_msec = 100; ///< Request header processing ngx_uint_t req_body_thread_timeout_msec = 150; ///< Request body processing timeout in milliseconds. ngx_uint_t res_header_thread_timeout_msec = 100; ///< Response header processing timeout in milliseconds. ngx_uint_t res_body_thread_timeout_msec = 150; ///< Response body processing timeout in milliseconds. +ngx_uint_t waiting_for_verdict_thread_timeout_msec = 150; ///< Wait thread processing timeout in milliseconds. ngx_http_inspection_mode_e inspection_mode = NON_BLOCKING_THREAD; ///< Default inspection mode. ngx_uint_t num_of_nginx_ipc_elements = 200; ///< Number of NGINX IPC elements. ngx_msec_t keep_alive_interval_msec = DEFAULT_KEEP_ALIVE_INTERVAL_MSEC; @@ -892,6 +895,10 @@ init_general_config(const char *conf_path) fail_mode_verdict = isFailOpenMode() == 1 ? NGX_OK : NGX_ERROR; fail_open_timeout = getFailOpenTimeout(); + // Setting fail wait open/close + fail_mode_hold_verdict = isFailOpenHoldMode() == 1 ? NGX_OK : NGX_ERROR; + fail_open_hold_timeout = getFailOpenHoldTimeout(); + // Setting attachment's variables. sessions_per_minute_limit_verdict = isFailOpenOnSessionLimit() ? TRAFFIC_VERDICT_ACCEPT : TRAFFIC_VERDICT_DROP; max_sessions_per_minute = getMaxSessionsPerMinute(); @@ -903,6 +910,7 @@ init_general_config(const char *conf_path) req_body_thread_timeout_msec = getReqBodyThreadTimeout(); res_header_thread_timeout_msec = getResHeaderThreadTimeout(); res_body_thread_timeout_msec = getResBodyThreadTimeout(); + waiting_for_verdict_thread_timeout_msec = getWaitingForVerdictThreadTimeout(); num_of_nginx_ipc_elements = getNumOfNginxIpcElements(); keep_alive_interval_msec = (ngx_msec_t) getKeepAliveIntervalMsec(); @@ -917,6 +925,8 @@ init_general_config(const char *conf_path) "debug level: %d, " "failure mode: %s, " "fail mode timeout: %u msec, " + "failure wait mode: %s, " + "fail mode wait timeout: %u msec, " "sessions per minute limit verdict: %s, " "max sessions per minute: %u, " "req max processing time: %u msec, " @@ -926,6 +936,7 @@ init_general_config(const char *conf_path) "req body thread timeout: %u msec, " "res header thread timeout: %u msec, " "res body thread timeout: %u msec, " + "wait thread timeout: %u msec, " "static resources path: %s, " "num of nginx ipc elements: %u, " "keep alive interval msec: %u msec", @@ -933,6 +944,8 @@ init_general_config(const char *conf_path) new_dbg_level, (fail_mode_verdict == NGX_OK ? "fail-open" : "fail-close"), fail_open_timeout, + (fail_mode_hold_verdict == NGX_OK ? "fail-open" : "fail-close"), + fail_open_hold_timeout, sessions_per_minute_limit_verdict == TRAFFIC_VERDICT_ACCEPT ? "Accpet" : "Drop", max_sessions_per_minute, req_max_proccessing_ms_time, @@ -942,6 +955,7 @@ init_general_config(const char *conf_path) req_body_thread_timeout_msec, res_header_thread_timeout_msec, res_body_thread_timeout_msec, + waiting_for_verdict_thread_timeout_msec, getStaticResourcesPath(), num_of_nginx_ipc_elements, keep_alive_interval_msec diff --git a/attachments/nginx/ngx_module/ngx_cp_utils.h b/attachments/nginx/ngx_module/ngx_cp_utils.h index 50882e4..294712d 100644 --- a/attachments/nginx/ngx_module/ngx_cp_utils.h +++ b/attachments/nginx/ngx_module/ngx_cp_utils.h @@ -46,10 +46,12 @@ } extern ngx_int_t fail_mode_verdict; +extern ngx_int_t fail_mode_hold_verdict; extern ngx_int_t dbg_is_needed; extern ngx_int_t num_of_connection_attempts; extern ngx_uint_t content_length_would_change; extern ngx_uint_t fail_open_timeout; +extern ngx_uint_t fail_open_hold_timeout; extern ngx_uint_t req_max_proccessing_ms_time; extern ngx_uint_t res_max_proccessing_ms_time; extern ngx_uint_t registration_thread_timeout_msec; @@ -57,6 +59,7 @@ extern ngx_uint_t req_header_thread_timeout_msec; extern ngx_uint_t req_body_thread_timeout_msec; extern ngx_uint_t res_header_thread_timeout_msec; extern ngx_uint_t res_body_thread_timeout_msec; +extern ngx_uint_t waiting_for_verdict_thread_timeout_msec; extern ngx_http_inspection_mode_e inspection_mode; extern ngx_uint_t num_of_nginx_ipc_elements; diff --git a/attachments/nginx/ngx_module/ngx_modules.c b/attachments/nginx/ngx_module/ngx_modules.c new file mode 100755 index 0000000..82eb10b --- /dev/null +++ b/attachments/nginx/ngx_module/ngx_modules.c @@ -0,0 +1,37 @@ +// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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. + +/// @file ngx_modules.c +/// \brief This file is generated from configuration and hold the data structures connecting the plugin to the server + +#include +#include + +extern ngx_module_t ngx_http_cp_attachment_module; + +ngx_module_t *ngx_modules[] = { + &ngx_http_cp_attachment_module, + NULL +}; + +char *ngx_module_names[] = { + "ngx_http_cp_attachment_module", + NULL +}; + +char *ngx_module_order[] = { + "ngx_http_cp_attachment_module", + "ngx_http_copy_filter_module", + NULL +}; diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 7482955..3c75a10 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -1,2 +1,3 @@ add_subdirectory(shmem_ipc) add_subdirectory(compression) +add_subdirectory(attachments) diff --git a/core/attachments/CMakeLists.txt b/core/attachments/CMakeLists.txt new file mode 100644 index 0000000..0b0657b --- /dev/null +++ b/core/attachments/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(http_configuration) diff --git a/core/attachments/http_configuration/CMakeLists.txt b/core/attachments/http_configuration/CMakeLists.txt new file mode 100644 index 0000000..424fa41 --- /dev/null +++ b/core/attachments/http_configuration/CMakeLists.txt @@ -0,0 +1 @@ +add_library(http_configuration http_configuration.cc) diff --git a/core/attachments/http_configuration/http_configuration.cc b/core/attachments/http_configuration/http_configuration.cc new file mode 100644 index 0000000..ecb001b --- /dev/null +++ b/core/attachments/http_configuration/http_configuration.cc @@ -0,0 +1,220 @@ +// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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 "http_configuration.h" + +#include + +#include "cereal/types/vector.hpp" + +#define DEFAULT_KEEP_ALIVE_INTERVAL_MSEC 30000 + +using namespace std; + +void +DebugConfig::save(cereal::JSONOutputArchive &archive) const +{ + archive( + cereal::make_nvp("clientIp", client), + cereal::make_nvp("listeningIp", server), + cereal::make_nvp("uriPrefix", uri), + cereal::make_nvp("hostName", host), + cereal::make_nvp("httpMethod", method), + cereal::make_nvp("listeningPort", port) + ); +} + +void +DebugConfig::load(cereal::JSONInputArchive &archive) +{ + try { + archive( + cereal::make_nvp("clientIp", client), + cereal::make_nvp("listeningIp", server), + cereal::make_nvp("uriPrefix", uri), + cereal::make_nvp("hostName", host), + cereal::make_nvp("httpMethod", method), + cereal::make_nvp("listeningPort", port) + ); + } catch (const cereal::Exception &) { + client = ""; + server = ""; + uri = ""; + host = ""; + method = ""; + port = 0; + } +} + +bool +DebugConfig::operator==(const DebugConfig &another) const +{ + return + client == another.client && + server == another.server && + port == another.port && + method == another.method && + host == another.host && + uri == another.uri; +} + +int +HttpAttachmentConfiguration::init(const string &conf_file) +{ + try { + ifstream file(conf_file); + cereal::JSONInputArchive ar(file); + load(ar); + return 1; + } catch (exception &e) { + return 0; + } +} + +void +HttpAttachmentConfiguration::save(cereal::JSONOutputArchive &archive) const +{ + archive( + cereal::make_nvp("context_values", dbg), + cereal::make_nvp("ip_ranges", exclude_sources), + cereal::make_nvp("dbg_level", getNumericalValue("dbg_level")), + cereal::make_nvp("static_resources_path", getStringValue("static_resources_path")), + cereal::make_nvp("is_fail_open_mode_enabled", getNumericalValue("is_fail_open_mode_enabled")), + cereal::make_nvp("fail_open_timeout", getNumericalValue("fail_open_timeout")), + cereal::make_nvp("is_fail_open_mode_hold_enabled", getNumericalValue("is_fail_open_mode_hold_enabled")), + cereal::make_nvp("fail_open_hold_timeout", getNumericalValue("fail_open_hold_timeout")), + cereal::make_nvp("sessions_per_minute_limit_verdict", getStringValue("sessions_per_minute_limit_verdict")), + cereal::make_nvp("max_sessions_per_minute", getNumericalValue("max_sessions_per_minute")), + cereal::make_nvp("res_proccessing_timeout_msec", getNumericalValue("res_proccessing_timeout_msec")), + cereal::make_nvp("req_proccessing_timeout_msec", getNumericalValue("req_proccessing_timeout_msec")), + cereal::make_nvp("registration_thread_timeout_msec", getNumericalValue("registration_thread_timeout_msec")), + cereal::make_nvp("req_header_thread_timeout_msec", getNumericalValue("req_header_thread_timeout_msec")), + cereal::make_nvp("req_body_thread_timeout_msec", getNumericalValue("req_body_thread_timeout_msec")), + cereal::make_nvp("res_header_thread_timeout_msec", getNumericalValue("res_header_thread_timeout_msec")), + cereal::make_nvp("res_body_thread_timeout_msec", getNumericalValue("res_body_thread_timeout_msec")), + cereal::make_nvp( + "waiting_for_verdict_thread_timeout_msec", + getNumericalValue("waiting_for_verdict_thread_timeout_msec") + ), + cereal::make_nvp("nginx_inspection_mode", getNumericalValue("inspection_mode")), + cereal::make_nvp("num_of_nginx_ipc_elements", getNumericalValue("num_of_nginx_ipc_elements")), + cereal::make_nvp("keep_alive_interval_msec", getNumericalValue("keep_alive_interval_msec")) + ); +} + +void +HttpAttachmentConfiguration::load(cereal::JSONInputArchive &archive) +{ + try { + archive(cereal::make_nvp("context_values", dbg)); + } catch (const cereal::Exception &) { + dbg = DebugConfig(); + } + + try { + archive(cereal::make_nvp("ip_ranges", exclude_sources)); + } catch (const cereal::Exception &) { + exclude_sources = {}; + } + + try { + string str; + archive(cereal::make_nvp("static_resources_path", str)); + string_values["static_resources_path"] = str; + } catch (const cereal::Exception &) { + string_values.erase("static_resources_path"); + } + + try { + string str; + archive(cereal::make_nvp("sessions_per_minute_limit_verdict", str)); + string_values["sessions_per_minute_limit_verdict"] = str; + } catch (const cereal::Exception &) { + string_values.erase("sessions_per_minute_limit_verdict"); + } + + loadNumericalValue(archive, "dbg_level", 0); + loadNumericalValue(archive, "is_fail_open_mode_enabled", 0); + loadNumericalValue(archive, "fail_open_timeout", 50); + loadNumericalValue(archive, "is_fail_open_mode_hold_enabled", 0); + loadNumericalValue(archive, "fail_open_hold_timeout", 200); + loadNumericalValue(archive, "sessions_per_minute_limit_verdict", 0); + loadNumericalValue(archive, "max_sessions_per_minute", 0); + loadNumericalValue(archive, "res_proccessing_timeout_msec", 3000); + loadNumericalValue(archive, "req_proccessing_timeout_msec", 3000); + loadNumericalValue(archive, "registration_thread_timeout_msec", 100); + loadNumericalValue(archive, "req_header_thread_timeout_msec", 100); + loadNumericalValue(archive, "req_body_thread_timeout_msec", 150); + loadNumericalValue(archive, "res_header_thread_timeout_msec", 100); + loadNumericalValue(archive, "res_body_thread_timeout_msec", 150); + loadNumericalValue(archive, "waiting_for_verdict_thread_timeout_msec", 150); + loadNumericalValue(archive, "nginx_inspection_mode", 0); + loadNumericalValue(archive, "num_of_nginx_ipc_elements", 200); + loadNumericalValue(archive, "keep_alive_interval_msec", DEFAULT_KEEP_ALIVE_INTERVAL_MSEC); + + try { + string user_check_logo_path; + archive(cereal::make_nvp("user_check_logo_path", user_check_logo_path)); + ifstream logo_file(user_check_logo_path); + if (!logo_file.is_open()) { + string_values.erase("user_check_logo"); + } else { + string_values["user_check_logo"] = string( + istreambuf_iterator(logo_file), + istreambuf_iterator() + ); + } + } catch (const cereal::Exception &) { + string_values.erase("user_check_logo"); + } +} + +bool +HttpAttachmentConfiguration::operator==(const HttpAttachmentConfiguration &other) const +{ + return + dbg == other.dbg && + numerical_values == other.numerical_values && + string_values == other.string_values && + exclude_sources == other.exclude_sources; +} + +unsigned int +HttpAttachmentConfiguration::getNumericalValue(const string &key) const +{ + auto elem = numerical_values.find(key); + return elem != numerical_values.end() ? elem->second : 0; +} + +const string & +HttpAttachmentConfiguration::getStringValue(const string &key) const +{ + auto elem = string_values.find(key); + return elem != string_values.end() ? elem->second : empty; +} + +void +HttpAttachmentConfiguration::loadNumericalValue( + cereal::JSONInputArchive &ar, + const string &name, + unsigned int default_value +) +{ + try { + unsigned int value; + ar(cereal::make_nvp(name, value)); + numerical_values[name] = value; + } catch (const cereal::Exception &) { + numerical_values[name] = default_value; + } +} diff --git a/core/compression/compression_utils.cc b/core/compression/compression_utils.cc index 85414ac..2b79d45 100644 --- a/core/compression/compression_utils.cc +++ b/core/compression/compression_utils.cc @@ -105,6 +105,7 @@ static const int zlib_no_flush = Z_NO_FLUSH; struct CompressionStream { CompressionStream() { bzero(&stream, sizeof(z_stream)); } + ~CompressionStream() { fini(); } tuple, bool> decompress(const unsigned char *data, uint32_t size) diff --git a/core/include/attachments/http_configuration.h b/core/include/attachments/http_configuration.h index 8c1bd77..20573cb 100644 --- a/core/include/attachments/http_configuration.h +++ b/core/include/attachments/http_configuration.h @@ -29,7 +29,7 @@ struct DebugConfig std::string client; std::string server; - uint port = 0; + unsigned int port = 0; std::string method; std::string host; std::string uri; @@ -45,21 +45,21 @@ public: bool operator==(const HttpAttachmentConfiguration &other) const; - uint getNumericalValue(const std::string &key) const; + unsigned int getNumericalValue(const std::string &key) const; const std::string & getStringValue(const std::string &key) const; const std::vector & getExcludeSources() const { return exclude_sources; } const DebugConfig & getDebugContext() const { return dbg; } - void setNumericalValue(const std::string &key, uint value) { numerical_values[key] = value; } + void setNumericalValue(const std::string &key, unsigned int value) { numerical_values[key] = value; } void setStringValue(const std::string &key, const std::string &value) { string_values[key] = value; } void setExcludeSources(const std::vector &new_sources) { exclude_sources = new_sources; } void setDebugContext(const DebugConfig &_dbg) { dbg = _dbg; } private: - void loadNumericalValue(cereal::JSONInputArchive &archive, const std::string &name, uint default_value); + void loadNumericalValue(cereal::JSONInputArchive &archive, const std::string &name, unsigned int default_value); DebugConfig dbg; - std::map numerical_values; + std::map numerical_values; std::map string_values; std::vector exclude_sources; std::string empty; diff --git a/core/include/attachments/nginx_attachment_common.h b/core/include/attachments/nginx_attachment_common.h index 08b15a2..01fa278 100644 --- a/core/include/attachments/nginx_attachment_common.h +++ b/core/include/attachments/nginx_attachment_common.h @@ -64,6 +64,7 @@ typedef enum ngx_http_chunk_type RESPONSE_END, CONTENT_LENGTH, METRIC_DATA_FROM_PLUGIN, + HOLD_DATA, COUNT } ngx_http_chunk_type_e; @@ -85,6 +86,7 @@ typedef enum ngx_http_plugin_metric_type IRRELEVANT_VERDICTS_COUNT, RECONF_VERDICTS_COUNT, INSPECT_VERDICTS_COUNT, + HOLD_VERDICTS_COUNT, AVERAGE_OVERALL_PPROCESSING_TIME_UNTIL_VERDICT, MAX_OVERALL_PPROCESSING_TIME_UNTIL_VERDICT, MIN_OVERALL_PPROCESSING_TIME_UNTIL_VERDICT, @@ -103,6 +105,7 @@ typedef enum ngx_http_plugin_metric_type MIN_REQ_BODY_SIZE_UPON_TIMEOUT, RES_HEADER_THREAD_TIMEOUT, RES_BODY_THREAD_TIMEOUT, + HOLD_THREAD_TIMEOUT, AVERAGE_RES_BODY_SIZE_UPON_TIMEOUT, MAX_RES_BODY_SIZE_UPON_TIMEOUT, MIN_RES_BODY_SIZE_UPON_TIMEOUT, @@ -139,7 +142,8 @@ typedef enum ngx_http_cp_verdict TRAFFIC_VERDICT_DROP, TRAFFIC_VERDICT_INJECT, TRAFFIC_VERDICT_IRRELEVANT, - TRAFFIC_VERDICT_RECONF + TRAFFIC_VERDICT_RECONF, + TRAFFIC_VERDICT_WAIT } ngx_http_cp_verdict_e; #ifdef __cplusplus diff --git a/core/include/attachments/nginx_attachment_util.h b/core/include/attachments/nginx_attachment_util.h index 3532ca0..b3240f4 100644 --- a/core/include/attachments/nginx_attachment_util.h +++ b/core/include/attachments/nginx_attachment_util.h @@ -33,12 +33,15 @@ ngx_http_inspection_mode_e getInspectionMode(); unsigned int getNumOfNginxIpcElements(); unsigned int getKeepAliveIntervalMsec(); unsigned int getDbgLevel(); -int isDebugContext(c_str client, c_str server, unsigned int port, c_str method, c_str host , c_str uri); +int isDebugContext(c_str client, c_str server, unsigned int port, c_str method, c_str host, c_str uri); c_str getStaticResourcesPath(); int isFailOpenMode(); unsigned int getFailOpenTimeout(); +int isFailOpenHoldMode(); +unsigned int getFailOpenHoldTimeout(); + unsigned int getMaxSessionsPerMinute(); int isFailOpenOnSessionLimit(); @@ -52,6 +55,8 @@ unsigned int getResProccessingTimeout(); unsigned int getResHeaderThreadTimeout(); unsigned int getResBodyThreadTimeout(); +unsigned int getWaitingForVerdictThreadTimeout(); + int isIPAddress(c_str ip_str); int isSkipSource(c_str ip_str); diff --git a/core/shmem_ipc/shared_ring_queue.c b/core/shmem_ipc/shared_ring_queue.c index 53f5c54..8f152e1 100644 --- a/core/shmem_ipc/shared_ring_queue.c +++ b/core/shmem_ipc/shared_ring_queue.c @@ -26,8 +26,9 @@ #include "shared_ipc_debug.h" -static const uint16_t empty_buff_mgmt_magic = 0xcafe; -static const uint16_t skip_buff_mgmt_magic = 0xbeef; +static const uint16_t empty_buff_mgmt_magic = 0xfffe; +static const uint16_t skip_buff_mgmt_magic = 0xfffd; +static const uint32_t max_write_size = 0xfffc; const uint16_t max_num_of_data_segments = sizeof(DataSegment)/sizeof(uint16_t); char g_rx_location_name[MAX_ONE_WAY_QUEUE_NAME_LENGTH] = ""; @@ -52,11 +53,8 @@ getNumOfDataSegmentsNeeded(uint16_t data_size) } static int -isThereEnoughMemoryInQueue(SharedRingQueue *queue, uint8_t num_of_elem_to_push) +isThereEnoughMemoryInQueue(uint16_t write_pos, uint16_t read_pos, uint8_t num_of_elem_to_push) { - uint16_t write_pos = queue->write_pos; - uint16_t read_pos = queue->read_pos; - uint16_t num_of_data_segments = queue->num_of_data_segments; int res; writeDebug( @@ -65,21 +63,21 @@ isThereEnoughMemoryInQueue(SharedRingQueue *queue, uint8_t num_of_elem_to_push) num_of_elem_to_push, write_pos, read_pos, - num_of_data_segments + g_num_of_data_segments ); - if (num_of_elem_to_push >= num_of_data_segments) { + if (num_of_elem_to_push >= g_num_of_data_segments) { writeDebug(TraceLevel, "Amount of elements to push is larger then amount of available elements in the queue"); return 0; } // add skipped elements during write that does not fit from cur write position till end of queue - if (write_pos + num_of_elem_to_push > num_of_data_segments) { - num_of_elem_to_push += num_of_data_segments - write_pos; + if (write_pos + num_of_elem_to_push > g_num_of_data_segments) { + num_of_elem_to_push += g_num_of_data_segments - write_pos; } // removing the aspect of circularity in queue and simulating as if the queue continued at its end - if (write_pos + num_of_elem_to_push >= num_of_data_segments) { - read_pos += num_of_data_segments; + if (write_pos + num_of_elem_to_push >= g_num_of_data_segments) { + read_pos += g_num_of_data_segments; } res = write_pos + num_of_elem_to_push < read_pos || write_pos >= read_pos; @@ -87,6 +85,22 @@ isThereEnoughMemoryInQueue(SharedRingQueue *queue, uint8_t num_of_elem_to_push) return res; } +static int +isGetPossitionSucceccful(SharedRingQueue *queue, uint16_t *read_pos, uint16_t *write_pos) +{ + if (g_num_of_data_segments == 0) return 0; + + *read_pos = queue->read_pos; + *write_pos = queue->write_pos; + + if (queue->num_of_data_segments != g_num_of_data_segments) return 0; + if (queue->size_of_memory != g_memory_size) return 0; + if (*read_pos > g_num_of_data_segments) return 0; + if (*write_pos > g_num_of_data_segments) return 0; + + return 1; +} + void resetRingQueue(SharedRingQueue *queue, uint16_t num_of_data_segments) { @@ -126,13 +140,14 @@ createSharedRingQueue(const char *shared_location_name, uint16_t num_of_data_seg g_num_of_data_segments = num_of_data_segments; - fd = shm_open(shared_location_name, shmem_fd_flags, S_IRWXU | S_IRWXG | S_IRWXO); + fd = shm_open(shared_location_name, shmem_fd_flags, S_IRUSR | S_IWUSR); if (fd == -1) { writeDebug( WarningLevel, - "createSharedRingQueue: Failed to open shared memory for '%s'. Errno: %d\n", + "createSharedRingQueue: Failed to open shared memory for '%s'. Errno: %d (%s)\n", shared_location_name, - errno + errno, + strerror(errno) ); return NULL; } @@ -257,7 +272,7 @@ dumpRingQueueShmem(SharedRingQueue *queue) writeDebug(WarningLevel, "mgmt_segment:"); buffer_mgmt = (uint16_t *)queue->mgmt_segment.data; - for (segment_idx = 0; segment_idx < max_num_of_data_segments; segment_idx++) { + for (segment_idx = 0; segment_idx < queue->num_of_data_segments; segment_idx++) { writeDebug(WarningLevel, "%s%u", (segment_idx == 0 ? " " : ", "), buffer_mgmt[segment_idx]); } @@ -275,39 +290,44 @@ dumpRingQueueShmem(SharedRingQueue *queue) int peekToQueue(SharedRingQueue *queue, const char **output_buffer, uint16_t *output_buffer_size) { - uint16_t read_pos = queue->read_pos; - const uint16_t num_of_data_segments = queue->num_of_data_segments; + uint16_t read_pos; + uint16_t write_pos; uint16_t *buffer_mgmt = (uint16_t *)queue->mgmt_segment.data; + if (!isGetPossitionSucceccful(queue, &read_pos, &write_pos)) { + writeDebug(WarningLevel, "Corrupted shared memory - cannot peek"); + return -1; + } + writeDebug( TraceLevel, "Reading data from queue. Read index: %u, number of queue elements: %u", read_pos, - num_of_data_segments + g_num_of_data_segments ); - if (isQueueEmpty(queue)) { + if (read_pos == write_pos) { writeDebug(WarningLevel, "peekToQueue: Failed to read from an empty queue\n"); return -1; } - if (read_pos >= num_of_data_segments) { + if (read_pos >= g_num_of_data_segments) { writeDebug( WarningLevel, "peekToQueue: Failed to read from a corrupted queue! (read_pos= %d > num_of_data_segments=%d)\n", read_pos, - num_of_data_segments + g_num_of_data_segments ); return CORRUPTED_SHMEM_ERROR; } if (buffer_mgmt[read_pos] == skip_buff_mgmt_magic) { - for ( ; read_pos < num_of_data_segments && buffer_mgmt[read_pos] == skip_buff_mgmt_magic; ++read_pos) { + for ( ; read_pos < g_num_of_data_segments && buffer_mgmt[read_pos] == skip_buff_mgmt_magic; ++read_pos) { buffer_mgmt[read_pos] = empty_buff_mgmt_magic; } } - if (read_pos == num_of_data_segments) read_pos = 0; + if (read_pos == g_num_of_data_segments) read_pos = 0; *output_buffer_size = buffer_mgmt[read_pos]; *output_buffer = queue->data_segment[read_pos].data; @@ -332,25 +352,42 @@ pushBuffersToQueue( ) { int idx; - const uint16_t num_of_queue_elem = queue->num_of_data_segments; - uint16_t write_pos = queue->write_pos; - uint16_t total_elem_size = 0; + uint32_t large_total_elem_size = 0; + uint16_t read_pos; + uint16_t write_pos; + uint16_t total_elem_size; uint16_t *buffer_mgmt = (uint16_t *)queue->mgmt_segment.data; uint16_t end_pos; uint16_t num_of_segments_to_write; char *current_copy_pos; + if (!isGetPossitionSucceccful(queue, &read_pos, &write_pos)) { + writeDebug(WarningLevel, "Corrupted shared memory - cannot push new buffers"); + return -1; + } + writeDebug( TraceLevel, "Writing new data to queue. write index: %u, number of queue elements: %u, number of elements to push: %u", write_pos, - num_of_queue_elem, + g_num_of_data_segments, num_of_input_buffers ); for (idx = 0; idx < num_of_input_buffers; idx++) { - total_elem_size += input_buffers_sizes[idx]; + large_total_elem_size += input_buffers_sizes[idx]; + + if (large_total_elem_size > max_write_size) { + writeDebug( + WarningLevel, + "Requested write size %u exceeds the %u write limit", + large_total_elem_size, + max_write_size + ); + return -1; + } } + total_elem_size = (uint16_t)large_total_elem_size; num_of_segments_to_write = getNumOfDataSegmentsNeeded(total_elem_size); @@ -362,23 +399,23 @@ pushBuffersToQueue( ); - if (!isThereEnoughMemoryInQueue(queue, num_of_segments_to_write)) { + if (!isThereEnoughMemoryInQueue(write_pos, read_pos, num_of_segments_to_write)) { writeDebug(WarningLevel, "Cannot write to a full queue\n"); return -1; } - if (write_pos >= num_of_queue_elem) { + if (write_pos >= g_num_of_data_segments) { writeDebug( WarningLevel, "Cannot write to a location outside the queue. Write index: %u, number of queue elements: %u", write_pos, - num_of_queue_elem + g_num_of_data_segments ); return -1; } - if (write_pos + num_of_segments_to_write > num_of_queue_elem) { - for ( ; write_pos < num_of_queue_elem; ++write_pos) { + if (write_pos + num_of_segments_to_write > g_num_of_data_segments) { + for ( ; write_pos < g_num_of_data_segments; ++write_pos) { buffer_mgmt[write_pos] = skip_buff_mgmt_magic; } write_pos = 0; @@ -411,8 +448,9 @@ pushBuffersToQueue( buffer_mgmt[write_pos] = skip_buff_mgmt_magic; } - queue->write_pos = write_pos < num_of_queue_elem ? write_pos : 0; - writeDebug(TraceLevel, "Successfully pushed data to queue. New write index: %u", queue->write_pos); + if (write_pos >= g_num_of_data_segments) write_pos = 0; + queue->write_pos = write_pos; + writeDebug(TraceLevel, "Successfully pushed data to queue. New write index: %u", write_pos); return 0; } @@ -427,19 +465,24 @@ int popFromQueue(SharedRingQueue *queue) { uint16_t num_of_read_segments; - uint16_t read_pos = queue->read_pos; + uint16_t read_pos; + uint16_t write_pos; uint16_t end_pos; - uint16_t num_of_data_segments = queue->num_of_data_segments; uint16_t *buffer_mgmt = (uint16_t *)queue->mgmt_segment.data; + if (!isGetPossitionSucceccful(queue, &read_pos, &write_pos)) { + writeDebug(WarningLevel, "Corrupted shared memory - cannot pop data"); + return -1; + } + writeDebug( TraceLevel, "Removing data from queue. new data to queue. Read index: %u, number of queue elements: %u", read_pos, - num_of_data_segments + g_num_of_data_segments ); - if (isQueueEmpty(queue)) { + if (read_pos == write_pos) { writeDebug(TraceLevel, "Cannot pop data from empty queue"); return -1; } @@ -460,16 +503,16 @@ popFromQueue(SharedRingQueue *queue) buffer_mgmt[read_pos] = empty_buff_mgmt_magic; } - if (read_pos < num_of_data_segments && buffer_mgmt[read_pos] == skip_buff_mgmt_magic) { - for ( ; read_pos < num_of_data_segments; ++read_pos ) { + if (read_pos < g_num_of_data_segments && buffer_mgmt[read_pos] == skip_buff_mgmt_magic) { + for ( ; read_pos < g_num_of_data_segments; ++read_pos ) { buffer_mgmt[read_pos] = empty_buff_mgmt_magic; } } - if (read_pos == num_of_data_segments) read_pos = 0; + if (read_pos == g_num_of_data_segments) read_pos = 0; queue->read_pos = read_pos; - writeDebug(TraceLevel, "Successfully popped data from queue. New read index: %u", queue->read_pos); + writeDebug(TraceLevel, "Successfully popped data from queue. New read index: %u", read_pos); return 0; } diff --git a/core/shmem_ipc/shmem_ipc.c b/core/shmem_ipc/shmem_ipc.c index d004da6..e492fe6 100644 --- a/core/shmem_ipc/shmem_ipc.c +++ b/core/shmem_ipc/shmem_ipc.c @@ -50,6 +50,7 @@ debugInitial(int is_error, const char *func, const char *file, int line_num, con va_start(args, fmt); vprintf(fmt, args); va_end(args); + printf("\n"); } void (*debug_int)(int is_error, const char *func, const char *file, int line_num, const char *fmt, ...) = debugInitial; @@ -100,7 +101,7 @@ createOneWayIPCQueue( return NULL; } - if (is_owner && chmod(shmem_path, 0666) == -1) { + if (is_owner && chown(shmem_path, user_id, group_id) == -1) { writeDebug(WarningLevel, "Failed to set the permissions"); destroySharedRingQueue(ring_queue, is_owner, isTowardsOwner(is_owner, is_tx_queue)); return NULL; diff --git a/docker/CMakeLists.txt b/docker/CMakeLists.txt new file mode 100644 index 0000000..97e72b1 --- /dev/null +++ b/docker/CMakeLists.txt @@ -0,0 +1,11 @@ +install(TARGETS ngx_module DESTINATION lib) + +add_custom_command( + OUTPUT ${CMAKE_INSTALL_PREFIX}/nginx-docker.img + COMMAND docker build -t nginx-docker ${CMAKE_INSTALL_PREFIX} + COMMAND docker tag nginx-docker ${OUTPUT_DOCKER_IMAGE} + COMMAND docker push ${OUTPUT_DOCKER_IMAGE} + COMMAND docker image save nginx-docker -o ${CMAKE_INSTALL_PREFIX}/nginx-docker.img +) + +add_custom_target(docker DEPENDS ${CMAKE_INSTALL_PREFIX}/nginx-docker.img) diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..759018e --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,18 @@ +FROM + +USER root + +RUN apk update +RUN apk add --no-cache -u busybox +RUN apk add --no-cache -u zlib +RUN apk add --no-cache libstdc++ + +USER + +COPY lib/libosrc_compression_utils.so /usr/lib/libosrc_compression_utils.so +COPY lib/libosrc_nginx_attachment_util.so /usr/lib/libosrc_nginx_attachment_util.so +COPY lib/libosrc_shmem_ipc.so /usr/lib/libosrc_shmem_ipc.so +COPY lib/libngx_module.so /usr/lib/nginx/modules/ngx_cp_attachment_module.so + +RUN echo "load_module /usr/lib/nginx/modules/ngx_cp_attachment_module.so;"|cat - /etc/nginx/nginx.conf> /tmp/out && mv /tmp/out /etc/nginx/nginx.conf +RUN [ -f /etc/nginx/template/nginx.tmpl ] && echo "load_module /usr/lib/nginx/modules/ngx_cp_attachment_module.so;"|cat - /etc/nginx/template/nginx.tmpl> /tmp/out.tmpl && mv /tmp/out.tmpl /etc/nginx/template/nginx.tmpl diff --git a/external/cereal/archives/json.hpp b/external/cereal/archives/json.hpp index 872b811..f864fb5 100644 --- a/external/cereal/archives/json.hpp +++ b/external/cereal/archives/json.hpp @@ -44,6 +44,7 @@ namespace cereal #ifndef CEREAL_RAPIDJSON_ASSERT #define CEREAL_RAPIDJSON_ASSERT(x) if(!(x)){ \ throw ::cereal::RapidJSONException("rapidjson internal assertion failure: " #x); } +#define RAPIDJSON_ASSERT(x) CEREAL_RAPIDJSON_ASSERT(x) #endif // RAPIDJSON_ASSERT // Enable support for parsing of nan, inf, -inf diff --git a/external/cereal/external/rapidjson/allocators.h b/external/cereal/external/rapidjson/allocators.h index 554dc4a..ddcf478 100644 --- a/external/cereal/external/rapidjson/allocators.h +++ b/external/cereal/external/rapidjson/allocators.h @@ -1,6 +1,6 @@ // 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. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // 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 @@ -12,12 +12,20 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -#ifndef CEREAL_RAPIDJSON_ALLOCATORS_H_ -#define CEREAL_RAPIDJSON_ALLOCATORS_H_ +#ifndef RAPIDJSON_ALLOCATORS_H_ +#define RAPIDJSON_ALLOCATORS_H_ #include "rapidjson.h" +#include "internal/meta.h" -CEREAL_RAPIDJSON_NAMESPACE_BEGIN +#include +#include + +#if RAPIDJSON_HAS_CXX11 +#include +#endif + +RAPIDJSON_NAMESPACE_BEGIN /////////////////////////////////////////////////////////////////////////////// // Allocator @@ -52,6 +60,19 @@ concept Allocator { \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 @@ -64,19 +85,26 @@ public: static const bool kNeedFree = true; void* Malloc(size_t size) { if (size) // behavior of malloc(0) is implementation defined. - return std::malloc(size); + return RAPIDJSON_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); + RAPIDJSON_FREE(originalPtr); return NULL; } - return std::realloc(originalPtr, newSize); + return RAPIDJSON_REALLOC(originalPtr, newSize); + } + static void Free(void *ptr) RAPIDJSON_NOEXCEPT { RAPIDJSON_FREE(ptr); } + + bool operator==(const CrtAllocator&) const RAPIDJSON_NOEXCEPT { + return true; + } + bool operator!=(const CrtAllocator&) const RAPIDJSON_NOEXCEPT { + return false; } - static void Free(void *ptr) { std::free(ptr); } }; /////////////////////////////////////////////////////////////////////////////// @@ -100,16 +128,64 @@ public: */ template class MemoryPoolAllocator { + //! 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. + }; + + struct SharedData { + ChunkHeader *chunkHead; //!< Head of the chunk linked-list. Only the head chunk serves allocation. + BaseAllocator* ownBaseAllocator; //!< base allocator created by this object. + size_t refcount; + bool ownBuffer; + }; + + static const size_t SIZEOF_SHARED_DATA = RAPIDJSON_ALIGN(sizeof(SharedData)); + static const size_t SIZEOF_CHUNK_HEADER = RAPIDJSON_ALIGN(sizeof(ChunkHeader)); + + static inline ChunkHeader *GetChunkHead(SharedData *shared) + { + return reinterpret_cast(reinterpret_cast(shared) + SIZEOF_SHARED_DATA); + } + static inline uint8_t *GetChunkBuffer(SharedData *shared) + { + return reinterpret_cast(shared->chunkHead) + SIZEOF_CHUNK_HEADER; + } + + static const size_t kDefaultChunkCapacity = RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY; //!< Default chunk capacity. + public: static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator) + static const bool kRefCounted = true; //!< Tell users that this allocator is reference counted on copy //! Constructor with chunkSize. /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. \param baseAllocator The allocator for allocating memory chunks. */ + explicit MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : - chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0) + chunk_capacity_(chunkSize), + baseAllocator_(baseAllocator ? baseAllocator : RAPIDJSON_NEW(BaseAllocator)()), + shared_(static_cast(baseAllocator_ ? baseAllocator_->Malloc(SIZEOF_SHARED_DATA + SIZEOF_CHUNK_HEADER) : 0)) { + RAPIDJSON_ASSERT(baseAllocator_ != 0); + RAPIDJSON_ASSERT(shared_ != 0); + if (baseAllocator) { + shared_->ownBaseAllocator = 0; + } + else { + shared_->ownBaseAllocator = baseAllocator_; + } + shared_->chunkHead = GetChunkHead(shared_); + shared_->chunkHead->capacity = 0; + shared_->chunkHead->size = 0; + shared_->chunkHead->next = 0; + shared_->ownBuffer = true; + shared_->refcount = 1; } //! Constructor with user-supplied buffer. @@ -123,41 +199,101 @@ public: \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) + chunk_capacity_(chunkSize), + baseAllocator_(baseAllocator), + shared_(static_cast(AlignBuffer(buffer, size))) { - CEREAL_RAPIDJSON_ASSERT(buffer != 0); - CEREAL_RAPIDJSON_ASSERT(size > sizeof(ChunkHeader)); - chunkHead_ = reinterpret_cast(buffer); - chunkHead_->capacity = size - sizeof(ChunkHeader); - chunkHead_->size = 0; - chunkHead_->next = 0; + RAPIDJSON_ASSERT(size >= SIZEOF_SHARED_DATA + SIZEOF_CHUNK_HEADER); + shared_->chunkHead = GetChunkHead(shared_); + shared_->chunkHead->capacity = size - SIZEOF_SHARED_DATA - SIZEOF_CHUNK_HEADER; + shared_->chunkHead->size = 0; + shared_->chunkHead->next = 0; + shared_->ownBaseAllocator = 0; + shared_->ownBuffer = false; + shared_->refcount = 1; } + MemoryPoolAllocator(const MemoryPoolAllocator& rhs) RAPIDJSON_NOEXCEPT : + chunk_capacity_(rhs.chunk_capacity_), + baseAllocator_(rhs.baseAllocator_), + shared_(rhs.shared_) + { + RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); + ++shared_->refcount; + } + MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) RAPIDJSON_NOEXCEPT + { + RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0); + ++rhs.shared_->refcount; + this->~MemoryPoolAllocator(); + baseAllocator_ = rhs.baseAllocator_; + chunk_capacity_ = rhs.chunk_capacity_; + shared_ = rhs.shared_; + return *this; + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + MemoryPoolAllocator(MemoryPoolAllocator&& rhs) RAPIDJSON_NOEXCEPT : + chunk_capacity_(rhs.chunk_capacity_), + baseAllocator_(rhs.baseAllocator_), + shared_(rhs.shared_) + { + RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0); + rhs.shared_ = 0; + } + MemoryPoolAllocator& operator=(MemoryPoolAllocator&& rhs) RAPIDJSON_NOEXCEPT + { + RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0); + this->~MemoryPoolAllocator(); + baseAllocator_ = rhs.baseAllocator_; + chunk_capacity_ = rhs.chunk_capacity_; + shared_ = rhs.shared_; + rhs.shared_ = 0; + return *this; + } +#endif + //! Destructor. /*! This deallocates all memory chunks, excluding the user-supplied buffer. */ - ~MemoryPoolAllocator() { + ~MemoryPoolAllocator() RAPIDJSON_NOEXCEPT { + if (!shared_) { + // do nothing if moved + return; + } + if (shared_->refcount > 1) { + --shared_->refcount; + return; + } Clear(); - CEREAL_RAPIDJSON_DELETE(ownBaseAllocator_); + BaseAllocator *a = shared_->ownBaseAllocator; + if (shared_->ownBuffer) { + baseAllocator_->Free(shared_); + } + RAPIDJSON_DELETE(a); } - //! Deallocates all memory chunks, excluding the user-supplied buffer. - void Clear() { - while (chunkHead_ && chunkHead_ != userBuffer_) { - ChunkHeader* next = chunkHead_->next; - baseAllocator_->Free(chunkHead_); - chunkHead_ = next; + //! Deallocates all memory chunks, excluding the first/user one. + void Clear() RAPIDJSON_NOEXCEPT { + RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); + for (;;) { + ChunkHeader* c = shared_->chunkHead; + if (!c->next) { + break; + } + shared_->chunkHead = c->next; + baseAllocator_->Free(c); } - if (chunkHead_ && chunkHead_ == userBuffer_) - chunkHead_->size = 0; // Clear user buffer + shared_->chunkHead->size = 0; } //! Computes the total capacity of allocated memory chunks. /*! \return total capacity in bytes. */ - size_t Capacity() const { + size_t Capacity() const RAPIDJSON_NOEXCEPT { + RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); size_t capacity = 0; - for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) + for (ChunkHeader* c = shared_->chunkHead; c != 0; c = c->next) capacity += c->capacity; return capacity; } @@ -165,25 +301,35 @@ public: //! Computes the memory blocks allocated. /*! \return total used bytes. */ - size_t Size() const { + size_t Size() const RAPIDJSON_NOEXCEPT { + RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); size_t size = 0; - for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) + for (ChunkHeader* c = shared_->chunkHead; c != 0; c = c->next) size += c->size; return size; } + //! Whether the allocator is shared. + /*! \return true or false. + */ + bool Shared() const RAPIDJSON_NOEXCEPT { + RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); + return shared_->refcount > 1; + } + //! Allocates a memory block. (concept Allocator) void* Malloc(size_t size) { + RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); if (!size) return NULL; - size = CEREAL_RAPIDJSON_ALIGN(size); - if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity) + size = RAPIDJSON_ALIGN(size); + if (RAPIDJSON_UNLIKELY(shared_->chunkHead->size + size > shared_->chunkHead->capacity)) if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size)) return NULL; - void *buffer = reinterpret_cast(chunkHead_) + CEREAL_RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size; - chunkHead_->size += size; + void *buffer = GetChunkBuffer(shared_) + shared_->chunkHead->size; + shared_->chunkHead->size += size; return buffer; } @@ -192,21 +338,22 @@ public: if (originalPtr == 0) return Malloc(newSize); + RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); if (newSize == 0) return NULL; - originalSize = CEREAL_RAPIDJSON_ALIGN(originalSize); - newSize = CEREAL_RAPIDJSON_ALIGN(newSize); + 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_) + CEREAL_RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) { + if (originalPtr == GetChunkBuffer(shared_) + shared_->chunkHead->size - originalSize) { size_t increment = static_cast(newSize - originalSize); - if (chunkHead_->size + increment <= chunkHead_->capacity) { - chunkHead_->size += increment; + if (shared_->chunkHead->size + increment <= shared_->chunkHead->capacity) { + shared_->chunkHead->size += increment; return originalPtr; } } @@ -222,50 +369,325 @@ public: } //! Frees a memory block (concept Allocator) - static void Free(void *ptr) { (void)ptr; } // Do nothing + static void Free(void *ptr) RAPIDJSON_NOEXCEPT { (void)ptr; } // Do nothing + + //! Compare (equality) with another MemoryPoolAllocator + bool operator==(const MemoryPoolAllocator& rhs) const RAPIDJSON_NOEXCEPT { + RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); + RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0); + return shared_ == rhs.shared_; + } + //! Compare (inequality) with another MemoryPoolAllocator + bool operator!=(const MemoryPoolAllocator& rhs) const RAPIDJSON_NOEXCEPT { + return !operator==(rhs); + } 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_ = CEREAL_RAPIDJSON_NEW(BaseAllocator()); - if (ChunkHeader* chunk = reinterpret_cast(baseAllocator_->Malloc(CEREAL_RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) { + shared_->ownBaseAllocator = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator)(); + if (ChunkHeader* chunk = static_cast(baseAllocator_->Malloc(SIZEOF_CHUNK_HEADER + capacity))) { chunk->capacity = capacity; chunk->size = 0; - chunk->next = chunkHead_; - chunkHead_ = chunk; + chunk->next = shared_->chunkHead; + shared_->chunkHead = chunk; return true; } else return false; } - static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity. + static inline void* AlignBuffer(void* buf, size_t &size) + { + RAPIDJSON_NOEXCEPT_ASSERT(buf != 0); + const uintptr_t mask = sizeof(void*) - 1; + const uintptr_t ubuf = reinterpret_cast(buf); + if (RAPIDJSON_UNLIKELY(ubuf & mask)) { + const uintptr_t abuf = (ubuf + mask) & ~mask; + RAPIDJSON_ASSERT(size >= abuf - ubuf); + buf = reinterpret_cast(abuf); + size -= abuf - ubuf; + } + return buf; + } - //! 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. + SharedData *shared_; //!< The shared data of the allocator }; -CEREAL_RAPIDJSON_NAMESPACE_END +namespace internal { + template + struct IsRefCounted : + public FalseType + { }; + template + struct IsRefCounted::Type> : + public TrueType + { }; +} -#endif // CEREAL_RAPIDJSON_ENCODINGS_H_ +template +inline T* Realloc(A& a, T* old_p, size_t old_n, size_t new_n) +{ + RAPIDJSON_NOEXCEPT_ASSERT(old_n <= std::numeric_limits::max() / sizeof(T) && new_n <= std::numeric_limits::max() / sizeof(T)); + return static_cast(a.Realloc(old_p, old_n * sizeof(T), new_n * sizeof(T))); +} + +template +inline T *Malloc(A& a, size_t n = 1) +{ + return Realloc(a, NULL, 0, n); +} + +template +inline void Free(A& a, T *p, size_t n = 1) +{ + static_cast(Realloc(a, p, n, 0)); +} + +#ifdef __GNUC__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) // std::allocator can safely be inherited +#endif + +template +class StdAllocator : + public std::allocator +{ + typedef std::allocator allocator_type; +#if RAPIDJSON_HAS_CXX11 + typedef std::allocator_traits traits_type; +#else + typedef allocator_type traits_type; +#endif + +public: + typedef BaseAllocator BaseAllocatorType; + + StdAllocator() RAPIDJSON_NOEXCEPT : + allocator_type(), + baseAllocator_() + { } + + StdAllocator(const StdAllocator& rhs) RAPIDJSON_NOEXCEPT : + allocator_type(rhs), + baseAllocator_(rhs.baseAllocator_) + { } + + template + StdAllocator(const StdAllocator& rhs) RAPIDJSON_NOEXCEPT : + allocator_type(rhs), + baseAllocator_(rhs.baseAllocator_) + { } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + StdAllocator(StdAllocator&& rhs) RAPIDJSON_NOEXCEPT : + allocator_type(std::move(rhs)), + baseAllocator_(std::move(rhs.baseAllocator_)) + { } +#endif +#if RAPIDJSON_HAS_CXX11 + using propagate_on_container_move_assignment = std::true_type; + using propagate_on_container_swap = std::true_type; +#endif + + /* implicit */ + StdAllocator(const BaseAllocator& allocator) RAPIDJSON_NOEXCEPT : + allocator_type(), + baseAllocator_(allocator) + { } + + ~StdAllocator() RAPIDJSON_NOEXCEPT + { } + + template + struct rebind { + typedef StdAllocator other; + }; + + typedef typename traits_type::size_type size_type; + typedef typename traits_type::difference_type difference_type; + + typedef typename traits_type::value_type value_type; + typedef typename traits_type::pointer pointer; + typedef typename traits_type::const_pointer const_pointer; + +#if RAPIDJSON_HAS_CXX11 + + typedef typename std::add_lvalue_reference::type &reference; + typedef typename std::add_lvalue_reference::type>::type &const_reference; + + pointer address(reference r) const RAPIDJSON_NOEXCEPT + { + return std::addressof(r); + } + const_pointer address(const_reference r) const RAPIDJSON_NOEXCEPT + { + return std::addressof(r); + } + + size_type max_size() const RAPIDJSON_NOEXCEPT + { + return traits_type::max_size(*this); + } + + template + void construct(pointer p, Args&&... args) + { + traits_type::construct(*this, p, std::forward(args)...); + } + void destroy(pointer p) + { + traits_type::destroy(*this, p); + } + +#else // !RAPIDJSON_HAS_CXX11 + + typedef typename allocator_type::reference reference; + typedef typename allocator_type::const_reference const_reference; + + pointer address(reference r) const RAPIDJSON_NOEXCEPT + { + return allocator_type::address(r); + } + const_pointer address(const_reference r) const RAPIDJSON_NOEXCEPT + { + return allocator_type::address(r); + } + + size_type max_size() const RAPIDJSON_NOEXCEPT + { + return allocator_type::max_size(); + } + + void construct(pointer p, const_reference r) + { + allocator_type::construct(p, r); + } + void destroy(pointer p) + { + allocator_type::destroy(p); + } + +#endif // !RAPIDJSON_HAS_CXX11 + + template + U* allocate(size_type n = 1, const void* = 0) + { + return RAPIDJSON_NAMESPACE::Malloc(baseAllocator_, n); + } + template + void deallocate(U* p, size_type n = 1) + { + RAPIDJSON_NAMESPACE::Free(baseAllocator_, p, n); + } + + pointer allocate(size_type n = 1, const void* = 0) + { + return allocate(n); + } + void deallocate(pointer p, size_type n = 1) + { + deallocate(p, n); + } + +#if RAPIDJSON_HAS_CXX11 + using is_always_equal = std::is_empty; +#endif + + template + bool operator==(const StdAllocator& rhs) const RAPIDJSON_NOEXCEPT + { + return baseAllocator_ == rhs.baseAllocator_; + } + template + bool operator!=(const StdAllocator& rhs) const RAPIDJSON_NOEXCEPT + { + return !operator==(rhs); + } + + //! rapidjson Allocator concept + static const bool kNeedFree = BaseAllocator::kNeedFree; + static const bool kRefCounted = internal::IsRefCounted::Value; + void* Malloc(size_t size) + { + return baseAllocator_.Malloc(size); + } + void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) + { + return baseAllocator_.Realloc(originalPtr, originalSize, newSize); + } + static void Free(void *ptr) RAPIDJSON_NOEXCEPT + { + BaseAllocator::Free(ptr); + } + +private: + template + friend class StdAllocator; // access to StdAllocator.* + + BaseAllocator baseAllocator_; +}; + +#if !RAPIDJSON_HAS_CXX17 // std::allocator deprecated in C++17 +template +class StdAllocator : + public std::allocator +{ + typedef std::allocator allocator_type; + +public: + typedef BaseAllocator BaseAllocatorType; + + StdAllocator() RAPIDJSON_NOEXCEPT : + allocator_type(), + baseAllocator_() + { } + + StdAllocator(const StdAllocator& rhs) RAPIDJSON_NOEXCEPT : + allocator_type(rhs), + baseAllocator_(rhs.baseAllocator_) + { } + + template + StdAllocator(const StdAllocator& rhs) RAPIDJSON_NOEXCEPT : + allocator_type(rhs), + baseAllocator_(rhs.baseAllocator_) + { } + + /* implicit */ + StdAllocator(const BaseAllocator& baseAllocator) RAPIDJSON_NOEXCEPT : + allocator_type(), + baseAllocator_(baseAllocator) + { } + + ~StdAllocator() RAPIDJSON_NOEXCEPT + { } + + template + struct rebind { + typedef StdAllocator other; + }; + + typedef typename allocator_type::value_type value_type; + +private: + template + friend class StdAllocator; // access to StdAllocator.* + + BaseAllocator baseAllocator_; +}; +#endif + +#ifdef __GNUC__ +RAPIDJSON_DIAG_POP +#endif + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_ENCODINGS_H_ diff --git a/external/cereal/external/rapidjson/cursorstreamwrapper.h b/external/cereal/external/rapidjson/cursorstreamwrapper.h new file mode 100644 index 0000000..fd6513d --- /dev/null +++ b/external/cereal/external/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. +// +// 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/external/cereal/external/rapidjson/document.h b/external/cereal/external/rapidjson/document.h index 46faeb1..4f1e246 100644 --- a/external/cereal/external/rapidjson/document.h +++ b/external/cereal/external/rapidjson/document.h @@ -1,6 +1,6 @@ // 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. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // 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 @@ -12,8 +12,8 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -#ifndef CEREAL_RAPIDJSON_DOCUMENT_H_ -#define CEREAL_RAPIDJSON_DOCUMENT_H_ +#ifndef RAPIDJSON_DOCUMENT_H_ +#define RAPIDJSON_DOCUMENT_H_ /*! \file document.h */ @@ -24,35 +24,42 @@ #include "encodedstream.h" #include // placement new #include - -CEREAL_RAPIDJSON_DIAG_PUSH -#ifdef _MSC_VER -CEREAL_RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant -CEREAL_RAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible loss of data +#ifdef __cpp_lib_three_way_comparison +#include #endif +RAPIDJSON_DIAG_PUSH #ifdef __clang__ -CEREAL_RAPIDJSON_DIAG_OFF(padded) -CEREAL_RAPIDJSON_DIAG_OFF(switch-enum) -CEREAL_RAPIDJSON_DIAG_OFF(c++98-compat) +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__ -CEREAL_RAPIDJSON_DIAG_OFF(effc++) -#if __GNUC__ >= 6 -CEREAL_RAPIDJSON_DIAG_OFF(terminate) // ignore throwing CEREAL_RAPIDJSON_ASSERT in CEREAL_RAPIDJSON_NOEXCEPT functions -#endif +RAPIDJSON_DIAG_OFF(effc++) #endif // __GNUC__ -#ifndef CEREAL_RAPIDJSON_NOMEMBERITERATORCLASS -#include // std::iterator, std::random_access_iterator_tag +#ifdef GetObject +// see https://github.com/Tencent/rapidjson/issues/1448 +// a former included windows.h might have defined a macro called GetObject, which affects +// GetObject defined here. This ensures the macro does not get applied +#pragma push_macro("GetObject") +#define RAPIDJSON_WINDOWS_GETOBJECT_WORKAROUND_APPLIED +#undef GetObject #endif -#if CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS -#include // std::move +#ifndef RAPIDJSON_NOMEMBERITERATORCLASS +#include // std::random_access_iterator_tag #endif -CEREAL_RAPIDJSON_NAMESPACE_BEGIN +#if RAPIDJSON_USE_MEMBERSMAP +#include // std::multimap +#endif + +RAPIDJSON_NAMESPACE_BEGIN // Forward declaration. template @@ -61,6 +68,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 ::RAPIDJSON_NAMESPACE::MemoryPoolAllocator<::RAPIDJSON_NAMESPACE::CrtAllocator> +#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 ::RAPIDJSON_NAMESPACE::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. @@ -68,15 +117,51 @@ 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); }; /////////////////////////////////////////////////////////////////////////////// // GenericMemberIterator -#ifndef CEREAL_RAPIDJSON_NOMEMBERITERATORCLASS +#ifndef RAPIDJSON_NOMEMBERITERATORCLASS //! (Constant) member iterator for a JSON object value /*! @@ -91,23 +176,20 @@ struct GenericMember { conversions from iterator values to \c NULL, e.g. from GenericValue::FindMember. - \note Define \c CEREAL_RAPIDJSON_NOMEMBERITERATORCLASS to fall back to a + \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 - : public std::iterator >::Type> { +class GenericMemberIterator { friend class GenericValue; template friend class GenericMemberIterator; typedef GenericMember PlainType; typedef typename internal::MaybeAddConst::Type ValueType; - typedef std::iterator BaseType; public: //! Iterator type itself @@ -117,12 +199,21 @@ public: //! 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 typename BaseType::pointer Pointer; + typedef pointer Pointer; //! Reference to (const) GenericMember - typedef typename BaseType::reference Reference; + typedef reference Reference; //! Signed integer type (e.g. \c ptrdiff_t) - typedef typename BaseType::difference_type DifferenceType; + typedef difference_type DifferenceType; //! Default constructor (singular value) /*! Creates an iterator pointing to no element. @@ -168,12 +259,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 @@ -193,27 +288,29 @@ private: Pointer ptr_; //!< raw pointer }; -#else // CEREAL_RAPIDJSON_NOMEMBERITERATORCLASS +#else // RAPIDJSON_NOMEMBERITERATORCLASS // class-based member iterator implementation disabled, use plain pointers template -struct GenericMemberIterator; +class GenericMemberIterator; //! non-const GenericMemberIterator template -struct GenericMemberIterator { +class GenericMemberIterator { +public: //! use plain pointer as iterator type typedef GenericMember* Iterator; }; //! const GenericMemberIterator template -struct GenericMemberIterator { +class GenericMemberIterator { +public: //! use plain const pointer as iterator type typedef const GenericMember* Iterator; }; -#endif // CEREAL_RAPIDJSON_NOMEMBERITERATORCLASS +#endif // RAPIDJSON_NOMEMBERITERATORCLASS /////////////////////////////////////////////////////////////////////////////// // GenericStringRef @@ -275,7 +372,7 @@ struct GenericStringRef { */ #endif template - GenericStringRef(const CharType (&str)[N]) CEREAL_RAPIDJSON_NOEXCEPT + GenericStringRef(const CharType (&str)[N]) RAPIDJSON_NOEXCEPT : s(str), length(N-1) {} //! Explicitly create string reference from \c const character pointer @@ -300,7 +397,7 @@ struct GenericStringRef { */ #endif explicit GenericStringRef(const CharType* str) - : s(str), length(internal::StrLen(str)){ CEREAL_RAPIDJSON_ASSERT(s != 0); } + : s(str), length(NotNullStrLen(str)) {} //! Create constant string reference from pointer and length #ifndef __clang__ // -Wdocumentation @@ -312,12 +409,10 @@ struct GenericStringRef { */ #endif GenericStringRef(const CharType* str, SizeType len) - : s(str), length(len) { CEREAL_RAPIDJSON_ASSERT(s != 0); } + : s(RAPIDJSON_LIKELY(str) ? str : emptyString), length(len) { RAPIDJSON_ASSERT(str != 0 || len == 0u); } GenericStringRef(const GenericStringRef& rhs) : s(rhs.s), length(rhs.length) {} - GenericStringRef& operator=(const GenericStringRef& rhs) { s = rhs.s; length = rhs.length; } - //! implicit conversion to plain CharType pointer operator const Ch *() const { return s; } @@ -325,11 +420,24 @@ struct GenericStringRef { 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 @@ -344,7 +452,7 @@ private: */ template inline GenericStringRef StringRef(const CharType* str) { - return GenericStringRef(str, internal::StrLen(str)); + return GenericStringRef(str); } //! Mark a character pointer as constant string @@ -367,7 +475,7 @@ inline GenericStringRef StringRef(const CharType* str, size_t length) return GenericStringRef(str, SizeType(length)); } -#if CEREAL_RAPIDJSON_HAS_STDSTRING +#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 @@ -378,7 +486,7 @@ inline GenericStringRef StringRef(const CharType* str, size_t length) \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 CEREAL_RAPIDJSON_HAS_STDSTRING. + \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. */ template inline GenericStringRef StringRef(const std::basic_string& str) { @@ -434,6 +542,26 @@ struct TypeHelper { 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(); } @@ -475,7 +603,7 @@ struct TypeHelper { static ValueType& Set(ValueType& v, const StringType data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); } }; -#if CEREAL_RAPIDJSON_HAS_STDSTRING +#if RAPIDJSON_HAS_STDSTRING template struct TypeHelper > { typedef std::basic_string StringType; @@ -507,7 +635,7 @@ struct TypeHelper { 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&) { v = data; } + static ValueType& Set(ValueType& v, ObjectType data, typename ValueType::AllocatorType&) { return v = data; } }; template @@ -536,7 +664,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. @@ -559,11 +687,11 @@ public: //@{ //! Default constructor creates a null value. - GenericValue() CEREAL_RAPIDJSON_NOEXCEPT : data_() { data_.f.flags = kNullFlag; } + GenericValue() RAPIDJSON_NOEXCEPT : data_() { data_.f.flags = kNullFlag; } -#if CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Move constructor in C++11 - GenericValue(GenericValue&& rhs) CEREAL_RAPIDJSON_NOEXCEPT : data_(rhs.data_) { + GenericValue(GenericValue&& rhs) RAPIDJSON_NOEXCEPT : data_(rhs.data_) { rhs.data_.f.flags = kNullFlag; // give up contents } #endif @@ -572,7 +700,7 @@ private: //! Copy constructor is not permitted. GenericValue(const GenericValue& rhs); -#if CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Moving from a GenericDocument is not permitted. template GenericValue(GenericDocument&& rhs); @@ -589,12 +717,12 @@ public: \param type Type of the value. \note Default content for number is zero. */ - explicit GenericValue(Type type) CEREAL_RAPIDJSON_NOEXCEPT : data_() { - static const uint16_t defaultFlags[7] = { + explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_() { + static const uint16_t defaultFlags[] = { kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag, kNumberAnyFlag }; - CEREAL_RAPIDJSON_ASSERT(type <= kNumberType); + RAPIDJSON_NOEXCEPT_ASSERT(type >= kNullType && type <= kNumberType); data_.f.flags = defaultFlags[type]; // Use ShortString to store empty string. @@ -607,10 +735,40 @@ public: \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< typename SourceAllocator > - GenericValue(const GenericValue& rhs, Allocator & allocator); + template + GenericValue(const GenericValue& rhs, Allocator& allocator, bool copyConstStrings = false) { + switch (rhs.GetType()) { + case kObjectType: + DoCopyMembers(rhs, allocator, copyConstStrings); + 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 @@ -618,65 +776,68 @@ public: 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 CEREAL_RAPIDJSON_DOXYGEN_RUNNING // hide SFINAE from Doxygen +#ifndef RAPIDJSON_DOXYGEN_RUNNING // hide SFINAE from Doxygen template - explicit GenericValue(T b, CEREAL_RAPIDJSON_ENABLEIF((internal::IsSame))) CEREAL_RAPIDJSON_NOEXCEPT // See #472 + explicit GenericValue(T b, RAPIDJSON_ENABLEIF((internal::IsSame))) RAPIDJSON_NOEXCEPT // See #472 #else - explicit GenericValue(bool b) CEREAL_RAPIDJSON_NOEXCEPT + explicit GenericValue(bool b) RAPIDJSON_NOEXCEPT #endif : data_() { // safe-guard against failing SFINAE - CEREAL_RAPIDJSON_STATIC_ASSERT((internal::IsSame::Value)); + RAPIDJSON_STATIC_ASSERT((internal::IsSame::Value)); data_.f.flags = b ? kTrueFlag : kFalseFlag; } //! Constructor for int value. - explicit GenericValue(int i) CEREAL_RAPIDJSON_NOEXCEPT : data_() { + 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) CEREAL_RAPIDJSON_NOEXCEPT : data_() { + 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) CEREAL_RAPIDJSON_NOEXCEPT : data_() { + 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) & CEREAL_RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) + if (!(static_cast(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) data_.f.flags |= kUintFlag; - if (!(static_cast(i64) & CEREAL_RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) + if (!(static_cast(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) data_.f.flags |= kIntFlag; } - else if (i64 >= static_cast(CEREAL_RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) + else if (i64 >= static_cast(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) data_.f.flags |= kIntFlag; } //! Constructor for uint64_t value. - explicit GenericValue(uint64_t u64) CEREAL_RAPIDJSON_NOEXCEPT : data_() { + explicit GenericValue(uint64_t u64) RAPIDJSON_NOEXCEPT : data_() { data_.n.u64 = u64; data_.f.flags = kNumberUint64Flag; - if (!(u64 & CEREAL_RAPIDJSON_UINT64_C2(0x80000000, 0x00000000))) + if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000))) data_.f.flags |= kInt64Flag; - if (!(u64 & CEREAL_RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) + if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) data_.f.flags |= kUintFlag; - if (!(u64 & CEREAL_RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) + if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) data_.f.flags |= kIntFlag; } //! Constructor for double value. - explicit GenericValue(double d) CEREAL_RAPIDJSON_NOEXCEPT : data_() { data_.n.d = d; data_.f.flags = kNumberDoubleFlag; } + 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) CEREAL_RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(StringRef(s, length)); } + 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) CEREAL_RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(s); } + 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); } @@ -684,9 +845,9 @@ public: //! Constructor for copy-string (i.e. do make a copy of string) GenericValue(const Ch*s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); } -#if CEREAL_RAPIDJSON_HAS_STDSTRING +#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 CEREAL_RAPIDJSON_HAS_STDSTRING. + /*! \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 @@ -697,7 +858,7 @@ public: \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) CEREAL_RAPIDJSON_NOEXCEPT : data_(a.value_.data_) { + GenericValue(Array a) RAPIDJSON_NOEXCEPT : data_(a.value_.data_) { a.value_.data_ = Data(); a.value_.data_.f.flags = kArrayFlag; } @@ -708,7 +869,7 @@ public: \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) CEREAL_RAPIDJSON_NOEXCEPT : data_(o.value_.data_) { + GenericValue(Object o) RAPIDJSON_NOEXCEPT : data_(o.value_.data_) { o.value_.data_ = Data(); o.value_.data_.f.flags = kObjectFlag; } @@ -717,25 +878,30 @@ public: /*! Need to destruct elements of array, members of object, or copy-string. */ ~GenericValue() { - if (Allocator::kNeedFree) { // Shortcut by Allocator's trait + // With RAPIDJSON_USE_MEMBERSMAP, the maps need to be destroyed to release + // their Allocator if it's refcounted (e.g. MemoryPoolAllocator). + if (Allocator::kNeedFree || (RAPIDJSON_USE_MEMBERSMAP+0 && + internal::IsRefCounted::Value)) { switch(data_.f.flags) { case kArrayFlag: { GenericValue* e = GetElementsPointer(); for (GenericValue* v = e; v != e + data_.a.size; ++v) v->~GenericValue(); - Allocator::Free(e); + if (Allocator::kNeedFree) { // Shortcut by Allocator's trait + Allocator::Free(e); + } } break; case kObjectFlag: - for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) - m->~Member(); - Allocator::Free(GetMembersPointer()); + DoFreeMembers(); break; case kCopyStringFlag: - Allocator::Free(const_cast(GetStringPointer())); + if (Allocator::kNeedFree) { // Shortcut by Allocator's trait + Allocator::Free(const_cast(GetStringPointer())); + } break; default: @@ -752,16 +918,22 @@ public: //! Assignment with move semantics. /*! \param rhs Source of the assignment. It will become a null value after assignment. */ - GenericValue& operator=(GenericValue& rhs) CEREAL_RAPIDJSON_NOEXCEPT { - CEREAL_RAPIDJSON_ASSERT(this != &rhs); - this->~GenericValue(); - RawAssign(rhs); + GenericValue& operator=(GenericValue& rhs) RAPIDJSON_NOEXCEPT { + if (RAPIDJSON_LIKELY(this != &rhs)) { + // Can't destroy "this" before assigning "rhs", otherwise "rhs" + // could be used after free if it's an sub-Value of "this", + // hence the temporary danse. + GenericValue temp; + temp.RawAssign(rhs); + this->~GenericValue(); + RawAssign(temp); + } return *this; } -#if CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Move assignment in C++11 - GenericValue& operator=(GenericValue&& rhs) CEREAL_RAPIDJSON_NOEXCEPT { + GenericValue& operator=(GenericValue&& rhs) RAPIDJSON_NOEXCEPT { return *this = rhs.Move(); } #endif @@ -771,7 +943,7 @@ public: \note This overload is needed to avoid clashes with the generic primitive type assignment overload below. \see GenericStringRef, operator=(T) */ - GenericValue& operator=(StringRefType str) CEREAL_RAPIDJSON_NOEXCEPT { + GenericValue& operator=(StringRefType str) RAPIDJSON_NOEXCEPT { GenericValue s(str); return *this = s; } @@ -789,7 +961,7 @@ public: use \ref SetBool() instead. */ template - CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::IsPointer), (GenericValue&)) + RAPIDJSON_DISABLEIF_RETURN((internal::IsPointer), (GenericValue&)) operator=(T value) { GenericValue v(value); return *this = v; @@ -800,12 +972,13 @@ public: \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) { - CEREAL_RAPIDJSON_ASSERT(static_cast(this) != static_cast(&rhs)); + 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); + new (this) GenericValue(rhs, allocator, copyConstStrings); return *this; } @@ -814,7 +987,7 @@ public: \param other Another value. \note Constant complexity. */ - GenericValue& Swap(GenericValue& other) CEREAL_RAPIDJSON_NOEXCEPT { + GenericValue& Swap(GenericValue& other) RAPIDJSON_NOEXCEPT { GenericValue temp; temp.RawAssign(*this); RawAssign(other); @@ -834,11 +1007,11 @@ public: \endcode \see Swap() */ - friend inline void swap(GenericValue& a, GenericValue& b) CEREAL_RAPIDJSON_NOEXCEPT { a.Swap(b); } + friend inline void swap(GenericValue& a, GenericValue& b) RAPIDJSON_NOEXCEPT { a.Swap(b); } //! Prepare Value for move semantics /*! \return *this */ - GenericValue& Move() CEREAL_RAPIDJSON_NOEXCEPT { return *this; } + GenericValue& Move() RAPIDJSON_NOEXCEPT { return *this; } //@} //!@name Equal-to and not-equal-to operators @@ -846,7 +1019,7 @@ public: //! Equal-to operator /*! \note If an object contains duplicated named member, comparing equality with any object is always \c false. - \note Linear time complexity (number of all values in the subtree and total lengths of all strings). + \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 { @@ -893,9 +1066,9 @@ public: //! Equal-to operator with const C-string pointer bool operator==(const Ch* rhs) const { return *this == GenericValue(StringRef(rhs)); } -#if CEREAL_RAPIDJSON_HAS_STDSTRING +#if RAPIDJSON_HAS_STDSTRING //! Equal-to operator with string object - /*! \note Requires the definition of the preprocessor symbol \ref CEREAL_RAPIDJSON_HAS_STDSTRING. + /*! \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 @@ -903,7 +1076,7 @@ public: //! 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 CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr,internal::IsGenericValue >), (bool)) operator==(const T& rhs) const { return *this == GenericValue(rhs); } + 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) @@ -917,18 +1090,20 @@ public: //! Not-equal-to operator with arbitrary types /*! \return !(*this == rhs) */ - template CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator!=(const T& rhs) const { return !(*this == rhs); } + template RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator!=(const T& rhs) const { return !(*this == rhs); } +#ifndef __cpp_impl_three_way_comparison //! Equal-to operator with arbitrary types (symmetric version) /*! \return (rhs == lhs) */ - template friend CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator==(const T& lhs, const GenericValue& rhs) { 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 CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); } + template friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); } //@} +#endif //!@name Type //@{ @@ -955,14 +1130,14 @@ public: uint64_t u = GetUint64(); volatile double d = static_cast(u); return (d >= 0.0) - && (d < static_cast(std::numeric_limits::max())) + && (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())) + 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 @@ -979,8 +1154,8 @@ public: 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())) + 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 @@ -998,7 +1173,7 @@ public: //!@name Bool //@{ - bool GetBool() const { CEREAL_RAPIDJSON_ASSERT(IsBool()); return data_.f.flags == kTrueFlag; } + 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; } @@ -1013,10 +1188,13 @@ public: GenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; } //! Get the number of members in the object. - SizeType MemberCount() const { CEREAL_RAPIDJSON_ASSERT(IsObject()); return data_.o.size; } + 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 { CEREAL_RAPIDJSON_ASSERT(IsObject()); return data_.o.size == 0; } + bool ObjectEmpty() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size == 0; } //! Get a value from an object associated with the name. /*! \pre IsObject() == true @@ -1028,12 +1206,12 @@ public: \note Linear time complexity. */ template - CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >),(GenericValue&)) operator[](T* name) { + RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >),(GenericValue&)) operator[](T* name) { GenericValue n(StringRef(name)); return (*this)[n]; } template - CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >),(const GenericValue&)) operator[](T* name) const { return const_cast(*this)[name]; } + 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 @@ -1050,21 +1228,36 @@ public: if (member != MemberEnd()) return member->value; else { - CEREAL_RAPIDJSON_ASSERT(false); // see above note + 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)]; +#if RAPIDJSON_HAS_CXX11 + // Use thread-local storage to prevent races between threads. + // Use static buffer and placement-new to prevent destruction, with + // alignas() to ensure proper alignment. + alignas(GenericValue) thread_local static char buffer[sizeof(GenericValue)]; return *new (buffer) GenericValue(); +#elif defined(_MSC_VER) && _MSC_VER < 1900 + // There's no way to solve both thread locality and proper alignment + // simultaneously. + __declspec(thread) static char buffer[sizeof(GenericValue)]; + return *new (buffer) GenericValue(); +#elif defined(__GNUC__) || defined(__clang__) + // This will generate -Wexit-time-destructors in clang, but that's + // better than having under-alignment. + __thread static GenericValue buffer; + return buffer; +#else + // Don't know what compiler this is, so don't know how to ensure + // thread-locality. + static GenericValue buffer; + return buffer; +#endif } } template const GenericValue& operator[](const GenericValue& name) const { return const_cast(*this)[name]; } -#if CEREAL_RAPIDJSON_HAS_STDSTRING +#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))]; } @@ -1072,16 +1265,28 @@ public: //! Const member iterator /*! \pre IsObject() == true */ - ConstMemberIterator MemberBegin() const { CEREAL_RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer()); } + ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer()); } //! Const \em past-the-end member iterator /*! \pre IsObject() == true */ - ConstMemberIterator MemberEnd() const { CEREAL_RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer() + data_.o.size); } + ConstMemberIterator MemberEnd() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer() + data_.o.size); } //! Member iterator /*! \pre IsObject() == true */ - MemberIterator MemberBegin() { CEREAL_RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer()); } + MemberIterator MemberBegin() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer()); } //! \em Past-the-end member iterator /*! \pre IsObject() == true */ - MemberIterator MemberEnd() { CEREAL_RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer() + data_.o.size); } + 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()); + DoReserveMembers(newCapacity, allocator); + return *this; + } //! Check whether a member exists in the object. /*! @@ -1093,7 +1298,7 @@ public: */ bool HasMember(const Ch* name) const { return FindMember(name) != MemberEnd(); } -#if CEREAL_RAPIDJSON_HAS_STDSTRING +#if RAPIDJSON_HAS_STDSTRING //! Check whether a member exists in the object with string object. /*! \param name Member name to be searched. @@ -1151,17 +1356,13 @@ public: */ template MemberIterator FindMember(const GenericValue& name) { - CEREAL_RAPIDJSON_ASSERT(IsObject()); - CEREAL_RAPIDJSON_ASSERT(name.IsString()); - MemberIterator member = MemberBegin(); - for ( ; member != MemberEnd(); ++member) - if (name.StringEqual(member->name)) - break; - return member; + RAPIDJSON_ASSERT(IsObject()); + RAPIDJSON_ASSERT(name.IsString()); + return DoFindMember(name); } template ConstMemberIterator FindMember(const GenericValue& name) const { return const_cast(*this).FindMember(name); } -#if CEREAL_RAPIDJSON_HAS_STDSTRING +#if RAPIDJSON_HAS_STDSTRING //! Find member by string object name. /*! \param name Member name to be searched. @@ -1184,25 +1385,9 @@ public: \note Amortized Constant time complexity. */ GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) { - CEREAL_RAPIDJSON_ASSERT(IsObject()); - CEREAL_RAPIDJSON_ASSERT(name.IsString()); - - ObjectData& o = data_.o; - if (o.size >= o.capacity) { - if (o.capacity == 0) { - o.capacity = kDefaultObjectCapacity; - SetMembersPointer(reinterpret_cast(allocator.Malloc(o.capacity * sizeof(Member)))); - } - else { - SizeType oldCapacity = o.capacity; - o.capacity += (oldCapacity + 1) / 2; // grow by factor 1.5 - SetMembersPointer(reinterpret_cast(allocator.Realloc(GetMembersPointer(), oldCapacity * sizeof(Member), o.capacity * sizeof(Member)))); - } - } - Member* members = GetMembersPointer(); - members[o.size].name.RawAssign(name); - members[o.size].value.RawAssign(value); - o.size++; + RAPIDJSON_ASSERT(IsObject()); + RAPIDJSON_ASSERT(name.IsString()); + DoAddMember(name, value, allocator); return *this; } @@ -1220,7 +1405,7 @@ public: return AddMember(name, v, allocator); } -#if CEREAL_RAPIDJSON_HAS_STDSTRING +#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. @@ -1254,13 +1439,13 @@ public: \note Amortized Constant time complexity. */ template - CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&)) + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&)) AddMember(GenericValue& name, T value, Allocator& allocator) { GenericValue v(value); return AddMember(name, v, allocator); } -#if CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS GenericValue& AddMember(GenericValue&& name, GenericValue&& value, Allocator& allocator) { return AddMember(name, value, allocator); } @@ -1274,7 +1459,7 @@ public: GenericValue n(name); return AddMember(n, value, allocator); } -#endif // CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS +#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Add a member (name-value pair) to the object. @@ -1324,7 +1509,7 @@ public: \note Amortized Constant time complexity. */ template - CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&)) + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&)) AddMember(StringRefType name, T value, Allocator& allocator) { GenericValue n(name); return AddMember(n, value, allocator); @@ -1335,10 +1520,8 @@ public: \note Linear time complexity. */ void RemoveAllMembers() { - CEREAL_RAPIDJSON_ASSERT(IsObject()); - for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) - m->~Member(); - data_.o.size = 0; + RAPIDJSON_ASSERT(IsObject()); + DoClearMembers(); } //! Remove a member in object by its name. @@ -1354,7 +1537,7 @@ public: return RemoveMember(n); } -#if CEREAL_RAPIDJSON_HAS_STDSTRING +#if RAPIDJSON_HAS_STDSTRING bool RemoveMember(const std::basic_string& name) { return RemoveMember(GenericValue(StringRef(name))); } #endif @@ -1378,18 +1561,11 @@ public: \note Constant time complexity. */ MemberIterator RemoveMember(MemberIterator m) { - CEREAL_RAPIDJSON_ASSERT(IsObject()); - CEREAL_RAPIDJSON_ASSERT(data_.o.size > 0); - CEREAL_RAPIDJSON_ASSERT(GetMembersPointer() != 0); - CEREAL_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; + RAPIDJSON_ASSERT(IsObject()); + RAPIDJSON_ASSERT(data_.o.size > 0); + RAPIDJSON_ASSERT(GetMembersPointer() != 0); + RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd()); + return DoRemoveMember(m); } //! Remove a member from an object by iterator. @@ -1415,19 +1591,13 @@ public: \note Linear time complexity. */ MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) { - CEREAL_RAPIDJSON_ASSERT(IsObject()); - CEREAL_RAPIDJSON_ASSERT(data_.o.size > 0); - CEREAL_RAPIDJSON_ASSERT(GetMembersPointer() != 0); - CEREAL_RAPIDJSON_ASSERT(first >= MemberBegin()); - CEREAL_RAPIDJSON_ASSERT(first <= last); - CEREAL_RAPIDJSON_ASSERT(last <= MemberEnd()); - - MemberIterator pos = MemberBegin() + (first - MemberBegin()); - for (MemberIterator itr = pos; itr != last; ++itr) - itr->~Member(); - std::memmove(&*pos, &*last, static_cast(MemberEnd() - last) * sizeof(Member)); - data_.o.size -= static_cast(last - first); - return pos; + 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()); + return DoEraseMembers(first, last); } //! Erase a member in object by its name. @@ -1440,7 +1610,7 @@ public: return EraseMember(n); } -#if CEREAL_RAPIDJSON_HAS_STDSTRING +#if RAPIDJSON_HAS_STDSTRING bool EraseMember(const std::basic_string& name) { return EraseMember(GenericValue(StringRef(name))); } #endif @@ -1455,8 +1625,10 @@ public: return false; } - Object GetObject() { CEREAL_RAPIDJSON_ASSERT(IsObject()); return Object(*this); } - ConstObject GetObject() const { CEREAL_RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); } + Object GetObject() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); } + Object GetObj() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); } + ConstObject GetObject() const { RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); } + ConstObject GetObj() const { RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); } //@} @@ -1468,20 +1640,20 @@ public: GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; } //! Get the number of elements in array. - SizeType Size() const { CEREAL_RAPIDJSON_ASSERT(IsArray()); return data_.a.size; } + SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; } //! Get the capacity of array. - SizeType Capacity() const { CEREAL_RAPIDJSON_ASSERT(IsArray()); return data_.a.capacity; } + SizeType Capacity() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.capacity; } //! Check whether the array is empty. - bool Empty() const { CEREAL_RAPIDJSON_ASSERT(IsArray()); return data_.a.size == 0; } + 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() { - CEREAL_RAPIDJSON_ASSERT(IsArray()); + RAPIDJSON_ASSERT(IsArray()); GenericValue* e = GetElementsPointer(); for (GenericValue* v = e; v != e + data_.a.size; ++v) v->~GenericValue(); @@ -1494,18 +1666,18 @@ public: \see operator[](T*) */ GenericValue& operator[](SizeType index) { - CEREAL_RAPIDJSON_ASSERT(IsArray()); - CEREAL_RAPIDJSON_ASSERT(index < data_.a.size); + 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() { CEREAL_RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer(); } + ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer(); } //! \em Past-the-end element iterator /*! \pre IsArray() == true */ - ValueIterator End() { CEREAL_RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer() + data_.a.size; } + ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer() + data_.a.size; } //! Constant element iterator /*! \pre IsArray() == true */ ConstValueIterator Begin() const { return const_cast(*this).Begin(); } @@ -1520,7 +1692,7 @@ public: \note Linear time complexity. */ GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) { - CEREAL_RAPIDJSON_ASSERT(IsArray()); + 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; @@ -1539,18 +1711,18 @@ public: \note Amortized constant time complexity. */ GenericValue& PushBack(GenericValue& value, Allocator& allocator) { - CEREAL_RAPIDJSON_ASSERT(IsArray()); + 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 CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS GenericValue& PushBack(GenericValue&& value, Allocator& allocator) { return PushBack(value, allocator); } -#endif // CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS +#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. @@ -1583,7 +1755,7 @@ public: \note Amortized constant time complexity. */ template - CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&)) + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&)) PushBack(T value, Allocator& allocator) { GenericValue v(value); return PushBack(v, allocator); @@ -1594,8 +1766,8 @@ public: \note Constant time complexity. */ GenericValue& PopBack() { - CEREAL_RAPIDJSON_ASSERT(IsArray()); - CEREAL_RAPIDJSON_ASSERT(!Empty()); + RAPIDJSON_ASSERT(IsArray()); + RAPIDJSON_ASSERT(!Empty()); GetElementsPointer()[--data_.a.size].~GenericValue(); return *this; } @@ -1620,43 +1792,43 @@ public: \note Linear time complexity. */ ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) { - CEREAL_RAPIDJSON_ASSERT(IsArray()); - CEREAL_RAPIDJSON_ASSERT(data_.a.size > 0); - CEREAL_RAPIDJSON_ASSERT(GetElementsPointer() != 0); - CEREAL_RAPIDJSON_ASSERT(first >= Begin()); - CEREAL_RAPIDJSON_ASSERT(first <= last); - CEREAL_RAPIDJSON_ASSERT(last <= End()); + 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(pos, last, static_cast(End() - last) * sizeof(GenericValue)); + 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() { CEREAL_RAPIDJSON_ASSERT(IsArray()); return Array(*this); } - ConstArray GetArray() const { CEREAL_RAPIDJSON_ASSERT(IsArray()); return ConstArray(*this); } + Array GetArray() { RAPIDJSON_ASSERT(IsArray()); return Array(*this); } + ConstArray GetArray() const { RAPIDJSON_ASSERT(IsArray()); return ConstArray(*this); } //@} //!@name Number //@{ - int GetInt() const { CEREAL_RAPIDJSON_ASSERT(data_.f.flags & kIntFlag); return data_.n.i.i; } - unsigned GetUint() const { CEREAL_RAPIDJSON_ASSERT(data_.f.flags & kUintFlag); return data_.n.u.u; } - int64_t GetInt64() const { CEREAL_RAPIDJSON_ASSERT(data_.f.flags & kInt64Flag); return data_.n.i64; } - uint64_t GetUint64() const { CEREAL_RAPIDJSON_ASSERT(data_.f.flags & kUint64Flag); return data_.n.u64; } + 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 { - CEREAL_RAPIDJSON_ASSERT(IsNumber()); + 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) - CEREAL_RAPIDJSON_ASSERT((data_.f.flags & kUint64Flag) != 0); return static_cast(data_.n.u64); // uint64_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. @@ -1671,19 +1843,19 @@ public: 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(f); return *this; } + GenericValue& SetFloat(float f) { this->~GenericValue(); new (this) GenericValue(static_cast(f)); return *this; } //@} //!@name String //@{ - const Ch* GetString() const { CEREAL_RAPIDJSON_ASSERT(IsString()); return (data_.f.flags & kInlineStrFlag) ? data_.ss.str : GetStringPointer(); } + const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return DataString(data_); } //! 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 { CEREAL_RAPIDJSON_ASSERT(IsString()); return ((data_.f.flags & kInlineStrFlag) ? (data_.ss.GetLength()) : data_.s.length); } + SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return DataStringLength(data_); } //! 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. @@ -1710,7 +1882,7 @@ public: \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) { this->~GenericValue(); SetStringRaw(StringRef(s, length), allocator); return *this; } + 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. @@ -1718,17 +1890,25 @@ public: \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(s, internal::StrLen(s), allocator); } + GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(StringRef(s), allocator); } -#if CEREAL_RAPIDJSON_HAS_STDSTRING + //! 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 CEREAL_RAPIDJSON_HAS_STDSTRING. + \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. */ - GenericValue& SetString(const std::basic_string& s, Allocator& allocator) { return SetString(s.data(), SizeType(s.size()), allocator); } + GenericValue& SetString(const std::basic_string& s, Allocator& allocator) { return SetString(StringRef(s), allocator); } #endif //@} @@ -1772,22 +1952,22 @@ public: case kTrueType: return handler.Bool(true); case kObjectType: - if (CEREAL_RAPIDJSON_UNLIKELY(!handler.StartObject())) + if (RAPIDJSON_UNLIKELY(!handler.StartObject())) return false; for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) { - CEREAL_RAPIDJSON_ASSERT(m->name.IsString()); // User may change the type of name by MemberIterator. - if (CEREAL_RAPIDJSON_UNLIKELY(!handler.Key(m->name.GetString(), m->name.GetStringLength(), (m->name.data_.f.flags & kCopyFlag) != 0))) + 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 (CEREAL_RAPIDJSON_UNLIKELY(!m->value.Accept(handler))) + if (RAPIDJSON_UNLIKELY(!m->value.Accept(handler))) return false; } return handler.EndObject(data_.o.size); case kArrayType: - if (CEREAL_RAPIDJSON_UNLIKELY(!handler.StartArray())) + if (RAPIDJSON_UNLIKELY(!handler.StartArray())) return false; - for (const GenericValue* v = Begin(); v != End(); ++v) - if (CEREAL_RAPIDJSON_UNLIKELY(!v->Accept(handler))) + for (ConstValueIterator v = Begin(); v != End(); ++v) + if (RAPIDJSON_UNLIKELY(!v->Accept(handler))) return false; return handler.EndArray(data_.a.size); @@ -1795,7 +1975,7 @@ public: return handler.String(GetString(), GetStringLength(), (data_.f.flags & kCopyFlag) != 0); default: - CEREAL_RAPIDJSON_ASSERT(GetType() == kNumberType); + 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); @@ -1822,30 +2002,31 @@ private: // 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, + // These casts are added to suppress the warning on MSVC about bitwise operations between enums of different types. + kTrueFlag = static_cast(kTrueType) | static_cast(kBoolFlag), + kFalseFlag = static_cast(kFalseType) | static_cast(kBoolFlag), + kNumberIntFlag = static_cast(kNumberType) | static_cast(kNumberFlag | kIntFlag | kInt64Flag), + kNumberUintFlag = static_cast(kNumberType) | static_cast(kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag), + kNumberInt64Flag = static_cast(kNumberType) | static_cast(kNumberFlag | kInt64Flag), + kNumberUint64Flag = static_cast(kNumberType) | static_cast(kNumberFlag | kUint64Flag), + kNumberDoubleFlag = static_cast(kNumberType) | static_cast(kNumberFlag | kDoubleFlag), + kNumberAnyFlag = static_cast(kNumberType) | static_cast(kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag), + kConstStringFlag = static_cast(kStringType) | static_cast(kStringFlag), + kCopyStringFlag = static_cast(kStringType) | static_cast(kStringFlag | kCopyFlag), + kShortStringFlag = static_cast(kStringType) | static_cast(kStringFlag | kCopyFlag | kInlineStrFlag), kObjectFlag = kObjectType, kArrayFlag = kArrayType, 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 CEREAL_RAPIDJSON_48BITPOINTER_OPTIMIZATION +#if RAPIDJSON_48BITPOINTER_OPTIMIZATION char payload[sizeof(SizeType) * 2 + 6]; // 2 x SizeType + lower 48-bit pointer -#elif CEREAL_RAPIDJSON_64BIT +#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 @@ -1866,7 +2047,7 @@ private: // 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 CEREAL_RAPIDJSON_48BITPOINTER_OPTIMIZATION=1 inline (for `UTF8`-encoded strings). + // 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]; @@ -1878,7 +2059,7 @@ private: // By using proper binary layout, retrieval of different integer types do not need conversions. union Number { -#if CEREAL_RAPIDJSON_ENDIAN == CEREAL_RAPIDJSON_LITTLEENDIAN +#if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN struct I { int i; char padding[4]; @@ -1921,14 +2102,301 @@ private: ObjectData o; ArrayData a; Flag f; - }; // 16 bytes in 32-bit mode, 24 bytes in 64-bit mode, 16 bytes in 64-bit with CEREAL_RAPIDJSON_48BITPOINTER_OPTIMIZATION + }; // 16 bytes in 32-bit mode, 24 bytes in 64-bit mode, 16 bytes in 64-bit with RAPIDJSON_48BITPOINTER_OPTIMIZATION - CEREAL_RAPIDJSON_FORCEINLINE const Ch* GetStringPointer() const { return CEREAL_RAPIDJSON_GETPOINTER(Ch, data_.s.str); } - CEREAL_RAPIDJSON_FORCEINLINE const Ch* SetStringPointer(const Ch* str) { return CEREAL_RAPIDJSON_SETPOINTER(Ch, data_.s.str, str); } - CEREAL_RAPIDJSON_FORCEINLINE GenericValue* GetElementsPointer() const { return CEREAL_RAPIDJSON_GETPOINTER(GenericValue, data_.a.elements); } - CEREAL_RAPIDJSON_FORCEINLINE GenericValue* SetElementsPointer(GenericValue* elements) { return CEREAL_RAPIDJSON_SETPOINTER(GenericValue, data_.a.elements, elements); } - CEREAL_RAPIDJSON_FORCEINLINE Member* GetMembersPointer() const { return CEREAL_RAPIDJSON_GETPOINTER(Member, data_.o.members); } - CEREAL_RAPIDJSON_FORCEINLINE Member* SetMembersPointer(Member* members) { return CEREAL_RAPIDJSON_SETPOINTER(Member, data_.o.members, members); } + static RAPIDJSON_FORCEINLINE const Ch* DataString(const Data& data) { + return (data.f.flags & kInlineStrFlag) ? data.ss.str : RAPIDJSON_GETPOINTER(Ch, data.s.str); + } + static RAPIDJSON_FORCEINLINE SizeType DataStringLength(const Data& data) { + return (data.f.flags & kInlineStrFlag) ? data.ss.GetLength() : data.s.length; + } + + 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); } + +#if RAPIDJSON_USE_MEMBERSMAP + + struct MapTraits { + struct Less { + bool operator()(const Data& s1, const Data& s2) const { + SizeType n1 = DataStringLength(s1), n2 = DataStringLength(s2); + int cmp = std::memcmp(DataString(s1), DataString(s2), sizeof(Ch) * (n1 < n2 ? n1 : n2)); + return cmp < 0 || (cmp == 0 && n1 < n2); + } + }; + typedef std::pair Pair; + typedef std::multimap > Map; + typedef typename Map::iterator Iterator; + }; + typedef typename MapTraits::Map Map; + typedef typename MapTraits::Less MapLess; + typedef typename MapTraits::Pair MapPair; + typedef typename MapTraits::Iterator MapIterator; + + // + // Layout of the members' map/array, re(al)located according to the needed capacity: + // + // {Map*}<>{capacity}<>{Member[capacity]}<>{MapIterator[capacity]} + // + // (where <> stands for the RAPIDJSON_ALIGN-ment, if needed) + // + + static RAPIDJSON_FORCEINLINE size_t GetMapLayoutSize(SizeType capacity) { + return RAPIDJSON_ALIGN(sizeof(Map*)) + + RAPIDJSON_ALIGN(sizeof(SizeType)) + + RAPIDJSON_ALIGN(capacity * sizeof(Member)) + + capacity * sizeof(MapIterator); + } + + static RAPIDJSON_FORCEINLINE SizeType &GetMapCapacity(Map* &map) { + return *reinterpret_cast(reinterpret_cast(&map) + + RAPIDJSON_ALIGN(sizeof(Map*))); + } + + static RAPIDJSON_FORCEINLINE Member* GetMapMembers(Map* &map) { + return reinterpret_cast(reinterpret_cast(&map) + + RAPIDJSON_ALIGN(sizeof(Map*)) + + RAPIDJSON_ALIGN(sizeof(SizeType))); + } + + static RAPIDJSON_FORCEINLINE MapIterator* GetMapIterators(Map* &map) { + return reinterpret_cast(reinterpret_cast(&map) + + RAPIDJSON_ALIGN(sizeof(Map*)) + + RAPIDJSON_ALIGN(sizeof(SizeType)) + + RAPIDJSON_ALIGN(GetMapCapacity(map) * sizeof(Member))); + } + + static RAPIDJSON_FORCEINLINE Map* &GetMap(Member* members) { + RAPIDJSON_ASSERT(members != 0); + return *reinterpret_cast(reinterpret_cast(members) - + RAPIDJSON_ALIGN(sizeof(SizeType)) - + RAPIDJSON_ALIGN(sizeof(Map*))); + } + + // Some compilers' debug mechanisms want all iterators to be destroyed, for their accounting.. + RAPIDJSON_FORCEINLINE MapIterator DropMapIterator(MapIterator& rhs) { +#if RAPIDJSON_HAS_CXX11 + MapIterator ret = std::move(rhs); +#else + MapIterator ret = rhs; +#endif + rhs.~MapIterator(); + return ret; + } + + Map* &DoReallocMap(Map** oldMap, SizeType newCapacity, Allocator& allocator) { + Map **newMap = static_cast(allocator.Malloc(GetMapLayoutSize(newCapacity))); + GetMapCapacity(*newMap) = newCapacity; + if (!oldMap) { + *newMap = new (allocator.Malloc(sizeof(Map))) Map(MapLess(), allocator); + } + else { + *newMap = *oldMap; + size_t count = (*oldMap)->size(); + std::memcpy(static_cast(GetMapMembers(*newMap)), + static_cast(GetMapMembers(*oldMap)), + count * sizeof(Member)); + MapIterator *oldIt = GetMapIterators(*oldMap), + *newIt = GetMapIterators(*newMap); + while (count--) { + new (&newIt[count]) MapIterator(DropMapIterator(oldIt[count])); + } + Allocator::Free(oldMap); + } + return *newMap; + } + + RAPIDJSON_FORCEINLINE Member* DoAllocMembers(SizeType capacity, Allocator& allocator) { + return GetMapMembers(DoReallocMap(0, capacity, allocator)); + } + + void DoReserveMembers(SizeType newCapacity, Allocator& allocator) { + ObjectData& o = data_.o; + if (newCapacity > o.capacity) { + Member* oldMembers = GetMembersPointer(); + Map **oldMap = oldMembers ? &GetMap(oldMembers) : 0, + *&newMap = DoReallocMap(oldMap, newCapacity, allocator); + RAPIDJSON_SETPOINTER(Member, o.members, GetMapMembers(newMap)); + o.capacity = newCapacity; + } + } + + template + MemberIterator DoFindMember(const GenericValue& name) { + if (Member* members = GetMembersPointer()) { + Map* &map = GetMap(members); + MapIterator mit = map->find(reinterpret_cast(name.data_)); + if (mit != map->end()) { + return MemberIterator(&members[mit->second]); + } + } + return MemberEnd(); + } + + void DoClearMembers() { + if (Member* members = GetMembersPointer()) { + Map* &map = GetMap(members); + MapIterator* mit = GetMapIterators(map); + for (SizeType i = 0; i < data_.o.size; i++) { + map->erase(DropMapIterator(mit[i])); + members[i].~Member(); + } + data_.o.size = 0; + } + } + + void DoFreeMembers() { + if (Member* members = GetMembersPointer()) { + GetMap(members)->~Map(); + for (SizeType i = 0; i < data_.o.size; i++) { + members[i].~Member(); + } + if (Allocator::kNeedFree) { // Shortcut by Allocator's trait + Map** map = &GetMap(members); + Allocator::Free(*map); + Allocator::Free(map); + } + } + } + +#else // !RAPIDJSON_USE_MEMBERSMAP + + RAPIDJSON_FORCEINLINE Member* DoAllocMembers(SizeType capacity, Allocator& allocator) { + return Malloc(allocator, capacity); + } + + void DoReserveMembers(SizeType newCapacity, Allocator& allocator) { + ObjectData& o = data_.o; + if (newCapacity > o.capacity) { + Member* newMembers = Realloc(allocator, GetMembersPointer(), o.capacity, newCapacity); + RAPIDJSON_SETPOINTER(Member, o.members, newMembers); + o.capacity = newCapacity; + } + } + + template + MemberIterator DoFindMember(const GenericValue& name) { + MemberIterator member = MemberBegin(); + for ( ; member != MemberEnd(); ++member) + if (name.StringEqual(member->name)) + break; + return member; + } + + void DoClearMembers() { + for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) + m->~Member(); + data_.o.size = 0; + } + + void DoFreeMembers() { + for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) + m->~Member(); + Allocator::Free(GetMembersPointer()); + } + +#endif // !RAPIDJSON_USE_MEMBERSMAP + + void DoAddMember(GenericValue& name, GenericValue& value, Allocator& allocator) { + ObjectData& o = data_.o; + if (o.size >= o.capacity) + DoReserveMembers(o.capacity ? (o.capacity + (o.capacity + 1) / 2) : kDefaultObjectCapacity, allocator); + Member* members = GetMembersPointer(); + Member* m = members + o.size; + m->name.RawAssign(name); + m->value.RawAssign(value); +#if RAPIDJSON_USE_MEMBERSMAP + Map* &map = GetMap(members); + MapIterator* mit = GetMapIterators(map); + new (&mit[o.size]) MapIterator(map->insert(MapPair(m->name.data_, o.size))); +#endif + ++o.size; + } + + MemberIterator DoRemoveMember(MemberIterator m) { + ObjectData& o = data_.o; + Member* members = GetMembersPointer(); +#if RAPIDJSON_USE_MEMBERSMAP + Map* &map = GetMap(members); + MapIterator* mit = GetMapIterators(map); + SizeType mpos = static_cast(&*m - members); + map->erase(DropMapIterator(mit[mpos])); +#endif + MemberIterator last(members + (o.size - 1)); + if (o.size > 1 && m != last) { +#if RAPIDJSON_USE_MEMBERSMAP + new (&mit[mpos]) MapIterator(DropMapIterator(mit[&*last - members])); + mit[mpos]->second = mpos; +#endif + *m = *last; // Move the last one to this place + } + else { + m->~Member(); // Only one left, just destroy + } + --o.size; + return m; + } + + MemberIterator DoEraseMembers(ConstMemberIterator first, ConstMemberIterator last) { + ObjectData& o = data_.o; + MemberIterator beg = MemberBegin(), + pos = beg + (first - beg), + end = MemberEnd(); +#if RAPIDJSON_USE_MEMBERSMAP + Map* &map = GetMap(GetMembersPointer()); + MapIterator* mit = GetMapIterators(map); +#endif + for (MemberIterator itr = pos; itr != last; ++itr) { +#if RAPIDJSON_USE_MEMBERSMAP + map->erase(DropMapIterator(mit[itr - beg])); +#endif + itr->~Member(); + } +#if RAPIDJSON_USE_MEMBERSMAP + if (first != last) { + // Move remaining members/iterators + MemberIterator next = pos + (last - first); + for (MemberIterator itr = pos; next != end; ++itr, ++next) { + std::memcpy(static_cast(&*itr), &*next, sizeof(Member)); + SizeType mpos = static_cast(itr - beg); + new (&mit[mpos]) MapIterator(DropMapIterator(mit[next - beg])); + mit[mpos]->second = mpos; + } + } +#else + std::memmove(static_cast(&*pos), &*last, + static_cast(end - last) * sizeof(Member)); +#endif + o.size -= static_cast(last - first); + return pos; + } + + template + void DoCopyMembers(const GenericValue& rhs, Allocator& allocator, bool copyConstStrings) { + RAPIDJSON_ASSERT(rhs.GetType() == kObjectType); + + data_.f.flags = kObjectFlag; + SizeType count = rhs.data_.o.size; + Member* lm = DoAllocMembers(count, allocator); + const typename GenericValue::Member* rm = rhs.GetMembersPointer(); +#if RAPIDJSON_USE_MEMBERSMAP + Map* &map = GetMap(lm); + MapIterator* mit = GetMapIterators(map); +#endif + 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); +#if RAPIDJSON_USE_MEMBERSMAP + new (&mit[i]) MapIterator(map->insert(MapPair(lm[i].name.data_, i))); +#endif + } + data_.o.size = data_.o.capacity = count; + SetMembersPointer(lm); + } // Initialize this value as array with initial data, without calling destructor. void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) { @@ -1936,7 +2404,7 @@ private: if (count) { GenericValue* e = static_cast(allocator.Malloc(count * sizeof(GenericValue))); SetElementsPointer(e); - std::memcpy(e, values, count * sizeof(GenericValue)); + std::memcpy(static_cast(e), values, count * sizeof(GenericValue)); } else SetElementsPointer(0); @@ -1947,9 +2415,16 @@ private: void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) { data_.f.flags = kObjectFlag; if (count) { - Member* m = static_cast(allocator.Malloc(count * sizeof(Member))); + Member* m = DoAllocMembers(count, allocator); SetMembersPointer(m); - std::memcpy(m, members, count * sizeof(Member)); + std::memcpy(static_cast(m), members, count * sizeof(Member)); +#if RAPIDJSON_USE_MEMBERSMAP + Map* &map = GetMap(m); + MapIterator* mit = GetMapIterators(map); + for (SizeType i = 0; i < count; i++) { + new (&mit[i]) MapIterator(map->insert(MapPair(m[i].name.data_, i))); + } +#endif } else SetMembersPointer(0); @@ -1957,7 +2432,7 @@ private: } //! Initialize this value as constant string, without calling destructor. - void SetStringRaw(StringRefType s) CEREAL_RAPIDJSON_NOEXCEPT { + void SetStringRaw(StringRefType s) RAPIDJSON_NOEXCEPT { data_.f.flags = kConstStringFlag; SetStringPointer(s); data_.s.length = s.length; @@ -1981,7 +2456,7 @@ private: } //! Assignment without calling destructor - void RawAssign(GenericValue& rhs) CEREAL_RAPIDJSON_NOEXCEPT { + void RawAssign(GenericValue& rhs) RAPIDJSON_NOEXCEPT { data_ = rhs.data_; // data_.f.flags = rhs.data_.f.flags; rhs.data_.f.flags = kNullFlag; @@ -1989,8 +2464,8 @@ private: template bool StringEqual(const GenericValue& rhs) const { - CEREAL_RAPIDJSON_ASSERT(IsString()); - CEREAL_RAPIDJSON_ASSERT(rhs.IsString()); + RAPIDJSON_ASSERT(IsString()); + RAPIDJSON_ASSERT(rhs.IsString()); const SizeType len1 = GetStringLength(); const SizeType len2 = rhs.GetStringLength(); @@ -2020,12 +2495,13 @@ 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. typedef GenericValue ValueType; //!< Value type of the document. typedef Allocator AllocatorType; //!< Allocator type from template parameter. + typedef StackAllocator StackAllocatorType; //!< StackAllocator type from template parameter. //! Constructor /*! Creates an empty document of specified type. @@ -2038,7 +2514,7 @@ public: GenericValue(type), allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_() { if (!allocator_) - ownAllocator_ = allocator_ = CEREAL_RAPIDJSON_NEW(Allocator()); + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); } //! Constructor @@ -2051,12 +2527,12 @@ public: allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_() { if (!allocator_) - ownAllocator_ = allocator_ = CEREAL_RAPIDJSON_NEW(Allocator()); + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); } -#if CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Move constructor in C++11 - GenericDocument(GenericDocument&& rhs) CEREAL_RAPIDJSON_NOEXCEPT + GenericDocument(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT : ValueType(std::forward(rhs)), // explicit cast to avoid prohibited move from Document allocator_(rhs.allocator_), ownAllocator_(rhs.ownAllocator_), @@ -2070,12 +2546,19 @@ public: #endif ~GenericDocument() { + // Clear the ::ValueType before ownAllocator is destroyed, ~ValueType() + // runs last and may access its elements or members which would be freed + // with an allocator like MemoryPoolAllocator (CrtAllocator does not + // free its data when destroyed, but MemoryPoolAllocator does). + if (ownAllocator_) { + ValueType::SetNull(); + } Destroy(); } -#if CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Move assignment in C++11 - GenericDocument& operator=(GenericDocument&& rhs) CEREAL_RAPIDJSON_NOEXCEPT + 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. @@ -2103,7 +2586,7 @@ public: \note Constant complexity. \see GenericValue::Swap */ - GenericDocument& Swap(GenericDocument& rhs) CEREAL_RAPIDJSON_NOEXCEPT { + GenericDocument& Swap(GenericDocument& rhs) RAPIDJSON_NOEXCEPT { ValueType::Swap(rhs); stack_.Swap(rhs.stack_); internal::Swap(allocator_, rhs.allocator_); @@ -2112,6 +2595,10 @@ public: 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: @@ -2124,7 +2611,7 @@ public: \endcode \see Swap() */ - friend inline void swap(GenericDocument& a, GenericDocument& b) CEREAL_RAPIDJSON_NOEXCEPT { a.Swap(b); } + 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. @@ -2135,7 +2622,7 @@ public: GenericDocument& Populate(Generator& g) { ClearStackOnExit scope(*this); if (g(*this)) { - CEREAL_RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object + 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; @@ -2158,7 +2645,7 @@ public: ClearStackOnExit scope(*this); parseResult_ = reader.template Parse(is, *this); if (parseResult_) { - CEREAL_RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object + 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; @@ -2219,7 +2706,7 @@ public: */ template GenericDocument& Parse(const typename SourceEncoding::Ch* str) { - CEREAL_RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); + RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); GenericStringStream s(str); return ParseStream(s); } @@ -2242,8 +2729,8 @@ public: template GenericDocument& Parse(const typename SourceEncoding::Ch* str, size_t length) { - CEREAL_RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); - MemoryStream ms(static_cast(str), length * sizeof(typename SourceEncoding::Ch)); + RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); + MemoryStream ms(reinterpret_cast(str), length * sizeof(typename SourceEncoding::Ch)); EncodedInputStream is(ms); ParseStream(is); return *this; @@ -2258,7 +2745,7 @@ public: return Parse(str, length); } -#if CEREAL_RAPIDJSON_HAS_STDSTRING +#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) @@ -2273,14 +2760,14 @@ public: GenericDocument& Parse(const std::basic_string& str) { return Parse(str); } -#endif // CEREAL_RAPIDJSON_HAS_STDSTRING +#endif // RAPIDJSON_HAS_STDSTRING //!@} //!@name Handling parse errors //!@{ - //! Whether a parse error has occured in the last parsing. + //! Whether a parse error has occurred in the last parsing. bool HasParseError() const { return parseResult_.IsError(); } //! Get the \ref ParseErrorCode of last parsing. @@ -2306,7 +2793,7 @@ public: //! Get the allocator of this document. Allocator& GetAllocator() { - CEREAL_RAPIDJSON_ASSERT(allocator_); + RAPIDJSON_ASSERT(allocator_); return *allocator_; } @@ -2388,7 +2875,7 @@ private: } void Destroy() { - CEREAL_RAPIDJSON_DELETE(ownAllocator_); + RAPIDJSON_DELETE(ownAllocator_); } static const size_t kDefaultStackCapacity = 1024; @@ -2401,39 +2888,11 @@ private: //! GenericDocument with UTF8 encoding typedef GenericDocument > Document; -// defined here due to the dependency on GenericDocument -template -template -inline -GenericValue::GenericValue(const GenericValue& rhs, Allocator& allocator) -{ - switch (rhs.GetType()) { - case kObjectType: - case kArrayType: { // perform deep copy via SAX Handler - GenericDocument d(&allocator); - rhs.Accept(d); - RawAssign(*d.stack_.template Pop(1)); - } - break; - case kStringType: - if (rhs.data_.f.flags == kConstStringFlag) { - 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; - } -} //! 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 CEREAL_RAPIDJSON_HAS_CXX11_RANGE_FOR=1. + 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 { @@ -2454,6 +2913,7 @@ public: GenericArray& operator=(const GenericArray& rhs) { value_ = rhs.value_; return *this; } ~GenericArray() {} + operator ValueType&() const { return value_; } SizeType Size() const { return value_.Size(); } SizeType Capacity() const { return value_.Capacity(); } bool Empty() const { return value_.Empty(); } @@ -2463,16 +2923,16 @@ public: 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 CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS GenericArray PushBack(ValueType&& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } -#endif // CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS +#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS GenericArray PushBack(StringRefType value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } - template CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (const GenericArray&)) PushBack(T 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 CEREAL_RAPIDJSON_HAS_CXX11_RANGE_FOR +#if RAPIDJSON_HAS_CXX11_RANGE_FOR ValueIterator begin() const { return value_.Begin(); } ValueIterator end() const { return value_.End(); } #endif @@ -2486,7 +2946,7 @@ private: //! 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 CEREAL_RAPIDJSON_HAS_CXX11_RANGE_FOR=1. + 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 { @@ -2509,43 +2969,46 @@ public: GenericObject& operator=(const GenericObject& rhs) { value_ = rhs.value_; return *this; } ~GenericObject() {} + operator ValueType&() const { return value_; } 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 CEREAL_RAPIDJSON_HAS_STDSTRING +#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 CEREAL_RAPIDJSON_HAS_STDSTRING +#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 CEREAL_RAPIDJSON_HAS_STDSTRING +#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 CEREAL_RAPIDJSON_HAS_STDSTRING +#if RAPIDJSON_HAS_STDSTRING GenericObject AddMember(ValueType& name, std::basic_string& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } #endif - template CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) AddMember(ValueType& name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } -#if CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS + 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 // CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS +#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 CEREAL_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() { return value_.RemoveAllMembers(); } + 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 CEREAL_RAPIDJSON_HAS_STDSTRING +#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); } @@ -2553,12 +3016,12 @@ public: 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 CEREAL_RAPIDJSON_HAS_STDSTRING +#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 CEREAL_RAPIDJSON_HAS_CXX11_RANGE_FOR +#if RAPIDJSON_HAS_CXX11_RANGE_FOR MemberIterator begin() const { return value_.MemberBegin(); } MemberIterator end() const { return value_.MemberEnd(); } #endif @@ -2569,7 +3032,12 @@ private: ValueType& value_; }; -CEREAL_RAPIDJSON_NAMESPACE_END -CEREAL_RAPIDJSON_DIAG_POP +RAPIDJSON_NAMESPACE_END +RAPIDJSON_DIAG_POP -#endif // CEREAL_RAPIDJSON_DOCUMENT_H_ +#ifdef RAPIDJSON_WINDOWS_GETOBJECT_WORKAROUND_APPLIED +#pragma pop_macro("GetObject") +#undef RAPIDJSON_WINDOWS_GETOBJECT_WORKAROUND_APPLIED +#endif + +#endif // RAPIDJSON_DOCUMENT_H_ diff --git a/external/cereal/external/rapidjson/encodedstream.h b/external/cereal/external/rapidjson/encodedstream.h index 9671394..cf046b8 100644 --- a/external/cereal/external/rapidjson/encodedstream.h +++ b/external/cereal/external/rapidjson/encodedstream.h @@ -1,6 +1,6 @@ // 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. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // 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 @@ -12,23 +12,23 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -#ifndef CEREAL_RAPIDJSON_ENCODEDSTREAM_H_ -#define CEREAL_RAPIDJSON_ENCODEDSTREAM_H_ +#ifndef RAPIDJSON_ENCODEDSTREAM_H_ +#define RAPIDJSON_ENCODEDSTREAM_H_ #include "stream.h" #include "memorystream.h" #ifdef __GNUC__ -CEREAL_RAPIDJSON_DIAG_PUSH -CEREAL_RAPIDJSON_DIAG_OFF(effc++) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) #endif #ifdef __clang__ -CEREAL_RAPIDJSON_DIAG_PUSH -CEREAL_RAPIDJSON_DIAG_OFF(padded) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) #endif -CEREAL_RAPIDJSON_NAMESPACE_BEGIN +RAPIDJSON_NAMESPACE_BEGIN //! Input byte stream wrapper with a statically bound encoding. /*! @@ -37,7 +37,7 @@ CEREAL_RAPIDJSON_NAMESPACE_BEGIN */ template class EncodedInputStream { - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); public: typedef typename Encoding::Ch Ch; @@ -50,10 +50,10 @@ public: size_t Tell() const { return is_.Tell(); } // Not implemented - void Put(Ch) { CEREAL_RAPIDJSON_ASSERT(false); } - void Flush() { CEREAL_RAPIDJSON_ASSERT(false); } - Ch* PutBegin() { CEREAL_RAPIDJSON_ASSERT(false); return 0; } - size_t PutEnd(Ch*) { CEREAL_RAPIDJSON_ASSERT(false); return 0; } + 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&); @@ -98,7 +98,7 @@ private: */ template class EncodedOutputStream { - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); public: typedef typename Encoding::Ch Ch; @@ -111,11 +111,11 @@ public: void Flush() { os_.Flush(); } // Not implemented - Ch Peek() const { CEREAL_RAPIDJSON_ASSERT(false); return 0;} - Ch Take() { CEREAL_RAPIDJSON_ASSERT(false); return 0;} - size_t Tell() const { CEREAL_RAPIDJSON_ASSERT(false); return 0; } - Ch* PutBegin() { CEREAL_RAPIDJSON_ASSERT(false); return 0; } - size_t PutEnd(Ch*) { CEREAL_RAPIDJSON_ASSERT(false); return 0; } + 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&); @@ -124,7 +124,7 @@ private: OutputByteStream& os_; }; -#define CEREAL_RAPIDJSON_ENCODINGS_FUNC(x) UTF8::x, UTF16LE::x, UTF16BE::x, UTF32LE::x, UTF32BE::x +#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. /*! @@ -133,7 +133,7 @@ private: */ template class AutoUTFInputStream { - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); public: typedef CharType Ch; @@ -143,9 +143,9 @@ public: \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) { - CEREAL_RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE); + RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE); DetectType(); - static const TakeFunc f[] = { CEREAL_RAPIDJSON_ENCODINGS_FUNC(Take) }; + static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) }; takeFunc_ = f[type_]; current_ = takeFunc_(*is_); } @@ -158,10 +158,10 @@ public: size_t Tell() const { return is_->Tell(); } // Not implemented - void Put(Ch) { CEREAL_RAPIDJSON_ASSERT(false); } - void Flush() { CEREAL_RAPIDJSON_ASSERT(false); } - Ch* PutBegin() { CEREAL_RAPIDJSON_ASSERT(false); return 0; } - size_t PutEnd(Ch*) { CEREAL_RAPIDJSON_ASSERT(false); return 0; } + 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&); @@ -200,7 +200,7 @@ private: // xx xx xx xx UTF-8 if (!hasBOM_) { - unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0); + 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; @@ -212,8 +212,8 @@ private: } // Runtime check whether the size of character type is sufficient. It only perform checks with assertion. - if (type_ == kUTF16LE || type_ == kUTF16BE) CEREAL_RAPIDJSON_ASSERT(sizeof(Ch) >= 2); - if (type_ == kUTF32LE || type_ == kUTF32BE) CEREAL_RAPIDJSON_ASSERT(sizeof(Ch) >= 4); + 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); @@ -231,7 +231,7 @@ private: */ template class AutoUTFOutputStream { - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); public: typedef CharType Ch; @@ -242,13 +242,13 @@ public: \param putBOM Whether to write BOM at the beginning of the stream. */ AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) { - CEREAL_RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE); + 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) CEREAL_RAPIDJSON_ASSERT(sizeof(Ch) >= 2); - if (type_ == kUTF32LE || type_ == kUTF32BE) CEREAL_RAPIDJSON_ASSERT(sizeof(Ch) >= 4); + if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2); + if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4); - static const PutFunc f[] = { CEREAL_RAPIDJSON_ENCODINGS_FUNC(Put) }; + static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) }; putFunc_ = f[type_]; if (putBOM) @@ -261,11 +261,11 @@ public: void Flush() { os_->Flush(); } // Not implemented - Ch Peek() const { CEREAL_RAPIDJSON_ASSERT(false); return 0;} - Ch Take() { CEREAL_RAPIDJSON_ASSERT(false); return 0;} - size_t Tell() const { CEREAL_RAPIDJSON_ASSERT(false); return 0; } - Ch* PutBegin() { CEREAL_RAPIDJSON_ASSERT(false); return 0; } - size_t PutEnd(Ch*) { CEREAL_RAPIDJSON_ASSERT(false); return 0; } + 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&); @@ -273,7 +273,7 @@ private: void PutBOM() { typedef void (*PutBOMFunc)(OutputByteStream&); - static const PutBOMFunc f[] = { CEREAL_RAPIDJSON_ENCODINGS_FUNC(PutBOM) }; + static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) }; f[type_](*os_); } @@ -284,16 +284,16 @@ private: PutFunc putFunc_; }; -#undef CEREAL_RAPIDJSON_ENCODINGS_FUNC +#undef RAPIDJSON_ENCODINGS_FUNC -CEREAL_RAPIDJSON_NAMESPACE_END +RAPIDJSON_NAMESPACE_END #ifdef __clang__ -CEREAL_RAPIDJSON_DIAG_POP +RAPIDJSON_DIAG_POP #endif #ifdef __GNUC__ -CEREAL_RAPIDJSON_DIAG_POP +RAPIDJSON_DIAG_POP #endif -#endif // CEREAL_RAPIDJSON_FILESTREAM_H_ +#endif // RAPIDJSON_FILESTREAM_H_ diff --git a/external/cereal/external/rapidjson/encodings.h b/external/cereal/external/rapidjson/encodings.h index ed00b97..50ad18b 100644 --- a/external/cereal/external/rapidjson/encodings.h +++ b/external/cereal/external/rapidjson/encodings.h @@ -1,6 +1,6 @@ // 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. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // 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 @@ -12,22 +12,22 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -#ifndef CEREAL_RAPIDJSON_ENCODINGS_H_ -#define CEREAL_RAPIDJSON_ENCODINGS_H_ +#ifndef RAPIDJSON_ENCODINGS_H_ +#define RAPIDJSON_ENCODINGS_H_ #include "rapidjson.h" -#ifdef _MSC_VER -CEREAL_RAPIDJSON_DIAG_PUSH -CEREAL_RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data -CEREAL_RAPIDJSON_DIAG_OFF(4702) // unreachable code +#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__) -CEREAL_RAPIDJSON_DIAG_PUSH -CEREAL_RAPIDJSON_DIAG_OFF(effc++) -CEREAL_RAPIDJSON_DIAG_OFF(overflow) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +RAPIDJSON_DIAG_OFF(overflow) #endif -CEREAL_RAPIDJSON_NAMESPACE_BEGIN +RAPIDJSON_NAMESPACE_BEGIN /////////////////////////////////////////////////////////////////////////////// // Encoding @@ -112,7 +112,7 @@ struct UTF8 { os.Put(static_cast(0x80 | (codepoint & 0x3F))); } else { - CEREAL_RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + 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))); @@ -134,7 +134,7 @@ struct UTF8 { PutUnsafe(os, static_cast(0x80 | (codepoint & 0x3F))); } else { - CEREAL_RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + 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))); @@ -144,9 +144,9 @@ struct UTF8 { template static bool Decode(InputStream& is, unsigned* codepoint) { -#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast(c) & 0x3Fu) -#define TRANS(mask) result &= ((GetRange(static_cast(c)) & mask) != 0) -#define TAIL() COPY(); TRANS(0x70) +#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); @@ -157,48 +157,48 @@ struct UTF8 { if (type >= 32) { *codepoint = 0; } else { - *codepoint = (0xFF >> type) & static_cast(c); + *codepoint = (0xFFu >> type) & static_cast(c); } bool result = true; switch (type) { - case 2: TAIL(); return result; - case 3: TAIL(); TAIL(); return result; - case 4: COPY(); TRANS(0x50); TAIL(); return result; - case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result; - case 6: TAIL(); TAIL(); TAIL(); return result; - case 10: COPY(); TRANS(0x20); TAIL(); return result; - case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result; + 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 COPY -#undef TRANS -#undef TAIL +#undef RAPIDJSON_COPY +#undef RAPIDJSON_TRANS +#undef RAPIDJSON_TAIL } template static bool Validate(InputStream& is, OutputStream& os) { -#define COPY() os.Put(c = is.Take()) -#define TRANS(mask) result &= ((GetRange(static_cast(c)) & mask) != 0) -#define TAIL() COPY(); TRANS(0x70) +#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; - COPY(); + RAPIDJSON_COPY(); if (!(c & 0x80)) return true; bool result = true; switch (GetRange(static_cast(c))) { - case 2: TAIL(); return result; - case 3: TAIL(); TAIL(); return result; - case 4: COPY(); TRANS(0x50); TAIL(); return result; - case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result; - case 6: TAIL(); TAIL(); TAIL(); return result; - case 10: COPY(); TRANS(0x20); TAIL(); return result; - case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result; + 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 COPY -#undef TRANS -#undef TAIL +#undef RAPIDJSON_COPY +#undef RAPIDJSON_TRANS +#undef RAPIDJSON_TAIL } static unsigned char GetRange(unsigned char c) { @@ -221,7 +221,7 @@ struct UTF8 { template static CharType TakeBOM(InputByteStream& is) { - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); typename InputByteStream::Ch c = Take(is); if (static_cast(c) != 0xEFu) return c; c = is.Take(); @@ -234,13 +234,13 @@ struct UTF8 { template static Ch Take(InputByteStream& is) { - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); return static_cast(is.Take()); } template static void PutBOM(OutputByteStream& os) { - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast(0xEFu)); os.Put(static_cast(0xBBu)); os.Put(static_cast(0xBFu)); @@ -248,7 +248,7 @@ struct UTF8 { template static void Put(OutputByteStream& os, Ch c) { - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast(c)); } }; @@ -268,44 +268,44 @@ struct UTF8 { template struct UTF16 { typedef CharType Ch; - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2); + RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2); enum { supportUnicode = 1 }; template static void Encode(OutputStream& os, unsigned codepoint) { - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); if (codepoint <= 0xFFFF) { - CEREAL_RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair + RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair os.Put(static_cast(codepoint)); } else { - CEREAL_RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); unsigned v = codepoint - 0x10000; os.Put(static_cast((v >> 10) | 0xD800)); - os.Put((v & 0x3FF) | 0xDC00); + os.Put(static_cast((v & 0x3FF) | 0xDC00)); } } template static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); if (codepoint <= 0xFFFF) { - CEREAL_RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair + RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair PutUnsafe(os, static_cast(codepoint)); } else { - CEREAL_RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); unsigned v = codepoint - 0x10000; PutUnsafe(os, static_cast((v >> 10) | 0xD800)); - PutUnsafe(os, (v & 0x3FF) | 0xDC00); + PutUnsafe(os, static_cast((v & 0x3FF) | 0xDC00)); } } template static bool Decode(InputStream& is, unsigned* codepoint) { - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); typename InputStream::Ch c = is.Take(); if (c < 0xD800 || c > 0xDFFF) { *codepoint = static_cast(c); @@ -323,8 +323,8 @@ struct UTF16 { template static bool Validate(InputStream& is, OutputStream& os) { - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); + 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) @@ -342,14 +342,14 @@ template struct UTF16LE : UTF16 { template static CharType TakeBOM(InputByteStream& is) { - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + 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) { - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + 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); @@ -357,14 +357,14 @@ struct UTF16LE : UTF16 { template static void PutBOM(OutputByteStream& os) { - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + 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) { - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + 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)); } @@ -375,29 +375,29 @@ template struct UTF16BE : UTF16 { template static CharType TakeBOM(InputByteStream& is) { - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + 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) { - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); unsigned c = static_cast(static_cast(is.Take())) << 8; - c |= static_cast(is.Take()); + c |= static_cast(static_cast(is.Take())); return static_cast(c); } template static void PutBOM(OutputByteStream& os) { - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + 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) { - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + 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)); } @@ -417,27 +417,27 @@ struct UTF16BE : UTF16 { template struct UTF32 { typedef CharType Ch; - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4); + RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4); enum { supportUnicode = 1 }; template static void Encode(OutputStream& os, unsigned codepoint) { - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4); - CEREAL_RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4); + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); os.Put(codepoint); } template static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4); - CEREAL_RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4); + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); PutUnsafe(os, codepoint); } template static bool Decode(InputStream& is, unsigned* codepoint) { - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4); + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4); Ch c = is.Take(); *codepoint = c; return c <= 0x10FFFF; @@ -445,7 +445,7 @@ struct UTF32 { template static bool Validate(InputStream& is, OutputStream& os) { - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4); + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4); Ch c; os.Put(c = is.Take()); return c <= 0x10FFFF; @@ -457,14 +457,14 @@ template struct UTF32LE : UTF32 { template static CharType TakeBOM(InputByteStream& is) { - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + 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) { - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + 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; @@ -474,7 +474,7 @@ struct UTF32LE : UTF32 { template static void PutBOM(OutputByteStream& os) { - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast(0xFFu)); os.Put(static_cast(0xFEu)); os.Put(static_cast(0x00u)); @@ -483,7 +483,7 @@ struct UTF32LE : UTF32 { template static void Put(OutputByteStream& os, CharType c) { - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + 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)); @@ -496,14 +496,14 @@ template struct UTF32BE : UTF32 { template static CharType TakeBOM(InputByteStream& is) { - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + 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) { - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + 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; @@ -513,7 +513,7 @@ struct UTF32BE : UTF32 { template static void PutBOM(OutputByteStream& os) { - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast(0x00u)); os.Put(static_cast(0x00u)); os.Put(static_cast(0xFEu)); @@ -522,7 +522,7 @@ struct UTF32BE : UTF32 { template static void Put(OutputByteStream& os, CharType c) { - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + 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)); @@ -546,13 +546,13 @@ struct ASCII { template static void Encode(OutputStream& os, unsigned codepoint) { - CEREAL_RAPIDJSON_ASSERT(codepoint <= 0x7F); + RAPIDJSON_ASSERT(codepoint <= 0x7F); os.Put(static_cast(codepoint & 0xFF)); } template static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { - CEREAL_RAPIDJSON_ASSERT(codepoint <= 0x7F); + RAPIDJSON_ASSERT(codepoint <= 0x7F); PutUnsafe(os, static_cast(codepoint & 0xFF)); } @@ -572,26 +572,26 @@ struct ASCII { template static CharType TakeBOM(InputByteStream& is) { - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + 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) { - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); return static_cast(is.Take()); } template static void PutBOM(OutputByteStream& os) { - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); (void)os; } template static void Put(OutputByteStream& os, Ch c) { - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast(c)); } }; @@ -617,37 +617,37 @@ struct AutoUTF { enum { supportUnicode = 1 }; -#define CEREAL_RAPIDJSON_ENCODINGS_FUNC(x) UTF8::x, UTF16LE::x, UTF16BE::x, UTF32LE::x, UTF32BE::x +#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8::x, UTF16LE::x, UTF16BE::x, UTF32LE::x, UTF32BE::x template - CEREAL_RAPIDJSON_FORCEINLINE static void Encode(OutputStream& os, unsigned codepoint) { + static RAPIDJSON_FORCEINLINE void Encode(OutputStream& os, unsigned codepoint) { typedef void (*EncodeFunc)(OutputStream&, unsigned); - static const EncodeFunc f[] = { CEREAL_RAPIDJSON_ENCODINGS_FUNC(Encode) }; + static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) }; (*f[os.GetType()])(os, codepoint); } template - CEREAL_RAPIDJSON_FORCEINLINE static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { + static RAPIDJSON_FORCEINLINE void EncodeUnsafe(OutputStream& os, unsigned codepoint) { typedef void (*EncodeFunc)(OutputStream&, unsigned); - static const EncodeFunc f[] = { CEREAL_RAPIDJSON_ENCODINGS_FUNC(EncodeUnsafe) }; + static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(EncodeUnsafe) }; (*f[os.GetType()])(os, codepoint); } template - CEREAL_RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) { + static RAPIDJSON_FORCEINLINE bool Decode(InputStream& is, unsigned* codepoint) { typedef bool (*DecodeFunc)(InputStream&, unsigned*); - static const DecodeFunc f[] = { CEREAL_RAPIDJSON_ENCODINGS_FUNC(Decode) }; + static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) }; return (*f[is.GetType()])(is, codepoint); } template - CEREAL_RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { + static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) { typedef bool (*ValidateFunc)(InputStream&, OutputStream&); - static const ValidateFunc f[] = { CEREAL_RAPIDJSON_ENCODINGS_FUNC(Validate) }; + static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) }; return (*f[is.GetType()])(is, os); } -#undef CEREAL_RAPIDJSON_ENCODINGS_FUNC +#undef RAPIDJSON_ENCODINGS_FUNC }; /////////////////////////////////////////////////////////////////////////////// @@ -658,7 +658,7 @@ template struct Transcoder { //! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream. template - CEREAL_RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) { + static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) { unsigned codepoint; if (!SourceEncoding::Decode(is, &codepoint)) return false; @@ -667,7 +667,7 @@ struct Transcoder { } template - CEREAL_RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) { + static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) { unsigned codepoint; if (!SourceEncoding::Decode(is, &codepoint)) return false; @@ -677,7 +677,7 @@ struct Transcoder { //! Validate one Unicode codepoint from an encoded stream. template - CEREAL_RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { + static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) { return Transcode(is, os); // Since source/target encoding is different, must transcode. } }; @@ -690,27 +690,27 @@ inline void PutUnsafe(Stream& stream, typename Stream::Ch c); template struct Transcoder { template - CEREAL_RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) { + 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 - CEREAL_RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) { + 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 - CEREAL_RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { + static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) { return Encoding::Validate(is, os); // source/target encoding are the same } }; -CEREAL_RAPIDJSON_NAMESPACE_END +RAPIDJSON_NAMESPACE_END -#if defined(__GNUC__) || defined(_MSC_VER) -CEREAL_RAPIDJSON_DIAG_POP +#if defined(__GNUC__) || (defined(_MSC_VER) && !defined(__clang__)) +RAPIDJSON_DIAG_POP #endif -#endif // CEREAL_RAPIDJSON_ENCODINGS_H_ +#endif // RAPIDJSON_ENCODINGS_H_ diff --git a/external/cereal/external/rapidjson/error/en.h b/external/cereal/external/rapidjson/error/en.h index ea93bf8..5d2e57b 100644 --- a/external/cereal/external/rapidjson/error/en.h +++ b/external/cereal/external/rapidjson/error/en.h @@ -1,6 +1,6 @@ // 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. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // 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 @@ -12,63 +12,111 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -#ifndef CEREAL_RAPIDJSON_ERROR_EN_H_ -#define CEREAL_RAPIDJSON_ERROR_EN_H_ +#ifndef RAPIDJSON_ERROR_EN_H_ +#define RAPIDJSON_ERROR_EN_H_ #include "error.h" #ifdef __clang__ -CEREAL_RAPIDJSON_DIAG_PUSH -CEREAL_RAPIDJSON_DIAG_OFF(switch-enum) -CEREAL_RAPIDJSON_DIAG_OFF(covered-switch-default) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(switch-enum) +RAPIDJSON_DIAG_OFF(covered-switch-default) #endif -CEREAL_RAPIDJSON_NAMESPACE_BEGIN +RAPIDJSON_NAMESPACE_BEGIN //! Maps error code of parsing into error message. /*! - \ingroup CEREAL_RAPIDJSON_ERRORS + \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 CEREAL_RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) { +inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) { switch (parseErrorCode) { - case kParseErrorNone: return CEREAL_RAPIDJSON_ERROR_STRING("No error."); + case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error."); - case kParseErrorDocumentEmpty: return CEREAL_RAPIDJSON_ERROR_STRING("The document is empty."); - case kParseErrorDocumentRootNotSingular: return CEREAL_RAPIDJSON_ERROR_STRING("The document root must not be followed by other values."); + 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 CEREAL_RAPIDJSON_ERROR_STRING("Invalid value."); + case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value."); - case kParseErrorObjectMissName: return CEREAL_RAPIDJSON_ERROR_STRING("Missing a name for object member."); - case kParseErrorObjectMissColon: return CEREAL_RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member."); - case kParseErrorObjectMissCommaOrCurlyBracket: return CEREAL_RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member."); + 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 CEREAL_RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element."); + case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element."); - case kParseErrorStringUnicodeEscapeInvalidHex: return CEREAL_RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string."); - case kParseErrorStringUnicodeSurrogateInvalid: return CEREAL_RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid."); - case kParseErrorStringEscapeInvalid: return CEREAL_RAPIDJSON_ERROR_STRING("Invalid escape character in string."); - case kParseErrorStringMissQuotationMark: return CEREAL_RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string."); - case kParseErrorStringInvalidEncoding: return CEREAL_RAPIDJSON_ERROR_STRING("Invalid encoding in string."); + 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 CEREAL_RAPIDJSON_ERROR_STRING("Number too big to be stored in double."); - case kParseErrorNumberMissFraction: return CEREAL_RAPIDJSON_ERROR_STRING("Miss fraction part in number."); - case kParseErrorNumberMissExponent: return CEREAL_RAPIDJSON_ERROR_STRING("Miss exponent in number."); + 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 CEREAL_RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error."); - case kParseErrorUnspecificSyntaxError: return CEREAL_RAPIDJSON_ERROR_STRING("Unspecific syntax error."); + case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error."); + case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error."); - default: return CEREAL_RAPIDJSON_ERROR_STRING("Unknown error."); + default: return RAPIDJSON_ERROR_STRING("Unknown error."); } } -CEREAL_RAPIDJSON_NAMESPACE_END +//! Maps error code of validation into error message. +/*! + \ingroup RAPIDJSON_ERRORS + \param validateErrorCode Error code obtained from validator. + \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* GetValidateError_En(ValidateErrorCode validateErrorCode) { + switch (validateErrorCode) { + case kValidateErrors: return RAPIDJSON_ERROR_STRING("One or more validation errors have occurred"); + case kValidateErrorNone: return RAPIDJSON_ERROR_STRING("No error."); + + case kValidateErrorMultipleOf: return RAPIDJSON_ERROR_STRING("Number '%actual' is not a multiple of the 'multipleOf' value '%expected'."); + case kValidateErrorMaximum: return RAPIDJSON_ERROR_STRING("Number '%actual' is greater than the 'maximum' value '%expected'."); + case kValidateErrorExclusiveMaximum: return RAPIDJSON_ERROR_STRING("Number '%actual' is greater than or equal to the 'exclusiveMaximum' value '%expected'."); + case kValidateErrorMinimum: return RAPIDJSON_ERROR_STRING("Number '%actual' is less than the 'minimum' value '%expected'."); + case kValidateErrorExclusiveMinimum: return RAPIDJSON_ERROR_STRING("Number '%actual' is less than or equal to the 'exclusiveMinimum' value '%expected'."); + + case kValidateErrorMaxLength: return RAPIDJSON_ERROR_STRING("String '%actual' is longer than the 'maxLength' value '%expected'."); + case kValidateErrorMinLength: return RAPIDJSON_ERROR_STRING("String '%actual' is shorter than the 'minLength' value '%expected'."); + case kValidateErrorPattern: return RAPIDJSON_ERROR_STRING("String '%actual' does not match the 'pattern' regular expression."); + + case kValidateErrorMaxItems: return RAPIDJSON_ERROR_STRING("Array of length '%actual' is longer than the 'maxItems' value '%expected'."); + case kValidateErrorMinItems: return RAPIDJSON_ERROR_STRING("Array of length '%actual' is shorter than the 'minItems' value '%expected'."); + case kValidateErrorUniqueItems: return RAPIDJSON_ERROR_STRING("Array has duplicate items at indices '%duplicates' but 'uniqueItems' is true."); + case kValidateErrorAdditionalItems: return RAPIDJSON_ERROR_STRING("Array has an additional item at index '%disallowed' that is not allowed by the schema."); + + case kValidateErrorMaxProperties: return RAPIDJSON_ERROR_STRING("Object has '%actual' members which is more than 'maxProperties' value '%expected'."); + case kValidateErrorMinProperties: return RAPIDJSON_ERROR_STRING("Object has '%actual' members which is less than 'minProperties' value '%expected'."); + case kValidateErrorRequired: return RAPIDJSON_ERROR_STRING("Object is missing the following members required by the schema: '%missing'."); + case kValidateErrorAdditionalProperties: return RAPIDJSON_ERROR_STRING("Object has an additional member '%disallowed' that is not allowed by the schema."); + case kValidateErrorPatternProperties: return RAPIDJSON_ERROR_STRING("Object has 'patternProperties' that are not allowed by the schema."); + case kValidateErrorDependencies: return RAPIDJSON_ERROR_STRING("Object has missing property or schema dependencies, refer to following errors."); + + case kValidateErrorEnum: return RAPIDJSON_ERROR_STRING("Property has a value that is not one of its allowed enumerated values."); + case kValidateErrorType: return RAPIDJSON_ERROR_STRING("Property has a type '%actual' that is not in the following list: '%expected'."); + + case kValidateErrorOneOf: return RAPIDJSON_ERROR_STRING("Property did not match any of the sub-schemas specified by 'oneOf', refer to following errors."); + case kValidateErrorOneOfMatch: return RAPIDJSON_ERROR_STRING("Property matched more than one of the sub-schemas specified by 'oneOf'."); + case kValidateErrorAllOf: return RAPIDJSON_ERROR_STRING("Property did not match all of the sub-schemas specified by 'allOf', refer to following errors."); + case kValidateErrorAnyOf: return RAPIDJSON_ERROR_STRING("Property did not match any of the sub-schemas specified by 'anyOf', refer to following errors."); + case kValidateErrorNot: return RAPIDJSON_ERROR_STRING("Property matched the sub-schema specified by 'not'."); + + default: return RAPIDJSON_ERROR_STRING("Unknown error."); + } +} + +RAPIDJSON_NAMESPACE_END #ifdef __clang__ -CEREAL_RAPIDJSON_DIAG_POP +RAPIDJSON_DIAG_POP #endif -#endif // CEREAL_RAPIDJSON_ERROR_EN_H_ +#endif // RAPIDJSON_ERROR_EN_H_ diff --git a/external/cereal/external/rapidjson/error/error.h b/external/cereal/external/rapidjson/error/error.h index c2638f1..6270da1 100644 --- a/external/cereal/external/rapidjson/error/error.h +++ b/external/cereal/external/rapidjson/error/error.h @@ -1,6 +1,6 @@ // 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. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // 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 @@ -12,53 +12,53 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -#ifndef CEREAL_RAPIDJSON_ERROR_ERROR_H_ -#define CEREAL_RAPIDJSON_ERROR_ERROR_H_ +#ifndef RAPIDJSON_ERROR_ERROR_H_ +#define RAPIDJSON_ERROR_ERROR_H_ #include "../rapidjson.h" #ifdef __clang__ -CEREAL_RAPIDJSON_DIAG_PUSH -CEREAL_RAPIDJSON_DIAG_OFF(padded) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) #endif /*! \file error.h */ -/*! \defgroup CEREAL_RAPIDJSON_ERRORS RapidJSON error handling */ +/*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */ /////////////////////////////////////////////////////////////////////////////// -// CEREAL_RAPIDJSON_ERROR_CHARTYPE +// RAPIDJSON_ERROR_CHARTYPE //! Character type of error messages. -/*! \ingroup CEREAL_RAPIDJSON_ERRORS +/*! \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 CEREAL_RAPIDJSON_ERROR_CHARTYPE -#define CEREAL_RAPIDJSON_ERROR_CHARTYPE char +#ifndef RAPIDJSON_ERROR_CHARTYPE +#define RAPIDJSON_ERROR_CHARTYPE char #endif /////////////////////////////////////////////////////////////////////////////// -// CEREAL_RAPIDJSON_ERROR_STRING +// RAPIDJSON_ERROR_STRING -//! Macro for converting string literial to \ref CEREAL_RAPIDJSON_ERROR_CHARTYPE[]. -/*! \ingroup CEREAL_RAPIDJSON_ERRORS +//! 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 CEREAL_RAPIDJSON_ERROR_STRING -#define CEREAL_RAPIDJSON_ERROR_STRING(x) x +#ifndef RAPIDJSON_ERROR_STRING +#define RAPIDJSON_ERROR_STRING(x) x #endif -CEREAL_RAPIDJSON_NAMESPACE_BEGIN +RAPIDJSON_NAMESPACE_BEGIN /////////////////////////////////////////////////////////////////////////////// // ParseErrorCode //! Error code of parsing. -/*! \ingroup CEREAL_RAPIDJSON_ERRORS +/*! \ingroup RAPIDJSON_ERRORS \see GenericReader::Parse, GenericReader::GetParseErrorCode */ enum ParseErrorCode { @@ -91,7 +91,7 @@ enum ParseErrorCode { //! Result of parsing (wraps ParseErrorCode) /*! - \ingroup CEREAL_RAPIDJSON_ERRORS + \ingroup RAPIDJSON_ERRORS \code Document doc; ParseResult ok = doc.Parse("[42]"); @@ -104,6 +104,8 @@ enum ParseErrorCode { \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) {} @@ -115,8 +117,8 @@ public: //! Get the error offset, if \ref IsError(), 0 otherwise. size_t Offset() const { return offset_; } - //! Conversion to \c bool, returns \c true, iff !\ref IsError(). - operator bool() const { return !IsError(); } + //! 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; } @@ -124,6 +126,10 @@ public: 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. @@ -135,21 +141,76 @@ private: }; //! Function pointer type of GetParseError(). -/*! \ingroup CEREAL_RAPIDJSON_ERRORS +/*! \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 CEREAL_RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode()); + const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode()); \endcode */ -typedef const CEREAL_RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode); +typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode); -CEREAL_RAPIDJSON_NAMESPACE_END +/////////////////////////////////////////////////////////////////////////////// +// ValidateErrorCode + +//! Error codes when validating. +/*! \ingroup RAPIDJSON_ERRORS + \see GenericSchemaValidator +*/ +enum ValidateErrorCode { + kValidateErrors = -1, //!< Top level error code when kValidateContinueOnErrorsFlag set. + kValidateErrorNone = 0, //!< No error. + + kValidateErrorMultipleOf, //!< Number is not a multiple of the 'multipleOf' value. + kValidateErrorMaximum, //!< Number is greater than the 'maximum' value. + kValidateErrorExclusiveMaximum, //!< Number is greater than or equal to the 'maximum' value. + kValidateErrorMinimum, //!< Number is less than the 'minimum' value. + kValidateErrorExclusiveMinimum, //!< Number is less than or equal to the 'minimum' value. + + kValidateErrorMaxLength, //!< String is longer than the 'maxLength' value. + kValidateErrorMinLength, //!< String is longer than the 'maxLength' value. + kValidateErrorPattern, //!< String does not match the 'pattern' regular expression. + + kValidateErrorMaxItems, //!< Array is longer than the 'maxItems' value. + kValidateErrorMinItems, //!< Array is shorter than the 'minItems' value. + kValidateErrorUniqueItems, //!< Array has duplicate items but 'uniqueItems' is true. + kValidateErrorAdditionalItems, //!< Array has additional items that are not allowed by the schema. + + kValidateErrorMaxProperties, //!< Object has more members than 'maxProperties' value. + kValidateErrorMinProperties, //!< Object has less members than 'minProperties' value. + kValidateErrorRequired, //!< Object is missing one or more members required by the schema. + kValidateErrorAdditionalProperties, //!< Object has additional members that are not allowed by the schema. + kValidateErrorPatternProperties, //!< See other errors. + kValidateErrorDependencies, //!< Object has missing property or schema dependencies. + + kValidateErrorEnum, //!< Property has a value that is not one of its allowed enumerated values + kValidateErrorType, //!< Property has a type that is not allowed by the schema.. + + kValidateErrorOneOf, //!< Property did not match any of the sub-schemas specified by 'oneOf'. + kValidateErrorOneOfMatch, //!< Property matched more than one of the sub-schemas specified by 'oneOf'. + kValidateErrorAllOf, //!< Property did not match all of the sub-schemas specified by 'allOf'. + kValidateErrorAnyOf, //!< Property did not match any of the sub-schemas specified by 'anyOf'. + kValidateErrorNot //!< Property matched the sub-schema specified by 'not'. +}; + +//! Function pointer type of GetValidateError(). +/*! \ingroup RAPIDJSON_ERRORS + + This is the prototype for \c GetValidateError_X(), where \c X is a locale. + User can dynamically change locale in runtime, e.g.: +\code + GetValidateErrorFunc GetValidateError = GetValidateError_En; // or whatever + const RAPIDJSON_ERROR_CHARTYPE* s = GetValidateError(validator.GetInvalidSchemaCode()); +\endcode +*/ +typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetValidateErrorFunc)(ValidateErrorCode); + +RAPIDJSON_NAMESPACE_END #ifdef __clang__ -CEREAL_RAPIDJSON_DIAG_POP +RAPIDJSON_DIAG_POP #endif -#endif // CEREAL_RAPIDJSON_ERROR_ERROR_H_ +#endif // RAPIDJSON_ERROR_ERROR_H_ diff --git a/external/cereal/external/rapidjson/filereadstream.h b/external/cereal/external/rapidjson/filereadstream.h index abafb54..f8bb43c 100644 --- a/external/cereal/external/rapidjson/filereadstream.h +++ b/external/cereal/external/rapidjson/filereadstream.h @@ -1,6 +1,6 @@ // 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. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // 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 @@ -12,20 +12,20 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -#ifndef CEREAL_RAPIDJSON_FILEREADSTREAM_H_ -#define CEREAL_RAPIDJSON_FILEREADSTREAM_H_ +#ifndef RAPIDJSON_FILEREADSTREAM_H_ +#define RAPIDJSON_FILEREADSTREAM_H_ #include "stream.h" #include #ifdef __clang__ -CEREAL_RAPIDJSON_DIAG_PUSH -CEREAL_RAPIDJSON_DIAG_OFF(padded) -CEREAL_RAPIDJSON_DIAG_OFF(unreachable-code) -CEREAL_RAPIDJSON_DIAG_OFF(missing-noreturn) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +RAPIDJSON_DIAG_OFF(unreachable-code) +RAPIDJSON_DIAG_OFF(missing-noreturn) #endif -CEREAL_RAPIDJSON_NAMESPACE_BEGIN +RAPIDJSON_NAMESPACE_BEGIN //! File byte stream for input using fread(). /*! @@ -42,8 +42,8 @@ public: \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) { - CEREAL_RAPIDJSON_ASSERT(fp_ != 0); - CEREAL_RAPIDJSON_ASSERT(bufferSize >= 4); + RAPIDJSON_ASSERT(fp_ != 0); + RAPIDJSON_ASSERT(bufferSize >= 4); Read(); } @@ -52,14 +52,14 @@ public: size_t Tell() const { return count_ + static_cast(current_ - buffer_); } // Not implemented - void Put(Ch) { CEREAL_RAPIDJSON_ASSERT(false); } - void Flush() { CEREAL_RAPIDJSON_ASSERT(false); } - Ch* PutBegin() { CEREAL_RAPIDJSON_ASSERT(false); return 0; } - size_t PutEnd(Ch*) { CEREAL_RAPIDJSON_ASSERT(false); return 0; } + 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 <= bufferLast_) ? current_ : 0; + return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0; } private: @@ -68,7 +68,7 @@ private: ++current_; else if (!eof_) { count_ += readCount_; - readCount_ = fread(buffer_, 1, bufferSize_, fp_); + readCount_ = std::fread(buffer_, 1, bufferSize_, fp_); bufferLast_ = buffer_ + readCount_ - 1; current_ = buffer_; @@ -90,10 +90,10 @@ private: bool eof_; }; -CEREAL_RAPIDJSON_NAMESPACE_END +RAPIDJSON_NAMESPACE_END #ifdef __clang__ -CEREAL_RAPIDJSON_DIAG_POP +RAPIDJSON_DIAG_POP #endif -#endif // CEREAL_RAPIDJSON_FILESTREAM_H_ +#endif // RAPIDJSON_FILESTREAM_H_ diff --git a/external/cereal/external/rapidjson/filewritestream.h b/external/cereal/external/rapidjson/filewritestream.h index 9a60099..5d89588 100644 --- a/external/cereal/external/rapidjson/filewritestream.h +++ b/external/cereal/external/rapidjson/filewritestream.h @@ -1,6 +1,6 @@ // 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. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // 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 @@ -12,20 +12,20 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -#ifndef CEREAL_RAPIDJSON_FILEWRITESTREAM_H_ -#define CEREAL_RAPIDJSON_FILEWRITESTREAM_H_ +#ifndef RAPIDJSON_FILEWRITESTREAM_H_ +#define RAPIDJSON_FILEWRITESTREAM_H_ #include "stream.h" #include #ifdef __clang__ -CEREAL_RAPIDJSON_DIAG_PUSH -CEREAL_RAPIDJSON_DIAG_OFF(unreachable-code) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(unreachable-code) #endif -CEREAL_RAPIDJSON_NAMESPACE_BEGIN +RAPIDJSON_NAMESPACE_BEGIN -//! Wrapper of C file stream for input using fread(). +//! Wrapper of C file stream for output using fwrite(). /*! \note implements Stream concept */ @@ -34,7 +34,7 @@ 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_) { - CEREAL_RAPIDJSON_ASSERT(fp_ != 0); + RAPIDJSON_ASSERT(fp_ != 0); } void Put(char c) { @@ -62,7 +62,7 @@ public: void Flush() { if (current_ != buffer_) { - size_t result = fwrite(buffer_, 1, static_cast(current_ - buffer_), fp_); + 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 @@ -72,11 +72,11 @@ public: } // Not implemented - char Peek() const { CEREAL_RAPIDJSON_ASSERT(false); return 0; } - char Take() { CEREAL_RAPIDJSON_ASSERT(false); return 0; } - size_t Tell() const { CEREAL_RAPIDJSON_ASSERT(false); return 0; } - char* PutBegin() { CEREAL_RAPIDJSON_ASSERT(false); return 0; } - size_t PutEnd(char*) { CEREAL_RAPIDJSON_ASSERT(false); return 0; } + 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. @@ -95,10 +95,10 @@ inline void PutN(FileWriteStream& stream, char c, size_t n) { stream.PutN(c, n); } -CEREAL_RAPIDJSON_NAMESPACE_END +RAPIDJSON_NAMESPACE_END #ifdef __clang__ -CEREAL_RAPIDJSON_DIAG_POP +RAPIDJSON_DIAG_POP #endif -#endif // CEREAL_RAPIDJSON_FILESTREAM_H_ +#endif // RAPIDJSON_FILESTREAM_H_ diff --git a/external/cereal/external/rapidjson/fwd.h b/external/cereal/external/rapidjson/fwd.h index 1b15c66..d62f77f 100644 --- a/external/cereal/external/rapidjson/fwd.h +++ b/external/cereal/external/rapidjson/fwd.h @@ -1,6 +1,6 @@ // 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. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // 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 @@ -12,12 +12,12 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -#ifndef CEREAL_RAPIDJSON_FWD_H_ -#define CEREAL_RAPIDJSON_FWD_H_ +#ifndef RAPIDJSON_FWD_H_ +#define RAPIDJSON_FWD_H_ #include "rapidjson.h" -CEREAL_RAPIDJSON_NAMESPACE_BEGIN +RAPIDJSON_NAMESPACE_BEGIN // encodings.h @@ -102,7 +102,7 @@ class PrettyWriter; // document.h template -struct GenericMember; +class GenericMember; template class GenericMemberIterator; @@ -146,6 +146,6 @@ class GenericSchemaValidator; typedef GenericSchemaValidator, void>, CrtAllocator> SchemaValidator; -CEREAL_RAPIDJSON_NAMESPACE_END +RAPIDJSON_NAMESPACE_END -#endif // CEREAL_RAPIDJSON_RAPIDJSONFWD_H_ +#endif // RAPIDJSON_RAPIDJSONFWD_H_ diff --git a/external/cereal/external/rapidjson/internal/biginteger.h b/external/cereal/external/rapidjson/internal/biginteger.h index f8a5a50..af48738 100644 --- a/external/cereal/external/rapidjson/internal/biginteger.h +++ b/external/cereal/external/rapidjson/internal/biginteger.h @@ -1,6 +1,6 @@ // 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. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // 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 @@ -12,17 +12,21 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -#ifndef CEREAL_RAPIDJSON_BIGINTEGER_H_ -#define CEREAL_RAPIDJSON_BIGINTEGER_H_ +#ifndef RAPIDJSON_BIGINTEGER_H_ +#define RAPIDJSON_BIGINTEGER_H_ #include "../rapidjson.h" -#if defined(_MSC_VER) && defined(_M_AMD64) +#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && defined(_M_AMD64) #include // for _umul128 +#if !defined(_ARM64EC_) #pragma intrinsic(_umul128) +#else +#pragma comment(lib,"softintrin") +#endif #endif -CEREAL_RAPIDJSON_NAMESPACE_BEGIN +RAPIDJSON_NAMESPACE_BEGIN namespace internal { class BigInteger { @@ -37,8 +41,9 @@ public: digits_[0] = u; } - BigInteger(const char* decimals, size_t length) : count_(1) { - CEREAL_RAPIDJSON_ASSERT(length > 0); + template + BigInteger(const Ch* 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 @@ -130,10 +135,10 @@ public: size_t offset = shift / kTypeBit; size_t interShift = shift % kTypeBit; - CEREAL_RAPIDJSON_ASSERT(count_ + offset <= kCapacity); + RAPIDJSON_ASSERT(count_ + offset <= kCapacity); if (interShift == 0) { - std::memmove(&digits_[count_ - 1 + offset], &digits_[count_ - 1], count_ * sizeof(Type)); + std::memmove(digits_ + offset, digits_, count_ * sizeof(Type)); count_ += offset; } else { @@ -175,7 +180,7 @@ public: 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 }; if (exp == 0) return *this; - for (; exp >= 27; exp -= 27) *this *= CEREAL_RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27 + 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; @@ -185,7 +190,7 @@ public: // Assume this != rhs bool Difference(const BigInteger& rhs, BigInteger* out) const { int cmp = Compare(rhs); - CEREAL_RAPIDJSON_ASSERT(cmp != 0); + RAPIDJSON_ASSERT(cmp != 0); const BigInteger *a, *b; // Makes a > b bool ret; if (cmp < 0) { a = &rhs; b = this; ret = true; } @@ -217,11 +222,12 @@ public: } size_t GetCount() const { return count_; } - Type GetDigit(size_t index) const { CEREAL_RAPIDJSON_ASSERT(index < count_); return digits_[index]; } + 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) { + template + void AppendDecimal64(const Ch* begin, const Ch* end) { uint64_t u = ParseUint64(begin, end); if (IsZero()) *this = u; @@ -232,15 +238,16 @@ private: } void PushBack(Type digit) { - CEREAL_RAPIDJSON_ASSERT(count_ < kCapacity); + RAPIDJSON_ASSERT(count_ < kCapacity); digits_[count_++] = digit; } - static uint64_t ParseUint64(const char* begin, const char* end) { + template + static uint64_t ParseUint64(const Ch* begin, const Ch* end) { uint64_t r = 0; - for (const char* p = begin; p != end; ++p) { - CEREAL_RAPIDJSON_ASSERT(*p >= '0' && *p <= '9'); - r = r * 10u + static_cast(*p - '0'); + for (const Ch* p = begin; p != end; ++p) { + RAPIDJSON_ASSERT(*p >= Ch('0') && *p <= Ch('9')); + r = r * 10u + static_cast(*p - Ch('0')); } return r; } @@ -285,6 +292,6 @@ private: }; } // namespace internal -CEREAL_RAPIDJSON_NAMESPACE_END +RAPIDJSON_NAMESPACE_END -#endif // CEREAL_RAPIDJSON_BIGINTEGER_H_ +#endif // RAPIDJSON_BIGINTEGER_H_ diff --git a/external/cereal/external/rapidjson/internal/clzll.h b/external/cereal/external/rapidjson/internal/clzll.h new file mode 100644 index 0000000..8fc5118 --- /dev/null +++ b/external/cereal/external/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. +// +// 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) && !defined(UNDER_CE) +#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) && !defined(UNDER_CE) + 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 = 0; + 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/external/cereal/external/rapidjson/internal/diyfp.h b/external/cereal/external/rapidjson/internal/diyfp.h index ab7d66b..f7d4653 100644 --- a/external/cereal/external/rapidjson/internal/diyfp.h +++ b/external/cereal/external/rapidjson/internal/diyfp.h @@ -1,43 +1,48 @@ // 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. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // 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 +// 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 CEREAL_RAPIDJSON_DIYFP_H_ -#define CEREAL_RAPIDJSON_DIYFP_H_ +#ifndef RAPIDJSON_DIYFP_H_ +#define RAPIDJSON_DIYFP_H_ #include "../rapidjson.h" +#include "clzll.h" +#include -#if defined(_MSC_VER) && defined(_M_AMD64) +#if defined(_MSC_VER) && defined(_M_AMD64) && !defined(__INTEL_COMPILER) #include -#pragma intrinsic(_BitScanReverse64) +#if !defined(_ARM64EC_) #pragma intrinsic(_umul128) +#else +#pragma comment(lib,"softintrin") +#endif #endif -CEREAL_RAPIDJSON_NAMESPACE_BEGIN +RAPIDJSON_NAMESPACE_BEGIN namespace internal { #ifdef __GNUC__ -CEREAL_RAPIDJSON_DIAG_PUSH -CEREAL_RAPIDJSON_DIAG_OFF(effc++) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) #endif #ifdef __clang__ -CEREAL_RAPIDJSON_DIAG_PUSH -CEREAL_RAPIDJSON_DIAG_OFF(padded) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) #endif struct DiyFp { @@ -56,7 +61,7 @@ struct DiyFp { if (biased_e != 0) { f = significand + kDpHiddenBit; e = biased_e - kDpExponentBias; - } + } else { f = significand; e = kDpMinExponent + 1; @@ -99,21 +104,8 @@ struct DiyFp { } DiyFp Normalize() const { -#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 { @@ -141,7 +133,16 @@ struct DiyFp { double d; uint64_t u64; }u; - const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 : + 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; @@ -153,9 +154,9 @@ struct DiyFp { static const int kDpMaxExponent = 0x7FF - kDpExponentBias; static const int kDpMinExponent = -kDpExponentBias; static const int kDpDenormalExponent = -kDpExponentBias + 1; - static const uint64_t kDpExponentMask = CEREAL_RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); - static const uint64_t kDpSignificandMask = CEREAL_RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); - static const uint64_t kDpHiddenBit = CEREAL_RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); + 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; @@ -164,50 +165,50 @@ struct DiyFp { inline DiyFp GetCachedPowerByIndex(size_t index) { // 10^-348, 10^-340, ..., 10^340 static const uint64_t kCachedPowers_F[] = { - CEREAL_RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), CEREAL_RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76), - CEREAL_RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), CEREAL_RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea), - CEREAL_RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), CEREAL_RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df), - CEREAL_RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), CEREAL_RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f), - CEREAL_RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), CEREAL_RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c), - CEREAL_RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), CEREAL_RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5), - CEREAL_RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), CEREAL_RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d), - CEREAL_RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), CEREAL_RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637), - CEREAL_RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), CEREAL_RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7), - CEREAL_RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), CEREAL_RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5), - CEREAL_RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), CEREAL_RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b), - CEREAL_RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), CEREAL_RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996), - CEREAL_RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), CEREAL_RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6), - CEREAL_RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), CEREAL_RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8), - CEREAL_RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), CEREAL_RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053), - CEREAL_RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), CEREAL_RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd), - CEREAL_RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), CEREAL_RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94), - CEREAL_RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), CEREAL_RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b), - CEREAL_RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), CEREAL_RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac), - CEREAL_RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), CEREAL_RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3), - CEREAL_RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), CEREAL_RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb), - CEREAL_RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), CEREAL_RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c), - CEREAL_RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), CEREAL_RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000), - CEREAL_RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), CEREAL_RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984), - CEREAL_RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), CEREAL_RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70), - CEREAL_RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), CEREAL_RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245), - CEREAL_RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), CEREAL_RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8), - CEREAL_RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), CEREAL_RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a), - CEREAL_RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), CEREAL_RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea), - CEREAL_RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), CEREAL_RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85), - CEREAL_RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), CEREAL_RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2), - CEREAL_RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), CEREAL_RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3), - CEREAL_RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), CEREAL_RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25), - CEREAL_RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), CEREAL_RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece), - CEREAL_RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), CEREAL_RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5), - CEREAL_RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), CEREAL_RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a), - CEREAL_RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), CEREAL_RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c), - CEREAL_RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), CEREAL_RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a), - CEREAL_RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), CEREAL_RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129), - CEREAL_RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), CEREAL_RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429), - CEREAL_RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), CEREAL_RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d), - CEREAL_RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), CEREAL_RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841), - CEREAL_RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), CEREAL_RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9), - CEREAL_RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b) + 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, @@ -220,9 +221,10 @@ inline DiyFp GetCachedPowerByIndex(size_t index) { 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; @@ -238,21 +240,22 @@ inline DiyFp GetCachedPower(int e, int* K) { } inline DiyFp GetCachedPower10(int exp, int *outExp) { - unsigned index = (static_cast(exp) + 348u) / 8u; - *outExp = -348 + static_cast(index) * 8; - return GetCachedPowerByIndex(index); - } + RAPIDJSON_ASSERT(exp >= -348); + unsigned index = static_cast(exp + 348) / 8u; + *outExp = -348 + static_cast(index) * 8; + return GetCachedPowerByIndex(index); +} #ifdef __GNUC__ -CEREAL_RAPIDJSON_DIAG_POP +RAPIDJSON_DIAG_POP #endif #ifdef __clang__ -CEREAL_RAPIDJSON_DIAG_POP -CEREAL_RAPIDJSON_DIAG_OFF(padded) +RAPIDJSON_DIAG_POP +RAPIDJSON_DIAG_OFF(padded) #endif } // namespace internal -CEREAL_RAPIDJSON_NAMESPACE_END +RAPIDJSON_NAMESPACE_END -#endif // CEREAL_RAPIDJSON_DIYFP_H_ +#endif // RAPIDJSON_DIYFP_H_ diff --git a/external/cereal/external/rapidjson/internal/dtoa.h b/external/cereal/external/rapidjson/internal/dtoa.h index c59c92e..cd45672 100644 --- a/external/cereal/external/rapidjson/internal/dtoa.h +++ b/external/cereal/external/rapidjson/internal/dtoa.h @@ -1,6 +1,6 @@ // 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. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // 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 @@ -16,20 +16,20 @@ // Loitsch, Florian. "Printing floating-point numbers quickly and accurately with // integers." ACM Sigplan Notices 45.6 (2010): 233-243. -#ifndef CEREAL_RAPIDJSON_DTOA_ -#define CEREAL_RAPIDJSON_DTOA_ +#ifndef RAPIDJSON_DTOA_ +#define RAPIDJSON_DTOA_ #include "itoa.h" // GetDigitsLut() #include "diyfp.h" #include "ieee754.h" -CEREAL_RAPIDJSON_NAMESPACE_BEGIN +RAPIDJSON_NAMESPACE_BEGIN namespace internal { #ifdef __GNUC__ -CEREAL_RAPIDJSON_DIAG_PUSH -CEREAL_RAPIDJSON_DIAG_OFF(effc++) -CEREAL_RAPIDJSON_DIAG_OFF(array-bounds) // some gcc versions generate wrong warnings https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124 +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) { @@ -41,7 +41,7 @@ inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uin } } -inline unsigned CountDecimalDigit32(uint32_t n) { +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; @@ -58,12 +58,16 @@ inline unsigned CountDecimalDigit32(uint32_t n) { } 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 }; + static const uint64_t kPow10[] = { 1ULL, 10ULL, 100ULL, 1000ULL, 10000ULL, 100000ULL, 1000000ULL, 10000000ULL, 100000000ULL, + 1000000000ULL, 10000000000ULL, 100000000000ULL, 1000000000000ULL, + 10000000000000ULL, 100000000000000ULL, 1000000000000000ULL, + 10000000000000000ULL, 100000000000000000ULL, 1000000000000000000ULL, + 10000000000000000000ULL }; 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); - unsigned kappa = CountDecimalDigit32(p1); // kappa in [0, 9] + int kappa = CountDecimalDigit32(p1); // kappa in [0, 9] *len = 0; while (kappa > 0) { @@ -86,7 +90,7 @@ inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buff 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); + GrisuRound(buffer, *len, delta, tmp, kPow10[kappa] << -one.e, wp_w.f); return; } } @@ -102,8 +106,8 @@ inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buff kappa--; if (p2 < delta) { *K += kappa; - int index = -static_cast(kappa); - GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[-static_cast(kappa)] : 0)); + int index = -kappa; + GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 20 ? kPow10[index] : 0)); return; } } @@ -214,7 +218,7 @@ inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) { } inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324) { - CEREAL_RAPIDJSON_ASSERT(maxDecimalPlaces >= 1); + RAPIDJSON_ASSERT(maxDecimalPlaces >= 1); Double d(value); if (d.IsZero()) { if (d.Sign()) @@ -236,10 +240,10 @@ inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324) { } #ifdef __GNUC__ -CEREAL_RAPIDJSON_DIAG_POP +RAPIDJSON_DIAG_POP #endif } // namespace internal -CEREAL_RAPIDJSON_NAMESPACE_END +RAPIDJSON_NAMESPACE_END -#endif // CEREAL_RAPIDJSON_DTOA_ +#endif // RAPIDJSON_DTOA_ diff --git a/external/cereal/external/rapidjson/internal/ieee754.h b/external/cereal/external/rapidjson/internal/ieee754.h index 35845a1..68c9e96 100644 --- a/external/cereal/external/rapidjson/internal/ieee754.h +++ b/external/cereal/external/rapidjson/internal/ieee754.h @@ -1,6 +1,6 @@ // 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. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // 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 @@ -12,12 +12,12 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -#ifndef CEREAL_RAPIDJSON_IEEE754_ -#define CEREAL_RAPIDJSON_IEEE754_ +#ifndef RAPIDJSON_IEEE754_ +#define RAPIDJSON_IEEE754_ #include "../rapidjson.h" -CEREAL_RAPIDJSON_NAMESPACE_BEGIN +RAPIDJSON_NAMESPACE_BEGIN namespace internal { class Double { @@ -30,7 +30,7 @@ public: uint64_t Uint64Value() const { return u_; } double NextPositiveDouble() const { - CEREAL_RAPIDJSON_ASSERT(!Sign()); + RAPIDJSON_ASSERT(!Sign()); return Double(u_ + 1).Value(); } @@ -48,23 +48,23 @@ public: int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; } uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; } - static unsigned EffectiveSignificandSize(int order) { + static int EffectiveSignificandSize(int order) { if (order >= -1021) return 53; else if (order <= -1074) return 0; else - return static_cast(order) + 1074; + 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 = CEREAL_RAPIDJSON_UINT64_C2(0x80000000, 0x00000000); - static const uint64_t kExponentMask = CEREAL_RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); - static const uint64_t kSignificandMask = CEREAL_RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); - static const uint64_t kHiddenBit = CEREAL_RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); + 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_; @@ -73,6 +73,6 @@ private: }; } // namespace internal -CEREAL_RAPIDJSON_NAMESPACE_END +RAPIDJSON_NAMESPACE_END -#endif // CEREAL_RAPIDJSON_IEEE754_ +#endif // RAPIDJSON_IEEE754_ diff --git a/external/cereal/external/rapidjson/internal/itoa.h b/external/cereal/external/rapidjson/internal/itoa.h index 3e83658..9fe8c93 100644 --- a/external/cereal/external/rapidjson/internal/itoa.h +++ b/external/cereal/external/rapidjson/internal/itoa.h @@ -1,23 +1,23 @@ // 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. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // 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 +// 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 CEREAL_RAPIDJSON_ITOA_ -#define CEREAL_RAPIDJSON_ITOA_ +#ifndef RAPIDJSON_ITOA_ +#define RAPIDJSON_ITOA_ #include "../rapidjson.h" -CEREAL_RAPIDJSON_NAMESPACE_BEGIN +RAPIDJSON_NAMESPACE_BEGIN namespace internal { inline const char* GetDigitsLut() { @@ -37,12 +37,14 @@ inline const char* GetDigitsLut() { } 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) @@ -55,13 +57,13 @@ inline char* u32toa(uint32_t value, char* buffer) { // 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) @@ -69,7 +71,7 @@ inline char* u32toa(uint32_t value, char* buffer) { if (value >= 100000) *buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2 + 1]; - + *buffer++ = cDigitsLut[d3]; *buffer++ = cDigitsLut[d3 + 1]; *buffer++ = cDigitsLut[d4]; @@ -77,10 +79,10 @@ inline char* u32toa(uint32_t value, char* buffer) { } 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]; @@ -91,13 +93,13 @@ inline char* u32toa(uint32_t value, char* buffer) { 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]; @@ -111,6 +113,7 @@ inline char* u32toa(uint32_t value, char* buffer) { } inline char* i32toa(int32_t value, char* buffer) { + RAPIDJSON_ASSERT(buffer != 0); uint32_t u = static_cast(value); if (value < 0) { *buffer++ = '-'; @@ -121,6 +124,7 @@ inline char* i32toa(int32_t value, char* 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; @@ -131,13 +135,13 @@ inline char* u64toa(uint64_t value, char* buffer) { 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) @@ -150,13 +154,13 @@ inline char* u64toa(uint64_t value, char* buffer) { // 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) @@ -164,7 +168,7 @@ inline char* u64toa(uint64_t value, char* buffer) { if (value >= 100000) *buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2 + 1]; - + *buffer++ = cDigitsLut[d3]; *buffer++ = cDigitsLut[d3 + 1]; *buffer++ = cDigitsLut[d4]; @@ -174,22 +178,22 @@ inline char* u64toa(uint64_t value, char* buffer) { 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; @@ -207,9 +211,8 @@ inline char* u64toa(uint64_t value, char* buffer) { *buffer++ = cDigitsLut[d3 + 1]; if (value >= kTen9) *buffer++ = cDigitsLut[d4]; - if (value >= kTen8) - *buffer++ = cDigitsLut[d4 + 1]; - + + *buffer++ = cDigitsLut[d4 + 1]; *buffer++ = cDigitsLut[d5]; *buffer++ = cDigitsLut[d5 + 1]; *buffer++ = cDigitsLut[d6]; @@ -222,7 +225,7 @@ inline char* u64toa(uint64_t value, char* buffer) { 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) { @@ -232,7 +235,7 @@ inline char* u64toa(uint64_t value, char* buffer) { } 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]; @@ -245,28 +248,28 @@ inline char* u64toa(uint64_t value, char* buffer) { *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]; @@ -284,11 +287,12 @@ inline char* u64toa(uint64_t value, char* buffer) { *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++ = '-'; @@ -299,6 +303,6 @@ inline char* i64toa(int64_t value, char* buffer) { } } // namespace internal -CEREAL_RAPIDJSON_NAMESPACE_END +RAPIDJSON_NAMESPACE_END -#endif // CEREAL_RAPIDJSON_ITOA_ +#endif // RAPIDJSON_ITOA_ diff --git a/external/cereal/external/rapidjson/internal/meta.h b/external/cereal/external/rapidjson/internal/meta.h index c98db90..27092dc 100644 --- a/external/cereal/external/rapidjson/internal/meta.h +++ b/external/cereal/external/rapidjson/internal/meta.h @@ -1,6 +1,6 @@ // 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. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // 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 @@ -12,26 +12,27 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -#ifndef CEREAL_RAPIDJSON_INTERNAL_META_H_ -#define CEREAL_RAPIDJSON_INTERNAL_META_H_ +#ifndef RAPIDJSON_INTERNAL_META_H_ +#define RAPIDJSON_INTERNAL_META_H_ #include "../rapidjson.h" #ifdef __GNUC__ -CEREAL_RAPIDJSON_DIAG_PUSH -CEREAL_RAPIDJSON_DIAG_OFF(effc++) -#endif -#if defined(_MSC_VER) -CEREAL_RAPIDJSON_DIAG_PUSH -CEREAL_RAPIDJSON_DIAG_OFF(6334) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) #endif -#if CEREAL_RAPIDJSON_HAS_CXX11_TYPETRAITS +#if defined(_MSC_VER) && !defined(__clang__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(6334) +#endif + +#if RAPIDJSON_HAS_CXX11_TYPETRAITS #include #endif -//@cond CEREAL_RAPIDJSON_INTERNAL -CEREAL_RAPIDJSON_NAMESPACE_BEGIN +//@cond RAPIDJSON_INTERNAL +RAPIDJSON_NAMESPACE_BEGIN namespace internal { // Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching @@ -96,7 +97,7 @@ template struct IsPointer : TrueType {}; /////////////////////////////////////////////////////////////////////////////// // IsBaseOf // -#if CEREAL_RAPIDJSON_HAS_CXX11_TYPETRAITS +#if RAPIDJSON_HAS_CXX11_TYPETRAITS template struct IsBaseOf : BoolType< ::std::is_base_of::value> {}; @@ -104,8 +105,8 @@ template struct IsBaseOf #else // simplified version adopted from Boost template struct IsBaseOfImpl { - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0); - CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0); + RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0); + RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0); typedef char (&Yes)[1]; typedef char (&No) [2]; @@ -125,7 +126,7 @@ template struct IsBaseOfImpl { template struct IsBaseOf : OrExpr, BoolExpr > >::Type {}; -#endif // CEREAL_RAPIDJSON_HAS_CXX11_TYPETRAITS +#endif // RAPIDJSON_HAS_CXX11_TYPETRAITS ////////////////////////////////////////////////////////////////////////// @@ -148,34 +149,38 @@ struct SfinaeTag {}; template struct RemoveSfinaeTag; template struct RemoveSfinaeTag { typedef T Type; }; -#define CEREAL_RAPIDJSON_REMOVEFPTR_(type) \ - typename ::CEREAL_RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \ - < ::CEREAL_RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type +#define RAPIDJSON_REMOVEFPTR_(type) \ + typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \ + < ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type -#define CEREAL_RAPIDJSON_ENABLEIF(cond) \ - typename ::CEREAL_RAPIDJSON_NAMESPACE::internal::EnableIf \ - ::Type * = NULL +#define RAPIDJSON_ENABLEIF(cond) \ + typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ + ::Type * = NULL -#define CEREAL_RAPIDJSON_DISABLEIF(cond) \ - typename ::CEREAL_RAPIDJSON_NAMESPACE::internal::DisableIf \ - ::Type * = NULL +#define RAPIDJSON_DISABLEIF(cond) \ + typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ + ::Type * = NULL -#define CEREAL_RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \ - typename ::CEREAL_RAPIDJSON_NAMESPACE::internal::EnableIf \ - ::Type +#define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \ + typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ + ::Type -#define CEREAL_RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \ - typename ::CEREAL_RAPIDJSON_NAMESPACE::internal::DisableIf \ - ::Type +#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \ + typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ + ::Type } // namespace internal -CEREAL_RAPIDJSON_NAMESPACE_END +RAPIDJSON_NAMESPACE_END //@endcond -#if defined(__GNUC__) || defined(_MSC_VER) -CEREAL_RAPIDJSON_DIAG_POP +#if defined(_MSC_VER) && !defined(__clang__) +RAPIDJSON_DIAG_POP #endif -#endif // CEREAL_RAPIDJSON_INTERNAL_META_H_ +#ifdef __GNUC__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_INTERNAL_META_H_ diff --git a/external/cereal/external/rapidjson/internal/pow10.h b/external/cereal/external/rapidjson/internal/pow10.h index 7f796a1..eae1a43 100644 --- a/external/cereal/external/rapidjson/internal/pow10.h +++ b/external/cereal/external/rapidjson/internal/pow10.h @@ -1,6 +1,6 @@ // 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. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // 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 @@ -12,12 +12,12 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -#ifndef CEREAL_RAPIDJSON_POW10_ -#define CEREAL_RAPIDJSON_POW10_ +#ifndef RAPIDJSON_POW10_ +#define RAPIDJSON_POW10_ #include "../rapidjson.h" -CEREAL_RAPIDJSON_NAMESPACE_BEGIN +RAPIDJSON_NAMESPACE_BEGIN namespace internal { //! Computes integer powers of 10 in double (10.0^n). @@ -45,11 +45,11 @@ inline double Pow10(int n) { 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 }; - CEREAL_RAPIDJSON_ASSERT(n >= 0 && n <= 308); + RAPIDJSON_ASSERT(n >= 0 && n <= 308); return e[n]; } } // namespace internal -CEREAL_RAPIDJSON_NAMESPACE_END +RAPIDJSON_NAMESPACE_END -#endif // CEREAL_RAPIDJSON_POW10_ +#endif // RAPIDJSON_POW10_ diff --git a/external/cereal/external/rapidjson/internal/regex.h b/external/cereal/external/rapidjson/internal/regex.h index 3bfa3ec..6446c40 100644 --- a/external/cereal/external/rapidjson/internal/regex.h +++ b/external/cereal/external/rapidjson/internal/regex.h @@ -1,6 +1,6 @@ // 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. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // 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 @@ -12,43 +12,68 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -#ifndef CEREAL_RAPIDJSON_INTERNAL_REGEX_H_ -#define CEREAL_RAPIDJSON_INTERNAL_REGEX_H_ +#ifndef RAPIDJSON_INTERNAL_REGEX_H_ +#define RAPIDJSON_INTERNAL_REGEX_H_ #include "../allocators.h" #include "../stream.h" #include "stack.h" #ifdef __clang__ -CEREAL_RAPIDJSON_DIAG_PUSH -CEREAL_RAPIDJSON_DIAG_OFF(padded) -CEREAL_RAPIDJSON_DIAG_OFF(switch-enum) -CEREAL_RAPIDJSON_DIAG_OFF(implicit-fallthrough) +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__ -CEREAL_RAPIDJSON_DIAG_PUSH -CEREAL_RAPIDJSON_DIAG_OFF(effc++) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) #endif -#ifdef _MSC_VER -CEREAL_RAPIDJSON_DIAG_PUSH -CEREAL_RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated +#ifndef RAPIDJSON_REGEX_VERBOSE +#define RAPIDJSON_REGEX_VERBOSE 0 #endif -#ifndef CEREAL_RAPIDJSON_REGEX_VERBOSE -#define CEREAL_RAPIDJSON_REGEX_VERBOSE 0 -#endif - -CEREAL_RAPIDJSON_NAMESPACE_BEGIN +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: @@ -84,45 +109,29 @@ static const SizeType kRegexInvalidRange = ~SizeType(0); template class GenericRegex { public: + typedef Encoding EncodingType; typedef typename Encoding::Ch Ch; + template friend class GenericRegexSearch; GenericRegex(const Ch* source, Allocator* allocator = 0) : - states_(allocator, 256), ranges_(allocator, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(), - stateSet_(), state0_(allocator, 0), state1_(allocator, 0), anchorBegin_(), anchorEnd_() + 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 > ds(ss); + DecodedStream, Encoding> ds(ss); Parse(ds); } - ~GenericRegex() { - Allocator::Free(stateSet_); + ~GenericRegex() + { + RAPIDJSON_DELETE(ownAllocator_); } bool IsValid() const { return root_ != kRegexInvalidState; } - template - bool Match(InputStream& is) const { - return SearchWithAnchoring(is, true, true); - } - - bool Match(const Ch* s) const { - GenericStringStream is(s); - return Match(is); - } - - template - bool Search(InputStream& is) const { - return SearchWithAnchoring(is, anchorBegin_, anchorEnd_); - } - - bool Search(const Ch* s) const { - GenericStringStream is(s); - return Search(is); - } - private: enum Operator { kZeroOrOne, @@ -157,54 +166,31 @@ private: SizeType minIndex; }; - 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_; - }; - State& GetState(SizeType index) { - CEREAL_RAPIDJSON_ASSERT(index < stateCount_); + RAPIDJSON_ASSERT(index < stateCount_); return states_.template Bottom()[index]; } const State& GetState(SizeType index) const { - CEREAL_RAPIDJSON_ASSERT(index < stateCount_); + RAPIDJSON_ASSERT(index < stateCount_); return states_.template Bottom()[index]; } Range& GetRange(SizeType index) { - CEREAL_RAPIDJSON_ASSERT(index < rangeCount_); + RAPIDJSON_ASSERT(index < rangeCount_); return ranges_.template Bottom()[index]; } const Range& GetRange(SizeType index) const { - CEREAL_RAPIDJSON_ASSERT(index < rangeCount_); + RAPIDJSON_ASSERT(index < rangeCount_); return ranges_.template Bottom()[index]; } template - void Parse(DecodedStream& ds) { - Allocator allocator; - Stack operandStack(&allocator, 256); // Frag - Stack operatorStack(&allocator, 256); // Operator - Stack atomCountStack(&allocator, 256); // unsigned (Atom per parenthesis) + 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; @@ -301,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); @@ -318,7 +305,7 @@ private: Patch(e->out, NewState(kRegexInvalidState, kRegexInvalidState, 0)); root_ = e->start; -#if CEREAL_RAPIDJSON_REGEX_VERBOSE +#if RAPIDJSON_REGEX_VERBOSE printf("root: %d\n", root_); for (SizeType i = 0; i < stateCount_ ; i++) { State& s = GetState(i); @@ -327,14 +314,6 @@ private: printf("\n"); #endif } - - // Preallocate buffer for SearchWithAnchoring() - CEREAL_RAPIDJSON_ASSERT(stateSet_ == 0); - if (stateCount_ > 0) { - stateSet_ = static_cast(states_.GetAllocator().Malloc(GetStateSetSize())); - state0_.template Reserve(stateCount_); - state1_.template Reserve(stateCount_); - } } SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) { @@ -375,7 +354,7 @@ private: bool Eval(Stack& operandStack, Operator op) { switch (op) { case kConcatenation: - CEREAL_RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag) * 2); + RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag) * 2); { Frag e2 = *operandStack.template Pop(1); Frag e1 = *operandStack.template Pop(1); @@ -413,8 +392,7 @@ private: } return false; - default: - CEREAL_RAPIDJSON_ASSERT(op == kOneOrMore); + case kOneOrMore: if (operandStack.GetSize() >= sizeof(Frag)) { Frag e = *operandStack.template Pop(1); SizeType s = NewState(kRegexInvalidState, e.start, 0); @@ -423,12 +401,16 @@ private: return true; } return false; + + default: + // syntax error (e.g. unclosed kLeftParenthesis) + return false; } } bool EvalQuantifier(Stack& operandStack, unsigned n, unsigned m) { - CEREAL_RAPIDJSON_ASSERT(n <= m); - CEREAL_RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag)); + RAPIDJSON_ASSERT(n <= m); + RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag)); if (n == 0) { if (m == 0) // a{0} not support @@ -483,7 +465,7 @@ private: } template - bool ParseUnsigned(DecodedStream& ds, unsigned* u) { + bool ParseUnsigned(DecodedStream& ds, unsigned* u) { unsigned r = 0; if (ds.Peek() < '0' || ds.Peek() > '9') return false; @@ -497,7 +479,7 @@ private: } template - bool ParseRange(DecodedStream& ds, SizeType* range) { + bool ParseRange(DecodedStream& ds, SizeType* range) { bool isBegin = true; bool negate = false; int step = 0; @@ -519,7 +501,7 @@ private: return false; // Error: nothing inside [] if (step == 2) { // Add trailing '-' SizeType r = NewRange('-'); - CEREAL_RAPIDJSON_ASSERT(current != kRegexInvalidRange); + RAPIDJSON_ASSERT(current != kRegexInvalidRange); GetRange(current).next = r; } if (negate) @@ -535,6 +517,7 @@ private: else if (!CharacterEscape(ds, &codepoint)) return false; // fall through to default + RAPIDJSON_DELIBERATE_FALLTHROUGH; default: switch (step) { @@ -544,6 +527,7 @@ private: break; } // fall through to step 0 for other characters + RAPIDJSON_DELIBERATE_FALLTHROUGH; case 0: { @@ -558,7 +542,7 @@ private: break; default: - CEREAL_RAPIDJSON_ASSERT(step == 2); + RAPIDJSON_ASSERT(step == 2); GetRange(current).end = codepoint; step = 0; } @@ -575,7 +559,7 @@ private: } template - bool CharacterEscape(DecodedStream& ds, unsigned* escapedCodepoint) { + bool CharacterEscape(DecodedStream& ds, unsigned* escapedCodepoint) { unsigned codepoint; switch (codepoint = ds.Take()) { case '^': @@ -603,72 +587,8 @@ private: } } - template - bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) const { - CEREAL_RAPIDJSON_ASSERT(IsValid()); - DecodedStream ds(is); - - state0_.Clear(); - Stack *current = &state0_, *next = &state1_; - const size_t stateSetSize = GetStateSetSize(); - std::memset(stateSet_, 0, stateSetSize); - - bool matched = AddState(*current, 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 = GetState(*s); - if (sr.codepoint == codepoint || - sr.codepoint == kAnyCharacterClass || - (sr.codepoint == kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint))) - { - matched = AddState(*next, sr.out) || matched; - if (!anchorEnd && matched) - return true; - } - if (!anchorBegin) - AddState(*next, root_); - } - internal::Swap(current, next); - } - - return matched; - } - - size_t GetStateSetSize() const { - return (stateCount_ + 31) / 32 * 4; - } - - // Return whether the added states is a match state - bool AddState(Stack& l, SizeType index) const { - CEREAL_RAPIDJSON_ASSERT(index != kRegexInvalidState); - - const State& s = GetState(index); - if (s.out1 != kRegexInvalidState) { // Split - bool matched = AddState(l, s.out); - return AddState(l, s.out1) || matched; - } - else if (!(stateSet_[index >> 5] & (1 << (index & 31)))) { - stateSet_[index >> 5] |= (1 << (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 = (GetRange(rangeIndex).start & kRangeNegationFlag) == 0; - while (rangeIndex != kRegexInvalidRange) { - const Range& r = GetRange(rangeIndex); - if (codepoint >= (r.start & ~kRangeNegationFlag) && codepoint <= r.end) - return yes; - rangeIndex = r.next; - } - return !yes; - } - + Allocator* ownAllocator_; + Allocator* allocator_; Stack states_; Stack ranges_; SizeType root_; @@ -678,24 +598,142 @@ private: static const unsigned kInfinityQuantifier = ~0u; // For SearchWithAnchoring() - uint32_t* stateSet_; // allocated by states_.GetAllocator() - mutable Stack state0_; - mutable Stack state1_; 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 -CEREAL_RAPIDJSON_NAMESPACE_END +RAPIDJSON_NAMESPACE_END -#ifdef __clang__ -CEREAL_RAPIDJSON_DIAG_POP +#ifdef __GNUC__ +RAPIDJSON_DIAG_POP #endif -#ifdef _MSC_VER -CEREAL_RAPIDJSON_DIAG_POP +#if defined(__clang__) || defined(_MSC_VER) +RAPIDJSON_DIAG_POP #endif -#endif // CEREAL_RAPIDJSON_INTERNAL_REGEX_H_ +#endif // RAPIDJSON_INTERNAL_REGEX_H_ diff --git a/external/cereal/external/rapidjson/internal/stack.h b/external/cereal/external/rapidjson/internal/stack.h index 768551e..73abd70 100644 --- a/external/cereal/external/rapidjson/internal/stack.h +++ b/external/cereal/external/rapidjson/internal/stack.h @@ -1,6 +1,6 @@ // 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. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // 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 @@ -12,18 +12,19 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -#ifndef CEREAL_RAPIDJSON_INTERNAL_STACK_H_ -#define CEREAL_RAPIDJSON_INTERNAL_STACK_H_ +#ifndef RAPIDJSON_INTERNAL_STACK_H_ +#define RAPIDJSON_INTERNAL_STACK_H_ #include "../allocators.h" #include "swap.h" +#include #if defined(__clang__) -CEREAL_RAPIDJSON_DIAG_PUSH -CEREAL_RAPIDJSON_DIAG_OFF(c++98-compat) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(c++98-compat) #endif -CEREAL_RAPIDJSON_NAMESPACE_BEGIN +RAPIDJSON_NAMESPACE_BEGIN namespace internal { /////////////////////////////////////////////////////////////////////////////// @@ -40,7 +41,7 @@ public: Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) { } -#if CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS Stack(Stack&& rhs) : allocator_(rhs.allocator_), ownAllocator_(rhs.ownAllocator_), @@ -62,7 +63,7 @@ public: Destroy(); } -#if CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS Stack& operator=(Stack&& rhs) { if (&rhs != this) { @@ -86,7 +87,7 @@ public: } #endif - void Swap(Stack& rhs) CEREAL_RAPIDJSON_NOEXCEPT { + void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT { internal::Swap(allocator_, rhs.allocator_); internal::Swap(ownAllocator_, rhs.ownAllocator_); internal::Swap(stack_, rhs.stack_); @@ -100,7 +101,7 @@ public: void ShrinkToFit() { if (Empty()) { // If the stack is empty, completely deallocate the memory. - Allocator::Free(stack_); + Allocator::Free(stack_); // NOLINT (+clang-analyzer-unix.Malloc) stack_ = 0; stackTop_ = 0; stackEnd_ = 0; @@ -112,21 +113,22 @@ public: // 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 - CEREAL_RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) { + RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) { // Expand the stack if needed - if (CEREAL_RAPIDJSON_UNLIKELY(stackTop_ + sizeof(T) * count > stackEnd_)) + if (RAPIDJSON_UNLIKELY(static_cast(sizeof(T) * count) > (stackEnd_ - stackTop_))) Expand(count); } template - CEREAL_RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) { + RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) { Reserve(count); return PushUnsafe(count); } template - CEREAL_RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) { - CEREAL_RAPIDJSON_ASSERT(stackTop_ + sizeof(T) * count <= stackEnd_); + 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; @@ -134,20 +136,20 @@ public: template T* Pop(size_t count) { - CEREAL_RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T)); + RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T)); stackTop_ -= count * sizeof(T); return reinterpret_cast(stackTop_); } template T* Top() { - CEREAL_RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); + RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); return reinterpret_cast(stackTop_ - sizeof(T)); } template const T* Top() const { - CEREAL_RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); + RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); return reinterpret_cast(stackTop_ - sizeof(T)); } @@ -168,7 +170,7 @@ public: } Allocator& GetAllocator() { - CEREAL_RAPIDJSON_ASSERT(allocator_); + RAPIDJSON_ASSERT(allocator_); return *allocator_; } @@ -183,7 +185,7 @@ private: size_t newCapacity; if (stack_ == 0) { if (!allocator_) - ownAllocator_ = allocator_ = CEREAL_RAPIDJSON_NEW(Allocator()); + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); newCapacity = initialCapacity_; } else { newCapacity = GetCapacity(); @@ -205,7 +207,7 @@ private: void Destroy() { Allocator::Free(stack_); - CEREAL_RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack + RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack } // Prohibit copy constructor & assignment operator. @@ -221,10 +223,10 @@ private: }; } // namespace internal -CEREAL_RAPIDJSON_NAMESPACE_END +RAPIDJSON_NAMESPACE_END #if defined(__clang__) -CEREAL_RAPIDJSON_DIAG_POP +RAPIDJSON_DIAG_POP #endif -#endif // CEREAL_RAPIDJSON_STACK_H_ +#endif // RAPIDJSON_STACK_H_ diff --git a/external/cereal/external/rapidjson/internal/strfunc.h b/external/cereal/external/rapidjson/internal/strfunc.h index 0c6973c..b698a8f 100644 --- a/external/cereal/external/rapidjson/internal/strfunc.h +++ b/external/cereal/external/rapidjson/internal/strfunc.h @@ -1,6 +1,6 @@ // 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. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // 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 @@ -12,12 +12,13 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -#ifndef CEREAL_RAPIDJSON_INTERNAL_STRFUNC_H_ -#define CEREAL_RAPIDJSON_INTERNAL_STRFUNC_H_ +#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_ +#define RAPIDJSON_INTERNAL_STRFUNC_H_ #include "../stream.h" +#include -CEREAL_RAPIDJSON_NAMESPACE_BEGIN +RAPIDJSON_NAMESPACE_BEGIN namespace internal { //! Custom strlen() which works on different character types. @@ -28,14 +29,41 @@ namespace internal { */ 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)); +} + +//! Custom strcmpn() which works on different character types. +/*! \tparam Ch Character type (e.g. char, wchar_t, short) + \param s1 Null-terminated input string. + \param s2 Null-terminated input string. + \return 0 if equal +*/ +template +inline int StrCmp(const Ch* s1, const Ch* s2) { + RAPIDJSON_ASSERT(s1 != 0); + RAPIDJSON_ASSERT(s2 != 0); + while(*s1 && (*s1 == *s2)) { s1++; s2++; } + return static_cast(*s1) < static_cast(*s2) ? -1 : static_cast(*s1) > static_cast(*s2); +} + //! 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; @@ -50,6 +78,6 @@ bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeT } } // namespace internal -CEREAL_RAPIDJSON_NAMESPACE_END +RAPIDJSON_NAMESPACE_END -#endif // CEREAL_RAPIDJSON_INTERNAL_STRFUNC_H_ +#endif // RAPIDJSON_INTERNAL_STRFUNC_H_ diff --git a/external/cereal/external/rapidjson/internal/strtod.h b/external/cereal/external/rapidjson/internal/strtod.h index 076434c..55f0e38 100644 --- a/external/cereal/external/rapidjson/internal/strtod.h +++ b/external/cereal/external/rapidjson/internal/strtod.h @@ -1,6 +1,6 @@ // 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. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // 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 @@ -12,15 +12,17 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -#ifndef CEREAL_RAPIDJSON_STRTOD_ -#define CEREAL_RAPIDJSON_STRTOD_ +#ifndef RAPIDJSON_STRTOD_ +#define RAPIDJSON_STRTOD_ #include "ieee754.h" #include "biginteger.h" #include "diyfp.h" #include "pow10.h" +#include +#include -CEREAL_RAPIDJSON_NAMESPACE_BEGIN +RAPIDJSON_NAMESPACE_BEGIN namespace internal { inline double FastPath(double significand, int exp) { @@ -126,46 +128,47 @@ inline bool StrtodFast(double d, int p, double* result) { } // Compute an approximation and see if it is within 1/2 ULP -inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosition, int exp, double* result) { +template +inline bool StrtodDiyFp(const Ch* decimals, int dLen, int dExp, double* result) { uint64_t significand = 0; - size_t i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999 - for (; i < length; i++) { - if (significand > CEREAL_RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || - (significand == CEREAL_RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5')) + 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] > Ch('5'))) break; - significand = significand * 10u + static_cast(decimals[i] - '0'); + significand = significand * 10u + static_cast(decimals[i] - Ch('0')); } - if (i < length && decimals[i] >= '5') // Rounding + if (i < dLen && decimals[i] >= Ch('5')) // Rounding significand++; - size_t remaining = length - i; - const unsigned kUlpShift = 3; - const unsigned kUlp = 1 << kUlpShift; + 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; - const int dExp = static_cast(decimalPosition) - static_cast(i) + exp; + dExp += remaining; int actualExp; DiyFp cachedPower = GetCachedPower10(dExp, &actualExp); if (actualExp != dExp) { static const DiyFp kPow10[] = { - DiyFp(CEREAL_RAPIDJSON_UINT64_C2(0xa0000000, 00000000), -60), // 10^1 - DiyFp(CEREAL_RAPIDJSON_UINT64_C2(0xc8000000, 00000000), -57), // 10^2 - DiyFp(CEREAL_RAPIDJSON_UINT64_C2(0xfa000000, 00000000), -54), // 10^3 - DiyFp(CEREAL_RAPIDJSON_UINT64_C2(0x9c400000, 00000000), -50), // 10^4 - DiyFp(CEREAL_RAPIDJSON_UINT64_C2(0xc3500000, 00000000), -47), // 10^5 - DiyFp(CEREAL_RAPIDJSON_UINT64_C2(0xf4240000, 00000000), -44), // 10^6 - DiyFp(CEREAL_RAPIDJSON_UINT64_C2(0x98968000, 00000000), -40) // 10^7 + 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 - 1; - CEREAL_RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7); - v = v * kPow10[adjustment]; - if (length + static_cast(adjustment)> 19u) // has more digits than decimal digits in 64-bit + 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; } @@ -177,17 +180,17 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit v = v.Normalize(); error <<= oldExp - v.e; - const unsigned effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e); - unsigned precisionSize = 64 - effectiveSignificandSize; + const int effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e); + int precisionSize = 64 - effectiveSignificandSize; if (precisionSize + kUlpShift >= 64) { - unsigned scaleExp = (precisionSize + kUlpShift) - 63; + int scaleExp = (precisionSize + kUlpShift) - 63; v.f >>= scaleExp; v.e += scaleExp; - error = (error >> scaleExp) + 1 + static_cast(kUlp); + error = (error >> scaleExp) + 1 + kUlp; precisionSize -= scaleExp; } - DiyFp rounded(v.f >> precisionSize, v.e + static_cast(precisionSize)); + 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)) { @@ -203,9 +206,10 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit return halfWay - static_cast(error) >= precisionBits || precisionBits >= halfWay + static_cast(error); } -inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) { - const BigInteger dInt(decimals, length); - const int dExp = static_cast(decimalPosition) - static_cast(length) + exp; +template +inline double StrtodBigInteger(double approx, const Ch* 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) @@ -221,49 +225,69 @@ inline double StrtodBigInteger(double approx, const char* decimals, size_t lengt return a.NextPositiveDouble(); } -inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) { - CEREAL_RAPIDJSON_ASSERT(d >= 0.0); - CEREAL_RAPIDJSON_ASSERT(length >= 1); +template +inline double StrtodFullPrecision(double d, int p, const Ch* decimals, size_t length, size_t decimalPosition, int exp) { + RAPIDJSON_ASSERT(d >= 0.0); + RAPIDJSON_ASSERT(length >= 1); - double result; + 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 (*decimals == '0' && length > 1) { - length--; + while (dLen > 0 && *decimals == '0') { + dLen--; decimals++; - decimalPosition--; } // Trim trailing zeros - while (decimals[length - 1] == '0' && length > 1) { - length--; - decimalPosition--; - exp++; + 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 = 780; - if (static_cast(length) > kMaxDecimalDigit) { - int delta = (static_cast(length) - kMaxDecimalDigit); - exp += delta; - decimalPosition -= static_cast(delta); - length = kMaxDecimalDigit; + const int kMaxDecimalDigit = 767 + 1; + if (dLen > kMaxDecimalDigit) { + dExp += dLen - kMaxDecimalDigit; + dLen = kMaxDecimalDigit; } - // If too small, underflow to zero - if (int(length) + exp < -324) + // If too small, underflow to zero. + // Any x <= 10^-324 is interpreted as zero. + if (dLen + dExp <= -324) return 0.0; - if (StrtodDiyFp(decimals, length, decimalPosition, exp, &result)) + // 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, length, decimalPosition, exp); + return StrtodBigInteger(result, decimals, dLen, dExp); } } // namespace internal -CEREAL_RAPIDJSON_NAMESPACE_END +RAPIDJSON_NAMESPACE_END -#endif // CEREAL_RAPIDJSON_STRTOD_ +#endif // RAPIDJSON_STRTOD_ diff --git a/external/cereal/external/rapidjson/internal/swap.h b/external/cereal/external/rapidjson/internal/swap.h index 5d8910c..2cf92f9 100644 --- a/external/cereal/external/rapidjson/internal/swap.h +++ b/external/cereal/external/rapidjson/internal/swap.h @@ -1,6 +1,6 @@ // 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. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // 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 @@ -12,17 +12,17 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -#ifndef CEREAL_RAPIDJSON_INTERNAL_SWAP_H_ -#define CEREAL_RAPIDJSON_INTERNAL_SWAP_H_ +#ifndef RAPIDJSON_INTERNAL_SWAP_H_ +#define RAPIDJSON_INTERNAL_SWAP_H_ #include "../rapidjson.h" #if defined(__clang__) -CEREAL_RAPIDJSON_DIAG_PUSH -CEREAL_RAPIDJSON_DIAG_OFF(c++98-compat) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(c++98-compat) #endif -CEREAL_RAPIDJSON_NAMESPACE_BEGIN +RAPIDJSON_NAMESPACE_BEGIN namespace internal { //! Custom swap() to avoid dependency on C++ header @@ -30,17 +30,17 @@ namespace internal { \note This has the same semantics as std::swap(). */ template -inline void Swap(T& a, T& b) CEREAL_RAPIDJSON_NOEXCEPT { +inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT { T tmp = a; a = b; b = tmp; } } // namespace internal -CEREAL_RAPIDJSON_NAMESPACE_END +RAPIDJSON_NAMESPACE_END #if defined(__clang__) -CEREAL_RAPIDJSON_DIAG_POP +RAPIDJSON_DIAG_POP #endif -#endif // CEREAL_RAPIDJSON_INTERNAL_SWAP_H_ +#endif // RAPIDJSON_INTERNAL_SWAP_H_ diff --git a/external/cereal/external/rapidjson/istreamwrapper.h b/external/cereal/external/rapidjson/istreamwrapper.h index e1c7ea8..01437ec 100644 --- a/external/cereal/external/rapidjson/istreamwrapper.h +++ b/external/cereal/external/rapidjson/istreamwrapper.h @@ -1,35 +1,33 @@ // 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. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // 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 +// 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 CEREAL_RAPIDJSON_ISTREAMWRAPPER_H_ -#define CEREAL_RAPIDJSON_ISTREAMWRAPPER_H_ +#ifndef RAPIDJSON_ISTREAMWRAPPER_H_ +#define RAPIDJSON_ISTREAMWRAPPER_H_ #include "stream.h" #include +#include #ifdef __clang__ -CEREAL_RAPIDJSON_DIAG_PUSH -CEREAL_RAPIDJSON_DIAG_OFF(padded) +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 -#ifdef _MSC_VER -CEREAL_RAPIDJSON_DIAG_PUSH -CEREAL_RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized -CEREAL_RAPIDJSON_DIAG_OFF(4127) // ignore assert(false) for triggering exception -#endif - -CEREAL_RAPIDJSON_NAMESPACE_BEGIN +RAPIDJSON_NAMESPACE_BEGIN //! Wrapper of \c std::basic_istream into RapidJSON's Stream concept. /*! @@ -46,71 +44,85 @@ CEREAL_RAPIDJSON_NAMESPACE_BEGIN \tparam StreamType Class derived from \c std::basic_istream. */ - + template class BasicIStreamWrapper { public: typedef typename StreamType::char_type Ch; - BasicIStreamWrapper(StreamType& stream) : stream_(stream), count_(), peekBuffer_() {} - Ch Peek() const { - typename StreamType::int_type c = stream_.peek(); - return CEREAL_RAPIDJSON_LIKELY(c != StreamType::traits_type::eof()) ? static_cast(c) : '\0'; + //! 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(); } - Ch Take() { - typename StreamType::int_type c = stream_.get(); - if (CEREAL_RAPIDJSON_LIKELY(c != StreamType::traits_type::eof())) { - count_++; - return static_cast(c); - } - else - return '\0'; + //! 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(); } - // tellg() may return -1 when failed. So we count by ourself. - size_t Tell() const { return count_; } + Ch Peek() const { return *current_; } + Ch Take() { Ch c = *current_; Read(); return c; } + size_t Tell() const { return count_ + static_cast(current_ - buffer_); } - Ch* PutBegin() { CEREAL_RAPIDJSON_ASSERT(false); return 0; } - void Put(Ch) { CEREAL_RAPIDJSON_ASSERT(false); } - void Flush() { CEREAL_RAPIDJSON_ASSERT(false); } - size_t PutEnd(Ch*) { CEREAL_RAPIDJSON_ASSERT(false); return 0; } + // 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 { - CEREAL_RAPIDJSON_ASSERT(sizeof(Ch) == 1); // Only usable for byte stream. - int i; - bool hasError = false; - for (i = 0; i < 4; ++i) { - typename StreamType::int_type c = stream_.get(); - if (c == StreamType::traits_type::eof()) { - hasError = true; - stream_.clear(); - break; - } - peekBuffer_[i] = static_cast(c); - } - for (--i; i >= 0; --i) - stream_.putback(peekBuffer_[i]); - return !hasError ? peekBuffer_ : 0; + return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0; } private: + BasicIStreamWrapper(); BasicIStreamWrapper(const BasicIStreamWrapper&); BasicIStreamWrapper& operator=(const BasicIStreamWrapper&); - StreamType& stream_; - size_t count_; //!< Number of characters read. Note: - mutable Ch peekBuffer_[4]; + 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) -CEREAL_RAPIDJSON_DIAG_POP +RAPIDJSON_DIAG_POP #endif -CEREAL_RAPIDJSON_NAMESPACE_END +RAPIDJSON_NAMESPACE_END -#endif // CEREAL_RAPIDJSON_ISTREAMWRAPPER_H_ +#endif // RAPIDJSON_ISTREAMWRAPPER_H_ diff --git a/external/cereal/external/rapidjson/memorybuffer.h b/external/cereal/external/rapidjson/memorybuffer.h index 0cd75cf..ffbc41e 100644 --- a/external/cereal/external/rapidjson/memorybuffer.h +++ b/external/cereal/external/rapidjson/memorybuffer.h @@ -1,6 +1,6 @@ // 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. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // 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 @@ -12,13 +12,13 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -#ifndef CEREAL_RAPIDJSON_MEMORYBUFFER_H_ -#define CEREAL_RAPIDJSON_MEMORYBUFFER_H_ +#ifndef RAPIDJSON_MEMORYBUFFER_H_ +#define RAPIDJSON_MEMORYBUFFER_H_ #include "stream.h" #include "internal/stack.h" -CEREAL_RAPIDJSON_NAMESPACE_BEGIN +RAPIDJSON_NAMESPACE_BEGIN //! Represents an in-memory output byte stream. /*! @@ -65,6 +65,6 @@ inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) { std::memset(memoryBuffer.stack_.Push(n), c, n * sizeof(c)); } -CEREAL_RAPIDJSON_NAMESPACE_END +RAPIDJSON_NAMESPACE_END -#endif // CEREAL_RAPIDJSON_MEMORYBUFFER_H_ +#endif // RAPIDJSON_MEMORYBUFFER_H_ diff --git a/external/cereal/external/rapidjson/memorystream.h b/external/cereal/external/rapidjson/memorystream.h index e48988c..77af6c9 100644 --- a/external/cereal/external/rapidjson/memorystream.h +++ b/external/cereal/external/rapidjson/memorystream.h @@ -1,34 +1,29 @@ // 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. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // 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 +// 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 CEREAL_RAPIDJSON_MEMORYSTREAM_H_ -#define CEREAL_RAPIDJSON_MEMORYSTREAM_H_ +#ifndef RAPIDJSON_MEMORYSTREAM_H_ +#define RAPIDJSON_MEMORYSTREAM_H_ #include "stream.h" #ifdef __clang__ -CEREAL_RAPIDJSON_DIAG_PUSH -CEREAL_RAPIDJSON_DIAG_OFF(unreachable-code) -CEREAL_RAPIDJSON_DIAG_OFF(missing-noreturn) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(unreachable-code) +RAPIDJSON_DIAG_OFF(missing-noreturn) #endif -#ifdef _MSC_VER -CEREAL_RAPIDJSON_DIAG_PUSH -CEREAL_RAPIDJSON_DIAG_OFF( 4127 ) // ignore assert(false) for triggering exception -#endif - -CEREAL_RAPIDJSON_NAMESPACE_BEGIN +RAPIDJSON_NAMESPACE_BEGIN //! Represents an in-memory input byte stream. /*! @@ -47,14 +42,14 @@ struct MemoryStream { MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {} - Ch Peek() const { return CEREAL_RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_; } - Ch Take() { return CEREAL_RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_++; } + 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() { CEREAL_RAPIDJSON_ASSERT(false); return 0; } - void Put(Ch) { CEREAL_RAPIDJSON_ASSERT(false); } - void Flush() { CEREAL_RAPIDJSON_ASSERT(false); } - size_t PutEnd(Ch*) { CEREAL_RAPIDJSON_ASSERT(false); return 0; } + 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 { @@ -67,10 +62,10 @@ struct MemoryStream { size_t size_; //!< Size of the stream. }; -CEREAL_RAPIDJSON_NAMESPACE_END +RAPIDJSON_NAMESPACE_END -#if defined(__clang__) || defined(_MSC_VER) -CEREAL_RAPIDJSON_DIAG_POP +#ifdef __clang__ +RAPIDJSON_DIAG_POP #endif -#endif // CEREAL_RAPIDJSON_MEMORYBUFFER_H_ +#endif // RAPIDJSON_MEMORYBUFFER_H_ diff --git a/external/cereal/external/rapidjson/ostreamwrapper.h b/external/cereal/external/rapidjson/ostreamwrapper.h index 58c034a..11ed4d3 100644 --- a/external/cereal/external/rapidjson/ostreamwrapper.h +++ b/external/cereal/external/rapidjson/ostreamwrapper.h @@ -1,6 +1,6 @@ // 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. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // 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 @@ -12,18 +12,18 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -#ifndef CEREAL_RAPIDJSON_OSTREAMWRAPPER_H_ -#define CEREAL_RAPIDJSON_OSTREAMWRAPPER_H_ +#ifndef RAPIDJSON_OSTREAMWRAPPER_H_ +#define RAPIDJSON_OSTREAMWRAPPER_H_ #include "stream.h" #include #ifdef __clang__ -CEREAL_RAPIDJSON_DIAG_PUSH -CEREAL_RAPIDJSON_DIAG_OFF(padded) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) #endif -CEREAL_RAPIDJSON_NAMESPACE_BEGIN +RAPIDJSON_NAMESPACE_BEGIN //! Wrapper of \c std::basic_ostream into RapidJSON's Stream concept. /*! @@ -56,11 +56,11 @@ public: } // Not implemented - char Peek() const { CEREAL_RAPIDJSON_ASSERT(false); return 0; } - char Take() { CEREAL_RAPIDJSON_ASSERT(false); return 0; } - size_t Tell() const { CEREAL_RAPIDJSON_ASSERT(false); return 0; } - char* PutBegin() { CEREAL_RAPIDJSON_ASSERT(false); return 0; } - size_t PutEnd(char*) { CEREAL_RAPIDJSON_ASSERT(false); return 0; } + 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&); @@ -73,9 +73,9 @@ typedef BasicOStreamWrapper OStreamWrapper; typedef BasicOStreamWrapper WOStreamWrapper; #ifdef __clang__ -CEREAL_RAPIDJSON_DIAG_POP +RAPIDJSON_DIAG_POP #endif -CEREAL_RAPIDJSON_NAMESPACE_END +RAPIDJSON_NAMESPACE_END -#endif // CEREAL_RAPIDJSON_OSTREAMWRAPPER_H_ +#endif // RAPIDJSON_OSTREAMWRAPPER_H_ diff --git a/external/cereal/external/rapidjson/pointer.h b/external/cereal/external/rapidjson/pointer.h index 1e4836c..67a9cb0 100644 --- a/external/cereal/external/rapidjson/pointer.h +++ b/external/cereal/external/rapidjson/pointer.h @@ -1,6 +1,6 @@ // 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. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // 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 @@ -12,28 +12,27 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -#ifndef CEREAL_RAPIDJSON_POINTER_H_ -#define CEREAL_RAPIDJSON_POINTER_H_ +#ifndef RAPIDJSON_POINTER_H_ +#define RAPIDJSON_POINTER_H_ #include "document.h" +#include "uri.h" #include "internal/itoa.h" #ifdef __clang__ -CEREAL_RAPIDJSON_DIAG_PUSH -CEREAL_RAPIDJSON_DIAG_OFF(switch-enum) +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 -#ifdef _MSC_VER -CEREAL_RAPIDJSON_DIAG_PUSH -CEREAL_RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated -#endif - -CEREAL_RAPIDJSON_NAMESPACE_BEGIN +RAPIDJSON_NAMESPACE_BEGIN static const SizeType kPointerInvalidIndex = ~SizeType(0); //!< Represents an invalid index in GenericPointer::Token //! Error code of parsing. -/*! \ingroup CEREAL_RAPIDJSON_ERRORS +/*! \ingroup RAPIDJSON_ERRORS \see GenericPointer::GenericPointer, GenericPointer::GetParseErrorCode */ enum PointerParseErrorCode { @@ -82,6 +81,8 @@ class GenericPointer { public: typedef typename ValueType::EncodingType EncodingType; //!< Encoding type from Value typedef typename ValueType::Ch Ch; //!< Character type from Value + typedef GenericUri UriType; + //! A token is the basic units of internal representation. /*! @@ -117,12 +118,12 @@ public: Parse(source, internal::StrLen(source)); } -#if CEREAL_RAPIDJSON_HAS_STDSTRING +#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 CEREAL_RAPIDJSON_HAS_STDSTRING. + \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()); @@ -165,7 +166,12 @@ public: 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* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { + GenericPointer(const GenericPointer& 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; } @@ -173,7 +179,7 @@ public: ~GenericPointer() { if (nameBuffer_) // If user-supplied tokens constructor is used, nameBuffer_ is nullptr and tokens_ are not deallocated. Allocator::Free(tokens_); - CEREAL_RAPIDJSON_DELETE(ownAllocator_); + RAPIDJSON_DELETE(ownAllocator_); } //! Assignment operator. @@ -197,6 +203,36 @@ public: 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 @@ -238,12 +274,12 @@ public: \return A new Pointer with appended token. */ template - CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >), (GenericPointer)) + RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >), (GenericPointer)) Append(T* name, Allocator* allocator = 0) const { - return Append(name, StrLen(name), allocator); + return Append(name, internal::StrLen(name), allocator); } -#if CEREAL_RAPIDJSON_HAS_STDSTRING +#if RAPIDJSON_HAS_STDSTRING //! Append a name token, and return a new Pointer /*! \param name Name to be appended. @@ -274,7 +310,7 @@ public: else { Ch name[21]; for (size_t i = 0; i <= length; i++) - name[i] = buffer[i]; + name[i] = static_cast(buffer[i]); Token token = { name, length, index }; return Append(token, allocator); } @@ -290,8 +326,8 @@ public: if (token.IsString()) return Append(token.GetString(), token.GetStringLength(), allocator); else { - CEREAL_RAPIDJSON_ASSERT(token.IsUint64()); - CEREAL_RAPIDJSON_ASSERT(token.GetUint64() <= SizeType(~0)); + RAPIDJSON_ASSERT(token.IsUint64()); + RAPIDJSON_ASSERT(token.GetUint64() <= SizeType(~0)); return Append(static_cast(token.GetUint64()), allocator); } } @@ -353,6 +389,33 @@ public: */ 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 @@ -399,7 +462,7 @@ public: \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 { - CEREAL_RAPIDJSON_ASSERT(IsValid()); + RAPIDJSON_ASSERT(IsValid()); ValueType* v = &root; bool exist = true; for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { @@ -428,10 +491,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 @@ -459,6 +523,70 @@ public: //@} + //!@name Compute URI + //@{ + + //! Compute the in-scope URI for a subtree. + // For use with JSON pointers into JSON schema documents. + /*! + \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. + \param rootUri Root URI + \param unresolvedTokenIndex If the pointer cannot resolve a token in the pointer, this parameter can obtain the index of unresolved token. + \param allocator Allocator for Uris + \return Uri if it can be resolved. Otherwise null. + + \note + There are only 3 situations when a URI 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. + */ + UriType GetUri(ValueType& root, const UriType& rootUri, size_t* unresolvedTokenIndex = 0, Allocator* allocator = 0) const { + static const Ch kIdString[] = { 'i', 'd', '\0' }; + static const ValueType kIdValue(kIdString, 2); + UriType base = UriType(rootUri, allocator); + RAPIDJSON_ASSERT(IsValid()); + ValueType* v = &root; + for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { + switch (v->GetType()) { + case kObjectType: + { + // See if we have an id, and if so resolve with the current base + typename ValueType::MemberIterator m = v->FindMember(kIdValue); + if (m != v->MemberEnd() && (m->value).IsString()) { + UriType here = UriType(m->value, allocator).Resolve(base, allocator); + base = here; + } + 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 UriType(allocator); + } + return base; + } + + UriType GetUri(const ValueType& root, const UriType& rootUri, size_t* unresolvedTokenIndex = 0, Allocator* allocator = 0) const { + return GetUri(const_cast(root), rootUri, unresolvedTokenIndex, allocator); + } + + //!@name Query value //@{ @@ -477,13 +605,13 @@ public: Use unresolvedTokenIndex to retrieve the token index. */ ValueType* Get(ValueType& root, size_t* unresolvedTokenIndex = 0) const { - CEREAL_RAPIDJSON_ASSERT(IsValid()); + 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(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; @@ -532,22 +660,22 @@ public: */ ValueType& GetWithDefault(ValueType& root, const ValueType& defaultValue, typename ValueType::AllocatorType& allocator) const { bool alreadyExist; - Value& v = Create(root, allocator, &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; - Value& v = Create(root, allocator, &alreadyExist); + ValueType& v = Create(root, allocator, &alreadyExist); return alreadyExist ? v : v.SetString(defaultValue, allocator); } -#if CEREAL_RAPIDJSON_HAS_STDSTRING +#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; - Value& v = Create(root, allocator, &alreadyExist); + ValueType& v = Create(root, allocator, &alreadyExist); return alreadyExist ? v : v.SetString(defaultValue, allocator); } #endif @@ -557,7 +685,7 @@ public: \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool */ template - CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) + 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); } @@ -574,7 +702,7 @@ public: return GetWithDefault(document, defaultValue, document.GetAllocator()); } -#if CEREAL_RAPIDJSON_HAS_STDSTRING +#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 { @@ -587,7 +715,7 @@ public: \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool */ template - CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) GetWithDefault(GenericDocument& document, T defaultValue) const { return GetWithDefault(document, defaultValue, document.GetAllocator()); } @@ -621,7 +749,7 @@ public: return Create(root, allocator) = ValueType(value, allocator).Move(); } -#if CEREAL_RAPIDJSON_HAS_STDSTRING +#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(); @@ -633,7 +761,7 @@ public: \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool */ template - CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) + 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(); } @@ -656,7 +784,7 @@ public: return Create(document) = ValueType(value, document.GetAllocator()).Move(); } -#if CEREAL_RAPIDJSON_HAS_STDSTRING +#if RAPIDJSON_HAS_STDSTRING //! Sets a std::basic_string in a document. template ValueType& Set(GenericDocument& document, const std::basic_string& value) const { @@ -669,7 +797,7 @@ public: \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool */ template - CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) Set(GenericDocument& document, T value) const { return Create(document) = value; } @@ -709,7 +837,7 @@ public: \note Erasing with an empty pointer \c Pointer(""), i.e. the root, always fail and return false. */ bool Erase(ValueType& root) const { - CEREAL_RAPIDJSON_ASSERT(IsValid()); + RAPIDJSON_ASSERT(IsValid()); if (tokenCount_ == 0) // Cannot erase the root return false; @@ -719,7 +847,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; @@ -758,7 +886,7 @@ private: */ Ch* CopyFromRaw(const GenericPointer& rhs, size_t extraToken = 0, size_t extraNameBufferSize = 0) { if (!allocator_) // allocator is independently owned. - ownAllocator_ = allocator_ = CEREAL_RAPIDJSON_NEW(Allocator()); + 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) @@ -800,13 +928,13 @@ private: */ #endif void Parse(const Ch* source, size_t length) { - CEREAL_RAPIDJSON_ASSERT(source != NULL); - CEREAL_RAPIDJSON_ASSERT(nameBuffer_ == 0); - CEREAL_RAPIDJSON_ASSERT(tokens_ == 0); + RAPIDJSON_ASSERT(source != NULL); + RAPIDJSON_ASSERT(nameBuffer_ == 0); + RAPIDJSON_ASSERT(tokens_ == 0); // Create own allocator if user did not supply. if (!allocator_) - ownAllocator_ = allocator_ = CEREAL_RAPIDJSON_NEW(Allocator()); + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); // Count number of '/' as tokenCount tokenCount_ = 0; @@ -831,7 +959,7 @@ private: } while (i < length) { - CEREAL_RAPIDJSON_ASSERT(source[i] == '/'); + RAPIDJSON_ASSERT(source[i] == '/'); i++; // consumes '/' token->name = name; @@ -918,7 +1046,7 @@ private: token++; } - CEREAL_RAPIDJSON_ASSERT(name <= nameBuffer_ + length); // Should not overflow buffer + RAPIDJSON_ASSERT(name <= nameBuffer_ + length); // Should not overflow buffer parseErrorCode_ = kPointerParseErrorNone; return; @@ -939,7 +1067,7 @@ private: */ template bool Stringify(OutputStream& os) const { - CEREAL_RAPIDJSON_ASSERT(IsValid()); + RAPIDJSON_ASSERT(IsValid()); if (uriFragment) os.Put('#'); @@ -1029,8 +1157,8 @@ private: 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(hexDigits[u >> 4]); - os_.Put(hexDigits[u & 15]); + os_.Put(static_cast(hexDigits[u >> 4])); + os_.Put(static_cast(hexDigits[u & 15])); } private: OutputStream& os_; @@ -1109,7 +1237,7 @@ typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointe return pointer.GetWithDefault(root, defaultValue, a); } -#if CEREAL_RAPIDJSON_HAS_STDSTRING +#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); @@ -1117,7 +1245,7 @@ typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointe #endif template -CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) +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); } @@ -1132,7 +1260,7 @@ typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&sou return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); } -#if CEREAL_RAPIDJSON_HAS_STDSTRING +#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); @@ -1140,7 +1268,7 @@ typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&sou #endif template -CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) +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); } @@ -1157,7 +1285,7 @@ typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& doc return pointer.GetWithDefault(document, defaultValue); } -#if CEREAL_RAPIDJSON_HAS_STDSTRING +#if RAPIDJSON_HAS_STDSTRING template typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, const std::basic_string& defaultValue) { return pointer.GetWithDefault(document, defaultValue); @@ -1165,7 +1293,7 @@ typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& doc #endif template -CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, T2 defaultValue) { return pointer.GetWithDefault(document, defaultValue); } @@ -1180,7 +1308,7 @@ typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& doc return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); } -#if CEREAL_RAPIDJSON_HAS_STDSTRING +#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); @@ -1188,7 +1316,7 @@ typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& doc #endif template -CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) +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); } @@ -1210,7 +1338,7 @@ typename T::ValueType& SetValueByPointer(T& root, const GenericPointer typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, const std::basic_string& value, typename T::AllocatorType& a) { return pointer.Set(root, value, a); @@ -1218,7 +1346,7 @@ typename T::ValueType& SetValueByPointer(T& root, const GenericPointer -CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) +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); } @@ -1238,7 +1366,7 @@ typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], co return GenericPointer(source, N - 1).Set(root, value, a); } -#if CEREAL_RAPIDJSON_HAS_STDSTRING +#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); @@ -1246,7 +1374,7 @@ typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], co #endif template -CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) +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); } @@ -1268,7 +1396,7 @@ typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, cons return pointer.Set(document, value); } -#if CEREAL_RAPIDJSON_HAS_STDSTRING +#if RAPIDJSON_HAS_STDSTRING template typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, const std::basic_string& value) { return pointer.Set(document, value); @@ -1276,7 +1404,7 @@ typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, cons #endif template -CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) SetValueByPointer(DocumentType& document, const GenericPointer& pointer, T2 value) { return pointer.Set(document, value); } @@ -1296,7 +1424,7 @@ typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, cons return GenericPointer(source, N - 1).Set(document, value); } -#if CEREAL_RAPIDJSON_HAS_STDSTRING +#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); @@ -1304,7 +1432,7 @@ typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, cons #endif template -CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) +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); } @@ -1345,14 +1473,10 @@ bool EraseValueByPointer(T& root, const CharType(&source)[N]) { //@} -CEREAL_RAPIDJSON_NAMESPACE_END +RAPIDJSON_NAMESPACE_END -#ifdef __clang__ -CEREAL_RAPIDJSON_DIAG_POP +#if defined(__clang__) || defined(_MSC_VER) +RAPIDJSON_DIAG_POP #endif -#ifdef _MSC_VER -CEREAL_RAPIDJSON_DIAG_POP -#endif - -#endif // CEREAL_RAPIDJSON_POINTER_H_ +#endif // RAPIDJSON_POINTER_H_ diff --git a/external/cereal/external/rapidjson/prettywriter.h b/external/cereal/external/rapidjson/prettywriter.h index 50a24fc..fe45df1 100644 --- a/external/cereal/external/rapidjson/prettywriter.h +++ b/external/cereal/external/rapidjson/prettywriter.h @@ -1,6 +1,6 @@ // 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. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // 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 @@ -12,17 +12,22 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -#ifndef CEREAL_RAPIDJSON_PRETTYWRITER_H_ -#define CEREAL_RAPIDJSON_PRETTYWRITER_H_ +#ifndef RAPIDJSON_PRETTYWRITER_H_ +#define RAPIDJSON_PRETTYWRITER_H_ #include "writer.h" #ifdef __GNUC__ -CEREAL_RAPIDJSON_DIAG_PUSH -CEREAL_RAPIDJSON_DIAG_OFF(effc++) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) #endif -CEREAL_RAPIDJSON_NAMESPACE_BEGIN +#if defined(__clang__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(c++98-compat) +#endif + +RAPIDJSON_NAMESPACE_BEGIN //! Combination of PrettyWriter format flags. /*! \see PrettyWriter::SetFormatOptions @@ -34,7 +39,7 @@ enum PrettyFormatOptions { //! Writer with indentation and spacing. /*! - \tparam OutputStream Type of ouptut os. + \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. @@ -42,7 +47,7 @@ enum PrettyFormatOptions { template, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags> class PrettyWriter : public Writer { public: - typedef Writer Base; + typedef Writer Base; typedef typename Base::Ch Ch; //! Constructor @@ -55,7 +60,12 @@ 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) : + 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'). @@ -63,7 +73,7 @@ public: \note The default indentation is 4 spaces. */ PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) { - CEREAL_RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r'); + RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r'); indentChar_ = indentChar; indentCharCount_ = indentCharCount; return *this; @@ -82,27 +92,29 @@ public: */ //@{ - bool Null() { PrettyPrefix(kNullType); return Base::WriteNull(); } - bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::WriteBool(b); } - bool Int(int i) { PrettyPrefix(kNumberType); return Base::WriteInt(i); } - bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::WriteUint(u); } - bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::WriteInt64(i64); } - bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::WriteUint64(u64); } - bool Double(double d) { PrettyPrefix(kNumberType); return Base::WriteDouble(d); } + 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::WriteString(str, length); + 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::WriteString(str, length); + return Base::EndValue(Base::WriteString(str, length)); } -#if CEREAL_RAPIDJSON_HAS_STDSTRING +#if RAPIDJSON_HAS_STDSTRING bool String(const std::basic_string& str) { return String(str.data(), SizeType(str.size())); } @@ -116,7 +128,7 @@ public: bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } -#if CEREAL_RAPIDJSON_HAS_STDSTRING +#if RAPIDJSON_HAS_STDSTRING bool Key(const std::basic_string& str) { return Key(str.data(), SizeType(str.size())); } @@ -124,19 +136,21 @@ public: bool EndObject(SizeType memberCount = 0) { (void)memberCount; - CEREAL_RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); - CEREAL_RAPIDJSON_ASSERT(!Base::level_stack_.template Top()->inArray); + 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::WriteEndObject(); + bool ret = Base::EndValue(Base::WriteEndObject()); (void)ret; - CEREAL_RAPIDJSON_ASSERT(ret == true); + RAPIDJSON_ASSERT(ret == true); if (Base::level_stack_.Empty()) // end of json text - Base::os_->Flush(); + Base::Flush(); return true; } @@ -148,19 +162,19 @@ public: bool EndArray(SizeType memberCount = 0) { (void)memberCount; - CEREAL_RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); - CEREAL_RAPIDJSON_ASSERT(Base::level_stack_.template Top()->inArray); + 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::WriteEndArray(); + bool ret = Base::EndValue(Base::WriteEndArray()); (void)ret; - CEREAL_RAPIDJSON_ASSERT(ret == true); + RAPIDJSON_ASSERT(ret == true); if (Base::level_stack_.Empty()) // end of json text - Base::os_->Flush(); + Base::Flush(); return true; } @@ -184,7 +198,11 @@ public: \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) { PrettyPrefix(type); return Base::WriteRawValue(json, length); } + 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) { @@ -222,18 +240,18 @@ protected: WriteIndent(); } if (!level->inArray && level->valueCount % 2 == 0) - CEREAL_RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name + RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name level->valueCount++; } else { - CEREAL_RAPIDJSON_ASSERT(!Base::hasRoot_); // Should only has one and only one root. + 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); + PutN(*Base::os_, static_cast(indentChar_), count); } Ch indentChar_; @@ -246,10 +264,14 @@ private: PrettyWriter& operator=(const PrettyWriter&); }; -CEREAL_RAPIDJSON_NAMESPACE_END +RAPIDJSON_NAMESPACE_END -#ifdef __GNUC__ -CEREAL_RAPIDJSON_DIAG_POP +#if defined(__clang__) +RAPIDJSON_DIAG_POP #endif -#endif // CEREAL_RAPIDJSON_CEREAL_RAPIDJSON_H_ +#ifdef __GNUC__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_RAPIDJSON_H_ diff --git a/external/cereal/external/rapidjson/rapidjson.h b/external/cereal/external/rapidjson/rapidjson.h index b79023c..a4e8953 100644 --- a/external/cereal/external/rapidjson/rapidjson.h +++ b/external/cereal/external/rapidjson/rapidjson.h @@ -1,6 +1,6 @@ // 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. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // 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 @@ -12,24 +12,24 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -#ifndef CEREAL_RAPIDJSON_CEREAL_RAPIDJSON_H_ -#define CEREAL_RAPIDJSON_CEREAL_RAPIDJSON_H_ +#ifndef RAPIDJSON_RAPIDJSON_H_ +#define RAPIDJSON_RAPIDJSON_H_ /*!\file rapidjson.h \brief common definitions and configuration - \see CEREAL_RAPIDJSON_CONFIG + \see RAPIDJSON_CONFIG */ -/*! \defgroup CEREAL_RAPIDJSON_CONFIG RapidJSON configuration +/*! \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 overriden or predefined + features can be configured in terms of overridden or predefined preprocessor macros at compile-time. - Some additional customization is available in the \ref CEREAL_RAPIDJSON_ERRORS APIs. + 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 @@ -40,43 +40,48 @@ #include // memset(), memcpy(), memmove(), memcmp() /////////////////////////////////////////////////////////////////////////////// -// CEREAL_RAPIDJSON_VERSION_STRING +// RAPIDJSON_VERSION_STRING // // ALWAYS synchronize the following 3 macros with corresponding variables in /CMakeLists.txt. // -//!@cond CEREAL_RAPIDJSON_HIDDEN_FROM_DOXYGEN +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN // token stringification -#define CEREAL_RAPIDJSON_STRINGIFY(x) CEREAL_RAPIDJSON_DO_STRINGIFY(x) -#define CEREAL_RAPIDJSON_DO_STRINGIFY(x) #x +#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 CEREAL_RAPIDJSON_MAJOR_VERSION - \ingroup CEREAL_RAPIDJSON_CONFIG +/*! \def RAPIDJSON_MAJOR_VERSION + \ingroup RAPIDJSON_CONFIG \brief Major version of RapidJSON in integer. */ -/*! \def CEREAL_RAPIDJSON_MINOR_VERSION - \ingroup CEREAL_RAPIDJSON_CONFIG +/*! \def RAPIDJSON_MINOR_VERSION + \ingroup RAPIDJSON_CONFIG \brief Minor version of RapidJSON in integer. */ -/*! \def CEREAL_RAPIDJSON_PATCH_VERSION - \ingroup CEREAL_RAPIDJSON_CONFIG +/*! \def RAPIDJSON_PATCH_VERSION + \ingroup RAPIDJSON_CONFIG \brief Patch version of RapidJSON in integer. */ -/*! \def CEREAL_RAPIDJSON_VERSION_STRING - \ingroup CEREAL_RAPIDJSON_CONFIG +/*! \def RAPIDJSON_VERSION_STRING + \ingroup RAPIDJSON_CONFIG \brief Version of RapidJSON in ".." string format. */ -#define CEREAL_RAPIDJSON_MAJOR_VERSION 1 -#define CEREAL_RAPIDJSON_MINOR_VERSION 0 -#define CEREAL_RAPIDJSON_PATCH_VERSION 2 -#define CEREAL_RAPIDJSON_VERSION_STRING \ - CEREAL_RAPIDJSON_STRINGIFY(CEREAL_RAPIDJSON_MAJOR_VERSION.CEREAL_RAPIDJSON_MINOR_VERSION.CEREAL_RAPIDJSON_PATCH_VERSION) +#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) /////////////////////////////////////////////////////////////////////////////// -// CEREAL_RAPIDJSON_NAMESPACE_(BEGIN|END) -/*! \def CEREAL_RAPIDJSON_NAMESPACE - \ingroup CEREAL_RAPIDJSON_CONFIG +// 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 @@ -84,52 +89,65 @@ a single binary, users can customize the name of the main RapidJSON namespace. - In case of a single nesting level, defining \c CEREAL_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 CEREAL_RAPIDJSON_NAMESPACE_BEGIN and \ref - CEREAL_RAPIDJSON_NAMESPACE_END need to be defined as well: + 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 CEREAL_RAPIDJSON_NAMESPACE my::rapidjson - #define CEREAL_RAPIDJSON_NAMESPACE_BEGIN namespace my { namespace rapidjson { - #define CEREAL_RAPIDJSON_NAMESPACE_END } } + #define RAPIDJSON_NAMESPACE my::rapidjson + #define RAPIDJSON_NAMESPACE_BEGIN namespace my { namespace rapidjson { + #define RAPIDJSON_NAMESPACE_END } } #include "rapidjson/..." \endcode \see rapidjson */ -/*! \def CEREAL_RAPIDJSON_NAMESPACE_BEGIN - \ingroup CEREAL_RAPIDJSON_CONFIG +/*! \def RAPIDJSON_NAMESPACE_BEGIN + \ingroup RAPIDJSON_CONFIG \brief provide custom rapidjson namespace (opening expression) - \see CEREAL_RAPIDJSON_NAMESPACE + \see RAPIDJSON_NAMESPACE */ -/*! \def CEREAL_RAPIDJSON_NAMESPACE_END - \ingroup CEREAL_RAPIDJSON_CONFIG +/*! \def RAPIDJSON_NAMESPACE_END + \ingroup RAPIDJSON_CONFIG \brief provide custom rapidjson namespace (closing expression) - \see CEREAL_RAPIDJSON_NAMESPACE + \see RAPIDJSON_NAMESPACE */ -#ifndef CEREAL_RAPIDJSON_NAMESPACE -#define CEREAL_RAPIDJSON_NAMESPACE rapidjson +#ifndef RAPIDJSON_NAMESPACE +#define RAPIDJSON_NAMESPACE rapidjson #endif -#ifndef CEREAL_RAPIDJSON_NAMESPACE_BEGIN -#define CEREAL_RAPIDJSON_NAMESPACE_BEGIN namespace CEREAL_RAPIDJSON_NAMESPACE { +#ifndef RAPIDJSON_NAMESPACE_BEGIN +#define RAPIDJSON_NAMESPACE_BEGIN namespace RAPIDJSON_NAMESPACE { #endif -#ifndef CEREAL_RAPIDJSON_NAMESPACE_END -#define CEREAL_RAPIDJSON_NAMESPACE_END } +#ifndef RAPIDJSON_NAMESPACE_END +#define RAPIDJSON_NAMESPACE_END } #endif /////////////////////////////////////////////////////////////////////////////// -// CEREAL_RAPIDJSON_HAS_STDSTRING +// __cplusplus macro -#ifndef CEREAL_RAPIDJSON_HAS_STDSTRING -#ifdef CEREAL_RAPIDJSON_DOXYGEN_RUNNING -#define CEREAL_RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN + +#if defined(_MSC_VER) +#define RAPIDJSON_CPLUSPLUS _MSVC_LANG #else -#define CEREAL_RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default +#define RAPIDJSON_CPLUSPLUS __cplusplus #endif -/*! \def CEREAL_RAPIDJSON_HAS_STDSTRING - \ingroup CEREAL_RAPIDJSON_CONFIG + +//!@endcond + +/////////////////////////////////////////////////////////////////////////////// +// 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 @@ -138,27 +156,45 @@ \hideinitializer */ -#endif // !defined(CEREAL_RAPIDJSON_HAS_STDSTRING) +#endif // !defined(RAPIDJSON_HAS_STDSTRING) -#if CEREAL_RAPIDJSON_HAS_STDSTRING +#if RAPIDJSON_HAS_STDSTRING #include -#endif // CEREAL_RAPIDJSON_HAS_STDSTRING +#endif // RAPIDJSON_HAS_STDSTRING /////////////////////////////////////////////////////////////////////////////// -// CEREAL_RAPIDJSON_NO_INT64DEFINE +// RAPIDJSON_USE_MEMBERSMAP -/*! \def CEREAL_RAPIDJSON_NO_INT64DEFINE - \ingroup CEREAL_RAPIDJSON_CONFIG +/*! \def RAPIDJSON_USE_MEMBERSMAP + \ingroup RAPIDJSON_CONFIG + \brief Enable RapidJSON support for object members handling in a \c std::multimap + + By defining this preprocessor symbol to \c 1, \ref rapidjson::GenericValue object + members are stored in a \c std::multimap for faster lookup and deletion times, a + trade off with a slightly slower insertion time and a small object allocat(or)ed + memory overhead. + + \hideinitializer +*/ +#ifndef RAPIDJSON_USE_MEMBERSMAP +#define RAPIDJSON_USE_MEMBERSMAP 0 // not by default +#endif + +/////////////////////////////////////////////////////////////////////////////// +// 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 CEREAL_RAPIDJSON_NO_INT64DEFINE to + If users have their own definition, define RAPIDJSON_NO_INT64DEFINE to prevent RapidJSON from defining its own types. */ -#ifndef CEREAL_RAPIDJSON_NO_INT64DEFINE -//!@cond CEREAL_RAPIDJSON_HIDDEN_FROM_DOXYGEN +#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" @@ -168,116 +204,111 @@ #include #endif //!@endcond -#ifdef CEREAL_RAPIDJSON_DOXYGEN_RUNNING -#define CEREAL_RAPIDJSON_NO_INT64DEFINE +#ifdef RAPIDJSON_DOXYGEN_RUNNING +#define RAPIDJSON_NO_INT64DEFINE #endif -#endif // CEREAL_RAPIDJSON_NO_INT64TYPEDEF +#endif // RAPIDJSON_NO_INT64TYPEDEF /////////////////////////////////////////////////////////////////////////////// -// CEREAL_RAPIDJSON_FORCEINLINE +// RAPIDJSON_FORCEINLINE -#ifndef CEREAL_RAPIDJSON_FORCEINLINE -//!@cond CEREAL_RAPIDJSON_HIDDEN_FROM_DOXYGEN +#ifndef RAPIDJSON_FORCEINLINE +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN #if defined(_MSC_VER) && defined(NDEBUG) -#define CEREAL_RAPIDJSON_FORCEINLINE __forceinline +#define RAPIDJSON_FORCEINLINE __forceinline #elif defined(__GNUC__) && __GNUC__ >= 4 && defined(NDEBUG) -#define CEREAL_RAPIDJSON_FORCEINLINE __attribute__((always_inline)) +#define RAPIDJSON_FORCEINLINE __attribute__((always_inline)) #else -#define CEREAL_RAPIDJSON_FORCEINLINE +#define RAPIDJSON_FORCEINLINE #endif //!@endcond -#endif // CEREAL_RAPIDJSON_FORCEINLINE +#endif // RAPIDJSON_FORCEINLINE /////////////////////////////////////////////////////////////////////////////// -// CEREAL_RAPIDJSON_ENDIAN -#define CEREAL_RAPIDJSON_LITTLEENDIAN 0 //!< Little endian machine -#define CEREAL_RAPIDJSON_BIGENDIAN 1 //!< Big endian machine +// RAPIDJSON_ENDIAN +#define RAPIDJSON_LITTLEENDIAN 0 //!< Little endian machine +#define RAPIDJSON_BIGENDIAN 1 //!< Big endian machine //! Endianness of the machine. /*! - \def CEREAL_RAPIDJSON_ENDIAN - \ingroup CEREAL_RAPIDJSON_CONFIG + \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 CEREAL_RAPIDJSON_ENDIAN to either - \ref CEREAL_RAPIDJSON_LITTLEENDIAN or \ref CEREAL_RAPIDJSON_BIGENDIAN. + 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 CEREAL_RAPIDJSON_ENDIAN +#ifndef RAPIDJSON_ENDIAN // Detect with GCC 4.6's macro # ifdef __BYTE_ORDER__ # if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -# define CEREAL_RAPIDJSON_ENDIAN CEREAL_RAPIDJSON_LITTLEENDIAN +# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN # elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ -# define CEREAL_RAPIDJSON_ENDIAN CEREAL_RAPIDJSON_BIGENDIAN +# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN # else -# error Unknown machine endianess detected. User needs to define CEREAL_RAPIDJSON_ENDIAN. +# 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 CEREAL_RAPIDJSON_ENDIAN CEREAL_RAPIDJSON_LITTLEENDIAN +# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN # elif (__BYTE_ORDER == __BIG_ENDIAN) -# define CEREAL_RAPIDJSON_ENDIAN CEREAL_RAPIDJSON_BIGENDIAN +# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN # else -# error Unknown machine endianess detected. User needs to define CEREAL_RAPIDJSON_ENDIAN. +# 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 CEREAL_RAPIDJSON_ENDIAN CEREAL_RAPIDJSON_LITTLEENDIAN +# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN # elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN) -# define CEREAL_RAPIDJSON_ENDIAN CEREAL_RAPIDJSON_BIGENDIAN +# 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 CEREAL_RAPIDJSON_ENDIAN CEREAL_RAPIDJSON_BIGENDIAN +# 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 CEREAL_RAPIDJSON_ENDIAN CEREAL_RAPIDJSON_LITTLEENDIAN -# elif defined(_MSC_VER) && defined(_M_ARM) -# define CEREAL_RAPIDJSON_ENDIAN CEREAL_RAPIDJSON_LITTLEENDIAN -# elif defined(CEREAL_RAPIDJSON_DOXYGEN_RUNNING) -# define CEREAL_RAPIDJSON_ENDIAN +# 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 endianess detected. User needs to define CEREAL_RAPIDJSON_ENDIAN. +# error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN. # endif -#endif // CEREAL_RAPIDJSON_ENDIAN +#endif // RAPIDJSON_ENDIAN /////////////////////////////////////////////////////////////////////////////// -// CEREAL_RAPIDJSON_64BIT +// RAPIDJSON_64BIT //! Whether using 64-bit architecture -#ifndef CEREAL_RAPIDJSON_64BIT +#ifndef RAPIDJSON_64BIT #if defined(__LP64__) || (defined(__x86_64__) && defined(__ILP32__)) || defined(_WIN64) || defined(__EMSCRIPTEN__) -#define CEREAL_RAPIDJSON_64BIT 1 +#define RAPIDJSON_64BIT 1 #else -#define CEREAL_RAPIDJSON_64BIT 0 +#define RAPIDJSON_64BIT 0 #endif -#endif // CEREAL_RAPIDJSON_64BIT +#endif // RAPIDJSON_64BIT /////////////////////////////////////////////////////////////////////////////// -// CEREAL_RAPIDJSON_ALIGN +// RAPIDJSON_ALIGN //! Data alignment of the machine. -/*! \ingroup CEREAL_RAPIDJSON_CONFIG +/*! \ingroup RAPIDJSON_CONFIG \param x pointer to align - Some machines require strict data alignment. Currently the default uses 4 bytes - alignment on 32-bit platforms and 8 bytes alignment for 64-bit platforms. - User can customize by defining the CEREAL_RAPIDJSON_ALIGN function macro. + Some machines require strict data alignment. The default is 8 bytes. + User can customize by defining the RAPIDJSON_ALIGN function macro. */ -#ifndef CEREAL_RAPIDJSON_ALIGN -#if CEREAL_RAPIDJSON_64BIT == 1 -#define CEREAL_RAPIDJSON_ALIGN(x) (((x) + static_cast(7u)) & ~static_cast(7u)) -#else -#define CEREAL_RAPIDJSON_ALIGN(x) (((x) + 3u) & ~3u) -#endif +#ifndef RAPIDJSON_ALIGN +#define RAPIDJSON_ALIGN(x) (((x) + static_cast(7u)) & ~static_cast(7u)) #endif /////////////////////////////////////////////////////////////////////////////// -// CEREAL_RAPIDJSON_UINT64_C2 +// RAPIDJSON_UINT64_C2 //! Construct a 64-bit literal by a pair of 32-bit integer. /*! @@ -285,309 +316,404 @@ 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 CEREAL_RAPIDJSON_UINT64_C2 -#define CEREAL_RAPIDJSON_UINT64_C2(high32, low32) ((static_cast(high32) << 32) | static_cast(low32)) +#ifndef RAPIDJSON_UINT64_C2 +#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast(high32) << 32) | static_cast(low32)) #endif /////////////////////////////////////////////////////////////////////////////// -// CEREAL_RAPIDJSON_48BITPOINTER_OPTIMIZATION +// RAPIDJSON_48BITPOINTER_OPTIMIZATION //! Use only lower 48-bit address for some pointers. /*! - \ingroup CEREAL_RAPIDJSON_CONFIG + \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 CEREAL_RAPIDJSON_48BITPOINTER_OPTIMIZATION +#ifndef RAPIDJSON_48BITPOINTER_OPTIMIZATION #if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64) -#define CEREAL_RAPIDJSON_48BITPOINTER_OPTIMIZATION 1 +#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 1 #else -#define CEREAL_RAPIDJSON_48BITPOINTER_OPTIMIZATION 0 +#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 0 #endif -#endif // CEREAL_RAPIDJSON_48BITPOINTER_OPTIMIZATION +#endif // RAPIDJSON_48BITPOINTER_OPTIMIZATION -#if CEREAL_RAPIDJSON_48BITPOINTER_OPTIMIZATION == 1 -#if CEREAL_RAPIDJSON_64BIT != 1 -#error CEREAL_RAPIDJSON_48BITPOINTER_OPTIMIZATION can only be set to 1 when CEREAL_RAPIDJSON_64BIT=1 +#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 CEREAL_RAPIDJSON_SETPOINTER(type, p, x) (p = reinterpret_cast((reinterpret_cast(p) & static_cast(CEREAL_RAPIDJSON_UINT64_C2(0xFFFF0000, 0x00000000))) | reinterpret_cast(reinterpret_cast(x)))) -#define CEREAL_RAPIDJSON_GETPOINTER(type, p) (reinterpret_cast(reinterpret_cast(p) & static_cast(CEREAL_RAPIDJSON_UINT64_C2(0x0000FFFF, 0xFFFFFFFF)))) +#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 CEREAL_RAPIDJSON_SETPOINTER(type, p, x) (p = (x)) -#define CEREAL_RAPIDJSON_GETPOINTER(type, p) (p) +#define RAPIDJSON_SETPOINTER(type, p, x) (p = (x)) +#define RAPIDJSON_GETPOINTER(type, p) (p) #endif /////////////////////////////////////////////////////////////////////////////// -// CEREAL_RAPIDJSON_SSE2/CEREAL_RAPIDJSON_SSE42/CEREAL_RAPIDJSON_SIMD +// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_NEON/RAPIDJSON_SIMD -/*! \def CEREAL_RAPIDJSON_SIMD - \ingroup CEREAL_RAPIDJSON_CONFIG - \brief Enable SSE2/SSE4.2 optimization. +/*! \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 or SSE4.2 SIMD extensions on modern Intel-compatible - processors. + based on the SSE2, SSE4.2 or NEon SIMD extensions on modern Intel + or ARM compatible processors. - To enable these optimizations, two different symbols can be defined; + To enable these optimizations, three different symbols can be defined; \code // Enable SSE2 optimization. - #define CEREAL_RAPIDJSON_SSE2 + #define RAPIDJSON_SSE2 // Enable SSE4.2 optimization. - #define CEREAL_RAPIDJSON_SSE42 + #define RAPIDJSON_SSE42 \endcode - \c CEREAL_RAPIDJSON_SSE42 takes precedence, if both are defined. + // 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 CEREAL_RAPIDJSON_SIMD to indicate the availability of the optimized code. + \c RAPIDJSON_SIMD to indicate the availability of the optimized code. */ -#if defined(CEREAL_RAPIDJSON_SSE2) || defined(CEREAL_RAPIDJSON_SSE42) \ - || defined(CEREAL_RAPIDJSON_DOXYGEN_RUNNING) -#define CEREAL_RAPIDJSON_SIMD +#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) \ + || defined(RAPIDJSON_NEON) || defined(RAPIDJSON_DOXYGEN_RUNNING) +#define RAPIDJSON_SIMD #endif /////////////////////////////////////////////////////////////////////////////// -// CEREAL_RAPIDJSON_NO_SIZETYPEDEFINE +// RAPIDJSON_NO_SIZETYPEDEFINE -#ifndef CEREAL_RAPIDJSON_NO_SIZETYPEDEFINE -/*! \def CEREAL_RAPIDJSON_NO_SIZETYPEDEFINE - \ingroup CEREAL_RAPIDJSON_CONFIG +#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 CEREAL_RAPIDJSON_NO_SIZETYPEDEFINE + #define RAPIDJSON_NO_SIZETYPEDEFINE namespace rapidjson { typedef ::std::size_t SizeType; } #include "rapidjson/..." \endcode \see rapidjson::SizeType */ -#ifdef CEREAL_RAPIDJSON_DOXYGEN_RUNNING -#define CEREAL_RAPIDJSON_NO_SIZETYPEDEFINE +#ifdef RAPIDJSON_DOXYGEN_RUNNING +#define RAPIDJSON_NO_SIZETYPEDEFINE #endif -CEREAL_RAPIDJSON_NAMESPACE_BEGIN +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 CEREAL_RAPIDJSON_NO_SIZETYPEDEFINE. + \ref RAPIDJSON_NO_SIZETYPEDEFINE. */ typedef unsigned SizeType; -CEREAL_RAPIDJSON_NAMESPACE_END +RAPIDJSON_NAMESPACE_END #endif // always import std::size_t to rapidjson namespace -CEREAL_RAPIDJSON_NAMESPACE_BEGIN +RAPIDJSON_NAMESPACE_BEGIN using std::size_t; -CEREAL_RAPIDJSON_NAMESPACE_END +RAPIDJSON_NAMESPACE_END /////////////////////////////////////////////////////////////////////////////// -// CEREAL_RAPIDJSON_ASSERT +// RAPIDJSON_ASSERT //! Assertion. -/*! \ingroup CEREAL_RAPIDJSON_CONFIG +/*! \ingroup RAPIDJSON_CONFIG By default, rapidjson uses C \c assert() for internal assertions. - User can override it by defining CEREAL_RAPIDJSON_ASSERT(x) macro. + User can override it by defining RAPIDJSON_ASSERT(x) macro. \note Parsing errors are handled and can be customized by the - \ref CEREAL_RAPIDJSON_ERRORS APIs. + \ref RAPIDJSON_ERRORS APIs. */ -#ifndef CEREAL_RAPIDJSON_ASSERT +#ifndef RAPIDJSON_ASSERT #include -#define CEREAL_RAPIDJSON_ASSERT(x) assert(x) -#endif // CEREAL_RAPIDJSON_ASSERT +#define RAPIDJSON_ASSERT(x) assert(x) +#endif // RAPIDJSON_ASSERT /////////////////////////////////////////////////////////////////////////////// -// CEREAL_RAPIDJSON_STATIC_ASSERT +// RAPIDJSON_STATIC_ASSERT -// Adopt from boost -#ifndef CEREAL_RAPIDJSON_STATIC_ASSERT +// Prefer C++11 static_assert, if available +#ifndef RAPIDJSON_STATIC_ASSERT +#if RAPIDJSON_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 CEREAL_RAPIDJSON_HIDDEN_FROM_DOXYGEN +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN #endif -CEREAL_RAPIDJSON_NAMESPACE_BEGIN +RAPIDJSON_NAMESPACE_BEGIN template struct STATIC_ASSERTION_FAILURE; template <> struct STATIC_ASSERTION_FAILURE { enum { value = 1 }; }; -template struct StaticAssertTest {}; -CEREAL_RAPIDJSON_NAMESPACE_END +template struct StaticAssertTest {}; +RAPIDJSON_NAMESPACE_END -#define CEREAL_RAPIDJSON_JOIN(X, Y) CEREAL_RAPIDJSON_DO_JOIN(X, Y) -#define CEREAL_RAPIDJSON_DO_JOIN(X, Y) CEREAL_RAPIDJSON_DO_JOIN2(X, Y) -#define CEREAL_RAPIDJSON_DO_JOIN2(X, Y) X##Y - -#if defined(__GNUC__) -#define CEREAL_RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused)) +#if defined(__GNUC__) || defined(__clang__) +#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused)) #else -#define CEREAL_RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE +#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE #endif #ifndef __clang__ //!@endcond #endif -/*! \def CEREAL_RAPIDJSON_STATIC_ASSERT +/*! \def RAPIDJSON_STATIC_ASSERT \brief (Internal) macro to check for conditions at compile-time \param x compile-time condition \hideinitializer */ -#define CEREAL_RAPIDJSON_STATIC_ASSERT(x) \ - typedef ::CEREAL_RAPIDJSON_NAMESPACE::StaticAssertTest< \ - sizeof(::CEREAL_RAPIDJSON_NAMESPACE::STATIC_ASSERTION_FAILURE)> \ - CEREAL_RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) CEREAL_RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE -#endif +#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 /////////////////////////////////////////////////////////////////////////////// -// CEREAL_RAPIDJSON_LIKELY, CEREAL_RAPIDJSON_UNLIKELY +// RAPIDJSON_LIKELY, RAPIDJSON_UNLIKELY //! Compiler branching hint for expression with high probability to be true. /*! - \ingroup CEREAL_RAPIDJSON_CONFIG + \ingroup RAPIDJSON_CONFIG \param x Boolean expression likely to be true. */ -#ifndef CEREAL_RAPIDJSON_LIKELY +#ifndef RAPIDJSON_LIKELY #if defined(__GNUC__) || defined(__clang__) -#define CEREAL_RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1) +#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1) #else -#define CEREAL_RAPIDJSON_LIKELY(x) (x) +#define RAPIDJSON_LIKELY(x) (x) #endif #endif //! Compiler branching hint for expression with low probability to be true. /*! - \ingroup CEREAL_RAPIDJSON_CONFIG + \ingroup RAPIDJSON_CONFIG \param x Boolean expression unlikely to be true. */ -#ifndef CEREAL_RAPIDJSON_UNLIKELY +#ifndef RAPIDJSON_UNLIKELY #if defined(__GNUC__) || defined(__clang__) -#define CEREAL_RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0) +#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0) #else -#define CEREAL_RAPIDJSON_UNLIKELY(x) (x) +#define RAPIDJSON_UNLIKELY(x) (x) #endif #endif /////////////////////////////////////////////////////////////////////////////// // Helpers -//!@cond CEREAL_RAPIDJSON_HIDDEN_FROM_DOXYGEN +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN -#define CEREAL_RAPIDJSON_MULTILINEMACRO_BEGIN do { -#define CEREAL_RAPIDJSON_MULTILINEMACRO_END \ +#define RAPIDJSON_MULTILINEMACRO_BEGIN do { +#define RAPIDJSON_MULTILINEMACRO_END \ } while((void)0, 0) // adopted from Boost -#define CEREAL_RAPIDJSON_VERSION_CODE(x,y,z) \ +#define RAPIDJSON_VERSION_CODE(x,y,z) \ (((x)*100000) + ((y)*100) + (z)) -/////////////////////////////////////////////////////////////////////////////// -// CEREAL_RAPIDJSON_DIAG_PUSH/POP, CEREAL_RAPIDJSON_DIAG_OFF - -#if defined(__GNUC__) -#define CEREAL_RAPIDJSON_GNUC \ - CEREAL_RAPIDJSON_VERSION_CODE(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__) +#if defined(__has_builtin) +#define RAPIDJSON_HAS_BUILTIN(x) __has_builtin(x) +#else +#define RAPIDJSON_HAS_BUILTIN(x) 0 #endif -#if defined(__clang__) || (defined(CEREAL_RAPIDJSON_GNUC) && CEREAL_RAPIDJSON_GNUC >= CEREAL_RAPIDJSON_VERSION_CODE(4,2,0)) +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF -#define CEREAL_RAPIDJSON_PRAGMA(x) _Pragma(CEREAL_RAPIDJSON_STRINGIFY(x)) -#define CEREAL_RAPIDJSON_DIAG_PRAGMA(x) CEREAL_RAPIDJSON_PRAGMA(GCC diagnostic x) -#define CEREAL_RAPIDJSON_DIAG_OFF(x) \ - CEREAL_RAPIDJSON_DIAG_PRAGMA(ignored CEREAL_RAPIDJSON_STRINGIFY(CEREAL_RAPIDJSON_JOIN(-W,x))) +#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(CEREAL_RAPIDJSON_GNUC) && CEREAL_RAPIDJSON_GNUC >= CEREAL_RAPIDJSON_VERSION_CODE(4,6,0)) -#define CEREAL_RAPIDJSON_DIAG_PUSH CEREAL_RAPIDJSON_DIAG_PRAGMA(push) -#define CEREAL_RAPIDJSON_DIAG_POP CEREAL_RAPIDJSON_DIAG_PRAGMA(pop) +#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 CEREAL_RAPIDJSON_DIAG_PUSH /* ignored */ -#define CEREAL_RAPIDJSON_DIAG_POP /* ignored */ +#define RAPIDJSON_DIAG_PUSH /* ignored */ +#define RAPIDJSON_DIAG_POP /* ignored */ #endif #elif defined(_MSC_VER) // pragma (MSVC specific) -#define CEREAL_RAPIDJSON_PRAGMA(x) __pragma(x) -#define CEREAL_RAPIDJSON_DIAG_PRAGMA(x) CEREAL_RAPIDJSON_PRAGMA(warning(x)) +#define RAPIDJSON_PRAGMA(x) __pragma(x) +#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(warning(x)) -#define CEREAL_RAPIDJSON_DIAG_OFF(x) CEREAL_RAPIDJSON_DIAG_PRAGMA(disable: x) -#define CEREAL_RAPIDJSON_DIAG_PUSH CEREAL_RAPIDJSON_DIAG_PRAGMA(push) -#define CEREAL_RAPIDJSON_DIAG_POP CEREAL_RAPIDJSON_DIAG_PRAGMA(pop) +#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 CEREAL_RAPIDJSON_DIAG_OFF(x) /* ignored */ -#define CEREAL_RAPIDJSON_DIAG_PUSH /* ignored */ -#define CEREAL_RAPIDJSON_DIAG_POP /* ignored */ +#define RAPIDJSON_DIAG_OFF(x) /* ignored */ +#define RAPIDJSON_DIAG_PUSH /* ignored */ +#define RAPIDJSON_DIAG_POP /* ignored */ -#endif // CEREAL_RAPIDJSON_DIAG_* +#endif // RAPIDJSON_DIAG_* /////////////////////////////////////////////////////////////////////////////// // C++11 features -#ifndef CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS -#if defined(__clang__) +#ifndef RAPIDJSON_HAS_CXX11 +#define RAPIDJSON_HAS_CXX11 (RAPIDJSON_CPLUSPLUS >= 201103L) +#endif + +#ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS +#if RAPIDJSON_HAS_CXX11 +#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 +#elif defined(__clang__) #if __has_feature(cxx_rvalue_references) && \ - (defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306) -#define CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 + (defined(_MSC_VER) || defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306) +#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 #else -#define CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS 0 +#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0 #endif -#elif (defined(CEREAL_RAPIDJSON_GNUC) && (CEREAL_RAPIDJSON_GNUC >= CEREAL_RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ - (defined(_MSC_VER) && _MSC_VER >= 1600) +#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 CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 +#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 #else -#define CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS 0 +#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0 #endif -#endif // CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS +#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS -#ifndef CEREAL_RAPIDJSON_HAS_CXX11_NOEXCEPT -#if defined(__clang__) -#define CEREAL_RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept) -#elif (defined(CEREAL_RAPIDJSON_GNUC) && (CEREAL_RAPIDJSON_GNUC >= CEREAL_RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) -// (defined(_MSC_VER) && _MSC_VER >= ????) // not yet supported -#define CEREAL_RAPIDJSON_HAS_CXX11_NOEXCEPT 1 +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS +#include // std::move +#endif + +#ifndef RAPIDJSON_HAS_CXX11_NOEXCEPT +#if RAPIDJSON_HAS_CXX11 +#define RAPIDJSON_HAS_CXX11_NOEXCEPT 1 +#elif 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 CEREAL_RAPIDJSON_HAS_CXX11_NOEXCEPT 0 +#define RAPIDJSON_HAS_CXX11_NOEXCEPT 0 #endif #endif -#if CEREAL_RAPIDJSON_HAS_CXX11_NOEXCEPT -#define CEREAL_RAPIDJSON_NOEXCEPT noexcept +#ifndef RAPIDJSON_NOEXCEPT +#if RAPIDJSON_HAS_CXX11_NOEXCEPT +#define RAPIDJSON_NOEXCEPT noexcept #else -#define CEREAL_RAPIDJSON_NOEXCEPT /* noexcept */ -#endif // CEREAL_RAPIDJSON_HAS_CXX11_NOEXCEPT +#define RAPIDJSON_NOEXCEPT throw() +#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT +#endif // no automatic detection, yet -#ifndef CEREAL_RAPIDJSON_HAS_CXX11_TYPETRAITS -#define CEREAL_RAPIDJSON_HAS_CXX11_TYPETRAITS 0 +#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 CEREAL_RAPIDJSON_HAS_CXX11_RANGE_FOR +#ifndef RAPIDJSON_HAS_CXX11_RANGE_FOR #if defined(__clang__) -#define CEREAL_RAPIDJSON_HAS_CXX11_RANGE_FOR __has_feature(cxx_range_for) -#elif (defined(CEREAL_RAPIDJSON_GNUC) && (CEREAL_RAPIDJSON_GNUC >= CEREAL_RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ - (defined(_MSC_VER) && _MSC_VER >= 1700) -#define CEREAL_RAPIDJSON_HAS_CXX11_RANGE_FOR 1 +#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 CEREAL_RAPIDJSON_HAS_CXX11_RANGE_FOR 0 +#define RAPIDJSON_HAS_CXX11_RANGE_FOR 0 +#endif +#endif // RAPIDJSON_HAS_CXX11_RANGE_FOR + +/////////////////////////////////////////////////////////////////////////////// +// C++17 features + +#ifndef RAPIDJSON_HAS_CXX17 +#define RAPIDJSON_HAS_CXX17 (RAPIDJSON_CPLUSPLUS >= 201703L) +#endif + +#if RAPIDJSON_HAS_CXX17 +# define RAPIDJSON_DELIBERATE_FALLTHROUGH [[fallthrough]] +#elif defined(__has_cpp_attribute) +# if __has_cpp_attribute(clang::fallthrough) +# define RAPIDJSON_DELIBERATE_FALLTHROUGH [[clang::fallthrough]] +# elif __has_cpp_attribute(fallthrough) +# define RAPIDJSON_DELIBERATE_FALLTHROUGH __attribute__((fallthrough)) +# else +# define RAPIDJSON_DELIBERATE_FALLTHROUGH +# endif +#else +# define RAPIDJSON_DELIBERATE_FALLTHROUGH #endif -#endif // CEREAL_RAPIDJSON_HAS_CXX11_RANGE_FOR //!@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 +#include +#define RAPIDJSON_NOEXCEPT_ASSERT(x) assert(x) +#else +#define RAPIDJSON_NOEXCEPT_ASSERT(x) RAPIDJSON_ASSERT(x) +#endif // RAPIDJSON_ASSERT_THROWS +#endif // RAPIDJSON_NOEXCEPT_ASSERT + +/////////////////////////////////////////////////////////////////////////////// +// malloc/realloc/free + +#ifndef RAPIDJSON_MALLOC +///! customization point for global \c malloc +#define RAPIDJSON_MALLOC(size) std::malloc(size) +#endif +#ifndef RAPIDJSON_REALLOC +///! customization point for global \c realloc +#define RAPIDJSON_REALLOC(ptr, new_size) std::realloc(ptr, new_size) +#endif +#ifndef RAPIDJSON_FREE +///! customization point for global \c free +#define RAPIDJSON_FREE(ptr) std::free(ptr) +#endif + /////////////////////////////////////////////////////////////////////////////// // new/delete -#ifndef CEREAL_RAPIDJSON_NEW +#ifndef RAPIDJSON_NEW ///! customization point for global \c new -#define CEREAL_RAPIDJSON_NEW(x) new x +#define RAPIDJSON_NEW(TypeName) new TypeName #endif -#ifndef CEREAL_RAPIDJSON_DELETE +#ifndef RAPIDJSON_DELETE ///! customization point for global \c delete -#define CEREAL_RAPIDJSON_DELETE(x) delete x +#define RAPIDJSON_DELETE(x) delete x #endif /////////////////////////////////////////////////////////////////////////////// @@ -595,9 +721,9 @@ CEREAL_RAPIDJSON_NAMESPACE_END /*! \namespace rapidjson \brief main RapidJSON namespace - \see CEREAL_RAPIDJSON_NAMESPACE + \see RAPIDJSON_NAMESPACE */ -CEREAL_RAPIDJSON_NAMESPACE_BEGIN +RAPIDJSON_NAMESPACE_BEGIN //! Type of JSON value enum Type { @@ -610,6 +736,6 @@ enum Type { kNumberType = 6 //!< number }; -CEREAL_RAPIDJSON_NAMESPACE_END +RAPIDJSON_NAMESPACE_END -#endif // CEREAL_RAPIDJSON_CEREAL_RAPIDJSON_H_ +#endif // RAPIDJSON_RAPIDJSON_H_ diff --git a/external/cereal/external/rapidjson/reader.h b/external/cereal/external/rapidjson/reader.h index ad8ff33..5554660 100644 --- a/external/cereal/external/rapidjson/reader.h +++ b/external/cereal/external/rapidjson/reader.h @@ -1,6 +1,6 @@ // 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. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // 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 @@ -12,61 +12,62 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -#ifndef CEREAL_RAPIDJSON_READER_H_ -#define CEREAL_RAPIDJSON_READER_H_ +#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(CEREAL_RAPIDJSON_SIMD) && defined(_MSC_VER) +#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER) #include #pragma intrinsic(_BitScanForward) #endif -#ifdef CEREAL_RAPIDJSON_SSE42 +#ifdef RAPIDJSON_SSE42 #include -#elif defined(CEREAL_RAPIDJSON_SSE2) +#elif defined(RAPIDJSON_SSE2) #include -#endif - -#ifdef _MSC_VER -CEREAL_RAPIDJSON_DIAG_PUSH -CEREAL_RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant -CEREAL_RAPIDJSON_DIAG_OFF(4702) // unreachable code +#elif defined(RAPIDJSON_NEON) +#include #endif #ifdef __clang__ -CEREAL_RAPIDJSON_DIAG_PUSH -CEREAL_RAPIDJSON_DIAG_OFF(old-style-cast) -CEREAL_RAPIDJSON_DIAG_OFF(padded) -CEREAL_RAPIDJSON_DIAG_OFF(switch-enum) +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__ -CEREAL_RAPIDJSON_DIAG_PUSH -CEREAL_RAPIDJSON_DIAG_OFF(effc++) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) #endif -//!@cond CEREAL_RAPIDJSON_HIDDEN_FROM_DOXYGEN -#define CEREAL_RAPIDJSON_NOTHING /* deliberately empty */ -#ifndef CEREAL_RAPIDJSON_PARSE_ERROR_EARLY_RETURN -#define CEREAL_RAPIDJSON_PARSE_ERROR_EARLY_RETURN(value) \ - CEREAL_RAPIDJSON_MULTILINEMACRO_BEGIN \ - if (CEREAL_RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \ - CEREAL_RAPIDJSON_MULTILINEMACRO_END +//!@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 CEREAL_RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID \ - CEREAL_RAPIDJSON_PARSE_ERROR_EARLY_RETURN(CEREAL_RAPIDJSON_NOTHING) +#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID \ + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING) //!@endcond -/*! \def CEREAL_RAPIDJSON_PARSE_ERROR_NORETURN - \ingroup CEREAL_RAPIDJSON_ERRORS +/*! \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) @@ -79,7 +80,7 @@ CEREAL_RAPIDJSON_DIAG_OFF(effc++) return value: \code - #define CEREAL_RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode,offset) \ + #define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode,offset) \ throw ParseException(parseErrorCode, #parseErrorCode, offset) #include // std::runtime_error @@ -93,50 +94,50 @@ CEREAL_RAPIDJSON_DIAG_OFF(effc++) #include "rapidjson/reader.h" \endcode - \see CEREAL_RAPIDJSON_PARSE_ERROR, rapidjson::GenericReader::Parse + \see RAPIDJSON_PARSE_ERROR, rapidjson::GenericReader::Parse */ -#ifndef CEREAL_RAPIDJSON_PARSE_ERROR_NORETURN -#define CEREAL_RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset) \ - CEREAL_RAPIDJSON_MULTILINEMACRO_BEGIN \ - CEREAL_RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \ +#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); \ - CEREAL_RAPIDJSON_MULTILINEMACRO_END + RAPIDJSON_MULTILINEMACRO_END #endif -/*! \def CEREAL_RAPIDJSON_PARSE_ERROR - \ingroup CEREAL_RAPIDJSON_ERRORS +/*! \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 CEREAL_RAPIDJSON_PARSE_ERROR_NORETURN and stops the parsing. + Invokes RAPIDJSON_PARSE_ERROR_NORETURN and stops the parsing. - \see CEREAL_RAPIDJSON_PARSE_ERROR_NORETURN + \see RAPIDJSON_PARSE_ERROR_NORETURN \hideinitializer */ -#ifndef CEREAL_RAPIDJSON_PARSE_ERROR -#define CEREAL_RAPIDJSON_PARSE_ERROR(parseErrorCode, offset) \ - CEREAL_RAPIDJSON_MULTILINEMACRO_BEGIN \ - CEREAL_RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \ - CEREAL_RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \ - CEREAL_RAPIDJSON_MULTILINEMACRO_END +#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 -CEREAL_RAPIDJSON_NAMESPACE_BEGIN +RAPIDJSON_NAMESPACE_BEGIN /////////////////////////////////////////////////////////////////////////////// // ParseFlag -/*! \def CEREAL_RAPIDJSON_PARSE_DEFAULT_FLAGS - \ingroup CEREAL_RAPIDJSON_CONFIG +/*! \def RAPIDJSON_PARSE_DEFAULT_FLAGS + \ingroup RAPIDJSON_CONFIG \brief User-defined kParseDefaultFlags definition. User can define this as any \c ParseFlag combinations. */ -#ifndef CEREAL_RAPIDJSON_PARSE_DEFAULT_FLAGS -#define CEREAL_RAPIDJSON_PARSE_DEFAULT_FLAGS kParseNoFlags +#ifndef RAPIDJSON_PARSE_DEFAULT_FLAGS +#define RAPIDJSON_PARSE_DEFAULT_FLAGS kParseNoFlags #endif //! Combination of parseFlags @@ -153,7 +154,8 @@ 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. - kParseDefaultFlags = CEREAL_RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized by defining CEREAL_RAPIDJSON_PARSE_DEFAULT_FLAGS + kParseEscapedApostropheFlag = 512, //!< Allow escaped apostrophe in strings. + kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS }; /////////////////////////////////////////////////////////////////////////////// @@ -276,7 +278,7 @@ inline const char* SkipWhitespace(const char* p, const char* end) { return p; } -#ifdef CEREAL_RAPIDJSON_SSE42 +#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 @@ -299,16 +301,9 @@ inline const char *SkipWhitespace_SIMD(const char* p) { for (;; p += 16) { const __m128i s = _mm_load_si128(reinterpret_cast(p)); - const int r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY)); - if (r != 0) { // some of characters is 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 - } + 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; } } @@ -325,22 +320,15 @@ inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { for (; p <= end - 16; p += 16) { const __m128i s = _mm_loadu_si128(reinterpret_cast(p)); - const int r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY)); - if (r != 0) { // some of characters is 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 - } + 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(CEREAL_RAPIDJSON_SSE2) +#elif defined(RAPIDJSON_SSE2) //! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once. inline const char *SkipWhitespace_SIMD(const char* p) { @@ -425,9 +413,94 @@ inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { return SkipWhitespace(p, end); } -#endif // CEREAL_RAPIDJSON_SSE2 +#elif defined(RAPIDJSON_NEON) -#ifdef CEREAL_RAPIDJSON_SIMD +//! 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_)); @@ -441,7 +514,7 @@ template<> inline void SkipWhitespace(StringStream& is) { template<> inline void SkipWhitespace(EncodedInputStream, MemoryStream>& is) { is.is_.src_ = SkipWhitespace_SIMD(is.is_.src_, is.is_.end_); } -#endif // CEREAL_RAPIDJSON_SIMD +#endif // RAPIDJSON_SIMD /////////////////////////////////////////////////////////////////////////////// // GenericReader @@ -471,7 +544,8 @@ public: /*! \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_() {} + GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) : + stack_(stackAllocator, stackCapacity), parseResult_(), state_(IterativeParsingStartState) {} //! Parse JSON text. /*! \tparam parseFlags Combination of \ref ParseFlag. @@ -491,23 +565,23 @@ public: ClearStackOnExit scope(*this); SkipWhitespaceAndComments(is); - CEREAL_RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); - if (CEREAL_RAPIDJSON_UNLIKELY(is.Peek() == '\0')) { - CEREAL_RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell()); - CEREAL_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); - CEREAL_RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); if (!(parseFlags & kParseStopWhenDoneFlag)) { SkipWhitespaceAndComments(is); - CEREAL_RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); - if (CEREAL_RAPIDJSON_UNLIKELY(is.Peek() != '\0')) { - CEREAL_RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell()); - CEREAL_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_); } } } @@ -527,7 +601,84 @@ public: return Parse(is, handler); } - //! Whether a parse error has occured in the last parsing. + //! 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. @@ -561,11 +712,11 @@ private: SkipWhitespace(is); if (parseFlags & kParseCommentsFlag) { - while (CEREAL_RAPIDJSON_UNLIKELY(Consume(is, '/'))) { + while (RAPIDJSON_UNLIKELY(Consume(is, '/'))) { if (Consume(is, '*')) { while (true) { - if (CEREAL_RAPIDJSON_UNLIKELY(is.Peek() == '\0')) - CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); + if (RAPIDJSON_UNLIKELY(is.Peek() == '\0')) + RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); else if (Consume(is, '*')) { if (Consume(is, '/')) break; @@ -574,10 +725,10 @@ private: is.Take(); } } - else if (CEREAL_RAPIDJSON_LIKELY(Consume(is, '/'))) - while (is.Peek() != '\0' && is.Take() != '\n'); + else if (RAPIDJSON_LIKELY(Consume(is, '/'))) + while (is.Peek() != '\0' && is.Take() != '\n') {} else - CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); + RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); SkipWhitespace(is); } @@ -587,42 +738,42 @@ private: // Parse object: { string : value, ... } template void ParseObject(InputStream& is, Handler& handler) { - CEREAL_RAPIDJSON_ASSERT(is.Peek() == '{'); + RAPIDJSON_ASSERT(is.Peek() == '{'); is.Take(); // Skip '{' - if (CEREAL_RAPIDJSON_UNLIKELY(!handler.StartObject())) - CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + if (RAPIDJSON_UNLIKELY(!handler.StartObject())) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); SkipWhitespaceAndComments(is); - CEREAL_RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; if (Consume(is, '}')) { - if (CEREAL_RAPIDJSON_UNLIKELY(!handler.EndObject(0))) // empty object - CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + if (RAPIDJSON_UNLIKELY(!handler.EndObject(0))) // empty object + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); return; } for (SizeType memberCount = 0;;) { - if (CEREAL_RAPIDJSON_UNLIKELY(is.Peek() != '"')) - CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); + if (RAPIDJSON_UNLIKELY(is.Peek() != '"')) + RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); ParseString(is, handler, true); - CEREAL_RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; SkipWhitespaceAndComments(is); - CEREAL_RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - if (CEREAL_RAPIDJSON_UNLIKELY(!Consume(is, ':'))) - CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); + if (RAPIDJSON_UNLIKELY(!Consume(is, ':'))) + RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); SkipWhitespaceAndComments(is); - CEREAL_RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; ParseValue(is, handler); - CEREAL_RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; SkipWhitespaceAndComments(is); - CEREAL_RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; ++memberCount; @@ -630,21 +781,21 @@ private: case ',': is.Take(); SkipWhitespaceAndComments(is); - CEREAL_RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; break; case '}': is.Take(); - if (CEREAL_RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount))) - CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount))) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); return; default: - CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); break; // This useless break is only for making warning and coverage happy + 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 (CEREAL_RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount))) - CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount))) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); is.Take(); return; } @@ -655,45 +806,45 @@ private: // Parse array: [ value, ... ] template void ParseArray(InputStream& is, Handler& handler) { - CEREAL_RAPIDJSON_ASSERT(is.Peek() == '['); + RAPIDJSON_ASSERT(is.Peek() == '['); is.Take(); // Skip '[' - if (CEREAL_RAPIDJSON_UNLIKELY(!handler.StartArray())) - CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + if (RAPIDJSON_UNLIKELY(!handler.StartArray())) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); SkipWhitespaceAndComments(is); - CEREAL_RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; if (Consume(is, ']')) { - if (CEREAL_RAPIDJSON_UNLIKELY(!handler.EndArray(0))) // empty array - CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + if (RAPIDJSON_UNLIKELY(!handler.EndArray(0))) // empty array + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); return; } for (SizeType elementCount = 0;;) { ParseValue(is, handler); - CEREAL_RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; ++elementCount; SkipWhitespaceAndComments(is); - CEREAL_RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; if (Consume(is, ',')) { SkipWhitespaceAndComments(is); - CEREAL_RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; } else if (Consume(is, ']')) { - if (CEREAL_RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount))) - CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount))) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); return; } else - CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); + RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); if (parseFlags & kParseTrailingCommasFlag) { if (is.Peek() == ']') { - if (CEREAL_RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount))) - CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount))) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); is.Take(); return; } @@ -703,46 +854,46 @@ private: template void ParseNull(InputStream& is, Handler& handler) { - CEREAL_RAPIDJSON_ASSERT(is.Peek() == 'n'); + RAPIDJSON_ASSERT(is.Peek() == 'n'); is.Take(); - if (CEREAL_RAPIDJSON_LIKELY(Consume(is, 'u') && Consume(is, 'l') && Consume(is, 'l'))) { - if (CEREAL_RAPIDJSON_UNLIKELY(!handler.Null())) - CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + if (RAPIDJSON_LIKELY(Consume(is, 'u') && Consume(is, 'l') && Consume(is, 'l'))) { + if (RAPIDJSON_UNLIKELY(!handler.Null())) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); } else - CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); } template void ParseTrue(InputStream& is, Handler& handler) { - CEREAL_RAPIDJSON_ASSERT(is.Peek() == 't'); + RAPIDJSON_ASSERT(is.Peek() == 't'); is.Take(); - if (CEREAL_RAPIDJSON_LIKELY(Consume(is, 'r') && Consume(is, 'u') && Consume(is, 'e'))) { - if (CEREAL_RAPIDJSON_UNLIKELY(!handler.Bool(true))) - CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + 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 - CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); } template void ParseFalse(InputStream& is, Handler& handler) { - CEREAL_RAPIDJSON_ASSERT(is.Peek() == 'f'); + RAPIDJSON_ASSERT(is.Peek() == 'f'); is.Take(); - if (CEREAL_RAPIDJSON_LIKELY(Consume(is, 'a') && Consume(is, 'l') && Consume(is, 's') && Consume(is, 'e'))) { - if (CEREAL_RAPIDJSON_UNLIKELY(!handler.Bool(false))) - CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + 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 - CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); } template - CEREAL_RAPIDJSON_FORCEINLINE static bool Consume(InputStream& is, typename InputStream::Ch expect) { - if (CEREAL_RAPIDJSON_LIKELY(is.Peek() == expect)) { + RAPIDJSON_FORCEINLINE static bool Consume(InputStream& is, typename InputStream::Ch expect) { + if (RAPIDJSON_LIKELY(is.Peek() == expect)) { is.Take(); return true; } @@ -750,7 +901,7 @@ private: return false; } - // Helper function to parse four hexidecimal digits in \uXXXX in ParseString(). + // Helper function to parse four hexadecimal digits in \uXXXX in ParseString(). template unsigned ParseHex4(InputStream& is, size_t escapeOffset) { unsigned codepoint = 0; @@ -765,8 +916,8 @@ private: else if (c >= 'a' && c <= 'f') codepoint -= 'a' - 10; else { - CEREAL_RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex, escapeOffset); - CEREAL_RAPIDJSON_PARSE_ERROR_EARLY_RETURN(0); + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex, escapeOffset); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(0); } is.Take(); } @@ -779,12 +930,12 @@ private: typedef CharType Ch; StackStream(internal::Stack& stack) : stack_(stack), length_(0) {} - CEREAL_RAPIDJSON_FORCEINLINE void Put(Ch c) { + RAPIDJSON_FORCEINLINE void Put(Ch c) { *stack_.template Push() = c; ++length_; } - CEREAL_RAPIDJSON_FORCEINLINE void* Push(SizeType count) { + RAPIDJSON_FORCEINLINE void* Push(SizeType count) { length_ += count; return stack_.template Push(count); } @@ -809,39 +960,39 @@ private: internal::StreamLocalCopy copy(is); InputStream& s(copy.s); - CEREAL_RAPIDJSON_ASSERT(s.Peek() == '\"'); + RAPIDJSON_ASSERT(s.Peek() == '\"'); s.Take(); // Skip '\"' bool success = false; if (parseFlags & kParseInsituFlag) { typename InputStream::Ch *head = s.PutBegin(); ParseStringToStream(s, s); - CEREAL_RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; size_t length = s.PutEnd(head) - 1; - CEREAL_RAPIDJSON_ASSERT(length <= 0xFFFFFFFF); + 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); - CEREAL_RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + 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 (CEREAL_RAPIDJSON_UNLIKELY(!success)) - CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell()); + 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 - CEREAL_RAPIDJSON_FORCEINLINE void ParseStringToStream(InputStream& is, OutputStream& os) { -//!@cond CEREAL_RAPIDJSON_HIDDEN_FROM_DOXYGEN + 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, '/', 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, @@ -856,68 +1007,80 @@ private: ScanCopyUnescapedString(is, os); Ch c = is.Peek(); - if (CEREAL_RAPIDJSON_UNLIKELY(c == '\\')) { // Escape - size_t escapeOffset = is.Tell(); // For invalid escaping, report the inital '\\' as error offset + 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) && CEREAL_RAPIDJSON_LIKELY(escape[static_cast(e)])) { + 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 (CEREAL_RAPIDJSON_LIKELY(e == 'u')) { // Unicode + 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); - CEREAL_RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - if (CEREAL_RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDBFF)) { - // Handle UTF-16 surrogate pair - if (CEREAL_RAPIDJSON_UNLIKELY(!Consume(is, '\\') || !Consume(is, 'u'))) - CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset); - unsigned codepoint2 = ParseHex4(is, escapeOffset); - CEREAL_RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - if (CEREAL_RAPIDJSON_UNLIKELY(codepoint2 < 0xDC00 || codepoint2 > 0xDFFF)) - CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset); - codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000; + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDFFF)) { + // high surrogate, check if followed by valid low surrogate + if (RAPIDJSON_LIKELY(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; + } + // single low surrogate + else + { + RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset); + } } TEncoding::Encode(os, codepoint); } else - CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, escapeOffset); + RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, escapeOffset); } - else if (CEREAL_RAPIDJSON_UNLIKELY(c == '"')) { // Closing double quote + else if (RAPIDJSON_UNLIKELY(c == '"')) { // Closing double quote is.Take(); os.Put('\0'); // null-terminate the string return; } - else if (CEREAL_RAPIDJSON_UNLIKELY(static_cast(c) < 0x20)) { // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF + else if (RAPIDJSON_UNLIKELY(static_cast(c) < 0x20)) { // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF if (c == '\0') - CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell()); + RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell()); else - CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell()); + RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, is.Tell()); } else { size_t offset = is.Tell(); - if (CEREAL_RAPIDJSON_UNLIKELY((parseFlags & kParseValidateEncodingFlag ? + if (RAPIDJSON_UNLIKELY((parseFlags & kParseValidateEncodingFlag ? !Transcoder::Validate(is, os) : !Transcoder::Transcode(is, os)))) - CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, offset); + RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, offset); } } } template - static CEREAL_RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InputStream&, OutputStream&) { + static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InputStream&, OutputStream&) { // Do nothing for generic version } -#if defined(CEREAL_RAPIDJSON_SSE2) || defined(CEREAL_RAPIDJSON_SSE42) +#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) // StringStream -> StackStream - static CEREAL_RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream& os) { + 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 (CEREAL_RAPIDJSON_UNLIKELY(*p == '\"') || CEREAL_RAPIDJSON_UNLIKELY(*p == '\\') || CEREAL_RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { is.src_ = p; return; } @@ -927,7 +1090,7 @@ private: // The rest of string using SIMD static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; - static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 }; + 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])); @@ -936,10 +1099,10 @@ private: 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, 0x19) == 0x19 + 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 (CEREAL_RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped + if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped SizeType length; #ifdef _MSC_VER // Find the index of first escaped unsigned long offset; @@ -948,11 +1111,13 @@ private: #else length = static_cast(__builtin_ffs(r) - 1); #endif - char* q = reinterpret_cast(os.Push(length)); - for (size_t i = 0; i < length; i++) - q[i] = p[i]; + if (length != 0) { + char* q = reinterpret_cast(os.Push(length)); + for (size_t i = 0; i < length; i++) + q[i] = p[i]; - p += length; + p += length; + } break; } _mm_storeu_si128(reinterpret_cast<__m128i *>(os.Push(16)), s); @@ -962,8 +1127,8 @@ private: } // InsituStringStream -> InsituStringStream - static CEREAL_RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InsituStringStream& is, InsituStringStream& os) { - CEREAL_RAPIDJSON_ASSERT(&is == &os); + static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InsituStringStream& is, InsituStringStream& os) { + RAPIDJSON_ASSERT(&is == &os); (void)os; if (is.src_ == is.dst_) { @@ -977,7 +1142,7 @@ private: // 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 (CEREAL_RAPIDJSON_UNLIKELY(*p == '\"') || CEREAL_RAPIDJSON_UNLIKELY(*p == '\\') || CEREAL_RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { is.src_ = p; is.dst_ = q; return; @@ -988,7 +1153,7 @@ private: // The rest of string using SIMD static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; - static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 }; + 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])); @@ -997,10 +1162,10 @@ private: 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, 0x19) == 0x19 + 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 (CEREAL_RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped + 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; @@ -1021,14 +1186,14 @@ private: } // When read/write pointers are the same for insitu stream, just skip unescaped characters - static CEREAL_RAPIDJSON_FORCEINLINE void SkipUnescapedString(InsituStringStream& is) { - CEREAL_RAPIDJSON_ASSERT(is.src_ == is.dst_); + 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 (CEREAL_RAPIDJSON_UNLIKELY(*p == '\"') || CEREAL_RAPIDJSON_UNLIKELY(*p == '\\') || CEREAL_RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { is.src_ = is.dst_ = p; return; } @@ -1036,7 +1201,7 @@ private: // The rest of string using SIMD static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; - static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 }; + 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])); @@ -1045,10 +1210,10 @@ private: 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, 0x19) == 0x19 + 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 (CEREAL_RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped + 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; @@ -1064,27 +1229,199 @@ private: is.src_ = is.dst_ = p; } -#endif +#elif defined(RAPIDJSON_NEON) + // StringStream -> StackStream + static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream& os) { + const char* p = is.src_; - template + // 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 { + template + class NumberStream { public: typedef typename InputStream::Ch Ch; NumberStream(GenericReader& reader, InputStream& s) : is(s) { (void)reader; } - ~NumberStream() {} - CEREAL_RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); } - CEREAL_RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); } - CEREAL_RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); } - CEREAL_RAPIDJSON_FORCEINLINE void Push(char) {} + 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; } + const StackCharacter* Pop() { return 0; } protected: NumberStream& operator=(const NumberStream&); @@ -1092,47 +1429,47 @@ private: InputStream& is; }; - template - class NumberStream : public NumberStream { - typedef NumberStream Base; + template + class NumberStream : public NumberStream { + typedef NumberStream Base; public: NumberStream(GenericReader& reader, InputStream& s) : Base(reader, s), stackStream(reader.stack_) {} - ~NumberStream() {} - CEREAL_RAPIDJSON_FORCEINLINE Ch TakePush() { - stackStream.Put(static_cast(Base::is.Peek())); + RAPIDJSON_FORCEINLINE Ch TakePush() { + stackStream.Put(static_cast(Base::is.Peek())); return Base::is.Take(); } - CEREAL_RAPIDJSON_FORCEINLINE void Push(char c) { + RAPIDJSON_FORCEINLINE void Push(StackCharacter c) { stackStream.Put(c); } size_t Length() { return stackStream.Length(); } - const char* Pop() { + const StackCharacter* Pop() { stackStream.Put('\0'); return stackStream.Pop(); } private: - StackStream stackStream; + StackStream stackStream; }; - template - class NumberStream : public NumberStream { - typedef NumberStream Base; + template + class NumberStream : public NumberStream { + typedef NumberStream Base; public: - NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is) {} - ~NumberStream() {} + NumberStream(GenericReader& reader, InputStream& s) : Base(reader, s) {} - CEREAL_RAPIDJSON_FORCEINLINE Ch Take() { return Base::TakePush(); } + RAPIDJSON_FORCEINLINE Ch Take() { return Base::TakePush(); } }; template void ParseNumber(InputStream& is, Handler& handler) { + typedef typename internal::SelectIf, typename TargetEncoding::Ch, char>::Type NumberCharacter; + internal::StreamLocalCopy copy(is); - NumberStream= '1' && s.Peek() <= '9')) { + else if (RAPIDJSON_LIKELY(s.Peek() >= '1' && s.Peek() <= '9')) { i = static_cast(s.TakePush() - '0'); if (minus) - while (CEREAL_RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { - if (CEREAL_RAPIDJSON_UNLIKELY(i >= 214748364)) { // 2^31 = 2147483648 - if (CEREAL_RAPIDJSON_LIKELY(i != 214748364 || s.Peek() > '8')) { + 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; @@ -1171,9 +1508,9 @@ private: significandDigit++; } else - while (CEREAL_RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { - if (CEREAL_RAPIDJSON_UNLIKELY(i >= 429496729)) { // 2^32 - 1 = 4294967295 - if (CEREAL_RAPIDJSON_LIKELY(i != 429496729 || s.Peek() > '5')) { + 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; @@ -1184,30 +1521,39 @@ private: } } // Parse NaN or Infinity here - else if ((parseFlags & kParseNanAndInfFlag) && CEREAL_RAPIDJSON_LIKELY((s.Peek() == 'I' || s.Peek() == 'N'))) { - useNanOrInf = true; - if (CEREAL_RAPIDJSON_LIKELY(Consume(s, 'N') && Consume(s, 'a') && Consume(s, 'N'))) { - d = std::numeric_limits::quiet_NaN(); + 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 (CEREAL_RAPIDJSON_LIKELY(Consume(s, 'I') && Consume(s, 'n') && Consume(s, 'f'))) { - d = (minus ? -std::numeric_limits::infinity() : std::numeric_limits::infinity()); - if (CEREAL_RAPIDJSON_UNLIKELY(s.Peek() == 'i' && !(Consume(s, 'i') && Consume(s, 'n') - && Consume(s, 'i') && Consume(s, 't') && Consume(s, 'y')))) - CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); + 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 - CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); } else - CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); // Parse 64bit int bool useDouble = false; if (use64bit) { if (minus) - while (CEREAL_RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { - if (CEREAL_RAPIDJSON_UNLIKELY(i64 >= CEREAL_RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC))) // 2^63 = 9223372036854775808 - if (CEREAL_RAPIDJSON_LIKELY(i64 != CEREAL_RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8')) { + 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; @@ -1216,9 +1562,9 @@ private: significandDigit++; } else - while (CEREAL_RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { - if (CEREAL_RAPIDJSON_UNLIKELY(i64 >= CEREAL_RAPIDJSON_UINT64_C2(0x19999999, 0x99999999))) // 2^64 - 1 = 18446744073709551615 - if (CEREAL_RAPIDJSON_LIKELY(i64 != CEREAL_RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || s.Peek() > '5')) { + 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; @@ -1230,9 +1576,7 @@ private: // Force double for big integer if (useDouble) { - while (CEREAL_RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { - if (CEREAL_RAPIDJSON_UNLIKELY(d >= 1.7976931348623157e307)) // DBL_MAX / 10.0 - CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset); + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { d = d * 10 + (s.TakePush() - '0'); } } @@ -1243,17 +1587,17 @@ private: if (Consume(s, '.')) { decimalPosition = s.Length(); - if (CEREAL_RAPIDJSON_UNLIKELY(!(s.Peek() >= '0' && s.Peek() <= '9'))) - CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell()); + if (RAPIDJSON_UNLIKELY(!(s.Peek() >= '0' && s.Peek() <= '9'))) + RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell()); if (!useDouble) { -#if CEREAL_RAPIDJSON_64BIT +#if RAPIDJSON_64BIT // Use i64 to store significand in 64-bit architecture if (!use64bit) i64 = i; - while (CEREAL_RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { - if (i64 > CEREAL_RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) // 2^53 - 1 for fast path + 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'); @@ -1271,11 +1615,11 @@ private: useDouble = true; } - while (CEREAL_RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { if (significandDigit < 17) { d = d * 10.0 + (s.TakePush() - '0'); --expFrac; - if (CEREAL_RAPIDJSON_LIKELY(d > 0.0)) + if (RAPIDJSON_LIKELY(d > 0.0)) significandDigit++; } else @@ -1299,28 +1643,37 @@ private: else if (Consume(s, '-')) expMinus = true; - if (CEREAL_RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + if (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { exp = static_cast(s.Take() - '0'); if (expMinus) { - while (CEREAL_RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + // (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 (exp >= 214748364) { // Issue #313: prevent overflow exponent - while (CEREAL_RAPIDJSON_UNLIKELY(s.Peek() >= '0' && s.Peek() <= '9')) // Consume the rest of exponent + 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 (CEREAL_RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { exp = exp * 10 + static_cast(s.Take() - '0'); - if (CEREAL_RAPIDJSON_UNLIKELY(exp > maxExp)) - CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset); + if (RAPIDJSON_UNLIKELY(exp > maxExp)) + RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset); } } } else - CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissExponent, s.Tell()); + RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissExponent, s.Tell()); if (expMinus) exp = -exp; @@ -1334,17 +1687,17 @@ private: 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; - CEREAL_RAPIDJSON_ASSERT(length <= 0xFFFFFFFF); + 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()); + GenericStringStream > srcStream(s.Pop()); StackStream dstStream(stack_); while (numCharsToCopy--) { - Transcoder, TargetEncoding>::Transcode(srcStream, dstStream); + Transcoder, TargetEncoding>::Transcode(srcStream, dstStream); } dstStream.Put('\0'); const typename TargetEncoding::Ch* str = dstStream.Pop(); @@ -1354,7 +1707,7 @@ private: } else { size_t length = s.Length(); - const char* decimal = s.Pop(); // Pop stack no matter if it will be used or not. + const NumberCharacter* decimal = s.Pop(); // Pop stack no matter if it will be used or not. if (useDouble) { int p = exp + expFrac; @@ -1363,6 +1716,13 @@ private: 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) { @@ -1383,8 +1743,8 @@ private: } } } - if (CEREAL_RAPIDJSON_UNLIKELY(!cont)) - CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorTermination, startOffset); + if (RAPIDJSON_UNLIKELY(!cont)) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, startOffset); } // Parse any JSON value @@ -1408,29 +1768,31 @@ private: // States enum IterativeParsingState { - IterativeParsingStartState = 0, - IterativeParsingFinishState, - IterativeParsingErrorState, + IterativeParsingFinishState = 0, // sink states at top + IterativeParsingErrorState, // sink states at top + IterativeParsingStartState, // Object states IterativeParsingObjectInitialState, IterativeParsingMemberKeyState, - IterativeParsingKeyValueDelimiterState, IterativeParsingMemberValueState, - IterativeParsingMemberDelimiterState, IterativeParsingObjectFinishState, // Array states IterativeParsingArrayInitialState, IterativeParsingElementState, - IterativeParsingElementDelimiterState, IterativeParsingArrayFinishState, // Single value state - IterativeParsingValueState - }; + IterativeParsingValueState, - enum { cIterativeParsingStateCount = IterativeParsingValueState + 1 }; + // Delimiter states (at bottom) + IterativeParsingElementDelimiterState, + IterativeParsingMemberDelimiterState, + IterativeParsingKeyValueDelimiterState, + + cIterativeParsingStateCount + }; // Tokens enum Token { @@ -1452,9 +1814,9 @@ private: kTokenCount }; - CEREAL_RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) { + RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) const { -//!@cond CEREAL_RAPIDJSON_HIDDEN_FROM_DOXYGEN +//!@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 @@ -1479,9 +1841,21 @@ private: return NumberToken; } - CEREAL_RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) { + 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 @@ -1496,18 +1870,6 @@ private: IterativeParsingValueState, // Null IterativeParsingValueState // Number }, - // 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 - }, // ObjectInitial { IterativeParsingErrorState, // Left bracket @@ -1536,20 +1898,6 @@ private: 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 - }, // MemberValue { IterativeParsingErrorState, // Left bracket @@ -1564,20 +1912,6 @@ private: IterativeParsingErrorState, // Null IterativeParsingErrorState // 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 - }, // ObjectFinish(sink state) { IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, @@ -1612,6 +1946,18 @@ private: 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) @@ -1626,18 +1972,34 @@ private: IterativeParsingElementState, // Null IterativeParsingElementState // Number }, - // ArrayFinish(sink state) + // MemberDelimiter { - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState + 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 }, - // Single Value (sink state) + // KeyValueDelimiter { - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState - } + 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]); @@ -1646,7 +2008,7 @@ private: // 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 - CEREAL_RAPIDJSON_FORCEINLINE IterativeParsingState Transit(IterativeParsingState src, Token token, IterativeParsingState dst, InputStream& is, Handler& handler) { + RAPIDJSON_FORCEINLINE IterativeParsingState Transit(IterativeParsingState src, Token token, IterativeParsingState dst, InputStream& is, Handler& handler) { (void)token; switch (dst) { @@ -1671,7 +2033,7 @@ private: bool hr = (dst == IterativeParsingObjectInitialState) ? handler.StartObject() : handler.StartArray(); // On handler short circuits the parsing. if (!hr) { - CEREAL_RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); return IterativeParsingErrorState; } else { @@ -1688,7 +2050,7 @@ private: return dst; case IterativeParsingKeyValueDelimiterState: - CEREAL_RAPIDJSON_ASSERT(token == ColonToken); + RAPIDJSON_ASSERT(token == ColonToken); is.Take(); return dst; @@ -1719,7 +2081,7 @@ private: { // Transit from delimiter is only allowed when trailing commas are enabled if (!(parseFlags & kParseTrailingCommasFlag) && src == IterativeParsingMemberDelimiterState) { - CEREAL_RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorObjectMissName, is.Tell()); + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorObjectMissName, is.Tell()); return IterativeParsingErrorState; } // Get member count. @@ -1736,7 +2098,7 @@ private: bool hr = handler.EndObject(c); // On handler short circuits the parsing. if (!hr) { - CEREAL_RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); return IterativeParsingErrorState; } else { @@ -1749,7 +2111,7 @@ private: { // Transit from delimiter is only allowed when trailing commas are enabled if (!(parseFlags & kParseTrailingCommasFlag) && src == IterativeParsingElementDelimiterState) { - CEREAL_RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorValueInvalid, is.Tell()); + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorValueInvalid, is.Tell()); return IterativeParsingErrorState; } // Get element count. @@ -1766,7 +2128,7 @@ private: bool hr = handler.EndArray(c); // On handler short circuits the parsing. if (!hr) { - CEREAL_RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); return IterativeParsingErrorState; } else { @@ -1786,7 +2148,7 @@ private: // 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. - CEREAL_RAPIDJSON_ASSERT(dst == IterativeParsingValueState); + RAPIDJSON_ASSERT(dst == IterativeParsingValueState); // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. ParseValue(is, handler); @@ -1805,19 +2167,27 @@ private: } switch (src) { - case IterativeParsingStartState: CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell()); return; - case IterativeParsingFinishState: CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell()); return; + case IterativeParsingStartState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell()); return; + case IterativeParsingFinishState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell()); return; case IterativeParsingObjectInitialState: - case IterativeParsingMemberDelimiterState: CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); return; - case IterativeParsingMemberKeyState: CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); return; - case IterativeParsingMemberValueState: CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); return; + 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: CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); return; - default: CEREAL_RAPIDJSON_ASSERT(src == IterativeParsingElementState); CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return; + 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(); @@ -1825,7 +2195,7 @@ private: IterativeParsingState state = IterativeParsingStartState; SkipWhitespaceAndComments(is); - CEREAL_RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); while (is.Peek() != '\0') { Token t = Tokenize(is.Peek()); IterativeParsingState n = Predict(state, t); @@ -1843,7 +2213,7 @@ private: break; SkipWhitespaceAndComments(is); - CEREAL_RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); } // Handle the end of file. @@ -1856,24 +2226,21 @@ private: 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; -CEREAL_RAPIDJSON_NAMESPACE_END +RAPIDJSON_NAMESPACE_END -#ifdef __clang__ -CEREAL_RAPIDJSON_DIAG_POP +#if defined(__clang__) || defined(_MSC_VER) +RAPIDJSON_DIAG_POP #endif #ifdef __GNUC__ -CEREAL_RAPIDJSON_DIAG_POP +RAPIDJSON_DIAG_POP #endif -#ifdef _MSC_VER -CEREAL_RAPIDJSON_DIAG_POP -#endif - -#endif // CEREAL_RAPIDJSON_READER_H_ +#endif // RAPIDJSON_READER_H_ diff --git a/external/cereal/external/rapidjson/schema.h b/external/cereal/external/rapidjson/schema.h index 1298755..188d659 100644 --- a/external/cereal/external/rapidjson/schema.h +++ b/external/cereal/external/rapidjson/schema.h @@ -12,68 +12,69 @@ // CONDITIONS OF ANY KIND, either express or implied-> See the License for the // specific language governing permissions and limitations under the License-> -#ifndef CEREAL_RAPIDJSON_SCHEMA_H_ -#define CEREAL_RAPIDJSON_SCHEMA_H_ +#ifndef RAPIDJSON_SCHEMA_H_ +#define RAPIDJSON_SCHEMA_H_ #include "document.h" #include "pointer.h" +#include "stringbuffer.h" +#include "error/en.h" +#include "uri.h" #include // abs, floor -#if !defined(CEREAL_RAPIDJSON_SCHEMA_USE_INTERNALREGEX) -#define CEREAL_RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1 +#if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX) +#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1 #else -#define CEREAL_RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0 +#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0 #endif -#if !CEREAL_RAPIDJSON_SCHEMA_USE_INTERNALREGEX && !defined(CEREAL_RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800)) -#define CEREAL_RAPIDJSON_SCHEMA_USE_STDREGEX 1 +#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 CEREAL_RAPIDJSON_SCHEMA_USE_STDREGEX 0 +#define RAPIDJSON_SCHEMA_USE_STDREGEX 0 #endif -#if CEREAL_RAPIDJSON_SCHEMA_USE_INTERNALREGEX +#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX #include "internal/regex.h" -#elif CEREAL_RAPIDJSON_SCHEMA_USE_STDREGEX +#elif RAPIDJSON_SCHEMA_USE_STDREGEX #include #endif -#if CEREAL_RAPIDJSON_SCHEMA_USE_INTERNALREGEX || CEREAL_RAPIDJSON_SCHEMA_USE_STDREGEX -#define CEREAL_RAPIDJSON_SCHEMA_HAS_REGEX 1 +#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX || RAPIDJSON_SCHEMA_USE_STDREGEX +#define RAPIDJSON_SCHEMA_HAS_REGEX 1 #else -#define CEREAL_RAPIDJSON_SCHEMA_HAS_REGEX 0 +#define RAPIDJSON_SCHEMA_HAS_REGEX 0 #endif -#ifndef CEREAL_RAPIDJSON_SCHEMA_VERBOSE -#define CEREAL_RAPIDJSON_SCHEMA_VERBOSE 0 +#ifndef RAPIDJSON_SCHEMA_VERBOSE +#define RAPIDJSON_SCHEMA_VERBOSE 0 #endif -#if CEREAL_RAPIDJSON_SCHEMA_VERBOSE +#if RAPIDJSON_SCHEMA_VERBOSE #include "stringbuffer.h" #endif -CEREAL_RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_PUSH #if defined(__GNUC__) -CEREAL_RAPIDJSON_DIAG_OFF(effc++) +RAPIDJSON_DIAG_OFF(effc++) #endif #ifdef __clang__ -CEREAL_RAPIDJSON_DIAG_OFF(weak-vtables) -CEREAL_RAPIDJSON_DIAG_OFF(exit-time-destructors) -CEREAL_RAPIDJSON_DIAG_OFF(c++98-compat-pedantic) -CEREAL_RAPIDJSON_DIAG_OFF(variadic-macros) +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 -#ifdef _MSC_VER -CEREAL_RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated -#endif - -CEREAL_RAPIDJSON_NAMESPACE_BEGIN +RAPIDJSON_NAMESPACE_BEGIN /////////////////////////////////////////////////////////////////////////////// // Verbose Utilities -#if CEREAL_RAPIDJSON_SCHEMA_VERBOSE +#if RAPIDJSON_SCHEMA_VERBOSE namespace internal { @@ -103,23 +104,46 @@ inline void PrintValidatorPointers(unsigned depth, const wchar_t* s, const wchar } // namespace internal -#endif // CEREAL_RAPIDJSON_SCHEMA_VERBOSE +#endif // RAPIDJSON_SCHEMA_VERBOSE /////////////////////////////////////////////////////////////////////////////// -// CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN +// RAPIDJSON_INVALID_KEYWORD_RETURN -#if CEREAL_RAPIDJSON_SCHEMA_VERBOSE -#define CEREAL_RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) internal::PrintInvalidKeyword(keyword) +#if RAPIDJSON_SCHEMA_VERBOSE +#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) internal::PrintInvalidKeyword(keyword) #else -#define CEREAL_RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) +#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) #endif -#define CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(keyword)\ -CEREAL_RAPIDJSON_MULTILINEMACRO_BEGIN\ - context.invalidKeyword = keyword.GetString();\ - CEREAL_RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword.GetString());\ +#define RAPIDJSON_INVALID_KEYWORD_RETURN(code)\ +RAPIDJSON_MULTILINEMACRO_BEGIN\ + context.invalidCode = code;\ + context.invalidKeyword = SchemaType::GetValidateErrorKeyword(code).GetString();\ + RAPIDJSON_INVALID_KEYWORD_VERBOSE(context.invalidKeyword);\ return false;\ -CEREAL_RAPIDJSON_MULTILINEMACRO_END +RAPIDJSON_MULTILINEMACRO_END + +/////////////////////////////////////////////////////////////////////////////// +// ValidateFlag + +/*! \def RAPIDJSON_VALIDATE_DEFAULT_FLAGS + \ingroup RAPIDJSON_CONFIG + \brief User-defined kValidateDefaultFlags definition. + + User can define this as any \c ValidateFlag combinations. +*/ +#ifndef RAPIDJSON_VALIDATE_DEFAULT_FLAGS +#define RAPIDJSON_VALIDATE_DEFAULT_FLAGS kValidateNoFlags +#endif + +//! Combination of validate flags +/*! \see + */ +enum ValidateFlag { + kValidateNoFlags = 0, //!< No flags are set. + kValidateContinueOnErrorFlag = 1, //!< Don't stop after first validation error. + kValidateDefaultFlags = RAPIDJSON_VALIDATE_DEFAULT_FLAGS //!< Default validate flags. Can be customized by defining RAPIDJSON_VALIDATE_DEFAULT_FLAGS +}; /////////////////////////////////////////////////////////////////////////////// // Forward declarations @@ -139,6 +163,8 @@ class ISchemaValidator { public: virtual ~ISchemaValidator() {} virtual bool IsValid() const = 0; + virtual void SetValidateFlags(unsigned flags) = 0; + virtual unsigned GetValidateFlags() const = 0; }; /////////////////////////////////////////////////////////////////////////////// @@ -148,7 +174,7 @@ template class ISchemaStateFactory { public: virtual ~ISchemaStateFactory() {} - virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&) = 0; + virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&, const bool inheritContinueOnErrors) = 0; virtual void DestroySchemaValidator(ISchemaValidator* validator) = 0; virtual void* CreateHasher() = 0; virtual uint64_t GetHashCode(void* hasher) = 0; @@ -157,6 +183,62 @@ public: 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(const ValidateErrorCode code) = 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, bool matched) = 0; + virtual void Disallowed() = 0; +}; + + /////////////////////////////////////////////////////////////////////////////// // Hasher @@ -216,7 +298,7 @@ public: bool IsValid() const { return stack_.GetSize() == sizeof(uint64_t); } uint64_t GetHashCode() const { - CEREAL_RAPIDJSON_ASSERT(IsValid()); + RAPIDJSON_ASSERT(IsValid()); return *stack_.template Top(); } @@ -236,7 +318,7 @@ private: bool WriteBuffer(Type type, const void* data, size_t len) { // FNV-1a from http://isthe.com/chongo/tech/comp/fnv/ - uint64_t h = Hash(CEREAL_RAPIDJSON_UINT64_C2(0x84222325, 0xcbf29ce4), type); + 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]); @@ -245,7 +327,7 @@ private: } static uint64_t Hash(uint64_t h, uint64_t d) { - static const uint64_t kPrime = CEREAL_RAPIDJSON_UINT64_C2(0x00000100, 0x000001b3); + static const uint64_t kPrime = RAPIDJSON_UINT64_C2(0x00000100, 0x000001b3); h ^= d; h *= kPrime; return h; @@ -261,6 +343,7 @@ template struct SchemaValidationContext { typedef Schema SchemaType; typedef ISchemaStateFactory SchemaValidatorFactoryType; + typedef IValidationErrorHandler ErrorHandlerType; typedef typename SchemaType::ValueType ValueType; typedef typename ValueType::Ch Ch; @@ -270,11 +353,13 @@ struct SchemaValidationContext { kPatternValidatorWithAdditionalProperty }; - SchemaValidationContext(SchemaValidatorFactoryType& f, const SchemaType* s) : + SchemaValidationContext(SchemaValidatorFactoryType& f, ErrorHandlerType& eh, const SchemaType* s) : factory(f), + error_handler(eh), schema(s), valueSchema(), invalidKeyword(), + invalidCode(), hasher(), arrayElementHashCodes(), validators(), @@ -295,13 +380,19 @@ struct SchemaValidationContext { if (hasher) factory.DestroryHasher(hasher); if (validators) { - for (SizeType i = 0; i < validatorCount; i++) - factory.DestroySchemaValidator(validators[i]); + for (SizeType i = 0; i < validatorCount; i++) { + if (validators[i]) { + factory.DestroySchemaValidator(validators[i]); + } + } factory.FreeState(validators); } if (patternPropertiesValidators) { - for (SizeType i = 0; i < patternPropertiesValidatorCount; i++) - factory.DestroySchemaValidator(patternPropertiesValidators[i]); + for (SizeType i = 0; i < patternPropertiesValidatorCount; i++) { + if (patternPropertiesValidators[i]) { + factory.DestroySchemaValidator(patternPropertiesValidators[i]); + } + } factory.FreeState(patternPropertiesValidators); } if (patternPropertiesSchemas) @@ -311,9 +402,11 @@ struct SchemaValidationContext { } SchemaValidatorFactoryType& factory; + ErrorHandlerType& error_handler; const SchemaType* schema; const SchemaType* valueSchema; const Ch* invalidKeyword; + ValidateErrorCode invalidCode; void* hasher; // Only validator access void* arrayElementHashCodes; // Only validator access this ISchemaValidator** validators; @@ -345,15 +438,22 @@ public: typedef SchemaValidationContext Context; typedef Schema SchemaType; typedef GenericValue SValue; + typedef IValidationErrorHandler ErrorHandler; + typedef GenericUri UriType; friend class GenericSchemaDocument; - Schema(SchemaDocumentType* schemaDocument, const PointerType& p, const ValueType& value, const ValueType& document, AllocatorType* allocator) : + Schema(SchemaDocumentType* schemaDocument, const PointerType& p, const ValueType& value, const ValueType& document, AllocatorType* allocator, const UriType& id = UriType()) : allocator_(allocator), + uri_(schemaDocument->GetURI(), *allocator), + id_(id), + pointer_(p, allocator), + typeless_(schemaDocument->GetTypeless()), enum_(), enumCount_(), not_(), type_((1 << kTotalSchemaType) - 1), // typeless validatorCount_(), + notValidatorIndex_(), properties_(), additionalPropertiesSchema_(), patternProperties_(), @@ -377,15 +477,34 @@ public: minLength_(0), maxLength_(~SizeType(0)), exclusiveMinimum_(false), - exclusiveMaximum_(false) + exclusiveMaximum_(false), + defaultValueLength_(0) { - typedef typename SchemaDocumentType::ValueType ValueType; typedef typename ValueType::ConstValueIterator ConstValueIterator; typedef typename ValueType::ConstMemberIterator ConstMemberIterator; + // PR #1393 + // Early add this Schema and its $ref(s) in schemaDocument's map to avoid infinite + // recursion (with recursive schemas), since schemaDocument->getSchema() is always + // checked before creating a new one. Don't cache typeless_, though. + if (this != typeless_) { + typedef typename SchemaDocumentType::SchemaEntry SchemaEntry; + SchemaEntry *entry = schemaDocument->schemaMap_.template Push(); + new (entry) SchemaEntry(pointer_, this, true, allocator_); + schemaDocument->AddSchemaRefs(this); + } + if (!value.IsObject()) return; + // If we have an id property, resolve it with the in-scope id + if (const ValueType* v = GetMember(value, GetIdString())) { + if (v->IsString()) { + UriType local(*v, allocator); + id_ = local.Resolve(id_, allocator); + } + } + if (const ValueType* v = GetMember(value, GetTypeString())) { type_ = 0; if (v->IsString()) @@ -395,29 +514,30 @@ public: AddType(*itr); } - if (const ValueType* v = GetMember(value, GetEnumString())) + 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[256 + 24]; + 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_++; + if (const ValueType* v = GetMember(value, GetNotString())) { + schemaDocument->CreateSchema(¬_, p.Append(GetNotString(), allocator_), *v, document, id_); + notValidatorIndex_ = validatorCount_; + validatorCount_++; + } } // Object @@ -432,7 +552,7 @@ public: 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()) @@ -453,7 +573,7 @@ public: for (SizeType i = 0; i < propertyCount_; i++) { new (&properties_[i]) Property(); properties_[i].name = allProperties[i]; - properties_[i].schema = GetTypeless(); + properties_[i].schema = typeless_; } } } @@ -463,7 +583,7 @@ public: 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); + schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document, id_); } } @@ -475,7 +595,7 @@ public: 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); + schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, q.Append(itr->name, allocator_), itr->value, document, id_); patternPropertyCount_++; } } @@ -507,7 +627,7 @@ public: } else if (itr->value.IsObject()) { hasSchemaDependencies_ = true; - schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document); + schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document, id_); properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_; validatorCount_++; } @@ -519,7 +639,7 @@ public: if (v->IsBool()) additionalProperties_ = v->GetBool(); else if (v->IsObject()) - schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document); + schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document, id_); } AssignIfExist(minProperties_, value, GetMinPropertiesString()); @@ -529,12 +649,12 @@ public: if (const ValueType* v = GetMember(value, GetItemsString())) { PointerType q = p.Append(GetItemsString(), allocator_); if (v->IsObject()) // List validation - schemaDocument->CreateSchema(&itemsList_, q, *v, document); + schemaDocument->CreateSchema(&itemsList_, q, *v, document, id_); 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); + schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document, id_); } } @@ -545,7 +665,7 @@ public: if (v->IsBool()) additionalItems_ = v->GetBool(); else if (v->IsObject()) - schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document); + schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document, id_); } AssignIfExist(uniqueItems_, value, GetUniqueItemsString()); @@ -572,12 +692,16 @@ public: 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() { - if (allocator_) { - allocator_->Free(enum_); - } + AllocatorType::Free(enum_); if (properties_) { for (SizeType i = 0; i < propertyCount_; i++) properties_[i].~Property(); @@ -589,14 +713,26 @@ public: AllocatorType::Free(patternProperties_); } AllocatorType::Free(itemsTuple_); -#if CEREAL_RAPIDJSON_SCHEMA_HAS_REGEX +#if RAPIDJSON_SCHEMA_HAS_REGEX if (pattern_) { pattern_->~RegexType(); - allocator_->Free(pattern_); + AllocatorType::Free(pattern_); } #endif } + const SValue& GetURI() const { + return uri_; + } + + const UriType& GetId() const { + return id_; + } + + const PointerType& GetPointer() const { + return pointer_; + } + bool BeginValue(Context& context) const { if (context.inArray) { if (uniqueItems_) @@ -610,19 +746,26 @@ public: else if (additionalItemsSchema_) context.valueSchema = additionalItemsSchema_; else if (additionalItems_) - context.valueSchema = GetTypeless(); - else - CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetItemsString()); + context.valueSchema = typeless_; + else { + context.error_handler.DisallowedItem(context.arrayElementIndex); + // Must set valueSchema for when kValidateContinueOnErrorFlag is set, else reports spurious type error + context.valueSchema = typeless_; + // Must bump arrayElementIndex for when kValidateContinueOnErrorFlag is set + context.arrayElementIndex++; + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAdditionalItems); + } } else - context.valueSchema = GetTypeless(); + context.valueSchema = typeless_; context.arrayElementIndex++; } return true; } - CEREAL_RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const { + RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const { + // Only check pattern properties if we have validators if (context.patternPropertiesValidatorCount > 0) { bool otherValid = false; SizeType count = context.patternPropertiesValidatorCount; @@ -637,67 +780,90 @@ public: } if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) { - if (!patternValid) - CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); + if (!patternValid) { + context.error_handler.PropertyViolations(context.patternPropertiesValidators, count); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPatternProperties); + } } else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) { - if (!patternValid || !otherValid) - CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); + if (!patternValid || !otherValid) { + context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPatternProperties); + } + } + else if (!patternValid && !otherValid) { // kPatternValidatorWithAdditionalProperty) + context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPatternProperties); } - else if (!patternValid && !otherValid) // kPatternValidatorWithAdditionalProperty) - CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); } - if (enum_) { + // For enums only check if we have a hasher + if (enum_ && context.hasher) { const uint64_t h = context.factory.GetHashCode(context.hasher); for (SizeType i = 0; i < enumCount_; i++) if (enum_[i] == h) goto foundEnum; - CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetEnumString()); + context.error_handler.DisallowedValue(kValidateErrorEnum); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorEnum); foundEnum:; } - if (allOf_.schemas) - for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++) - if (!context.validators[i]->IsValid()) - CEREAL_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; - CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetAnyOfString()); - foundAny:; - } + // Only check allOf etc if we have validators + if (context.validatorCount > 0) { + 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(kValidateErrorAllOf); + } - if (oneOf_.schemas) { - bool oneValid = false; - for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++) - if (context.validators[i]->IsValid()) { - if (oneValid) - CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString()); - else - oneValid = true; + 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(kValidateErrorAnyOf); + 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, true); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorOneOfMatch); + } else + oneValid = true; + } + if (!oneValid) { + context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count, false); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorOneOf); } - if (!oneValid) - CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString()); - } + } - if (not_ && context.validators[notValidatorIndex_]->IsValid()) - CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetNotString()); + if (not_ && context.validators[notValidatorIndex_]->IsValid()) { + context.error_handler.Disallowed(); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorNot); + } + } return true; } - bool Null(Context& context) const { - if (!(type_ & (1 << kNullSchemaType))) - CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + bool Null(Context& context) const { + if (!(type_ & (1 << kNullSchemaType))) { + DisallowedType(context, GetNullString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); + } return CreateParallelValidator(context); } - - bool Bool(Context& context, bool) const { - if (!(type_ & (1 << kBooleanSchemaType))) - CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + + bool Bool(Context& context, bool) const { + if (!(type_ & (1 << kBooleanSchemaType))) { + DisallowedType(context, GetBooleanString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); + } return CreateParallelValidator(context); } @@ -726,44 +892,56 @@ public: } bool Double(Context& context, double d) const { - if (!(type_ & (1 << kNumberSchemaType))) - CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + if (!(type_ & (1 << kNumberSchemaType))) { + DisallowedType(context, GetNumberString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); + } 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))) - CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + if (!(type_ & (1 << kStringSchemaType))) { + DisallowedType(context, GetStringString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); + } if (minLength_ != 0 || maxLength_ != SizeType(~0)) { SizeType count; if (internal::CountStringCodePoint(str, length, &count)) { - if (count < minLength_) - CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinLengthString()); - if (count > maxLength_) - CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxLengthString()); + if (count < minLength_) { + context.error_handler.TooShort(str, length, minLength_); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMinLength); + } + if (count > maxLength_) { + context.error_handler.TooLong(str, length, maxLength_); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMaxLength); + } } } - if (pattern_ && !IsPatternMatch(pattern_, str, length)) - CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternString()); + if (pattern_ && !IsPatternMatch(pattern_, str, length)) { + context.error_handler.DoesNotMatch(str, length); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPattern); + } return CreateParallelValidator(context); } - bool StartObject(Context& context) const { - if (!(type_ & (1 << kObjectSchemaType))) - CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + bool StartObject(Context& context) const { + if (!(type_ & (1 << kObjectSchemaType))) { + DisallowedType(context, GetObjectString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); + } if (hasDependencies_ || hasRequired_) { context.propertyExist = static_cast(context.factory.MallocState(sizeof(bool) * propertyCount_)); @@ -779,20 +957,22 @@ public: 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)) + if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len)) { context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema; + context.valueSchema = typeless_; + } } - SizeType index; + SizeType index = 0; if (FindPropertyIndex(ValueType(str, len).Move(), &index)) { if (context.patternPropertiesSchemaCount > 0) { context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema; - context.valueSchema = GetTypeless(); + context.valueSchema = typeless_; context.valuePatternValidatorType = Context::kPatternValidatorWithProperty; } else @@ -805,9 +985,9 @@ public: } if (additionalPropertiesSchema_) { - if (additionalPropertiesSchema_ && context.patternPropertiesSchemaCount > 0) { + if (context.patternPropertiesSchemaCount > 0) { context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_; - context.valueSchema = GetTypeless(); + context.valueSchema = typeless_; context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty; } else @@ -815,111 +995,186 @@ public: return true; } else if (additionalProperties_) { - context.valueSchema = GetTypeless(); + context.valueSchema = typeless_; return true; } - if (context.patternPropertiesSchemaCount == 0) // patternProperties are not additional properties - CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetAdditionalPropertiesString()); + if (context.patternPropertiesSchemaCount == 0) { // patternProperties are not additional properties + // Must set valueSchema for when kValidateContinueOnErrorFlag is set, else reports spurious type error + context.valueSchema = typeless_; + context.error_handler.DisallowedProperty(str, len); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAdditionalProperties); + } return true; } bool EndObject(Context& context, SizeType memberCount) const { - if (hasRequired_) + if (hasRequired_) { + context.error_handler.StartMissingProperties(); for (SizeType index = 0; index < propertyCount_; index++) - if (properties_[index].required) - if (!context.propertyExist[index]) - CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString()); + 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(kValidateErrorRequired); + } - if (memberCount < minProperties_) - CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString()); + if (memberCount < minProperties_) { + context.error_handler.TooFewProperties(memberCount, minProperties_); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMinProperties); + } - if (memberCount > maxProperties_) - CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxPropertiesString()); + if (memberCount > maxProperties_) { + context.error_handler.TooManyProperties(memberCount, maxProperties_); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMaxProperties); + } if (hasDependencies_) { - for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++) + context.error_handler.StartDependencyErrors(); + for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++) { + const Property& source = properties_[sourceIndex]; if (context.propertyExist[sourceIndex]) { - if (properties_[sourceIndex].dependencies) { + if (source.dependencies) { + context.error_handler.StartMissingDependentProperties(); for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++) - if (properties_[sourceIndex].dependencies[targetIndex] && !context.propertyExist[targetIndex]) - CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString()); + 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); } - else if (properties_[sourceIndex].dependenciesSchema) - if (!context.validators[properties_[sourceIndex].dependenciesValidatorIndex]->IsValid()) - CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString()); } + } + if (context.error_handler.EndDependencyErrors()) + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorDependencies); } return true; } - bool StartArray(Context& context) const { - if (!(type_ & (1 << kArraySchemaType))) - CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); - + bool StartArray(Context& context) const { context.arrayElementIndex = 0; - context.inArray = true; + context.inArray = true; // Ensure we note that we are in an array + + if (!(type_ & (1 << kArraySchemaType))) { + DisallowedType(context, GetArrayString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); + } return CreateParallelValidator(context); } - bool EndArray(Context& context, SizeType elementCount) const { + bool EndArray(Context& context, SizeType elementCount) const { context.inArray = false; - - if (elementCount < minItems_) - CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinItemsString()); - - if (elementCount > maxItems_) - CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxItemsString()); + + if (elementCount < minItems_) { + context.error_handler.TooFewItems(elementCount, minItems_); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMinItems); + } + + if (elementCount > maxItems_) { + context.error_handler.TooManyItems(elementCount, maxItems_); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMaxItems); + } return true; } + static const ValueType& GetValidateErrorKeyword(ValidateErrorCode validateErrorCode) { + switch (validateErrorCode) { + case kValidateErrorMultipleOf: return GetMultipleOfString(); + case kValidateErrorMaximum: return GetMaximumString(); + case kValidateErrorExclusiveMaximum: return GetMaximumString(); // Same + case kValidateErrorMinimum: return GetMinimumString(); + case kValidateErrorExclusiveMinimum: return GetMinimumString(); // Same + + case kValidateErrorMaxLength: return GetMaxLengthString(); + case kValidateErrorMinLength: return GetMinLengthString(); + case kValidateErrorPattern: return GetPatternString(); + + case kValidateErrorMaxItems: return GetMaxItemsString(); + case kValidateErrorMinItems: return GetMinItemsString(); + case kValidateErrorUniqueItems: return GetUniqueItemsString(); + case kValidateErrorAdditionalItems: return GetAdditionalItemsString(); + + case kValidateErrorMaxProperties: return GetMaxPropertiesString(); + case kValidateErrorMinProperties: return GetMinPropertiesString(); + case kValidateErrorRequired: return GetRequiredString(); + case kValidateErrorAdditionalProperties: return GetAdditionalPropertiesString(); + case kValidateErrorPatternProperties: return GetPatternPropertiesString(); + case kValidateErrorDependencies: return GetDependenciesString(); + + case kValidateErrorEnum: return GetEnumString(); + case kValidateErrorType: return GetTypeString(); + + case kValidateErrorOneOf: return GetOneOfString(); + case kValidateErrorOneOfMatch: return GetOneOfString(); // Same + case kValidateErrorAllOf: return GetAllOfString(); + case kValidateErrorAnyOf: return GetAnyOfString(); + case kValidateErrorNot: return GetNotString(); + + default: return GetNullString(); + } + } + + // Generate functions for string literal according to Ch -#define CEREAL_RAPIDJSON_STRING_(name, ...) \ +#define RAPIDJSON_STRING_(name, ...) \ static const ValueType& Get##name##String() {\ static const Ch s[] = { __VA_ARGS__, '\0' };\ - static const ValueType v(s, sizeof(s) / sizeof(Ch) - 1);\ + static const ValueType v(s, static_cast(sizeof(s) / sizeof(Ch) - 1));\ return v;\ } - CEREAL_RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l') - CEREAL_RAPIDJSON_STRING_(Boolean, 'b', 'o', 'o', 'l', 'e', 'a', 'n') - CEREAL_RAPIDJSON_STRING_(Object, 'o', 'b', 'j', 'e', 'c', 't') - CEREAL_RAPIDJSON_STRING_(Array, 'a', 'r', 'r', 'a', 'y') - CEREAL_RAPIDJSON_STRING_(String, 's', 't', 'r', 'i', 'n', 'g') - CEREAL_RAPIDJSON_STRING_(Number, 'n', 'u', 'm', 'b', 'e', 'r') - CEREAL_RAPIDJSON_STRING_(Integer, 'i', 'n', 't', 'e', 'g', 'e', 'r') - CEREAL_RAPIDJSON_STRING_(Type, 't', 'y', 'p', 'e') - CEREAL_RAPIDJSON_STRING_(Enum, 'e', 'n', 'u', 'm') - CEREAL_RAPIDJSON_STRING_(AllOf, 'a', 'l', 'l', 'O', 'f') - CEREAL_RAPIDJSON_STRING_(AnyOf, 'a', 'n', 'y', 'O', 'f') - CEREAL_RAPIDJSON_STRING_(OneOf, 'o', 'n', 'e', 'O', 'f') - CEREAL_RAPIDJSON_STRING_(Not, 'n', 'o', 't') - CEREAL_RAPIDJSON_STRING_(Properties, 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') - CEREAL_RAPIDJSON_STRING_(Required, 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'd') - CEREAL_RAPIDJSON_STRING_(Dependencies, 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'i', 'e', 's') - CEREAL_RAPIDJSON_STRING_(PatternProperties, 'p', 'a', 't', 't', 'e', 'r', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') - CEREAL_RAPIDJSON_STRING_(AdditionalProperties, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') - CEREAL_RAPIDJSON_STRING_(MinProperties, 'm', 'i', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') - CEREAL_RAPIDJSON_STRING_(MaxProperties, 'm', 'a', 'x', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') - CEREAL_RAPIDJSON_STRING_(Items, 'i', 't', 'e', 'm', 's') - CEREAL_RAPIDJSON_STRING_(MinItems, 'm', 'i', 'n', 'I', 't', 'e', 'm', 's') - CEREAL_RAPIDJSON_STRING_(MaxItems, 'm', 'a', 'x', 'I', 't', 'e', 'm', 's') - CEREAL_RAPIDJSON_STRING_(AdditionalItems, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'I', 't', 'e', 'm', 's') - CEREAL_RAPIDJSON_STRING_(UniqueItems, 'u', 'n', 'i', 'q', 'u', 'e', 'I', 't', 'e', 'm', 's') - CEREAL_RAPIDJSON_STRING_(MinLength, 'm', 'i', 'n', 'L', 'e', 'n', 'g', 't', 'h') - CEREAL_RAPIDJSON_STRING_(MaxLength, 'm', 'a', 'x', 'L', 'e', 'n', 'g', 't', 'h') - CEREAL_RAPIDJSON_STRING_(Pattern, 'p', 'a', 't', 't', 'e', 'r', 'n') - CEREAL_RAPIDJSON_STRING_(Minimum, 'm', 'i', 'n', 'i', 'm', 'u', 'm') - CEREAL_RAPIDJSON_STRING_(Maximum, 'm', 'a', 'x', 'i', 'm', 'u', 'm') - CEREAL_RAPIDJSON_STRING_(ExclusiveMinimum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'i', 'n', 'i', 'm', 'u', 'm') - CEREAL_RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm') - CEREAL_RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f') + 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') + RAPIDJSON_STRING_(Ref, '$', 'r', 'e', 'f') + RAPIDJSON_STRING_(Id, 'i', 'd') -#undef CEREAL_RAPIDJSON_STRING_ + RAPIDJSON_STRING_(SchemeEnd, ':') + RAPIDJSON_STRING_(AuthStart, '/', '/') + RAPIDJSON_STRING_(QueryStart, '?') + RAPIDJSON_STRING_(FragStart, '#') + RAPIDJSON_STRING_(Slash, '/') + RAPIDJSON_STRING_(Dot, '.') + +#undef RAPIDJSON_STRING_ private: enum SchemaValueType { @@ -933,9 +1188,9 @@ private: kTotalSchemaType }; -#if CEREAL_RAPIDJSON_SCHEMA_USE_INTERNALREGEX - typedef internal::GenericRegex RegexType; -#elif CEREAL_RAPIDJSON_SCHEMA_USE_STDREGEX +#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX + typedef internal::GenericRegex RegexType; +#elif RAPIDJSON_SCHEMA_USE_STDREGEX typedef std::basic_regex RegexType; #else typedef char RegexType; @@ -949,11 +1204,6 @@ private: SizeType count; }; - static const SchemaType* GetTypeless() { - static SchemaType typeless(0, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), 0); - return &typeless; - } - template void AddUniqueElement(V1& a, const V2& v) { for (typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr) @@ -988,18 +1238,18 @@ private: 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); + schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document, id_); out.begin = validatorCount_; validatorCount_ += out.count; } } } -#if CEREAL_RAPIDJSON_SCHEMA_USE_INTERNALREGEX +#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX template RegexType* CreatePattern(const ValueType& value) { if (value.IsString()) { - RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString()); + RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), allocator_); if (!r->IsValid()) { r->~RegexType(); AllocatorType::Free(r); @@ -1011,17 +1261,21 @@ private: } static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType) { - return pattern->Search(str); + GenericRegexSearch rs(*pattern); + return rs.Search(str); } -#elif CEREAL_RAPIDJSON_SCHEMA_USE_STDREGEX +#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 (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript); + 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; } @@ -1034,7 +1288,7 @@ private: RegexType* CreatePattern(const ValueType&) { return 0; } static bool IsPatternMatch(const RegexType*, const Ch *, SizeType) { return true; } -#endif // CEREAL_RAPIDJSON_SCHEMA_USE_STDREGEX +#endif // RAPIDJSON_SCHEMA_USE_STDREGEX void AddType(const ValueType& type) { if (type == GetNullString() ) type_ |= 1 << kNullSchemaType; @@ -1051,35 +1305,37 @@ private: context.hasher = context.factory.CreateHasher(); if (validatorCount_) { - CEREAL_RAPIDJSON_ASSERT(context.validators == 0); + RAPIDJSON_ASSERT(context.validators == 0); context.validators = static_cast(context.factory.MallocState(sizeof(ISchemaValidator*) * validatorCount_)); + std::memset(context.validators, 0, sizeof(ISchemaValidator*) * validatorCount_); context.validatorCount = validatorCount_; + // Always return after first failure for these sub-validators if (allOf_.schemas) - CreateSchemaValidators(context, allOf_); + CreateSchemaValidators(context, allOf_, false); if (anyOf_.schemas) - CreateSchemaValidators(context, anyOf_); - + CreateSchemaValidators(context, anyOf_, false); + if (oneOf_.schemas) - CreateSchemaValidators(context, oneOf_); - + CreateSchemaValidators(context, oneOf_, false); + if (not_) - context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_); - + context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_, false); + if (hasSchemaDependencies_) { for (SizeType i = 0; i < propertyCount_; i++) if (properties_[i].dependenciesSchema) - context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema); + context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema, false); } } return true; } - void CreateSchemaValidators(Context& context, const SchemaArray& schemas) const { + void CreateSchemaValidators(Context& context, const SchemaArray& schemas, const bool inheritContinueOnErrors) const { for (SizeType i = 0; i < schemas.count; i++) - context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i]); + context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i], inheritContinueOnErrors); } // O(n) @@ -1087,7 +1343,7 @@ private: SizeType len = name.GetStringLength(); const Ch* str = name.GetString(); for (SizeType index = 0; index < propertyCount_; index++) - if (properties_[index].name.GetStringLength() == len && + if (properties_[index].name.GetStringLength() == len && (std::memcmp(properties_[index].name.GetString(), str, sizeof(Ch) * len) == 0)) { *outIndex = index; @@ -1097,16 +1353,21 @@ private: } bool CheckInt(Context& context, int64_t i) const { - if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) - CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) { + DisallowedType(context, GetIntegerString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); + } if (!minimum_.IsNull()) { if (minimum_.IsInt64()) { - if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64()) - CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); + if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64()) { + context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_); + RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum); + } } else if (minimum_.IsUint64()) { - CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); // i <= max(int64_t) < minimum.GetUint64() + context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_); + RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum); // i <= max(int64_t) < minimum.GetUint64() } else if (!CheckDoubleMinimum(context, static_cast(i))) return false; @@ -1114,19 +1375,23 @@ private: if (!maximum_.IsNull()) { if (maximum_.IsInt64()) { - if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) - CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); + if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) { + context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_); + RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum); + } } - else if (maximum_.IsUint64()) - /* do nothing */; // i <= max(int64_t) < maximum_.GetUint64() + 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) - CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); + if (static_cast(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0) { + context.error_handler.NotMultipleOf(i, multipleOf_); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMultipleOf); + } } else if (!CheckDoubleMultipleOf(context, static_cast(i))) return false; @@ -1136,13 +1401,17 @@ private: } bool CheckUint(Context& context, uint64_t i) const { - if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) - CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) { + DisallowedType(context, GetIntegerString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); + } if (!minimum_.IsNull()) { if (minimum_.IsUint64()) { - if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64()) - CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); + if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64()) { + context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_); + RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum); + } } else if (minimum_.IsInt64()) /* do nothing */; // i >= 0 > minimum.Getint64() @@ -1152,19 +1421,25 @@ private: if (!maximum_.IsNull()) { if (maximum_.IsUint64()) { - if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64()) - CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); + if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64()) { + context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_); + RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum); + } + } + else if (maximum_.IsInt64()) { + context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_); + RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum); // i >= 0 > maximum_ } - else if (maximum_.IsInt64()) - CEREAL_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) - CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); + if (i % multipleOf_.GetUint64() != 0) { + context.error_handler.NotMultipleOf(i, multipleOf_); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMultipleOf); + } } else if (!CheckDoubleMultipleOf(context, static_cast(i))) return false; @@ -1174,14 +1449,18 @@ private: } bool CheckDoubleMinimum(Context& context, double d) const { - if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble()) - CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); + if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble()) { + context.error_handler.BelowMinimum(d, minimum_, exclusiveMinimum_); + RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum); + } return true; } bool CheckDoubleMaximum(Context& context, double d) const { - if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble()) - CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); + if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble()) { + context.error_handler.AboveMaximum(d, maximum_, exclusiveMaximum_); + RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum); + } return true; } @@ -1189,11 +1468,29 @@ private: 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) - CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); + if (r > 0.0) { + context.error_handler.NotMultipleOf(d, multipleOf_); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMultipleOf); + } 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); } @@ -1207,7 +1504,7 @@ private: struct PatternProperty { PatternProperty() : schema(), pattern() {} - ~PatternProperty() { + ~PatternProperty() { if (pattern) { pattern->~RegexType(); AllocatorType::Free(pattern); @@ -1218,6 +1515,10 @@ private: }; AllocatorType* allocator_; + SValue uri_; + UriType id_; + PointerType pointer_; + const SchemaType* typeless_; uint64_t* enum_; SizeType enumCount_; SchemaArray allOf_; @@ -1258,23 +1559,25 @@ private: SValue multipleOf_; bool exclusiveMinimum_; bool exclusiveMaximum_; + + SizeType defaultValueLength_; }; template struct TokenHelper { - CEREAL_RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) { + 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() = buffer[i]; + *documentStack.template Push() = static_cast(buffer[i]); } }; // Partial specialized version for char to prevent buffer copying. template struct TokenHelper { - CEREAL_RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) { + RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) { if (sizeof(SizeType) == 4) { char *buffer = documentStack.template Push(1 + 10); // '/' + uint *buffer++ = '/'; @@ -1299,9 +1602,12 @@ template class IGenericRemoteSchemaDocumentProvider { public: typedef typename SchemaDocumentType::Ch Ch; + typedef typename SchemaDocumentType::ValueType ValueType; + typedef typename SchemaDocumentType::AllocatorType AllocatorType; virtual ~IGenericRemoteSchemaDocumentProvider() {} virtual const SchemaDocumentType* GetRemoteDocument(const Ch* uri, SizeType length) = 0; + virtual const SchemaDocumentType* GetRemoteDocument(GenericUri uri) { return GetRemoteDocument(uri.GetBaseString(), uri.GetBaseStringLength()); } }; /////////////////////////////////////////////////////////////////////////////// @@ -1326,6 +1632,8 @@ public: typedef typename EncodingType::Ch Ch; typedef internal::Schema SchemaType; typedef GenericPointer PointerType; + typedef GenericValue SValue; + typedef GenericUri UriType; friend class internal::Schema; template friend class GenericSchemaValidator; @@ -1335,57 +1643,66 @@ public: 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. + \param pointer An optional JSON pointer to the start of the schema document */ - explicit GenericSchemaDocument(const ValueType& document, IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) : + explicit GenericSchemaDocument(const ValueType& document, const Ch* uri = 0, SizeType uriLength = 0, + IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0, + const PointerType& pointer = PointerType()) : // PR #1393 remoteProvider_(remoteProvider), allocator_(allocator), ownAllocator_(), root_(), + typeless_(), schemaMap_(allocator, kInitialSchemaMapSize), schemaRef_(allocator, kInitialSchemaRefSize) { if (!allocator_) - ownAllocator_ = allocator_ = CEREAL_RAPIDJSON_NEW(Allocator()); + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); + + Ch noUri[1] = {0}; + uri_.SetString(uri ? uri : noUri, uriLength, *allocator_); + docId_ = UriType(uri_, allocator_); + + typeless_ = static_cast(allocator_->Malloc(sizeof(SchemaType))); + new (typeless_) SchemaType(this, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), allocator_, docId_); // 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_); - } - } - refEntry->~SchemaRefEntry(); + // And call HandleRefSchema() if there are $ref. + // PR #1393 use input pointer if supplied + root_ = typeless_; + if (pointer.GetTokenCount() == 0) { + CreateSchemaRecursive(&root_, pointer, document, document, docId_); + } + else if (const ValueType* v = pointer.Get(document)) { + CreateSchema(&root_, pointer, *v, document, docId_); } - CEREAL_RAPIDJSON_ASSERT(root_ != 0); + RAPIDJSON_ASSERT(root_ != 0); schemaRef_.ShrinkToFit(); // Deallocate all memory for ref } -#if CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Move constructor in C++11 - GenericSchemaDocument(GenericSchemaDocument&& rhs) CEREAL_RAPIDJSON_NOEXCEPT : + 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_)) + schemaRef_(std::move(rhs.schemaRef_)), + uri_(std::move(rhs.uri_)), + docId_(rhs.docId_) { rhs.remoteProvider_ = 0; rhs.allocator_ = 0; rhs.ownAllocator_ = 0; + rhs.typeless_ = 0; } #endif @@ -1394,9 +1711,16 @@ public: while (!schemaMap_.Empty()) schemaMap_.template Pop(1)->~SchemaEntry(); - CEREAL_RAPIDJSON_DELETE(ownAllocator_); + if (typeless_) { + typeless_->~SchemaType(); + Allocator::Free(typeless_); + } + + RAPIDJSON_DELETE(ownAllocator_); } + const SValue& GetURI() const { return uri_; } + //! Get the root schema. const SchemaType& GetRoot() const { return *root_; } @@ -1406,12 +1730,7 @@ private: //! 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; - }; + typedef const PointerType* SchemaRefPtr; // PR #1393 struct SchemaEntry { SchemaEntry(const PointerType& p, SchemaType* s, bool o, Allocator* allocator) : pointer(p, allocator), schema(s), owned(o) {} @@ -1426,78 +1745,197 @@ private: bool owned; }; - void CreateSchemaRecursive(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) { - if (schema) - *schema = SchemaType::GetTypeless(); - + // Changed by PR #1393 + void CreateSchemaRecursive(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document, const UriType& id) { if (v.GetType() == kObjectType) { - const SchemaType* s = GetSchema(pointer); - if (!s) - CreateSchema(schema, pointer, v, document); + UriType newid = UriType(CreateSchema(schema, pointer, v, document, id), allocator_); for (typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr) - CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document); + CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document, newid); } else if (v.GetType() == kArrayType) for (SizeType i = 0; i < v.Size(); i++) - CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document); + CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document, id); } - void CreateSchema(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) { - CEREAL_RAPIDJSON_ASSERT(pointer.IsValid()); + // Changed by PR #1393 + const UriType& CreateSchema(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document, const UriType& id) { + 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 (const SchemaType* sc = GetSchema(pointer)) { + if (schema) + *schema = sc; + AddSchemaRefs(const_cast(sc)); + } + else if (!HandleRefSchema(pointer, schema, v, document, id)) { + // The new schema constructor adds itself and its $ref(s) to schemaMap_ + SchemaType* s = new (allocator_->Malloc(sizeof(SchemaType))) SchemaType(this, pointer, v, document, allocator_, id); if (schema) *schema = s; + return s->GetId(); } } + else { + if (schema) + *schema = typeless_; + AddSchemaRefs(typeless_); + } + return id; } - 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); + // Changed by PR #1393 + // TODO should this return a UriType& ? + bool HandleRefSchema(const PointerType& source, const SchemaType** schema, const ValueType& v, const ValueType& document, const UriType& id) { + typename ValueType::ConstMemberIterator itr = v.FindMember(SchemaType::GetRefString()); if (itr == v.MemberEnd()) return false; + // Resolve the source pointer to the $ref'ed schema (finally) + new (schemaRef_.template Push()) SchemaRefPtr(&source); + 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 + // First resolve $ref against the in-scope id + UriType scopeId = UriType(id, allocator_); + UriType ref = UriType(itr->value, allocator_).Resolve(scopeId, allocator_); + // See if the resolved $ref minus the fragment matches a resolved id in this document + // Search from the root. Returns the subschema in the document and its absolute JSON pointer. + PointerType basePointer = PointerType(); + const ValueType *base = FindId(document, ref, basePointer, docId_, false); + if (!base) { + // Remote reference - call the remote document provider if (remoteProvider_) { - if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i - 1)) { - PointerType pointer(&s[i], len - i, allocator_); - if (pointer.IsValid()) { - if (const SchemaType* sc = remoteDocument->GetSchema(pointer)) { - if (schema) - *schema = sc; + if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(ref)) { + const Ch* s = ref.GetFragString(); + len = ref.GetFragStringLength(); + if (len <= 1 || s[1] == '/') { + // JSON pointer fragment, absolute in the remote schema + const PointerType pointer(s, len, allocator_); + if (pointer.IsValid()) { + // Get the subschema + if (const SchemaType *sc = remoteDocument->GetSchema(pointer)) { + if (schema) + *schema = sc; + AddSchemaRefs(const_cast(sc)); + return true; + } + } + } else { + // Plain name fragment, not allowed + } + } + } + } + else { // Local reference + const Ch* s = ref.GetFragString(); + len = ref.GetFragStringLength(); + if (len <= 1 || s[1] == '/') { + // JSON pointer fragment, relative to the resolved URI + const PointerType relPointer(s, len, allocator_); + if (relPointer.IsValid()) { + // Get the subschema + if (const ValueType *pv = relPointer.Get(*base)) { + // Now get the absolute JSON pointer by adding relative to base + PointerType pointer(basePointer); + for (SizeType i = 0; i < relPointer.GetTokenCount(); i++) + pointer = pointer.Append(relPointer.GetTokens()[i], allocator_); + //GenericStringBuffer sb; + //pointer.StringifyUriFragment(sb); + if (pointer.IsValid() && !IsCyclicRef(pointer)) { + // Call CreateSchema recursively, but first compute the in-scope id for the $ref target as we have jumped there + // TODO: cache pointer <-> id mapping + size_t unresolvedTokenIndex; + scopeId = pointer.GetUri(document, docId_, &unresolvedTokenIndex, allocator_); + CreateSchema(schema, pointer, *pv, document, scopeId); 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)) + } else { + // Plain name fragment, relative to the resolved URI + // See if the fragment matches an id in this document. + // Search from the base we just established. Returns the subschema in the document and its absolute JSON pointer. + PointerType pointer = PointerType(); + if (const ValueType *pv = FindId(*base, ref, pointer, UriType(ref.GetBaseString(), ref.GetBaseStringLength(), allocator_), true, basePointer)) { + if (!IsCyclicRef(pointer)) { + //GenericStringBuffer sb; + //pointer.StringifyUriFragment(sb); + // Call CreateSchema recursively, but first compute the in-scope id for the $ref target as we have jumped there + // TODO: cache pointer <-> id mapping + size_t unresolvedTokenIndex; + scopeId = pointer.GetUri(document, docId_, &unresolvedTokenIndex, allocator_); + CreateSchema(schema, pointer, *pv, document, scopeId); return true; - - new (schemaRef_.template Push()) SchemaRefEntry(source, pointer, schema, allocator_); - return true; + } + } } } } } + + // Invalid/Unknown $ref + if (schema) + *schema = typeless_; + AddSchemaRefs(typeless_); + return true; + } + + //! Find the first subschema with a resolved 'id' that matches the specified URI. + // If full specified use all URI else ignore fragment. + // If found, return a pointer to the subschema and its JSON pointer. + // TODO cache pointer <-> id mapping + ValueType* FindId(const ValueType& doc, const UriType& finduri, PointerType& resptr, const UriType& baseuri, bool full, const PointerType& here = PointerType()) const { + SizeType i = 0; + ValueType* resval = 0; + UriType tempuri = UriType(finduri, allocator_); + UriType localuri = UriType(baseuri, allocator_); + if (doc.GetType() == kObjectType) { + // Establish the base URI of this object + typename ValueType::ConstMemberIterator m = doc.FindMember(SchemaType::GetIdString()); + if (m != doc.MemberEnd() && m->value.GetType() == kStringType) { + localuri = UriType(m->value, allocator_).Resolve(baseuri, allocator_); + } + // See if it matches + if (localuri.Match(finduri, full)) { + resval = const_cast(&doc); + resptr = here; + return resval; + } + // No match, continue looking + for (m = doc.MemberBegin(); m != doc.MemberEnd(); ++m) { + if (m->value.GetType() == kObjectType || m->value.GetType() == kArrayType) { + resval = FindId(m->value, finduri, resptr, localuri, full, here.Append(m->name.GetString(), m->name.GetStringLength(), allocator_)); + } + if (resval) break; + } + } else if (doc.GetType() == kArrayType) { + // Continue looking + for (typename ValueType::ConstValueIterator v = doc.Begin(); v != doc.End(); ++v) { + if (v->GetType() == kObjectType || v->GetType() == kArrayType) { + resval = FindId(*v, finduri, resptr, localuri, full, here.Append(i, allocator_)); + } + if (resval) break; + i++; + } + } + return resval; + } + + // Added by PR #1393 + void AddSchemaRefs(SchemaType* schema) { + while (!schemaRef_.Empty()) { + SchemaRefPtr *ref = schemaRef_.template Pop(1); + SchemaEntry *entry = schemaMap_.template Push(); + new (entry) SchemaEntry(**ref, schema, false, allocator_); + } + } + + // Added by PR #1393 + bool IsCyclicRef(const PointerType& pointer) const { + for (const SchemaRefPtr* ref = schemaRef_.template Bottom(); ref != schemaRef_.template End(); ++ref) + if (pointer == **ref) + return true; return false; } @@ -1515,6 +1953,8 @@ private: return PointerType(); } + const SchemaType* GetTypeless() const { return typeless_; } + static const size_t kInitialSchemaMapSize = 64; static const size_t kInitialSchemaRefSize = 64; @@ -1522,8 +1962,11 @@ private: 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 + internal::Stack schemaRef_; // Stores Pointer(s) from $ref(s) until resolved + SValue uri_; // Schema document URI + UriType docId_; }; //! GenericSchemaDocument using Value type. @@ -1552,13 +1995,16 @@ template < typename StateAllocator = CrtAllocator> class GenericSchemaValidator : public internal::ISchemaStateFactory, - public internal::ISchemaValidator -{ + 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. /*! @@ -1575,13 +2021,17 @@ public: : schemaDocument_(&schemaDocument), root_(schemaDocument.GetRoot()), - outputHandler_(GetNullHandler()), stateAllocator_(allocator), ownStateAllocator_(0), schemaStack_(allocator, schemaStackCapacity), documentStack_(allocator, documentStackCapacity), - valid_(true) -#if CEREAL_RAPIDJSON_SCHEMA_VERBOSE + outputHandler_(0), + error_(kObjectType), + currentError_(), + missingDependents_(), + valid_(true), + flags_(kValidateDefaultFlags) +#if RAPIDJSON_SCHEMA_VERBOSE , depth_(0) #endif { @@ -1603,13 +2053,17 @@ public: : schemaDocument_(&schemaDocument), root_(schemaDocument.GetRoot()), - outputHandler_(outputHandler), stateAllocator_(allocator), ownStateAllocator_(0), schemaStack_(allocator, schemaStackCapacity), documentStack_(allocator, documentStackCapacity), - valid_(true) -#if CEREAL_RAPIDJSON_SCHEMA_VERBOSE + outputHandler_(&outputHandler), + error_(kObjectType), + currentError_(), + missingDependents_(), + valid_(true), + flags_(kValidateDefaultFlags) +#if RAPIDJSON_SCHEMA_VERBOSE , depth_(0) #endif { @@ -1618,7 +2072,7 @@ public: //! Destructor. ~GenericSchemaValidator() { Reset(); - CEREAL_RAPIDJSON_DELETE(ownStateAllocator_); + RAPIDJSON_DELETE(ownStateAllocator_); } //! Reset the internal states. @@ -1626,47 +2080,287 @@ public: while (!schemaStack_.Empty()) PopSchema(); documentStack_.Clear(); + ResetError(); + } + + //! Reset the error state. + void ResetError() { + error_.SetObject(); + currentError_.SetNull(); + missingDependents_.SetNull(); valid_ = true; } + //! Implementation of ISchemaValidator + void SetValidateFlags(unsigned flags) { + flags_ = flags; + } + virtual unsigned GetValidateFlags() const { + return flags_; + } + //! Checks whether the current state is valid. // Implementation of ISchemaValidator - virtual bool IsValid() const { return valid_; } + virtual bool IsValid() const { + if (!valid_) return false; + if (GetContinueOnErrors() && !error_.ObjectEmpty()) return false; + return true; + } + + //! Gets the error object. + ValueType& GetError() { return error_; } + const ValueType& GetError() const { return error_; } //! Gets the JSON pointer pointed to the invalid schema. + // If reporting all errors, the stack will be empty. PointerType GetInvalidSchemaPointer() const { - return schemaStack_.Empty() ? PointerType() : schemaDocument_->GetPointer(&CurrentSchema()); + return schemaStack_.Empty() ? PointerType() : CurrentSchema().GetPointer(); } //! Gets the keyword of invalid schema. + // If reporting all errors, the stack will be empty, so return "errors". const Ch* GetInvalidSchemaKeyword() const { - return schemaStack_.Empty() ? 0 : CurrentContext().invalidKeyword; + if (!schemaStack_.Empty()) return CurrentContext().invalidKeyword; + if (GetContinueOnErrors() && !error_.ObjectEmpty()) return (const Ch*)GetErrorsString(); + return 0; + } + + //! Gets the error code of invalid schema. + // If reporting all errors, the stack will be empty, so return kValidateErrors. + ValidateErrorCode GetInvalidSchemaCode() const { + if (!schemaStack_.Empty()) return CurrentContext().invalidCode; + if (GetContinueOnErrors() && !error_.ObjectEmpty()) return kValidateErrors; + return kValidateErrorNone; } //! Gets the JSON pointer pointed to the invalid value. + // If reporting all errors, the stack will be empty. PointerType GetInvalidDocumentPointer() const { - return documentStack_.Empty() ? PointerType() : PointerType(documentStack_.template Bottom(), documentStack_.GetSize() / sizeof(Ch)); + if (documentStack_.Empty()) { + return PointerType(); + } + else { + return PointerType(documentStack_.template Bottom(), documentStack_.GetSize() / sizeof(Ch)); + } } -#if CEREAL_RAPIDJSON_SCHEMA_VERBOSE -#define CEREAL_RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() \ -CEREAL_RAPIDJSON_MULTILINEMACRO_BEGIN\ + void NotMultipleOf(int64_t actual, const SValue& expected) { + AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected); + } + void NotMultipleOf(uint64_t actual, const SValue& expected) { + AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected); + } + void NotMultipleOf(double actual, const SValue& expected) { + AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected); + } + void AboveMaximum(int64_t actual, const SValue& expected, bool exclusive) { + AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum, ValueType(actual).Move(), expected, + exclusive ? &SchemaType::GetExclusiveMaximumString : 0); + } + void AboveMaximum(uint64_t actual, const SValue& expected, bool exclusive) { + AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum, ValueType(actual).Move(), expected, + exclusive ? &SchemaType::GetExclusiveMaximumString : 0); + } + void AboveMaximum(double actual, const SValue& expected, bool exclusive) { + AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum, ValueType(actual).Move(), expected, + exclusive ? &SchemaType::GetExclusiveMaximumString : 0); + } + void BelowMinimum(int64_t actual, const SValue& expected, bool exclusive) { + AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum, ValueType(actual).Move(), expected, + exclusive ? &SchemaType::GetExclusiveMinimumString : 0); + } + void BelowMinimum(uint64_t actual, const SValue& expected, bool exclusive) { + AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum, ValueType(actual).Move(), expected, + exclusive ? &SchemaType::GetExclusiveMinimumString : 0); + } + void BelowMinimum(double actual, const SValue& expected, bool exclusive) { + AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum, ValueType(actual).Move(), expected, + exclusive ? &SchemaType::GetExclusiveMinimumString : 0); + } + + void TooLong(const Ch* str, SizeType length, SizeType expected) { + AddNumberError(kValidateErrorMaxLength, + ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move()); + } + void TooShort(const Ch* str, SizeType length, SizeType expected) { + AddNumberError(kValidateErrorMinLength, + 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(kValidateErrorPattern); + } + + void DisallowedItem(SizeType index) { + currentError_.SetObject(); + currentError_.AddMember(GetDisallowedString(), ValueType(index).Move(), GetStateAllocator()); + AddCurrentError(kValidateErrorAdditionalItems, true); + } + void TooFewItems(SizeType actualCount, SizeType expectedCount) { + AddNumberError(kValidateErrorMinItems, + ValueType(actualCount).Move(), SValue(expectedCount).Move()); + } + void TooManyItems(SizeType actualCount, SizeType expectedCount) { + AddNumberError(kValidateErrorMaxItems, + 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(kValidateErrorUniqueItems, true); + } + + void TooManyProperties(SizeType actualCount, SizeType expectedCount) { + AddNumberError(kValidateErrorMaxProperties, + ValueType(actualCount).Move(), SValue(expectedCount).Move()); + } + void TooFewProperties(SizeType actualCount, SizeType expectedCount) { + AddNumberError(kValidateErrorMinProperties, + 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(kValidateErrorRequired); + 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(kValidateErrorAdditionalProperties, 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()) { + // Create equivalent 'required' error + ValueType error(kObjectType); + ValidateErrorCode code = kValidateErrorRequired; + error.AddMember(GetMissingString(), missingDependents_.Move(), GetStateAllocator()); + AddErrorCode(error, code); + AddErrorInstanceLocation(error, false); + // When appending to a pointer ensure its allocator is used + PointerType schemaRef = GetInvalidSchemaPointer().Append(SchemaType::GetValidateErrorKeyword(kValidateErrorDependencies), &GetInvalidSchemaPointer().GetAllocator()); + AddErrorSchemaLocation(error, schemaRef.Append(sourceName.GetString(), sourceName.GetStringLength(), &GetInvalidSchemaPointer().GetAllocator())); + ValueType wrapper(kObjectType); + wrapper.AddMember(ValueType(SchemaType::GetValidateErrorKeyword(code), GetStateAllocator()).Move(), error, GetStateAllocator()); + currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(), wrapper, 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(kValidateErrorDependencies); + return true; + } + + void DisallowedValue(const ValidateErrorCode code = kValidateErrorEnum) { + currentError_.SetObject(); + AddCurrentError(code); + } + 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(kValidateErrorType); + } + void NotAllOf(ISchemaValidator** subvalidators, SizeType count) { + // Treat allOf like oneOf and anyOf to match https://rapidjson.org/md_doc_schema.html#allOf-anyOf-oneOf + AddErrorArray(kValidateErrorAllOf, subvalidators, count); + //for (SizeType i = 0; i < count; ++i) { + // MergeError(static_cast(subvalidators[i])->GetError()); + //} + } + void NoneOf(ISchemaValidator** subvalidators, SizeType count) { + AddErrorArray(kValidateErrorAnyOf, subvalidators, count); + } + void NotOneOf(ISchemaValidator** subvalidators, SizeType count, bool matched = false) { + AddErrorArray(matched ? kValidateErrorOneOfMatch : kValidateErrorOneOf, subvalidators, count); + } + void Disallowed() { + currentError_.SetObject(); + AddCurrentError(kValidateErrorNot); + } + +#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_(ErrorCode, 'e', 'r', 'r', 'o', 'r', 'C', 'o', 'd', 'e') + RAPIDJSON_STRING_(ErrorMessage, 'e', 'r', 'r', 'o', 'r', 'M', 'e', 's', 's', 'a', 'g', 'e') + 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());\ -CEREAL_RAPIDJSON_MULTILINEMACRO_END +RAPIDJSON_MULTILINEMACRO_END #else -#define CEREAL_RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() +#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() #endif -#define CEREAL_RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\ +#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\ if (!valid_) return false; \ - if (!BeginValue() || !CurrentSchema().method arg1) {\ - CEREAL_RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_();\ - return valid_ = false;\ + if ((!BeginValue() && !GetContinueOnErrors()) || (!CurrentSchema().method arg1 && !GetContinueOnErrors())) {\ + RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_();\ + valid_ = false;\ + return valid_;\ } -#define CEREAL_RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\ +#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;\ @@ -1678,72 +2372,87 @@ CEREAL_RAPIDJSON_MULTILINEMACRO_END static_cast(context->patternPropertiesValidators[i_])->method arg2;\ } -#define CEREAL_RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\ - return valid_ = EndValue() && outputHandler_.method arg2 +#define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\ + valid_ = (EndValue() || GetContinueOnErrors()) && (!outputHandler_ || outputHandler_->method arg2);\ + return valid_; -#define CEREAL_RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \ - CEREAL_RAPIDJSON_SCHEMA_HANDLE_BEGIN_ (method, arg1);\ - CEREAL_RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\ - CEREAL_RAPIDJSON_SCHEMA_HANDLE_END_ (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() { CEREAL_RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext() ), ( )); } - bool Bool(bool b) { CEREAL_RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool, (CurrentContext(), b), (b)); } - bool Int(int i) { CEREAL_RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int, (CurrentContext(), i), (i)); } - bool Uint(unsigned u) { CEREAL_RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint, (CurrentContext(), u), (u)); } - bool Int64(int64_t i) { CEREAL_RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), i), (i)); } - bool Uint64(uint64_t u) { CEREAL_RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); } - bool Double(double d) { CEREAL_RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); } + 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) - { CEREAL_RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); } + { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); } bool String(const Ch* str, SizeType length, bool copy) - { CEREAL_RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); } + { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); } bool StartObject() { - CEREAL_RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext())); - CEREAL_RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ()); - return valid_ = outputHandler_.StartObject(); + RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext())); + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ()); + valid_ = !outputHandler_ || outputHandler_->StartObject(); + return valid_; } 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; - CEREAL_RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy)); - return valid_ = outputHandler_.Key(str, len, copy); + if (!CurrentSchema().Key(CurrentContext(), str, len, copy) && !GetContinueOnErrors()) { + valid_ = false; + return valid_; + } + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy)); + valid_ = !outputHandler_ || outputHandler_->Key(str, len, copy); + return valid_; } - bool EndObject(SizeType memberCount) { + bool EndObject(SizeType memberCount) { if (!valid_) return false; - CEREAL_RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount)); - if (!CurrentSchema().EndObject(CurrentContext(), memberCount)) return valid_ = false; - CEREAL_RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount)); + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount)); + if (!CurrentSchema().EndObject(CurrentContext(), memberCount) && !GetContinueOnErrors()) { + valid_ = false; + return valid_; + } + RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount)); } bool StartArray() { - CEREAL_RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext())); - CEREAL_RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ()); - return valid_ = outputHandler_.StartArray(); + RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext())); + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ()); + valid_ = !outputHandler_ || outputHandler_->StartArray(); + return valid_; } bool EndArray(SizeType elementCount) { if (!valid_) return false; - CEREAL_RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount)); - if (!CurrentSchema().EndArray(CurrentContext(), elementCount)) return valid_ = false; - CEREAL_RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount)); + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount)); + if (!CurrentSchema().EndArray(CurrentContext(), elementCount) && !GetContinueOnErrors()) { + valid_ = false; + return valid_; + } + RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount)); } -#undef CEREAL_RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_ -#undef CEREAL_RAPIDJSON_SCHEMA_HANDLE_BEGIN_ -#undef CEREAL_RAPIDJSON_SCHEMA_HANDLE_PARALLEL_ -#undef CEREAL_RAPIDJSON_SCHEMA_HANDLE_VALUE_ +#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, -#if CEREAL_RAPIDJSON_SCHEMA_VERBOSE + virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root, const bool inheritContinueOnErrors) { + ISchemaValidator* sv = new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root, documentStack_.template Bottom(), documentStack_.GetSize(), +#if RAPIDJSON_SCHEMA_VERBOSE depth_ + 1, #endif &GetStateAllocator()); + sv->SetValidateFlags(inheritContinueOnErrors ? GetValidateFlags() : GetValidateFlags() & ~(unsigned)kValidateContinueOnErrorFlag); + return sv; } virtual void DestroySchemaValidator(ISchemaValidator* validator) { @@ -1771,7 +2480,7 @@ CEREAL_RAPIDJSON_MULTILINEMACRO_END } virtual void FreeState(void* p) { - return StateAllocator::Free(p); + StateAllocator::Free(p); } private: @@ -1782,7 +2491,8 @@ private: GenericSchemaValidator( const SchemaDocumentType& schemaDocument, const SchemaType& root, -#if CEREAL_RAPIDJSON_SCHEMA_VERBOSE + const char* basePath, size_t basePathSize, +#if RAPIDJSON_SCHEMA_VERBOSE unsigned depth, #endif StateAllocator* allocator = 0, @@ -1791,24 +2501,34 @@ private: : schemaDocument_(&schemaDocument), root_(root), - outputHandler_(GetNullHandler()), stateAllocator_(allocator), ownStateAllocator_(0), schemaStack_(allocator, schemaStackCapacity), documentStack_(allocator, documentStackCapacity), - valid_(true) -#if CEREAL_RAPIDJSON_SCHEMA_VERBOSE + outputHandler_(0), + error_(kObjectType), + currentError_(), + missingDependents_(), + valid_(true), + flags_(kValidateDefaultFlags) +#if RAPIDJSON_SCHEMA_VERBOSE , depth_(depth) #endif { + if (basePath && basePathSize) + memcpy(documentStack_.template Push(basePathSize), basePath, basePathSize); } StateAllocator& GetStateAllocator() { if (!stateAllocator_) - stateAllocator_ = ownStateAllocator_ = CEREAL_RAPIDJSON_NEW(StateAllocator()); + stateAllocator_ = ownStateAllocator_ = RAPIDJSON_NEW(StateAllocator)(); return *stateAllocator_; } + bool GetContinueOnErrors() const { + return flags_ & kValidateContinueOnErrorFlag; + } + bool BeginValue() { if (schemaStack_.Empty()) PushSchema(root_); @@ -1816,23 +2536,24 @@ private: if (CurrentContext().inArray) internal::TokenHelper, Ch>::AppendIndexToken(documentStack_, CurrentContext().arrayElementIndex); - if (!CurrentSchema().BeginValue(CurrentContext())) + if (!CurrentSchema().BeginValue(CurrentContext()) && !GetContinueOnErrors()) return false; SizeType count = CurrentContext().patternPropertiesSchemaCount; const SchemaType** sa = CurrentContext().patternPropertiesSchemas; typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType; bool valueUniqueness = CurrentContext().valueUniqueness; - if (CurrentContext().valueSchema) - PushSchema(*CurrentContext().valueSchema); + 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)); + std::memset(va, 0, sizeof(ISchemaValidator*) * count); for (SizeType i = 0; i < count; i++) - va[validatorCount++] = CreateSchemaValidator(*sa[i]); + va[validatorCount++] = CreateSchemaValidator(*sa[i], true); // Inherit continueOnError } CurrentContext().arrayUniqueness = valueUniqueness; @@ -1841,10 +2562,10 @@ private: } bool EndValue() { - if (!CurrentSchema().EndValue(CurrentContext())) + if (!CurrentSchema().EndValue(CurrentContext()) && !GetContinueOnErrors()) return false; -#if CEREAL_RAPIDJSON_SCHEMA_VERBOSE +#if RAPIDJSON_SCHEMA_VERBOSE GenericStringBuffer sb; schemaDocument_->GetPointer(&CurrentSchema()).Stringify(sb); @@ -1852,20 +2573,28 @@ private: documentStack_.template Pop(1); internal::PrintValidatorPointers(depth_, sb.GetString(), documentStack_.template Bottom()); #endif - - uint64_t h = CurrentContext().arrayUniqueness ? static_cast(CurrentContext().hasher)->GetHashCode() : 0; + void* hasher = CurrentContext().hasher; + uint64_t h = hasher && CurrentContext().arrayUniqueness ? static_cast(hasher)->GetHashCode() : 0; PopSchema(); if (!schemaStack_.Empty()) { Context& context = CurrentContext(); - if (context.valueUniqueness) { + // Only check uniqueness if there is a hasher + if (hasher && 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) - CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(SchemaType::GetUniqueItemsString()); + if (itr->GetUint64() == h) { + DuplicateItems(static_cast(itr - a->Begin()), a->Size()); + // Cleanup before returning if continuing + if (GetContinueOnErrors()) { + a->PushBack(h, GetStateAllocator()); + while (!documentStack_.Empty() && *documentStack_.template Pop(1) != '/'); + } + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorUniqueItems); + } a->PushBack(h, GetStateAllocator()); } } @@ -1894,9 +2623,9 @@ private: } } - CEREAL_RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push()) Context(*this, &schema); } + RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push()) Context(*this, *this, &schema); } - CEREAL_RAPIDJSON_FORCEINLINE void PopSchema() { + RAPIDJSON_FORCEINLINE void PopSchema() { Context* c = schemaStack_.template Pop(1); if (HashCodeArray* a = static_cast(c->arrayElementHashCodes)) { a->~HashCodeArray(); @@ -1905,26 +2634,98 @@ private: c->~Context(); } + void AddErrorInstanceLocation(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()); + } + + void AddErrorSchemaLocation(ValueType& result, PointerType schema = PointerType()) { + GenericStringBuffer sb; + SizeType len = CurrentSchema().GetURI().GetStringLength(); + if (len) memcpy(sb.Push(len), CurrentSchema().GetURI().GetString(), len * sizeof(Ch)); + if (schema.GetTokenCount()) schema.StringifyUriFragment(sb); + else GetInvalidSchemaPointer().StringifyUriFragment(sb); + ValueType schemaRef(sb.GetString(), static_cast(sb.GetSize() / sizeof(Ch)), + GetStateAllocator()); + result.AddMember(GetSchemaRefString(), schemaRef, GetStateAllocator()); + } + + void AddErrorCode(ValueType& result, const ValidateErrorCode code) { + result.AddMember(GetErrorCodeString(), code, 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 ValidateErrorCode code, bool parent = false) { + AddErrorCode(currentError_, code); + AddErrorInstanceLocation(currentError_, parent); + AddErrorSchemaLocation(currentError_); + AddError(ValueType(SchemaType::GetValidateErrorKeyword(code), 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 ValidateErrorCode code, 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(code); + } + + void AddErrorArray(const ValidateErrorCode code, + 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(code); + } + const SchemaType& CurrentSchema() const { return *schemaStack_.template Top()->schema; } Context& CurrentContext() { return *schemaStack_.template Top(); } const Context& CurrentContext() const { return *schemaStack_.template Top(); } - static OutputHandler& GetNullHandler() { - static OutputHandler nullHandler; - return nullHandler; - } - static const size_t kDefaultSchemaStackCapacity = 1024; static const size_t kDefaultDocumentStackCapacity = 256; const SchemaDocumentType* schemaDocument_; const SchemaType& root_; - OutputHandler& outputHandler_; 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 CEREAL_RAPIDJSON_SCHEMA_VERBOSE + unsigned flags_; +#if RAPIDJSON_SCHEMA_VERBOSE unsigned depth_; #endif }; @@ -1954,13 +2755,14 @@ 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_(), isValid_(true) {} + SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), invalidSchemaCode_(kValidateErrorNone), error_(kObjectType), isValid_(true) {} template bool operator()(Handler& handler) { @@ -1973,11 +2775,14 @@ public: invalidSchemaPointer_ = PointerType(); invalidSchemaKeyword_ = 0; invalidDocumentPointer_ = PointerType(); + error_.SetObject(); } else { invalidSchemaPointer_ = validator.GetInvalidSchemaPointer(); invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword(); + invalidSchemaCode_ = validator.GetInvalidSchemaCode(); invalidDocumentPointer_ = validator.GetInvalidDocumentPointer(); + error_.CopyFrom(validator.GetError(), allocator_); } return parseResult_; @@ -1988,6 +2793,8 @@ public: const PointerType& GetInvalidSchemaPointer() const { return invalidSchemaPointer_; } const Ch* GetInvalidSchemaKeyword() const { return invalidSchemaKeyword_; } const PointerType& GetInvalidDocumentPointer() const { return invalidDocumentPointer_; } + const ValueType& GetError() const { return error_; } + ValidateErrorCode GetInvalidSchemaCode() const { return invalidSchemaCode_; } private: InputStream& is_; @@ -1997,10 +2804,13 @@ private: PointerType invalidSchemaPointer_; const Ch* invalidSchemaKeyword_; PointerType invalidDocumentPointer_; + ValidateErrorCode invalidSchemaCode_; + StackAllocator allocator_; + ValueType error_; bool isValid_; }; -CEREAL_RAPIDJSON_NAMESPACE_END -CEREAL_RAPIDJSON_DIAG_POP +RAPIDJSON_NAMESPACE_END +RAPIDJSON_DIAG_POP -#endif // CEREAL_RAPIDJSON_SCHEMA_H_ +#endif // RAPIDJSON_SCHEMA_H_ diff --git a/external/cereal/external/rapidjson/stream.h b/external/cereal/external/rapidjson/stream.h index c05c2d4..1fd7091 100644 --- a/external/cereal/external/rapidjson/stream.h +++ b/external/cereal/external/rapidjson/stream.h @@ -1,25 +1,25 @@ // 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. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // 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 +// 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 CEREAL_RAPIDJSON_STREAM_H_ -#define CEREAL_RAPIDJSON_STREAM_H_ +#ifndef RAPIDJSON_STREAM_H_ +#define RAPIDJSON_STREAM_H_ #include "encodings.h" -CEREAL_RAPIDJSON_NAMESPACE_BEGIN +RAPIDJSON_NAMESPACE_BEGIN /////////////////////////////////////////////////////////////////////////////// // Stream @@ -100,6 +100,50 @@ inline void PutN(Stream& stream, Ch c, size_t n) { 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 @@ -116,10 +160,10 @@ struct GenericStringStream { Ch Take() { return *src_++; } size_t Tell() const { return static_cast(src_ - head_); } - Ch* PutBegin() { CEREAL_RAPIDJSON_ASSERT(false); return 0; } - void Put(Ch) { CEREAL_RAPIDJSON_ASSERT(false); } - void Flush() { CEREAL_RAPIDJSON_ASSERT(false); } - size_t PutEnd(Ch*) { CEREAL_RAPIDJSON_ASSERT(false); return 0; } + 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. @@ -152,7 +196,7 @@ struct GenericInsituStringStream { size_t Tell() { return static_cast(src_ - head_); } // Write - void Put(Ch c) { CEREAL_RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; } + 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); } @@ -174,6 +218,6 @@ struct StreamTraits > { //! Insitu string stream with UTF8 encoding. typedef GenericInsituStringStream > InsituStringStream; -CEREAL_RAPIDJSON_NAMESPACE_END +RAPIDJSON_NAMESPACE_END -#endif // CEREAL_RAPIDJSON_STREAM_H_ +#endif // RAPIDJSON_STREAM_H_ diff --git a/external/cereal/external/rapidjson/stringbuffer.h b/external/cereal/external/rapidjson/stringbuffer.h index 76eb730..82ad3ca 100644 --- a/external/cereal/external/rapidjson/stringbuffer.h +++ b/external/cereal/external/rapidjson/stringbuffer.h @@ -1,6 +1,6 @@ // 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. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // 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 @@ -12,24 +12,24 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -#ifndef CEREAL_RAPIDJSON_STRINGBUFFER_H_ -#define CEREAL_RAPIDJSON_STRINGBUFFER_H_ +#ifndef RAPIDJSON_STRINGBUFFER_H_ +#define RAPIDJSON_STRINGBUFFER_H_ #include "stream.h" #include "internal/stack.h" -#if CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS #include // std::move #endif #include "internal/stack.h" #if defined(__clang__) -CEREAL_RAPIDJSON_DIAG_PUSH -CEREAL_RAPIDJSON_DIAG_OFF(c++98-compat) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(c++98-compat) #endif -CEREAL_RAPIDJSON_NAMESPACE_BEGIN +RAPIDJSON_NAMESPACE_BEGIN //! Represents an in-memory output stream. /*! @@ -44,7 +44,7 @@ public: GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} -#if CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {} GenericStringBuffer& operator=(GenericStringBuffer&& rhs) { if (&rhs != this) @@ -78,8 +78,12 @@ public: 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_; @@ -108,10 +112,10 @@ inline void PutN(GenericStringBuffer >& stream, char c, size_t n) { std::memset(stream.stack_.Push(n), c, n * sizeof(c)); } -CEREAL_RAPIDJSON_NAMESPACE_END +RAPIDJSON_NAMESPACE_END #if defined(__clang__) -CEREAL_RAPIDJSON_DIAG_POP +RAPIDJSON_DIAG_POP #endif -#endif // CEREAL_RAPIDJSON_STRINGBUFFER_H_ +#endif // RAPIDJSON_STRINGBUFFER_H_ diff --git a/external/cereal/external/rapidjson/uri.h b/external/cereal/external/rapidjson/uri.h new file mode 100644 index 0000000..f93e508 --- /dev/null +++ b/external/cereal/external/rapidjson/uri.h @@ -0,0 +1,481 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// (C) Copyright IBM Corporation 2021 +// +// 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_URI_H_ +#define RAPIDJSON_URI_H_ + +#include "internal/strfunc.h" + +#if defined(__clang__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(c++98-compat) +#elif defined(_MSC_VER) +RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// GenericUri + +template +class GenericUri { +public: + typedef typename ValueType::Ch Ch; +#if RAPIDJSON_HAS_STDSTRING + typedef std::basic_string String; +#endif + + //! Constructors + GenericUri(Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() { + } + + GenericUri(const Ch* uri, SizeType len, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() { + Parse(uri, len); + } + + GenericUri(const Ch* uri, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() { + Parse(uri, internal::StrLen(uri)); + } + + // Use with specializations of GenericValue + template GenericUri(const T& uri, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() { + const Ch* u = uri.template Get(); // TypeHelper from document.h + Parse(u, internal::StrLen(u)); + } + +#if RAPIDJSON_HAS_STDSTRING + GenericUri(const String& uri, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() { + Parse(uri.c_str(), internal::StrLen(uri.c_str())); + } +#endif + + //! Copy constructor + GenericUri(const GenericUri& rhs) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(), ownAllocator_() { + *this = rhs; + } + + //! Copy constructor + GenericUri(const GenericUri& rhs, Allocator* allocator) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() { + *this = rhs; + } + + //! Destructor. + ~GenericUri() { + Free(); + RAPIDJSON_DELETE(ownAllocator_); + } + + //! Assignment operator + GenericUri& operator=(const GenericUri& rhs) { + if (this != &rhs) { + // Do not delete ownAllocator + Free(); + Allocate(rhs.GetStringLength()); + auth_ = CopyPart(scheme_, rhs.scheme_, rhs.GetSchemeStringLength()); + path_ = CopyPart(auth_, rhs.auth_, rhs.GetAuthStringLength()); + query_ = CopyPart(path_, rhs.path_, rhs.GetPathStringLength()); + frag_ = CopyPart(query_, rhs.query_, rhs.GetQueryStringLength()); + base_ = CopyPart(frag_, rhs.frag_, rhs.GetFragStringLength()); + uri_ = CopyPart(base_, rhs.base_, rhs.GetBaseStringLength()); + CopyPart(uri_, rhs.uri_, rhs.GetStringLength()); + } + return *this; + } + + //! Getters + // Use with specializations of GenericValue + template void Get(T& uri, Allocator& allocator) { + uri.template Set(this->GetString(), allocator); // TypeHelper from document.h + } + + const Ch* GetString() const { return uri_; } + SizeType GetStringLength() const { return uri_ == 0 ? 0 : internal::StrLen(uri_); } + const Ch* GetBaseString() const { return base_; } + SizeType GetBaseStringLength() const { return base_ == 0 ? 0 : internal::StrLen(base_); } + const Ch* GetSchemeString() const { return scheme_; } + SizeType GetSchemeStringLength() const { return scheme_ == 0 ? 0 : internal::StrLen(scheme_); } + const Ch* GetAuthString() const { return auth_; } + SizeType GetAuthStringLength() const { return auth_ == 0 ? 0 : internal::StrLen(auth_); } + const Ch* GetPathString() const { return path_; } + SizeType GetPathStringLength() const { return path_ == 0 ? 0 : internal::StrLen(path_); } + const Ch* GetQueryString() const { return query_; } + SizeType GetQueryStringLength() const { return query_ == 0 ? 0 : internal::StrLen(query_); } + const Ch* GetFragString() const { return frag_; } + SizeType GetFragStringLength() const { return frag_ == 0 ? 0 : internal::StrLen(frag_); } + +#if RAPIDJSON_HAS_STDSTRING + static String Get(const GenericUri& uri) { return String(uri.GetString(), uri.GetStringLength()); } + static String GetBase(const GenericUri& uri) { return String(uri.GetBaseString(), uri.GetBaseStringLength()); } + static String GetScheme(const GenericUri& uri) { return String(uri.GetSchemeString(), uri.GetSchemeStringLength()); } + static String GetAuth(const GenericUri& uri) { return String(uri.GetAuthString(), uri.GetAuthStringLength()); } + static String GetPath(const GenericUri& uri) { return String(uri.GetPathString(), uri.GetPathStringLength()); } + static String GetQuery(const GenericUri& uri) { return String(uri.GetQueryString(), uri.GetQueryStringLength()); } + static String GetFrag(const GenericUri& uri) { return String(uri.GetFragString(), uri.GetFragStringLength()); } +#endif + + //! Equality operators + bool operator==(const GenericUri& rhs) const { + return Match(rhs, true); + } + + bool operator!=(const GenericUri& rhs) const { + return !Match(rhs, true); + } + + bool Match(const GenericUri& uri, bool full = true) const { + Ch* s1; + Ch* s2; + if (full) { + s1 = uri_; + s2 = uri.uri_; + } else { + s1 = base_; + s2 = uri.base_; + } + if (s1 == s2) return true; + if (s1 == 0 || s2 == 0) return false; + return internal::StrCmp(s1, s2) == 0; + } + + //! Resolve this URI against another (base) URI in accordance with URI resolution rules. + // See https://tools.ietf.org/html/rfc3986 + // Use for resolving an id or $ref with an in-scope id. + // Returns a new GenericUri for the resolved URI. + GenericUri Resolve(const GenericUri& baseuri, Allocator* allocator = 0) { + GenericUri resuri; + resuri.allocator_ = allocator; + // Ensure enough space for combining paths + resuri.Allocate(GetStringLength() + baseuri.GetStringLength() + 1); // + 1 for joining slash + + if (!(GetSchemeStringLength() == 0)) { + // Use all of this URI + resuri.auth_ = CopyPart(resuri.scheme_, scheme_, GetSchemeStringLength()); + resuri.path_ = CopyPart(resuri.auth_, auth_, GetAuthStringLength()); + resuri.query_ = CopyPart(resuri.path_, path_, GetPathStringLength()); + resuri.frag_ = CopyPart(resuri.query_, query_, GetQueryStringLength()); + resuri.RemoveDotSegments(); + } else { + // Use the base scheme + resuri.auth_ = CopyPart(resuri.scheme_, baseuri.scheme_, baseuri.GetSchemeStringLength()); + if (!(GetAuthStringLength() == 0)) { + // Use this auth, path, query + resuri.path_ = CopyPart(resuri.auth_, auth_, GetAuthStringLength()); + resuri.query_ = CopyPart(resuri.path_, path_, GetPathStringLength()); + resuri.frag_ = CopyPart(resuri.query_, query_, GetQueryStringLength()); + resuri.RemoveDotSegments(); + } else { + // Use the base auth + resuri.path_ = CopyPart(resuri.auth_, baseuri.auth_, baseuri.GetAuthStringLength()); + if (GetPathStringLength() == 0) { + // Use the base path + resuri.query_ = CopyPart(resuri.path_, baseuri.path_, baseuri.GetPathStringLength()); + if (GetQueryStringLength() == 0) { + // Use the base query + resuri.frag_ = CopyPart(resuri.query_, baseuri.query_, baseuri.GetQueryStringLength()); + } else { + // Use this query + resuri.frag_ = CopyPart(resuri.query_, query_, GetQueryStringLength()); + } + } else { + if (path_[0] == '/') { + // Absolute path - use all of this path + resuri.query_ = CopyPart(resuri.path_, path_, GetPathStringLength()); + resuri.RemoveDotSegments(); + } else { + // Relative path - append this path to base path after base path's last slash + size_t pos = 0; + if (!(baseuri.GetAuthStringLength() == 0) && baseuri.GetPathStringLength() == 0) { + resuri.path_[pos] = '/'; + pos++; + } + size_t lastslashpos = baseuri.GetPathStringLength(); + while (lastslashpos > 0) { + if (baseuri.path_[lastslashpos - 1] == '/') break; + lastslashpos--; + } + std::memcpy(&resuri.path_[pos], baseuri.path_, lastslashpos * sizeof(Ch)); + pos += lastslashpos; + resuri.query_ = CopyPart(&resuri.path_[pos], path_, GetPathStringLength()); + resuri.RemoveDotSegments(); + } + // Use this query + resuri.frag_ = CopyPart(resuri.query_, query_, GetQueryStringLength()); + } + } + } + // Always use this frag + resuri.base_ = CopyPart(resuri.frag_, frag_, GetFragStringLength()); + + // Re-constitute base_ and uri_ + resuri.SetBase(); + resuri.uri_ = resuri.base_ + resuri.GetBaseStringLength() + 1; + resuri.SetUri(); + return resuri; + } + + //! Get the allocator of this GenericUri. + Allocator& GetAllocator() { return *allocator_; } + +private: + // Allocate memory for a URI + // Returns total amount allocated + std::size_t Allocate(std::size_t len) { + // Create own allocator if user did not supply. + if (!allocator_) + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); + + // Allocate one block containing each part of the URI (5) plus base plus full URI, all null terminated. + // Order: scheme, auth, path, query, frag, base, uri + // Note need to set, increment, assign in 3 stages to avoid compiler warning bug. + size_t total = (3 * len + 7) * sizeof(Ch); + scheme_ = static_cast(allocator_->Malloc(total)); + *scheme_ = '\0'; + auth_ = scheme_; + auth_++; + *auth_ = '\0'; + path_ = auth_; + path_++; + *path_ = '\0'; + query_ = path_; + query_++; + *query_ = '\0'; + frag_ = query_; + frag_++; + *frag_ = '\0'; + base_ = frag_; + base_++; + *base_ = '\0'; + uri_ = base_; + uri_++; + *uri_ = '\0'; + return total; + } + + // Free memory for a URI + void Free() { + if (scheme_) { + Allocator::Free(scheme_); + scheme_ = 0; + } + } + + // Parse a URI into constituent scheme, authority, path, query, & fragment parts + // Supports URIs that match regex ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))? as per + // https://tools.ietf.org/html/rfc3986 + void Parse(const Ch* uri, std::size_t len) { + std::size_t start = 0, pos1 = 0, pos2 = 0; + Allocate(len); + + // Look for scheme ([^:/?#]+):)? + if (start < len) { + while (pos1 < len) { + if (uri[pos1] == ':') break; + pos1++; + } + if (pos1 != len) { + while (pos2 < len) { + if (uri[pos2] == '/') break; + if (uri[pos2] == '?') break; + if (uri[pos2] == '#') break; + pos2++; + } + if (pos1 < pos2) { + pos1++; + std::memcpy(scheme_, &uri[start], pos1 * sizeof(Ch)); + scheme_[pos1] = '\0'; + start = pos1; + } + } + } + // Look for auth (//([^/?#]*))? + // Note need to set, increment, assign in 3 stages to avoid compiler warning bug. + auth_ = scheme_ + GetSchemeStringLength(); + auth_++; + *auth_ = '\0'; + if (start < len - 1 && uri[start] == '/' && uri[start + 1] == '/') { + pos2 = start + 2; + while (pos2 < len) { + if (uri[pos2] == '/') break; + if (uri[pos2] == '?') break; + if (uri[pos2] == '#') break; + pos2++; + } + std::memcpy(auth_, &uri[start], (pos2 - start) * sizeof(Ch)); + auth_[pos2 - start] = '\0'; + start = pos2; + } + // Look for path ([^?#]*) + // Note need to set, increment, assign in 3 stages to avoid compiler warning bug. + path_ = auth_ + GetAuthStringLength(); + path_++; + *path_ = '\0'; + if (start < len) { + pos2 = start; + while (pos2 < len) { + if (uri[pos2] == '?') break; + if (uri[pos2] == '#') break; + pos2++; + } + if (start != pos2) { + std::memcpy(path_, &uri[start], (pos2 - start) * sizeof(Ch)); + path_[pos2 - start] = '\0'; + if (path_[0] == '/') + RemoveDotSegments(); // absolute path - normalize + start = pos2; + } + } + // Look for query (\?([^#]*))? + // Note need to set, increment, assign in 3 stages to avoid compiler warning bug. + query_ = path_ + GetPathStringLength(); + query_++; + *query_ = '\0'; + if (start < len && uri[start] == '?') { + pos2 = start + 1; + while (pos2 < len) { + if (uri[pos2] == '#') break; + pos2++; + } + if (start != pos2) { + std::memcpy(query_, &uri[start], (pos2 - start) * sizeof(Ch)); + query_[pos2 - start] = '\0'; + start = pos2; + } + } + // Look for fragment (#(.*))? + // Note need to set, increment, assign in 3 stages to avoid compiler warning bug. + frag_ = query_ + GetQueryStringLength(); + frag_++; + *frag_ = '\0'; + if (start < len && uri[start] == '#') { + std::memcpy(frag_, &uri[start], (len - start) * sizeof(Ch)); + frag_[len - start] = '\0'; + } + + // Re-constitute base_ and uri_ + base_ = frag_ + GetFragStringLength() + 1; + SetBase(); + uri_ = base_ + GetBaseStringLength() + 1; + SetUri(); + } + + // Reconstitute base + void SetBase() { + Ch* next = base_; + std::memcpy(next, scheme_, GetSchemeStringLength() * sizeof(Ch)); + next+= GetSchemeStringLength(); + std::memcpy(next, auth_, GetAuthStringLength() * sizeof(Ch)); + next+= GetAuthStringLength(); + std::memcpy(next, path_, GetPathStringLength() * sizeof(Ch)); + next+= GetPathStringLength(); + std::memcpy(next, query_, GetQueryStringLength() * sizeof(Ch)); + next+= GetQueryStringLength(); + *next = '\0'; + } + + // Reconstitute uri + void SetUri() { + Ch* next = uri_; + std::memcpy(next, base_, GetBaseStringLength() * sizeof(Ch)); + next+= GetBaseStringLength(); + std::memcpy(next, frag_, GetFragStringLength() * sizeof(Ch)); + next+= GetFragStringLength(); + *next = '\0'; + } + + // Copy a part from one GenericUri to another + // Return the pointer to the next part to be copied to + Ch* CopyPart(Ch* to, Ch* from, std::size_t len) { + RAPIDJSON_ASSERT(to != 0); + RAPIDJSON_ASSERT(from != 0); + std::memcpy(to, from, len * sizeof(Ch)); + to[len] = '\0'; + Ch* next = to + len + 1; + return next; + } + + // Remove . and .. segments from the path_ member. + // https://tools.ietf.org/html/rfc3986 + // This is done in place as we are only removing segments. + void RemoveDotSegments() { + std::size_t pathlen = GetPathStringLength(); + std::size_t pathpos = 0; // Position in path_ + std::size_t newpos = 0; // Position in new path_ + + // Loop through each segment in original path_ + while (pathpos < pathlen) { + // Get next segment, bounded by '/' or end + size_t slashpos = 0; + while ((pathpos + slashpos) < pathlen) { + if (path_[pathpos + slashpos] == '/') break; + slashpos++; + } + // Check for .. and . segments + if (slashpos == 2 && path_[pathpos] == '.' && path_[pathpos + 1] == '.') { + // Backup a .. segment in the new path_ + // We expect to find a previously added slash at the end or nothing + RAPIDJSON_ASSERT(newpos == 0 || path_[newpos - 1] == '/'); + size_t lastslashpos = newpos; + // Make sure we don't go beyond the start segment + if (lastslashpos > 1) { + // Find the next to last slash and back up to it + lastslashpos--; + while (lastslashpos > 0) { + if (path_[lastslashpos - 1] == '/') break; + lastslashpos--; + } + // Set the new path_ position + newpos = lastslashpos; + } + } else if (slashpos == 1 && path_[pathpos] == '.') { + // Discard . segment, leaves new path_ unchanged + } else { + // Move any other kind of segment to the new path_ + RAPIDJSON_ASSERT(newpos <= pathpos); + std::memmove(&path_[newpos], &path_[pathpos], slashpos * sizeof(Ch)); + newpos += slashpos; + // Add slash if not at end + if ((pathpos + slashpos) < pathlen) { + path_[newpos] = '/'; + newpos++; + } + } + // Move to next segment + pathpos += slashpos + 1; + } + path_[newpos] = '\0'; + } + + Ch* uri_; // Everything + Ch* base_; // Everything except fragment + Ch* scheme_; // Includes the : + Ch* auth_; // Includes the // + Ch* path_; // Absolute if starts with / + Ch* query_; // Includes the ? + Ch* frag_; // Includes the # + + Allocator* allocator_; //!< The current allocator. It is either user-supplied or equal to ownAllocator_. + Allocator* ownAllocator_; //!< Allocator owned by this Uri. +}; + +//! GenericUri for Value (UTF-8, default allocator). +typedef GenericUri Uri; + +RAPIDJSON_NAMESPACE_END + +#if defined(__clang__) +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_URI_H_ diff --git a/external/cereal/external/rapidjson/writer.h b/external/cereal/external/rapidjson/writer.h index ae86cb5..8b38921 100644 --- a/external/cereal/external/rapidjson/writer.h +++ b/external/cereal/external/rapidjson/writer.h @@ -1,6 +1,6 @@ // 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. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // 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 @@ -12,10 +12,12 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -#ifndef CEREAL_RAPIDJSON_WRITER_H_ -#define CEREAL_RAPIDJSON_WRITER_H_ +#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" @@ -23,48 +25,49 @@ #include "stringbuffer.h" #include // placement new -#if defined(CEREAL_RAPIDJSON_SIMD) && defined(_MSC_VER) +#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER) #include #pragma intrinsic(_BitScanForward) #endif -#ifdef CEREAL_RAPIDJSON_SSE42 +#ifdef RAPIDJSON_SSE42 #include -#elif defined(CEREAL_RAPIDJSON_SSE2) +#elif defined(RAPIDJSON_SSE2) #include -#endif - -#ifdef _MSC_VER -CEREAL_RAPIDJSON_DIAG_PUSH -CEREAL_RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant +#elif defined(RAPIDJSON_NEON) +#include #endif #ifdef __clang__ -CEREAL_RAPIDJSON_DIAG_PUSH -CEREAL_RAPIDJSON_DIAG_OFF(padded) -CEREAL_RAPIDJSON_DIAG_OFF(unreachable-code) +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 -CEREAL_RAPIDJSON_NAMESPACE_BEGIN +RAPIDJSON_NAMESPACE_BEGIN /////////////////////////////////////////////////////////////////////////////// // WriteFlag -/*! \def CEREAL_RAPIDJSON_WRITE_DEFAULT_FLAGS - \ingroup CEREAL_RAPIDJSON_CONFIG +/*! \def RAPIDJSON_WRITE_DEFAULT_FLAGS + \ingroup RAPIDJSON_CONFIG \brief User-defined kWriteDefaultFlags definition. User can define this as any \c WriteFlag combinations. */ -#ifndef CEREAL_RAPIDJSON_WRITE_DEFAULT_FLAGS -#define CEREAL_RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNoFlags +#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 Inf, -Inf and NaN. - kWriteDefaultFlags = CEREAL_RAPIDJSON_WRITE_DEFAULT_FLAGS //!< Default write flags. Can be customized by defining CEREAL_RAPIDJSON_WRITE_DEFAULT_FLAGS + 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 @@ -103,6 +106,13 @@ public: 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, @@ -184,18 +194,20 @@ public: 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 CEREAL_RAPIDJSON_HAS_STDSTRING +#if RAPIDJSON_HAS_STDSTRING bool String(const std::basic_string& str) { return String(str.data(), SizeType(str.size())); } @@ -209,10 +221,18 @@ public: 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; - CEREAL_RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); - CEREAL_RAPIDJSON_ASSERT(!level_stack_.template Top()->inArray); + 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()); } @@ -225,8 +245,8 @@ public: bool EndArray(SizeType elementCount = 0) { (void)elementCount; - CEREAL_RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); - CEREAL_RAPIDJSON_ASSERT(level_stack_.template Top()->inArray); + RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); + RAPIDJSON_ASSERT(level_stack_.template Top()->inArray); level_stack_.template Pop(1); return EndValue(WriteEndArray()); } @@ -236,9 +256,9 @@ public: //@{ //! 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)); } - + 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. @@ -249,7 +269,21 @@ public: \param length Length of the json. \param type Type of the root of json. */ - bool RawValue(const Ch* json, size_t length, Type type) { Prefix(type); return EndValue(WriteRawValue(json, length)); } + 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(); + } + + static const size_t kDefaultLevelDepth = 32; protected: //! Information for each nested level @@ -259,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; @@ -283,7 +315,7 @@ protected: 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)); + PutUnsafe(*os_, static_cast(*p)); return true; } @@ -292,7 +324,7 @@ protected: 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)); + PutUnsafe(*os_, static_cast(*p)); return true; } @@ -301,7 +333,7 @@ protected: 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)); + PutUnsafe(*os_, static_cast(*p)); return true; } @@ -310,7 +342,7 @@ protected: char* end = internal::u64toa(u64, buffer); PutReserve(*os_, static_cast(end - buffer)); for (char* p = buffer; p != end; ++p) - PutUnsafe(*os_, static_cast(*p)); + PutUnsafe(*os_, static_cast(*p)); return true; } @@ -338,12 +370,12 @@ protected: 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)); + PutUnsafe(*os_, static_cast(*p)); return true; } bool WriteString(const Ch* str, SizeType length) { - static const typename TargetEncoding::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + 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 @@ -368,7 +400,7 @@ protected: if (!TargetEncoding::supportUnicode && static_cast(c) >= 0x80) { // Unicode escaping unsigned codepoint; - if (CEREAL_RAPIDJSON_UNLIKELY(!SourceEncoding::Decode(is, &codepoint))) + if (RAPIDJSON_UNLIKELY(!SourceEncoding::Decode(is, &codepoint))) return false; PutUnsafe(*os_, '\\'); PutUnsafe(*os_, 'u'); @@ -379,7 +411,7 @@ protected: PutUnsafe(*os_, hexDigits[(codepoint ) & 15]); } else { - CEREAL_RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF); + RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF); // Surrogate pair unsigned s = codepoint - 0x010000; unsigned lead = (s >> 10) + 0xD800; @@ -396,10 +428,10 @@ protected: PutUnsafe(*os_, hexDigits[(trail ) & 15]); } } - else if ((sizeof(Ch) == 1 || static_cast(c) < 256) && CEREAL_RAPIDJSON_UNLIKELY(escape[static_cast(c)])) { + 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)])); + PutUnsafe(*os_, static_cast(escape[static_cast(c)])); if (escape[static_cast(c)] == 'u') { PutUnsafe(*os_, '0'); PutUnsafe(*os_, '0'); @@ -407,7 +439,7 @@ protected: PutUnsafe(*os_, hexDigits[static_cast(c) & 0xF]); } } - else if (CEREAL_RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ? + else if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ? Transcoder::Validate(is, *os_) : Transcoder::TranscodeUnsafe(is, *os_)))) return false; @@ -417,7 +449,7 @@ protected: } bool ScanWriteUnescapedString(GenericStringStream& is, size_t length) { - return CEREAL_RAPIDJSON_LIKELY(is.Tell() < length); + return RAPIDJSON_LIKELY(is.Tell() < length); } bool WriteStartObject() { os_->Put('{'); return true; } @@ -427,16 +459,20 @@ protected: bool WriteRawValue(const Ch* json, size_t length) { PutReserve(*os_, length); - for (size_t i = 0; i < length; i++) { - CEREAL_RAPIDJSON_ASSERT(json[i] != '\0'); - PutUnsafe(*os_, json[i]); + 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 (CEREAL_RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is not at root + 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) @@ -445,19 +481,19 @@ protected: os_->Put((level->valueCount % 2 == 0) ? ',' : ':'); } if (!level->inArray && level->valueCount % 2 == 0) - CEREAL_RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name + RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name level->valueCount++; } else { - CEREAL_RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root. + 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 (CEREAL_RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text - os_->Flush(); + if (RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text + Flush(); return ret; } @@ -509,7 +545,7 @@ inline bool Writer::WriteUint64(uint64_t u) { template<> inline bool Writer::WriteDouble(double d) { if (internal::Double(d).IsNanOrInf()) { - // Note: This code path can only be reached if (CEREAL_RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag). + // Note: This code path can only be reached if (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag). if (!(kWriteDefaultFlags & kWriteNanAndInfFlag)) return false; if (internal::Double(d).IsNan()) { @@ -534,13 +570,13 @@ inline bool Writer::WriteDouble(double d) { return true; } -#if defined(CEREAL_RAPIDJSON_SSE2) || defined(CEREAL_RAPIDJSON_SSE42) +#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) template<> inline bool Writer::ScanWriteUnescapedString(StringStream& is, size_t length) { if (length < 16) - return CEREAL_RAPIDJSON_LIKELY(is.Tell() < length); + return RAPIDJSON_LIKELY(is.Tell() < length); - if (!CEREAL_RAPIDJSON_LIKELY(is.Tell() < length)) + if (!RAPIDJSON_LIKELY(is.Tell() < length)) return false; const char* p = is.src_; @@ -553,7 +589,7 @@ inline bool Writer::ScanWriteUnescapedString(StringStream& is, siz while (p != nextAligned) if (*p < 0x20 || *p == '\"' || *p == '\\') { is.src_ = p; - return CEREAL_RAPIDJSON_LIKELY(is.Tell() < length); + return RAPIDJSON_LIKELY(is.Tell() < length); } else os_->PutUnsafe(*p++); @@ -561,7 +597,7 @@ inline bool Writer::ScanWriteUnescapedString(StringStream& is, siz // The rest of string using SIMD static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; - static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 }; + 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])); @@ -570,10 +606,10 @@ inline bool Writer::ScanWriteUnescapedString(StringStream& is, siz 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, 0x19) == 0x19 + 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 (CEREAL_RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped + if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped SizeType len; #ifdef _MSC_VER // Find the index of first escaped unsigned long offset; @@ -593,18 +629,82 @@ inline bool Writer::ScanWriteUnescapedString(StringStream& is, siz } is.src_ = p; - return CEREAL_RAPIDJSON_LIKELY(is.Tell() < length); + return RAPIDJSON_LIKELY(is.Tell() < length); } -#endif // defined(CEREAL_RAPIDJSON_SSE2) || defined(CEREAL_RAPIDJSON_SSE42) +#elif defined(RAPIDJSON_NEON) +template<> +inline bool Writer::ScanWriteUnescapedString(StringStream& is, size_t length) { + if (length < 16) + return RAPIDJSON_LIKELY(is.Tell() < length); -CEREAL_RAPIDJSON_NAMESPACE_END + if (!RAPIDJSON_LIKELY(is.Tell() < length)) + return false; -#ifdef _MSC_VER -CEREAL_RAPIDJSON_DIAG_POP + 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 -#ifdef __clang__ -CEREAL_RAPIDJSON_DIAG_POP -#endif - -#endif // CEREAL_RAPIDJSON_CEREAL_RAPIDJSON_H_ +#endif // RAPIDJSON_RAPIDJSON_H_