Add docket support

This commit is contained in:
Ned Wright 2022-10-25 14:45:02 +00:00
parent 09847ac179
commit 3703b14ba6
71 changed files with 7126 additions and 2644 deletions

View File

@ -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)

View File

@ -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

View File

@ -1,11 +1,11 @@
<div align=center>
<img src="https://i2-s3-ui-static-content-prod-10.s3.eu-west-1.amazonaws.com/elpis/tree-no-bg-256.png" width="100" height="100">
<h1>openappsec/attachment</h1>
<h1>openappsec/attachement</h1>
</div>
## 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.
<strong>open-appsec Attachments</strong> connect between processes that provide HTTP data and the <strong>open-appsec Agent</strong> 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=/<absolute-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 `<output path>` 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 <input docker image> build_out
$ cmake -DCMAKE_INSTALL_PREFIX=build_out -DOUTPUT_DOCKER_IMAGE=<output 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.

View File

@ -1 +1,2 @@
add_subdirectory(nginx_attachment_util)
add_subdirectory(ngx_module)

View File

@ -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)

View File

@ -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)
{

View File

@ -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)

View File

@ -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 <input nginx compilation flags file> | --docker <input docker name>] <compilation artifacts directory>"
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|<DOCKER BASE IMAGE>|${2}|g" ${BUILD_OUTPUT_DIR}/Dockerfile
docker run -it ${2} whoami > /tmp/usertouse
USER_NAME="$(cat /tmp/usertouse)"
rm /tmp/usertouse
sed -i "s|<DOCKER USER>|${USER_NAME}|g" ${BUILD_OUTPUT_DIR}/Dockerfile
fi

View File

@ -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

View File

@ -380,8 +380,12 @@ compression_chain_filter(
}
ngx_memcpy(curr_input_link->buf, output_buffer, sizeof(ngx_buf_t));
// 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");

View File

@ -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:

View File

@ -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,9 +249,29 @@ 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.
// 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_BODY
);
if (is_last_part) session_data_p->was_request_fully_inspected = 1;
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,
@ -263,19 +284,21 @@ ngx_http_cp_req_body_filter_thread(void *_ctx)
}
THREAD_CTX_RETURN(NGX_ERROR);
}
session_data_p->remaining_messages_to_reply++;
}
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
&ctx->modifications,
REQUEST_END
);
if (is_last_part) session_data_p->was_request_fully_inspected = 1;
}
return NULL;
}
@ -283,7 +306,7 @@ ngx_http_cp_req_body_filter_thread(void *_ctx)
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;

View File

@ -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.

View File

@ -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);
}
@ -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,

View File

@ -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

View File

@ -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.

View File

@ -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,12 +560,21 @@ 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;
}

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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 <ngx_config.h>
#include <ngx_core.h>
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
};

View File

@ -1,2 +1,3 @@
add_subdirectory(shmem_ipc)
add_subdirectory(compression)
add_subdirectory(attachments)

View File

@ -0,0 +1 @@
add_subdirectory(http_configuration)

View File

@ -0,0 +1 @@
add_library(http_configuration http_configuration.cc)

View File

@ -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 <fstream>
#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<char>(logo_file),
istreambuf_iterator<char>()
);
}
} 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;
}
}

View File

@ -105,6 +105,7 @@ static const int zlib_no_flush = Z_NO_FLUSH;
struct CompressionStream
{
CompressionStream() { bzero(&stream, sizeof(z_stream)); }
~CompressionStream() { fini(); }
tuple<basic_string<unsigned char>, bool>
decompress(const unsigned char *data, uint32_t size)

View File

@ -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<std::string> & 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<std::string> &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<std::string, uint> numerical_values;
std::map<std::string, unsigned int> numerical_values;
std::map<std::string, std::string> string_values;
std::vector<std::string> exclude_sources;
std::string empty;

View File

@ -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

View File

@ -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);

View File

@ -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;
}

View File

@ -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;

11
docker/CMakeLists.txt Normal file
View File

@ -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)

18
docker/Dockerfile Normal file
View File

@ -0,0 +1,18 @@
FROM <DOCKER BASE IMAGE>
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 <DOCKER 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

View File

@ -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

View File

@ -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 <memory>
#include <limits>
#if RAPIDJSON_HAS_CXX11
#include <type_traits>
#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 <typename BaseAllocator = CrtAllocator>
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<ChunkHeader*>(reinterpret_cast<uint8_t*>(shared) + SIZEOF_SHARED_DATA);
}
static inline uint8_t *GetChunkBuffer(SharedData *shared)
{
return reinterpret_cast<uint8_t*>(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<SharedData*>(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<SharedData*>(AlignBuffer(buffer, size)))
{
CEREAL_RAPIDJSON_ASSERT(buffer != 0);
CEREAL_RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));
chunkHead_ = reinterpret_cast<ChunkHeader*>(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;
}
if (chunkHead_ && chunkHead_ == userBuffer_)
chunkHead_->size = 0; // Clear user buffer
shared_->chunkHead = c->next;
baseAllocator_->Free(c);
}
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<char *>(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<char *>(chunkHead_) + CEREAL_RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) {
if (originalPtr == GetChunkBuffer(shared_) + shared_->chunkHead->size - originalSize) {
size_t increment = static_cast<size_t>(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<ChunkHeader*>(baseAllocator_->Malloc(CEREAL_RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) {
shared_->ownBaseAllocator = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator)();
if (ChunkHeader* chunk = static_cast<ChunkHeader*>(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<uintptr_t>(buf);
if (RAPIDJSON_UNLIKELY(ubuf & mask)) {
const uintptr_t abuf = (ubuf + mask) & ~mask;
RAPIDJSON_ASSERT(size >= abuf - ubuf);
buf = reinterpret_cast<void*>(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<typename, typename = void>
struct IsRefCounted :
public FalseType
{ };
template<typename T>
struct IsRefCounted<T, typename internal::EnableIfCond<T::kRefCounted>::Type> :
public TrueType
{ };
}
#endif // CEREAL_RAPIDJSON_ENCODINGS_H_
template<typename T, typename A>
inline T* Realloc(A& a, T* old_p, size_t old_n, size_t new_n)
{
RAPIDJSON_NOEXCEPT_ASSERT(old_n <= std::numeric_limits<size_t>::max() / sizeof(T) && new_n <= std::numeric_limits<size_t>::max() / sizeof(T));
return static_cast<T*>(a.Realloc(old_p, old_n * sizeof(T), new_n * sizeof(T)));
}
template<typename T, typename A>
inline T *Malloc(A& a, size_t n = 1)
{
return Realloc<T, A>(a, NULL, 0, n);
}
template<typename T, typename A>
inline void Free(A& a, T *p, size_t n = 1)
{
static_cast<void>(Realloc<T, A>(a, p, n, 0));
}
#ifdef __GNUC__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++) // std::allocator can safely be inherited
#endif
template <typename T, typename BaseAllocator = CrtAllocator>
class StdAllocator :
public std::allocator<T>
{
typedef std::allocator<T> allocator_type;
#if RAPIDJSON_HAS_CXX11
typedef std::allocator_traits<allocator_type> 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<typename U>
StdAllocator(const StdAllocator<U, BaseAllocator>& 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<typename U>
struct rebind {
typedef StdAllocator<U, BaseAllocator> 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<value_type>::type &reference;
typedef typename std::add_lvalue_reference<typename std::add_const<value_type>::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 <typename ...Args>
void construct(pointer p, Args&&... args)
{
traits_type::construct(*this, p, std::forward<Args>(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 <typename U>
U* allocate(size_type n = 1, const void* = 0)
{
return RAPIDJSON_NAMESPACE::Malloc<U>(baseAllocator_, n);
}
template <typename U>
void deallocate(U* p, size_type n = 1)
{
RAPIDJSON_NAMESPACE::Free<U>(baseAllocator_, p, n);
}
pointer allocate(size_type n = 1, const void* = 0)
{
return allocate<value_type>(n);
}
void deallocate(pointer p, size_type n = 1)
{
deallocate<value_type>(p, n);
}
#if RAPIDJSON_HAS_CXX11
using is_always_equal = std::is_empty<BaseAllocator>;
#endif
template<typename U>
bool operator==(const StdAllocator<U, BaseAllocator>& rhs) const RAPIDJSON_NOEXCEPT
{
return baseAllocator_ == rhs.baseAllocator_;
}
template<typename U>
bool operator!=(const StdAllocator<U, BaseAllocator>& rhs) const RAPIDJSON_NOEXCEPT
{
return !operator==(rhs);
}
//! rapidjson Allocator concept
static const bool kNeedFree = BaseAllocator::kNeedFree;
static const bool kRefCounted = internal::IsRefCounted<BaseAllocator>::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 <typename, typename>
friend class StdAllocator; // access to StdAllocator<!T>.*
BaseAllocator baseAllocator_;
};
#if !RAPIDJSON_HAS_CXX17 // std::allocator<void> deprecated in C++17
template <typename BaseAllocator>
class StdAllocator<void, BaseAllocator> :
public std::allocator<void>
{
typedef std::allocator<void> 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<typename U>
StdAllocator(const StdAllocator<U, BaseAllocator>& rhs) RAPIDJSON_NOEXCEPT :
allocator_type(rhs),
baseAllocator_(rhs.baseAllocator_)
{ }
/* implicit */
StdAllocator(const BaseAllocator& baseAllocator) RAPIDJSON_NOEXCEPT :
allocator_type(),
baseAllocator_(baseAllocator)
{ }
~StdAllocator() RAPIDJSON_NOEXCEPT
{ }
template<typename U>
struct rebind {
typedef StdAllocator<U, BaseAllocator> other;
};
typedef typename allocator_type::value_type value_type;
private:
template <typename, typename>
friend class StdAllocator; // access to StdAllocator<!T>.*
BaseAllocator baseAllocator_;
};
#endif
#ifdef __GNUC__
RAPIDJSON_DIAG_POP
#endif
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_ENCODINGS_H_

View File

@ -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 <typename InputStream, typename Encoding = UTF8<> >
class CursorStreamWrapper : public GenericStreamWrapper<InputStream, Encoding> {
public:
typedef typename Encoding::Ch Ch;
CursorStreamWrapper(InputStream& is):
GenericStreamWrapper<InputStream, Encoding>(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_

File diff suppressed because it is too large Load Diff

View File

@ -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 <typename Encoding, typename InputByteStream>
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 <typename Encoding, typename OutputByteStream>
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<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
//! Input stream wrapper with dynamically bound encoding and automatic encoding detection.
/*!
@ -133,7 +133,7 @@ private:
*/
template <typename CharType, typename InputByteStream>
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 <typename CharType, typename OutputByteStream>
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_

View File

@ -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<Ch>(0x80 | (codepoint & 0x3F)));
}
else {
CEREAL_RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
os.Put(static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
@ -134,7 +134,7 @@ struct UTF8 {
PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F)));
}
else {
CEREAL_RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
PutUnsafe(os, static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
@ -144,9 +144,9 @@ struct UTF8 {
template <typename InputStream>
static bool Decode(InputStream& is, unsigned* codepoint) {
#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast<unsigned char>(c) & 0x3Fu)
#define TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
#define TAIL() COPY(); TRANS(0x70)
#define RAPIDJSON_COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast<unsigned char>(c) & 0x3Fu)
#define RAPIDJSON_TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
#define RAPIDJSON_TAIL() RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x70)
typename InputStream::Ch c = is.Take();
if (!(c & 0x80)) {
*codepoint = static_cast<unsigned char>(c);
@ -157,48 +157,48 @@ struct UTF8 {
if (type >= 32) {
*codepoint = 0;
} else {
*codepoint = (0xFF >> type) & static_cast<unsigned char>(c);
*codepoint = (0xFFu >> type) & static_cast<unsigned char>(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 <typename InputStream, typename OutputStream>
static bool Validate(InputStream& is, OutputStream& os) {
#define COPY() os.Put(c = is.Take())
#define TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
#define TAIL() COPY(); TRANS(0x70)
#define RAPIDJSON_COPY() os.Put(c = is.Take())
#define RAPIDJSON_TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(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<unsigned char>(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 <typename InputByteStream>
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<unsigned char>(c) != 0xEFu) return c;
c = is.Take();
@ -234,13 +234,13 @@ struct UTF8 {
template <typename InputByteStream>
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<Ch>(is.Take());
}
template <typename OutputByteStream>
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<typename OutputByteStream::Ch>(0xEFu));
os.Put(static_cast<typename OutputByteStream::Ch>(0xBBu));
os.Put(static_cast<typename OutputByteStream::Ch>(0xBFu));
@ -248,7 +248,7 @@ struct UTF8 {
template <typename OutputByteStream>
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<typename OutputByteStream::Ch>(c));
}
};
@ -268,44 +268,44 @@ struct UTF8 {
template<typename CharType = wchar_t>
struct UTF16 {
typedef CharType Ch;
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2);
RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2);
enum { supportUnicode = 1 };
template<typename OutputStream>
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<typename OutputStream::Ch>(codepoint));
}
else {
CEREAL_RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
unsigned v = codepoint - 0x10000;
os.Put(static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
os.Put((v & 0x3FF) | 0xDC00);
os.Put(static_cast<typename OutputStream::Ch>((v & 0x3FF) | 0xDC00));
}
}
template<typename OutputStream>
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<typename OutputStream::Ch>(codepoint));
}
else {
CEREAL_RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
unsigned v = codepoint - 0x10000;
PutUnsafe(os, static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
PutUnsafe(os, (v & 0x3FF) | 0xDC00);
PutUnsafe(os, static_cast<typename OutputStream::Ch>((v & 0x3FF) | 0xDC00));
}
}
template <typename InputStream>
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<unsigned>(c);
@ -323,8 +323,8 @@ struct UTF16 {
template <typename InputStream, typename OutputStream>
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<typename OutputStream::Ch>(c = is.Take()));
if (c < 0xD800 || c > 0xDFFF)
@ -342,14 +342,14 @@ template<typename CharType = wchar_t>
struct UTF16LE : UTF16<CharType> {
template <typename InputByteStream>
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<uint16_t>(c) == 0xFEFFu ? Take(is) : c;
}
template <typename InputByteStream>
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<uint8_t>(is.Take());
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
return static_cast<CharType>(c);
@ -357,14 +357,14 @@ struct UTF16LE : UTF16<CharType> {
template <typename OutputByteStream>
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<typename OutputByteStream::Ch>(0xFFu));
os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
}
template <typename OutputByteStream>
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<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));
os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));
}
@ -375,29 +375,29 @@ template<typename CharType = wchar_t>
struct UTF16BE : UTF16<CharType> {
template <typename InputByteStream>
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<uint16_t>(c) == 0xFEFFu ? Take(is) : c;
}
template <typename InputByteStream>
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<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
c |= static_cast<uint8_t>(is.Take());
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take()));
return static_cast<CharType>(c);
}
template <typename OutputByteStream>
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<typename OutputByteStream::Ch>(0xFEu));
os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
}
template <typename OutputByteStream>
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<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));
os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));
}
@ -417,27 +417,27 @@ struct UTF16BE : UTF16<CharType> {
template<typename CharType = unsigned>
struct UTF32 {
typedef CharType Ch;
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4);
RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4);
enum { supportUnicode = 1 };
template<typename OutputStream>
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<typename OutputStream>
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 <typename InputStream>
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 <typename InputStream, typename OutputStream>
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<typename CharType = unsigned>
struct UTF32LE : UTF32<CharType> {
template <typename InputByteStream>
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<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c;
}
template <typename InputByteStream>
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<uint8_t>(is.Take());
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16;
@ -474,7 +474,7 @@ struct UTF32LE : UTF32<CharType> {
template <typename OutputByteStream>
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<typename OutputByteStream::Ch>(0xFFu));
os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
@ -483,7 +483,7 @@ struct UTF32LE : UTF32<CharType> {
template <typename OutputByteStream>
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<typename OutputByteStream::Ch>(c & 0xFFu));
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu));
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu));
@ -496,14 +496,14 @@ template<typename CharType = unsigned>
struct UTF32BE : UTF32<CharType> {
template <typename InputByteStream>
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<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c;
}
template <typename InputByteStream>
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<unsigned>(static_cast<uint8_t>(is.Take())) << 24;
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16;
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
@ -513,7 +513,7 @@ struct UTF32BE : UTF32<CharType> {
template <typename OutputByteStream>
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<typename OutputByteStream::Ch>(0x00u));
os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
@ -522,7 +522,7 @@ struct UTF32BE : UTF32<CharType> {
template <typename OutputByteStream>
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<typename OutputByteStream::Ch>((c >> 24) & 0xFFu));
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu));
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu));
@ -546,13 +546,13 @@ struct ASCII {
template<typename OutputStream>
static void Encode(OutputStream& os, unsigned codepoint) {
CEREAL_RAPIDJSON_ASSERT(codepoint <= 0x7F);
RAPIDJSON_ASSERT(codepoint <= 0x7F);
os.Put(static_cast<Ch>(codepoint & 0xFF));
}
template<typename OutputStream>
static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
CEREAL_RAPIDJSON_ASSERT(codepoint <= 0x7F);
RAPIDJSON_ASSERT(codepoint <= 0x7F);
PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF));
}
@ -572,26 +572,26 @@ struct ASCII {
template <typename InputByteStream>
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<uint8_t>(Take(is));
return static_cast<Ch>(c);
}
template <typename InputByteStream>
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<Ch>(is.Take());
}
template <typename OutputByteStream>
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 <typename OutputByteStream>
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<typename OutputByteStream::Ch>(c));
}
};
@ -617,37 +617,37 @@ struct AutoUTF {
enum { supportUnicode = 1 };
#define CEREAL_RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
template<typename OutputStream>
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<typename OutputStream>
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 <typename InputStream>
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 <typename InputStream, typename OutputStream>
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<typename SourceEncoding, typename TargetEncoding>
struct Transcoder {
//! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream.
template<typename InputStream, typename OutputStream>
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<typename InputStream, typename OutputStream>
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<typename InputStream, typename OutputStream>
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<typename Encoding>
struct Transcoder<Encoding, Encoding> {
template<typename InputStream, typename OutputStream>
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<typename InputStream, typename OutputStream>
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<typename InputStream, typename OutputStream>
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_

View File

@ -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_

View File

@ -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_

View File

@ -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 <cstdio>
#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<size_t>(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_

View File

@ -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 <cstdio>
#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<size_t>(current_ - buffer_), fp_);
size_t result = std::fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);
if (result < static_cast<size_t>(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_

View File

@ -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 <typename Encoding, typename Allocator>
struct GenericMember;
class GenericMember;
template <bool Const, typename Encoding, typename Allocator>
class GenericMemberIterator;
@ -146,6 +146,6 @@ class GenericSchemaValidator;
typedef GenericSchemaValidator<SchemaDocument, BaseReaderHandler<UTF8<char>, void>, CrtAllocator> SchemaValidator;
CEREAL_RAPIDJSON_NAMESPACE_END
RAPIDJSON_NAMESPACE_END
#endif // CEREAL_RAPIDJSON_RAPIDJSONFWD_H_
#endif // RAPIDJSON_RAPIDJSONFWD_H_

View File

@ -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 <intrin.h> // 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<typename Ch>
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<uint32_t>(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<typename Ch>
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<typename Ch>
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<unsigned>(*p - '0');
for (const Ch* p = begin; p != end; ++p) {
RAPIDJSON_ASSERT(*p >= Ch('0') && *p <= Ch('9'));
r = r * 10u + static_cast<unsigned>(*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_

View File

@ -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 <intrin.h>
#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<uint32_t>(x >> 32)))
return 63 - (r + 32);
// Scan the low 32 bits.
_BitScanReverse(&r, static_cast<uint32_t>(x & 0xFFFFFFFF));
#endif // _WIN64
return 63 - r;
#elif (defined(__GNUC__) && __GNUC__ >= 4) || RAPIDJSON_HAS_BUILTIN(__builtin_clzll)
// __builtin_clzll wrapper
return static_cast<uint32_t>(__builtin_clzll(x));
#else
// naive version
uint32_t r = 0;
while (!(x & (static_cast<uint64_t>(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_

View File

@ -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,28 +16,33 @@
// 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 <limits>
#if defined(_MSC_VER) && defined(_M_AMD64)
#if defined(_MSC_VER) && defined(_M_AMD64) && !defined(__INTEL_COMPILER)
#include <intrin.h>
#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 {
@ -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<int>(clzll(f));
return DiyFp(f << s, e - s);
#else
DiyFp res = *this;
while (!(res.f & (static_cast<uint64_t>(1) << 63))) {
res.f <<= 1;
res.e--;
}
return res;
#endif
}
DiyFp NormalizeBoundary() const {
@ -141,6 +133,15 @@ struct DiyFp {
double d;
uint64_t u64;
}u;
RAPIDJSON_ASSERT(f <= kDpHiddenBit + kDpSignificandMask);
if (e < kDpDenormalExponent) {
// Underflow.
return 0.0;
}
if (e >= kDpMaxExponent) {
// Overflow.
return std::numeric_limits<double>::infinity();
}
const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 :
static_cast<uint64_t>(e + kDpExponentBias);
u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize);
@ -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,6 +221,7 @@ 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]);
}
@ -238,21 +240,22 @@ inline DiyFp GetCachedPower(int e, int* K) {
}
inline DiyFp GetCachedPower10(int exp, int *outExp) {
unsigned index = (static_cast<unsigned>(exp) + 348u) / 8u;
RAPIDJSON_ASSERT(exp >= -348);
unsigned index = static_cast<unsigned>(exp + 348) / 8u;
*outExp = -348 + static_cast<int>(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_

View File

@ -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<uint32_t>(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<uint64_t>(p1) << -one.e) + p2;
if (tmp <= delta) {
*K += kappa;
GrisuRound(buffer, *len, delta, tmp, static_cast<uint64_t>(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<int>(kappa);
GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[-static_cast<int>(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_

View File

@ -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<unsigned>(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_

View File

@ -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_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,6 +37,8 @@ inline const char* GetDigitsLut() {
}
inline char* u32toa(uint32_t value, char* buffer) {
RAPIDJSON_ASSERT(buffer != 0);
const char* cDigitsLut = GetDigitsLut();
if (value < 10000) {
@ -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<uint32_t>(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;
@ -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];
@ -289,6 +292,7 @@ inline char* u64toa(uint64_t value, char* buffer) {
}
inline char* i64toa(int64_t value, char* buffer) {
RAPIDJSON_ASSERT(buffer != 0);
uint64_t u = static_cast<uint64_t>(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_

View File

@ -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 <type_traits>
#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 <typename T> struct IsPointer<T*> : TrueType {};
///////////////////////////////////////////////////////////////////////////////
// IsBaseOf
//
#if CEREAL_RAPIDJSON_HAS_CXX11_TYPETRAITS
#if RAPIDJSON_HAS_CXX11_TYPETRAITS
template <typename B, typename D> struct IsBaseOf
: BoolType< ::std::is_base_of<B,D>::value> {};
@ -104,8 +105,8 @@ template <typename B, typename D> struct IsBaseOf
#else // simplified version adopted from Boost
template<typename B, typename D> 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<typename B, typename D> struct IsBaseOfImpl {
template <typename B, typename D> struct IsBaseOf
: OrExpr<IsSame<B, D>, BoolExpr<IsBaseOfImpl<B, D> > >::Type {};
#endif // CEREAL_RAPIDJSON_HAS_CXX11_TYPETRAITS
#endif // RAPIDJSON_HAS_CXX11_TYPETRAITS
//////////////////////////////////////////////////////////////////////////
@ -148,34 +149,38 @@ struct SfinaeTag {};
template <typename T> struct RemoveSfinaeTag;
template <typename T> struct RemoveSfinaeTag<SfinaeTag&(*)(T)> { 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 \
<CEREAL_RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
#define RAPIDJSON_ENABLEIF(cond) \
typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
#define CEREAL_RAPIDJSON_DISABLEIF(cond) \
typename ::CEREAL_RAPIDJSON_NAMESPACE::internal::DisableIf \
<CEREAL_RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
#define RAPIDJSON_DISABLEIF(cond) \
typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
#define CEREAL_RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \
typename ::CEREAL_RAPIDJSON_NAMESPACE::internal::EnableIf \
<CEREAL_RAPIDJSON_REMOVEFPTR_(cond), \
CEREAL_RAPIDJSON_REMOVEFPTR_(returntype)>::Type
#define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \
typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
<RAPIDJSON_REMOVEFPTR_(cond), \
RAPIDJSON_REMOVEFPTR_(returntype)>::Type
#define CEREAL_RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \
typename ::CEREAL_RAPIDJSON_NAMESPACE::internal::DisableIf \
<CEREAL_RAPIDJSON_REMOVEFPTR_(cond), \
CEREAL_RAPIDJSON_REMOVEFPTR_(returntype)>::Type
#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \
typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
<RAPIDJSON_REMOVEFPTR_(cond), \
RAPIDJSON_REMOVEFPTR_(returntype)>::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_

View File

@ -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_

View File

@ -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 <typename SourceStream, typename Encoding>
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 <typename Encoding, typename Allocator>
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 <typename Encoding, typename Allocator = CrtAllocator>
class GenericRegex {
public:
typedef Encoding EncodingType;
typedef typename Encoding::Ch Ch;
template <typename, typename> 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<Encoding> ss(source);
DecodedStream<GenericStringStream<Encoding> > ds(ss);
DecodedStream<GenericStringStream<Encoding>, Encoding> ds(ss);
Parse(ds);
}
~GenericRegex() {
Allocator::Free(stateSet_);
~GenericRegex()
{
RAPIDJSON_DELETE(ownAllocator_);
}
bool IsValid() const {
return root_ != kRegexInvalidState;
}
template <typename InputStream>
bool Match(InputStream& is) const {
return SearchWithAnchoring(is, true, true);
}
bool Match(const Ch* s) const {
GenericStringStream<Encoding> is(s);
return Match(is);
}
template <typename InputStream>
bool Search(InputStream& is) const {
return SearchWithAnchoring(is, anchorBegin_, anchorEnd_);
}
bool Search(const Ch* s) const {
GenericStringStream<Encoding> is(s);
return Search(is);
}
private:
enum Operator {
kZeroOrOne,
@ -157,54 +166,31 @@ private:
SizeType minIndex;
};
template <typename SourceStream>
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<State>()[index];
}
const State& GetState(SizeType index) const {
CEREAL_RAPIDJSON_ASSERT(index < stateCount_);
RAPIDJSON_ASSERT(index < stateCount_);
return states_.template Bottom<State>()[index];
}
Range& GetRange(SizeType index) {
CEREAL_RAPIDJSON_ASSERT(index < rangeCount_);
RAPIDJSON_ASSERT(index < rangeCount_);
return ranges_.template Bottom<Range>()[index];
}
const Range& GetRange(SizeType index) const {
CEREAL_RAPIDJSON_ASSERT(index < rangeCount_);
RAPIDJSON_ASSERT(index < rangeCount_);
return ranges_.template Bottom<Range>()[index];
}
template <typename InputStream>
void Parse(DecodedStream<InputStream>& ds) {
Allocator allocator;
Stack<Allocator> operandStack(&allocator, 256); // Frag
Stack<Allocator> operatorStack(&allocator, 256); // Operator
Stack<Allocator> atomCountStack(&allocator, 256); // unsigned (Atom per parenthesis)
void Parse(DecodedStream<InputStream, Encoding>& ds) {
Stack<Allocator> operandStack(allocator_, 256); // Frag
Stack<Allocator> operatorStack(allocator_, 256); // Operator
Stack<Allocator> atomCountStack(allocator_, 256); // unsigned (Atom per parenthesis)
*atomCountStack.template Push<unsigned>() = 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<unsigned*>(states_.GetAllocator().Malloc(GetStateSetSize()));
state0_.template Reserve<SizeType>(stateCount_);
state1_.template Reserve<SizeType>(stateCount_);
}
}
SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) {
@ -375,7 +354,7 @@ private:
bool Eval(Stack<Allocator>& 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<Frag>(1);
Frag e1 = *operandStack.template Pop<Frag>(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<Frag>(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<Allocator>& 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 <typename InputStream>
bool ParseUnsigned(DecodedStream<InputStream>& ds, unsigned* u) {
bool ParseUnsigned(DecodedStream<InputStream, Encoding>& ds, unsigned* u) {
unsigned r = 0;
if (ds.Peek() < '0' || ds.Peek() > '9')
return false;
@ -497,7 +479,7 @@ private:
}
template <typename InputStream>
bool ParseRange(DecodedStream<InputStream>& ds, SizeType* range) {
bool ParseRange(DecodedStream<InputStream, Encoding>& 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 <typename InputStream>
bool CharacterEscape(DecodedStream<InputStream>& ds, unsigned* escapedCodepoint) {
bool CharacterEscape(DecodedStream<InputStream, Encoding>& ds, unsigned* escapedCodepoint) {
unsigned codepoint;
switch (codepoint = ds.Take()) {
case '^':
@ -603,72 +587,8 @@ private:
}
}
template <typename InputStream>
bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) const {
CEREAL_RAPIDJSON_ASSERT(IsValid());
DecodedStream<InputStream> ds(is);
state0_.Clear();
Stack<Allocator> *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<SizeType>(); s != current->template End<SizeType>(); ++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<Allocator>& 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<SizeType>() = 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<Allocator> states_;
Stack<Allocator> ranges_;
SizeType root_;
@ -678,24 +598,142 @@ private:
static const unsigned kInfinityQuantifier = ~0u;
// For SearchWithAnchoring()
uint32_t* stateSet_; // allocated by states_.GetAllocator()
mutable Stack<Allocator> state0_;
mutable Stack<Allocator> state1_;
bool anchorBegin_;
bool anchorEnd_;
};
template <typename RegexType, typename Allocator = CrtAllocator>
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<unsigned*>(allocator_->Malloc(GetStateSetSize()));
state0_.template Reserve<SizeType>(regex_.stateCount_);
state1_.template Reserve<SizeType>(regex_.stateCount_);
}
~GenericRegexSearch() {
Allocator::Free(stateSet_);
RAPIDJSON_DELETE(ownAllocator_);
}
template <typename InputStream>
bool Match(InputStream& is) {
return SearchWithAnchoring(is, true, true);
}
bool Match(const Ch* s) {
GenericStringStream<Encoding> is(s);
return Match(is);
}
template <typename InputStream>
bool Search(InputStream& is) {
return SearchWithAnchoring(is, regex_.anchorBegin_, regex_.anchorEnd_);
}
bool Search(const Ch* s) {
GenericStringStream<Encoding> is(s);
return Search(is);
}
private:
typedef typename RegexType::State State;
typedef typename RegexType::Range Range;
template <typename InputStream>
bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) {
DecodedStream<InputStream, Encoding> ds(is);
state0_.Clear();
Stack<Allocator> *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<SizeType>(); s != current->template End<SizeType>(); ++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<Allocator>& 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<SizeType>() = 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<Allocator> state0_;
Stack<Allocator> state1_;
uint32_t* stateSet_;
};
typedef GenericRegex<UTF8<> > Regex;
typedef GenericRegexSearch<Regex> 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_

View File

@ -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 <cstddef>
#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<typename T>
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<std::ptrdiff_t>(sizeof(T) * count) > (stackEnd_ - stackTop_)))
Expand<T>(count);
}
template<typename T>
CEREAL_RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
Reserve<T>(count);
return PushUnsafe<T>(count);
}
template<typename T>
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<std::ptrdiff_t>(sizeof(T) * count) <= (stackEnd_ - stackTop_));
T* ret = reinterpret_cast<T*>(stackTop_);
stackTop_ += sizeof(T) * count;
return ret;
@ -134,20 +136,20 @@ public:
template<typename T>
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<T*>(stackTop_);
}
template<typename T>
T* Top() {
CEREAL_RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
return reinterpret_cast<T*>(stackTop_ - sizeof(T));
}
template<typename T>
const T* Top() const {
CEREAL_RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
return reinterpret_cast<T*>(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_

View File

@ -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 <cwchar>
CEREAL_RAPIDJSON_NAMESPACE_BEGIN
RAPIDJSON_NAMESPACE_BEGIN
namespace internal {
//! Custom strlen() which works on different character types.
@ -28,14 +29,41 @@ namespace internal {
*/
template <typename Ch>
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<typename Ch>
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<unsigned>(*s1) < static_cast<unsigned>(*s2) ? -1 : static_cast<unsigned>(*s1) > static_cast<unsigned>(*s2);
}
//! Returns number of code points in a encoded string.
template<typename Encoding>
bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) {
RAPIDJSON_ASSERT(s != 0);
RAPIDJSON_ASSERT(outCount != 0);
GenericStringStream<Encoding> 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_

View File

@ -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 <climits>
#include <limits>
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<typename Ch>
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<unsigned>(decimals[i] - '0');
significand = significand * 10u + static_cast<unsigned>(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<int>(decimalPosition) - static_cast<int>(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<unsigned>(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<int>(kUlp);
error = (error >> scaleExp) + 1 + kUlp;
precisionSize -= scaleExp;
}
DiyFp rounded(v.f >> precisionSize, v.e + static_cast<int>(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<unsigned>(error)) {
@ -203,9 +206,10 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
return halfWay - static_cast<unsigned>(error) >= precisionBits || precisionBits >= halfWay + static_cast<unsigned>(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<int>(decimalPosition) - static_cast<int>(length) + exp;
template<typename Ch>
inline double StrtodBigInteger(double approx, const Ch* decimals, int dLen, int dExp) {
RAPIDJSON_ASSERT(dLen >= 0);
const BigInteger dInt(decimals, static_cast<unsigned>(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<typename Ch>
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<int>(length);
RAPIDJSON_ASSERT(length >= decimalPosition);
RAPIDJSON_ASSERT(length - decimalPosition <= INT_MAX);
int dExpAdjust = static_cast<int>(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<int>(length) > kMaxDecimalDigit) {
int delta = (static_cast<int>(length) - kMaxDecimalDigit);
exp += delta;
decimalPosition -= static_cast<unsigned>(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<double>::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_

View File

@ -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++ <algorithm> header
@ -30,17 +30,17 @@ namespace internal {
\note This has the same semantics as std::swap().
*/
template <typename T>
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_

View File

@ -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,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_ISTREAMWRAPPER_H_
#define CEREAL_RAPIDJSON_ISTREAMWRAPPER_H_
#ifndef RAPIDJSON_ISTREAMWRAPPER_H_
#define RAPIDJSON_ISTREAMWRAPPER_H_
#include "stream.h"
#include <iosfwd>
#include <ios>
#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.
/*!
@ -51,66 +49,80 @@ template <typename StreamType>
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<Ch>(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<Ch>(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<size_t>(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<Ch>(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<std::streamsize>(bufferSize_))) {
readCount_ = static_cast<size_t>(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<std::istream> IStreamWrapper;
typedef BasicIStreamWrapper<std::wistream> 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_

View File

@ -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<char>(n), c, n * sizeof(c));
}
CEREAL_RAPIDJSON_NAMESPACE_END
RAPIDJSON_NAMESPACE_END
#endif // CEREAL_RAPIDJSON_MEMORYBUFFER_H_
#endif // RAPIDJSON_MEMORYBUFFER_H_

View File

@ -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,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_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<size_t>(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_

View File

@ -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 <iosfwd>
#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<std::ostream> OStreamWrapper;
typedef BasicOStreamWrapper<std::wostream> 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_

View File

@ -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<ValueType, Allocator> 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<Ch>& 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<Token*>(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 <typename T>
CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >), (GenericPointer))
RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::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<Ch>(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<SizeType>(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<Ch>(t->name, t->length));
typename ValueType::MemberIterator m = v->FindMember(GenericValue<EncodingType>(GenericStringRef<Ch>(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<EncodingType>(GenericStringRef<Ch>(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<size_t>(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<ValueType&>(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<Ch>(t->name, t->length));
typename ValueType::MemberIterator m = v->FindMember(GenericValue<EncodingType>(GenericStringRef<Ch>(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<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);
}
#endif
@ -557,7 +685,7 @@ public:
\tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
*/
template <typename T>
CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (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 <typename stackAllocator>
ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const std::basic_string<Ch>& 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 <typename T, typename stackAllocator>
CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& 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<Ch>& 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 <typename T>
CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (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 <typename stackAllocator>
ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const std::basic_string<Ch>& 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 <typename T, typename stackAllocator>
CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& 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<Ch>(t->name, t->length));
typename ValueType::MemberIterator m = v->FindMember(GenericValue<EncodingType>(GenericStringRef<Ch>(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 uriFragment, typename OutputStream>
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<unsigned char>(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<typename OutputStream::Ch>(hexDigits[u >> 4]));
os_.Put(static_cast<typename OutputStream::Ch>(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>
typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, const std::basic_string<typename T::Ch>& 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 <typename T, typename T2>
CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& 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<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);
}
#if CEREAL_RAPIDJSON_HAS_STDSTRING
#if RAPIDJSON_HAS_STDSTRING
template <typename T, typename CharType, size_t N>
typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const std::basic_string<typename T::Ch>& defaultValue, typename T::AllocatorType& a) {
return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);
@ -1140,7 +1268,7 @@ typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&sou
#endif
template <typename T, typename CharType, size_t N, typename T2>
CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
GetValueByPointerWithDefault(T& root, const CharType(&source)[N], T2 defaultValue, typename T::AllocatorType& a) {
return GenericPointer<typename T::ValueType>(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>
typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const std::basic_string<typename DocumentType::Ch>& defaultValue) {
return pointer.GetWithDefault(document, defaultValue);
@ -1165,7 +1293,7 @@ typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& doc
#endif
template <typename DocumentType, typename T2>
CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, T2 defaultValue) {
return pointer.GetWithDefault(document, defaultValue);
}
@ -1180,7 +1308,7 @@ typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& doc
return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);
}
#if CEREAL_RAPIDJSON_HAS_STDSTRING
#if RAPIDJSON_HAS_STDSTRING
template <typename DocumentType, typename CharType, size_t N>
typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const std::basic_string<typename DocumentType::Ch>& defaultValue) {
return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);
@ -1188,7 +1316,7 @@ typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& doc
#endif
template <typename DocumentType, typename CharType, size_t N, typename T2>
CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], T2 defaultValue) {
return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);
}
@ -1210,7 +1338,7 @@ typename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename
return pointer.Set(root, value, a);
}
#if CEREAL_RAPIDJSON_HAS_STDSTRING
#if RAPIDJSON_HAS_STDSTRING
template <typename T>
typename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, const std::basic_string<typename T::Ch>& value, typename T::AllocatorType& a) {
return pointer.Set(root, value, a);
@ -1218,7 +1346,7 @@ typename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename
#endif
template <typename T, typename T2>
CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& 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<typename T::ValueType>(source, N - 1).Set(root, value, a);
}
#if CEREAL_RAPIDJSON_HAS_STDSTRING
#if RAPIDJSON_HAS_STDSTRING
template <typename T, typename CharType, size_t N>
typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const std::basic_string<typename T::Ch>& value, typename T::AllocatorType& a) {
return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
@ -1246,7 +1374,7 @@ typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], co
#endif
template <typename T, typename CharType, size_t N, typename T2>
CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
SetValueByPointer(T& root, const CharType(&source)[N], T2 value, typename T::AllocatorType& a) {
return GenericPointer<typename T::ValueType>(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>
typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const std::basic_string<typename DocumentType::Ch>& value) {
return pointer.Set(document, value);
@ -1276,7 +1404,7 @@ typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, cons
#endif
template <typename DocumentType, typename T2>
CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, T2 value) {
return pointer.Set(document, value);
}
@ -1296,7 +1424,7 @@ typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, cons
return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
}
#if CEREAL_RAPIDJSON_HAS_STDSTRING
#if RAPIDJSON_HAS_STDSTRING
template <typename DocumentType, typename CharType, size_t N>
typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const std::basic_string<typename DocumentType::Ch>& value) {
return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
@ -1304,7 +1432,7 @@ typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, cons
#endif
template <typename DocumentType, typename CharType, size_t N, typename T2>
CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
SetValueByPointer(DocumentType& document, const CharType(&source)[N], T2 value) {
return GenericPointer<typename DocumentType::ValueType>(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_

View File

@ -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 OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
class PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags> {
public:
typedef Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator> Base;
typedef Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags> 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<PrettyWriter>(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<Ch>& 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<Ch>& 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<typename Base::Level>()->inArray);
RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); // not inside an Object
RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray); // currently inside an Array, not Object
RAPIDJSON_ASSERT(0 == Base::level_stack_.template Top<typename Base::Level>()->valueCount % 2); // Object has a Key without a Value
bool empty = Base::level_stack_.template Pop<typename Base::Level>(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<typename Base::Level>()->inArray);
RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray);
bool empty = Base::level_stack_.template Pop<typename Base::Level>(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<typename TargetEncoding::Ch>(indentChar_), count);
PutN(*Base::os_, static_cast<typename OutputStream::Ch>(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_

View File

@ -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 <cstring> // 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 "<major>.<minor>.<patch>" 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 <string>
#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 <inttypes.h>
#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 <endian.h>
# 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<uint64_t>(7u)) & ~static_cast<uint64_t>(7u))
#else
#define CEREAL_RAPIDJSON_ALIGN(x) (((x) + 3u) & ~3u)
#endif
#ifndef RAPIDJSON_ALIGN
#define RAPIDJSON_ALIGN(x) (((x) + static_cast<size_t>(7u)) & ~static_cast<size_t>(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<uint64_t>(high32) << 32) | static_cast<uint64_t>(low32))
#ifndef RAPIDJSON_UINT64_C2
#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast<uint64_t>(high32) << 32) | static_cast<uint64_t>(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<type *>((reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(CEREAL_RAPIDJSON_UINT64_C2(0xFFFF0000, 0x00000000))) | reinterpret_cast<uintptr_t>(reinterpret_cast<const void*>(x))))
#define CEREAL_RAPIDJSON_GETPOINTER(type, p) (reinterpret_cast<type *>(reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(CEREAL_RAPIDJSON_UINT64_C2(0x0000FFFF, 0xFFFFFFFF))))
#define RAPIDJSON_SETPOINTER(type, p, x) (p = reinterpret_cast<type *>((reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0xFFFF0000, 0x00000000))) | reinterpret_cast<uintptr_t>(reinterpret_cast<const void*>(x))))
#define RAPIDJSON_GETPOINTER(type, p) (reinterpret_cast<type *>(reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(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 <cassert>
#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 <bool x> struct STATIC_ASSERTION_FAILURE;
template <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; };
template<int x> struct StaticAssertTest {};
CEREAL_RAPIDJSON_NAMESPACE_END
template <size_t x> 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<bool(x) >)> \
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<bool(x) >)> \
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 <utility> // 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 <cassert>
#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_

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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
@ -14,12 +14,12 @@
#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 <typename InputStream, typename Encoding = UTF8<> >
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<size_t>(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<size_t>(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<size_t>(dst_ - begin); }
@ -174,6 +218,6 @@ struct StreamTraits<GenericInsituStringStream<Encoding> > {
//! Insitu string stream with UTF8 encoding.
typedef GenericInsituStringStream<UTF8<> > InsituStringStream;
CEREAL_RAPIDJSON_NAMESPACE_END
RAPIDJSON_NAMESPACE_END
#endif // CEREAL_RAPIDJSON_STREAM_H_
#endif // RAPIDJSON_STREAM_H_

View File

@ -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 <utility> // 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<Ch>();
}
//! 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<Allocator> stack_;
@ -108,10 +112,10 @@ inline void PutN(GenericStringBuffer<UTF8<> >& stream, char c, size_t n) {
std::memset(stream.stack_.Push<char>(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_

481
external/cereal/external/rapidjson/uri.h vendored Normal file
View File

@ -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 <typename ValueType, typename Allocator=CrtAllocator>
class GenericUri {
public:
typedef typename ValueType::Ch Ch;
#if RAPIDJSON_HAS_STDSTRING
typedef std::basic_string<Ch> 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<Ch>(uri));
}
// Use with specializations of GenericValue
template<typename T> GenericUri(const T& uri, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() {
const Ch* u = uri.template Get<const Ch*>(); // TypeHelper from document.h
Parse(u, internal::StrLen<Ch>(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<Ch>(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<typename T> void Get(T& uri, Allocator& allocator) {
uri.template Set<const Ch*>(this->GetString(), allocator); // TypeHelper from document.h
}
const Ch* GetString() const { return uri_; }
SizeType GetStringLength() const { return uri_ == 0 ? 0 : internal::StrLen<Ch>(uri_); }
const Ch* GetBaseString() const { return base_; }
SizeType GetBaseStringLength() const { return base_ == 0 ? 0 : internal::StrLen<Ch>(base_); }
const Ch* GetSchemeString() const { return scheme_; }
SizeType GetSchemeStringLength() const { return scheme_ == 0 ? 0 : internal::StrLen<Ch>(scheme_); }
const Ch* GetAuthString() const { return auth_; }
SizeType GetAuthStringLength() const { return auth_ == 0 ? 0 : internal::StrLen<Ch>(auth_); }
const Ch* GetPathString() const { return path_; }
SizeType GetPathStringLength() const { return path_ == 0 ? 0 : internal::StrLen<Ch>(path_); }
const Ch* GetQueryString() const { return query_; }
SizeType GetQueryStringLength() const { return query_ == 0 ? 0 : internal::StrLen<Ch>(query_); }
const Ch* GetFragString() const { return frag_; }
SizeType GetFragStringLength() const { return frag_ == 0 ? 0 : internal::StrLen<Ch>(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<Ch>(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<Ch*>(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<Value> Uri;
RAPIDJSON_NAMESPACE_END
#if defined(__clang__)
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_URI_H_

View File

@ -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 <new> // placement new
#if defined(CEREAL_RAPIDJSON_SIMD) && defined(_MSC_VER)
#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER)
#include <intrin.h>
#pragma intrinsic(_BitScanForward)
#endif
#ifdef CEREAL_RAPIDJSON_SSE42
#ifdef RAPIDJSON_SSE42
#include <nmmintrin.h>
#elif defined(CEREAL_RAPIDJSON_SSE2)
#elif defined(RAPIDJSON_SSE2)
#include <emmintrin.h>
#endif
#ifdef _MSC_VER
CEREAL_RAPIDJSON_DIAG_PUSH
CEREAL_RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
#elif defined(RAPIDJSON_NEON)
#include <arm_neon.h>
#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<Ch>& 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<Ch>& 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<Level>()->inArray);
RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); // not inside an Object
RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray); // currently inside an Array, not Object
RAPIDJSON_ASSERT(0 == level_stack_.template Top<Level>()->valueCount % 2); // Object has a Key without a Value
level_stack_.template Pop<Level>(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<Level>()->inArray);
RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);
level_stack_.template Pop<Level>(1);
return EndValue(WriteEndArray());
}
@ -236,8 +256,8 @@ 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)); }
//@}
@ -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<size_t>(end - buffer));
for (const char* p = buffer; p != end; ++p)
PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
return true;
}
@ -292,7 +324,7 @@ protected:
const char* end = internal::u32toa(u, buffer);
PutReserve(*os_, static_cast<size_t>(end - buffer));
for (const char* p = buffer; p != end; ++p)
PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
return true;
}
@ -301,7 +333,7 @@ protected:
const char* end = internal::i64toa(i64, buffer);
PutReserve(*os_, static_cast<size_t>(end - buffer));
for (const char* p = buffer; p != end; ++p)
PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
return true;
}
@ -310,7 +342,7 @@ protected:
char* end = internal::u64toa(u64, buffer);
PutReserve(*os_, static_cast<size_t>(end - buffer));
for (char* p = buffer; p != end; ++p)
PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
return true;
}
@ -338,12 +370,12 @@ protected:
char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
PutReserve(*os_, static_cast<size_t>(end - buffer));
for (char* p = buffer; p != end; ++p)
PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*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<unsigned>(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<unsigned>(c) < 256) && CEREAL_RAPIDJSON_UNLIKELY(escape[static_cast<unsigned char>(c)])) {
else if ((sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256) && RAPIDJSON_UNLIKELY(escape[static_cast<unsigned char>(c)])) {
is.Take();
PutUnsafe(*os_, '\\');
PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(escape[static_cast<unsigned char>(c)]));
PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(escape[static_cast<unsigned char>(c)]));
if (escape[static_cast<unsigned char>(c)] == 'u') {
PutUnsafe(*os_, '0');
PutUnsafe(*os_, '0');
@ -407,7 +439,7 @@ protected:
PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) & 0xF]);
}
}
else if (CEREAL_RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ?
else if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ?
Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) :
Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_))))
return false;
@ -417,7 +449,7 @@ protected:
}
bool ScanWriteUnescapedString(GenericStringStream<SourceEncoding>& 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<SourceEncoding> is(json);
while (RAPIDJSON_LIKELY(is.Tell() < length)) {
RAPIDJSON_ASSERT(is.Peek() != '\0');
if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ?
Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) :
Transcoder<SourceEncoding, TargetEncoding>::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<Level>();
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<StringBuffer>::WriteUint64(uint64_t u) {
template<>
inline bool Writer<StringBuffer>::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<StringBuffer>::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<StringBuffer>::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<StringBuffer>::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<StringBuffer>::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<const __m128i *>(&dquote[0]));
const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
@ -570,10 +606,10 @@ inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, siz
const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(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<unsigned short>(_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<StringBuffer>::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<StringBuffer>::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<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
const char* endAligned = reinterpret_cast<const char*>(reinterpret_cast<size_t>(end) & static_cast<size_t>(~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<const uint8_t *>(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<char*>(os_->PushUnsafe(len));
for (size_t i = 0; i < len; i++)
q[i] = p[i];
p += len;
break;
}
vst1q_u8(reinterpret_cast<uint8_t *>(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_