diff --git a/cpp/CHANGELOG.md b/cpp/CHANGELOG.md index 7d08d56ebe..19e96e9662 100644 --- a/cpp/CHANGELOG.md +++ b/cpp/CHANGELOG.md @@ -67,6 +67,7 @@ Please mark all change in change log and use the ticket from JIRA. - MS-422 - Support DeleteTask in Multi-GpuResource case - MS-428 - Add PushTaskByDataLocality in scheduler - MS-440 - Add DumpTaskTables in sdk +- MS-442 - Merge Knowhere ## New Feature - MS-343 - Implement ResourceMgr diff --git a/cpp/build.sh b/cpp/build.sh index 500eac6c67..f61a5ea2e9 100755 --- a/cpp/build.sh +++ b/cpp/build.sh @@ -10,7 +10,7 @@ DB_PATH="/opt/milvus" PROFILING="OFF" BUILD_FAISS_WITH_MKL="OFF" USE_JFROG_CACHE="OFF" -KNOWHERE_BUILD_DIR="`pwd`/thirdparty/knowhere/cmake_build" +KNOWHERE_BUILD_DIR="`pwd`/src/core/cmake_build" while getopts "p:d:t:k:uhlrcgmj" arg do diff --git a/cpp/src/core/.gitignore b/cpp/src/core/.gitignore new file mode 100644 index 0000000000..c263e61d36 --- /dev/null +++ b/cpp/src/core/.gitignore @@ -0,0 +1 @@ +cmake_build \ No newline at end of file diff --git a/cpp/src/core/CMakeLists.txt b/cpp/src/core/CMakeLists.txt new file mode 100644 index 0000000000..1024a71e71 --- /dev/null +++ b/cpp/src/core/CMakeLists.txt @@ -0,0 +1,75 @@ +#------------------------------------------------------------------------------- +# Copyright 上海赜睿信息科技有限公司(Zilliz) - All Rights Reserved +# Unauthorized copying of this file, via any medium is strictly prohibited. +# Proprietary and confidential. +#------------------------------------------------------------------------------- + +cmake_minimum_required(VERSION 3.14) +message(STATUS "Building using CMake version: ${CMAKE_VERSION}") + +set(KNOWHERE_VERSION "0.1.0") +string(REGEX MATCH "^[0-9]+\\.[0-9]+\\.[0-9]+" KNOWHERE_BASE_VERSION "${KNOWHERE_VERSION}") +project(knowhere VERSION "${KNOWHERE_BASE_VERSION}" LANGUAGES CUDA C CXX) +set(CMAKE_CXX_STANDARD 14) + +set(KNOWHERE_VERSION_MAJOR "${knowhere_VERSION_MAJOR}") +set(KNOWHERE_VERSION_MINOR "${knowhere_VERSION_MINOR}") +set(KNOWHERE_VERSION_PATCH "${knowhere_VERSION_PATCH}") +if(KNOWHERE_VERSION_MAJOR STREQUAL "" + OR KNOWHERE_VERSION_MINOR STREQUAL "" + OR KNOWHERE_VERSION_PATCH STREQUAL "") + message(FATAL_ERROR "Failed to determine Knowhere version from '${KNOWHERE_VERSION}'") +endif() + +message(STATUS "Knowhere version: " + "${KNOWHERE_VERSION_MAJOR}.${KNOWHERE_VERSION_MINOR}.${KNOWHERE_VERSION_PATCH} " + "(full: '${KNOWHERE_VERSION}')") + +# if no build build type is specified, default to release builds +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif(NOT CMAKE_BUILD_TYPE) + +if(CMAKE_BUILD_TYPE STREQUAL "Release") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -fPIC -fopenmp") +else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -g -fPIC -fopenmp") +endif() +MESSAGE(STATUS "CMAKE_CXX_FLAGS" ${CMAKE_CXX_FLAGS}) + +find_package(CUDA) +#set(CUDA_NVCC_FLAGS "${CUDA_NVCC_FLAGS} -Xcompiler -fPIC -std=c++11 -D_FORCE_INLINES --expt-extended-lambda") +#set(CUDA_NVCC_FLAGS "${CUDA_NVCC_FLAGS} -O0 -g") + +if(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)") + message("building milvus_engine on x86 architecture") + set(KNOWHERE_BUILD_ARCH x86_64) +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "(ppc)") + message("building milvus_engine on ppc architecture") + set(KNOWHERE_BUILD_ARCH ppc64le) +else() + message("unknown processor type") + message("CMAKE_SYSTEM_PROCESSOR=${CMAKE_SYSTEM_PROCESSOR}") + set(KNOWHERE_BUILD_ARCH unknown) +endif() + +if(CMAKE_BUILD_TYPE STREQUAL "Release") + set(BUILD_TYPE "release") +else() + set(BUILD_TYPE "debug") +endif() +message(STATUS "Build type = ${BUILD_TYPE}") + +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake") +include(ExternalProject) +include(DefineOptions) +include(BuildUtils) +include(ThirdPartyPackages) + +add_subdirectory(src) + +if(BUILD_UNIT_TEST STREQUAL "ON") + add_subdirectory(test) +endif() + +config_summary() diff --git a/cpp/src/core/build.sh b/cpp/src/core/build.sh new file mode 100755 index 0000000000..a77a16cf0b --- /dev/null +++ b/cpp/src/core/build.sh @@ -0,0 +1,88 @@ +#!/bin/bash + +BUILD_TYPE="Debug" +BUILD_UNITTEST="OFF" +INSTALL_PREFIX=$(pwd)/cmake_build +MAKE_CLEAN="OFF" +PROFILING="OFF" +BUILD_FAISS_WITH_MKL="OFF" +USE_JFROG_CACHE="OFF" + +while getopts "p:d:t:uhrcgmj" arg +do + case $arg in + t) + BUILD_TYPE=$OPTARG # BUILD_TYPE + ;; + u) + echo "Build and run unittest cases" ; + BUILD_UNITTEST="ON"; + ;; + p) + INSTALL_PREFIX=$OPTARG + ;; + r) + if [[ -d cmake_build ]]; then + rm ./cmake_build -r + MAKE_CLEAN="ON" + fi + ;; + g) + PROFILING="ON" + ;; + m) + BUILD_FAISS_WITH_MKL="ON" + ;; + j) + USE_JFROG_CACHE="ON" + ;; + h) # help + echo " + +parameter: +-t: build type(default: Debug) +-u: building unit test options(default: OFF) +-p: install prefix(default: $(pwd)/knowhere) +-r: remove previous build directory(default: OFF) +-g: profiling(default: OFF) +-m: build faiss with MKL(default: OFF) + +usage: +./build.sh -t \${BUILD_TYPE} [-u] [-h] [-g] [-r] [-c] [-m] + " + exit 0 + ;; + ?) + echo "unknown argument" + exit 1 + ;; + esac +done + +if [[ ! -d cmake_build ]]; then + mkdir cmake_build + MAKE_CLEAN="ON" +fi + +cd cmake_build + +CUDA_COMPILER=/usr/local/cuda/bin/nvcc + +if [[ ${MAKE_CLEAN} == "ON" ]]; then + CMAKE_CMD="cmake -DBUILD_UNIT_TEST=${BUILD_UNITTEST} \ + -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} + -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ + -DCMAKE_CUDA_COMPILER=${CUDA_COMPILER} \ + -DMILVUS_ENABLE_PROFILING=${PROFILING} \ + -DBUILD_FAISS_WITH_MKL=${BUILD_FAISS_WITH_MKL} \ + -DUSE_JFROG_CACHE=${USE_JFROG_CACHE} \ + ../" + echo ${CMAKE_CMD} + + ${CMAKE_CMD} + make clean +fi + +make -j 8 || exit 1 + +make install || exit 1 diff --git a/cpp/src/core/cmake/BuildUtils.cmake b/cpp/src/core/cmake/BuildUtils.cmake new file mode 100644 index 0000000000..2d778bf703 --- /dev/null +++ b/cpp/src/core/cmake/BuildUtils.cmake @@ -0,0 +1,199 @@ +# Define a function that check last file modification +function(Check_Last_Modify cache_check_lists_file_path working_dir last_modified_commit_id) + if(EXISTS "${working_dir}") + if(EXISTS "${cache_check_lists_file_path}") + set(GIT_LOG_SKIP_NUM 0) + set(_MATCH_ALL ON CACHE BOOL "Match all") + set(_LOOP_STATUS ON CACHE BOOL "Whether out of loop") + file(STRINGS ${cache_check_lists_file_path} CACHE_IGNORE_TXT) + while(_LOOP_STATUS) + foreach(_IGNORE_ENTRY ${CACHE_IGNORE_TXT}) + if(NOT _IGNORE_ENTRY MATCHES "^[^#]+") + continue() + endif() + + set(_MATCH_ALL OFF) + execute_process(COMMAND git log --no-merges -1 --skip=${GIT_LOG_SKIP_NUM} --name-status --pretty= WORKING_DIRECTORY ${working_dir} OUTPUT_VARIABLE CHANGE_FILES) + if(NOT CHANGE_FILES STREQUAL "") + string(REPLACE "\n" ";" _CHANGE_FILES ${CHANGE_FILES}) + foreach(_FILE_ENTRY ${_CHANGE_FILES}) + string(REGEX MATCH "[^ \t]+$" _FILE_NAME ${_FILE_ENTRY}) + execute_process(COMMAND sh -c "echo ${_FILE_NAME} | grep ${_IGNORE_ENTRY}" RESULT_VARIABLE return_code) + if (return_code EQUAL 0) + execute_process(COMMAND git log --no-merges -1 --skip=${GIT_LOG_SKIP_NUM} --pretty=%H WORKING_DIRECTORY ${working_dir} OUTPUT_VARIABLE LAST_MODIFIED_COMMIT_ID) + set (${last_modified_commit_id} ${LAST_MODIFIED_COMMIT_ID} PARENT_SCOPE) + set(_LOOP_STATUS OFF) + endif() + endforeach() + else() + set(_LOOP_STATUS OFF) + endif() + endforeach() + + if(_MATCH_ALL) + execute_process(COMMAND git log --no-merges -1 --skip=${GIT_LOG_SKIP_NUM} --pretty=%H WORKING_DIRECTORY ${working_dir} OUTPUT_VARIABLE LAST_MODIFIED_COMMIT_ID) + set (${last_modified_commit_id} ${LAST_MODIFIED_COMMIT_ID} PARENT_SCOPE) + set(_LOOP_STATUS OFF) + endif() + + math(EXPR GIT_LOG_SKIP_NUM "${GIT_LOG_SKIP_NUM} + 1") + endwhile(_LOOP_STATUS) + else() + execute_process(COMMAND git log --no-merges -1 --skip=${GIT_LOG_SKIP_NUM} --pretty=%H WORKING_DIRECTORY ${working_dir} OUTPUT_VARIABLE LAST_MODIFIED_COMMIT_ID) + set (${last_modified_commit_id} ${LAST_MODIFIED_COMMIT_ID} PARENT_SCOPE) + endif() + else() + message(FATAL_ERROR "The directory ${working_dir} does not exist") + endif() +endfunction() + +# Define a function that extracts a cached package +function(ExternalProject_Use_Cache project_name package_file install_path) + message(STATUS "Will use cached package file: ${package_file}") + + ExternalProject_Add(${project_name} + DOWNLOAD_COMMAND ${CMAKE_COMMAND} -E echo + "No download step needed (using cached package)" + CONFIGURE_COMMAND ${CMAKE_COMMAND} -E echo + "No configure step needed (using cached package)" + BUILD_COMMAND ${CMAKE_COMMAND} -E echo + "No build step needed (using cached package)" + INSTALL_COMMAND ${CMAKE_COMMAND} -E echo + "No install step needed (using cached package)" + ) + + # We want our tar files to contain the Install/ prefix (not for any + # very special reason, only for consistency and so that we can identify them + # in the extraction logs) which means that we must extract them in the + # binary (top-level build) directory to have them installed in the right + # place for subsequent ExternalProjects to pick them up. It seems that the + # only way to control the working directory is with Add_Step! + ExternalProject_Add_Step(${project_name} extract + ALWAYS 1 + COMMAND + ${CMAKE_COMMAND} -E echo + "Extracting ${package_file} to ${install_path}" + COMMAND + ${CMAKE_COMMAND} -E tar xzvf ${package_file} ${install_path} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) + + ExternalProject_Add_StepTargets(${project_name} extract) +endfunction() + +# Define a function that to create a new cached package +function(ExternalProject_Create_Cache project_name package_file install_path cache_username cache_password cache_path) + if(EXISTS ${package_file}) + message(STATUS "Removing existing package file: ${package_file}") + file(REMOVE ${package_file}) + endif() + + message(STATUS "Will create cached package file: ${package_file}") + + ExternalProject_Add_Step(${project_name} package + DEPENDEES install + BYPRODUCTS ${package_file} + COMMAND ${CMAKE_COMMAND} -E echo "Updating cached package file: ${package_file}" + COMMAND ${CMAKE_COMMAND} -E tar czvf ${package_file} ${install_path} + COMMAND ${CMAKE_COMMAND} -E echo "Uploading package file ${package_file} to ${cache_path}" + COMMAND curl -u${cache_username}:${cache_password} -T ${package_file} ${cache_path} + ) + + ExternalProject_Add_StepTargets(${project_name} package) +endfunction() + +function(ADD_THIRDPARTY_LIB LIB_NAME) + set(options) + set(one_value_args SHARED_LIB STATIC_LIB) + set(multi_value_args DEPS INCLUDE_DIRECTORIES) + cmake_parse_arguments(ARG + "${options}" + "${one_value_args}" + "${multi_value_args}" + ${ARGN}) + if(ARG_UNPARSED_ARGUMENTS) + message(SEND_ERROR "Error: unrecognized arguments: ${ARG_UNPARSED_ARGUMENTS}") + endif() + + if(ARG_STATIC_LIB AND ARG_SHARED_LIB) + if(NOT ARG_STATIC_LIB) + message(FATAL_ERROR "No static or shared library provided for ${LIB_NAME}") + endif() + + set(AUG_LIB_NAME "${LIB_NAME}_static") + add_library(${AUG_LIB_NAME} STATIC IMPORTED) + set_target_properties(${AUG_LIB_NAME} + PROPERTIES IMPORTED_LOCATION "${ARG_STATIC_LIB}") + if(ARG_DEPS) + set_target_properties(${AUG_LIB_NAME} + PROPERTIES INTERFACE_LINK_LIBRARIES "${ARG_DEPS}") + endif() + message(STATUS "Added static library dependency ${AUG_LIB_NAME}: ${ARG_STATIC_LIB}") + if(ARG_INCLUDE_DIRECTORIES) + set_target_properties(${AUG_LIB_NAME} + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES + "${ARG_INCLUDE_DIRECTORIES}") + endif() + + set(AUG_LIB_NAME "${LIB_NAME}_shared") + add_library(${AUG_LIB_NAME} SHARED IMPORTED) + + if(WIN32) + # Mark the ".lib" location as part of a Windows DLL + set_target_properties(${AUG_LIB_NAME} + PROPERTIES IMPORTED_IMPLIB "${ARG_SHARED_LIB}") + else() + set_target_properties(${AUG_LIB_NAME} + PROPERTIES IMPORTED_LOCATION "${ARG_SHARED_LIB}") + endif() + if(ARG_DEPS) + set_target_properties(${AUG_LIB_NAME} + PROPERTIES INTERFACE_LINK_LIBRARIES "${ARG_DEPS}") + endif() + message(STATUS "Added shared library dependency ${AUG_LIB_NAME}: ${ARG_SHARED_LIB}") + if(ARG_INCLUDE_DIRECTORIES) + set_target_properties(${AUG_LIB_NAME} + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES + "${ARG_INCLUDE_DIRECTORIES}") + endif() + elseif(ARG_STATIC_LIB) + set(AUG_LIB_NAME "${LIB_NAME}_static") + add_library(${AUG_LIB_NAME} STATIC IMPORTED) + set_target_properties(${AUG_LIB_NAME} + PROPERTIES IMPORTED_LOCATION "${ARG_STATIC_LIB}") + if(ARG_DEPS) + set_target_properties(${AUG_LIB_NAME} + PROPERTIES INTERFACE_LINK_LIBRARIES "${ARG_DEPS}") + endif() + message(STATUS "Added static library dependency ${AUG_LIB_NAME}: ${ARG_STATIC_LIB}") + if(ARG_INCLUDE_DIRECTORIES) + set_target_properties(${AUG_LIB_NAME} + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES + "${ARG_INCLUDE_DIRECTORIES}") + endif() + elseif(ARG_SHARED_LIB) + set(AUG_LIB_NAME "${LIB_NAME}_shared") + add_library(${AUG_LIB_NAME} SHARED IMPORTED) + + if(WIN32) + # Mark the ".lib" location as part of a Windows DLL + set_target_properties(${AUG_LIB_NAME} + PROPERTIES IMPORTED_IMPLIB "${ARG_SHARED_LIB}") + else() + set_target_properties(${AUG_LIB_NAME} + PROPERTIES IMPORTED_LOCATION "${ARG_SHARED_LIB}") + endif() + message(STATUS "Added shared library dependency ${AUG_LIB_NAME}: ${ARG_SHARED_LIB}") + if(ARG_DEPS) + set_target_properties(${AUG_LIB_NAME} + PROPERTIES INTERFACE_LINK_LIBRARIES "${ARG_DEPS}") + endif() + if(ARG_INCLUDE_DIRECTORIES) + set_target_properties(${AUG_LIB_NAME} + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES + "${ARG_INCLUDE_DIRECTORIES}") + endif() + else() + message(FATAL_ERROR "No static or shared library provided for ${LIB_NAME}") + endif() +endfunction() diff --git a/cpp/src/core/cmake/DefineOptions.cmake b/cpp/src/core/cmake/DefineOptions.cmake new file mode 100644 index 0000000000..589e2d9ae8 --- /dev/null +++ b/cpp/src/core/cmake/DefineOptions.cmake @@ -0,0 +1,164 @@ + +macro(set_option_category name) + set(KNOWHERE_OPTION_CATEGORY ${name}) + list(APPEND "KNOWHERE_OPTION_CATEGORIES" ${name}) +endmacro() + +macro(define_option name description default) + option(${name} ${description} ${default}) + list(APPEND "KNOWHERE_${KNOWHERE_OPTION_CATEGORY}_OPTION_NAMES" ${name}) + set("${name}_OPTION_DESCRIPTION" ${description}) + set("${name}_OPTION_DEFAULT" ${default}) + set("${name}_OPTION_TYPE" "bool") +endmacro() + +function(list_join lst glue out) + if("${${lst}}" STREQUAL "") + set(${out} "" PARENT_SCOPE) + return() + endif() + + list(GET ${lst} 0 joined) + list(REMOVE_AT ${lst} 0) + foreach(item ${${lst}}) + set(joined "${joined}${glue}${item}") + endforeach() + set(${out} ${joined} PARENT_SCOPE) +endfunction() + +macro(define_option_string name description default) + set(${name} ${default} CACHE STRING ${description}) + list(APPEND "KNOWHERE_${KNOWHERE_OPTION_CATEGORY}_OPTION_NAMES" ${name}) + set("${name}_OPTION_DESCRIPTION" ${description}) + set("${name}_OPTION_DEFAULT" "\"${default}\"") + set("${name}_OPTION_TYPE" "string") + + set("${name}_OPTION_ENUM" ${ARGN}) + list_join("${name}_OPTION_ENUM" "|" "${name}_OPTION_ENUM") + if(NOT ("${${name}_OPTION_ENUM}" STREQUAL "")) + set_property(CACHE ${name} PROPERTY STRINGS ${ARGN}) + endif() +endmacro() + +#---------------------------------------------------------------------- +set_option_category("Thirdparty") + +set(KNOWHERE_DEPENDENCY_SOURCE_DEFAULT "AUTO") + +define_option_string(KNOWHERE_DEPENDENCY_SOURCE + "Method to use for acquiring KNOWHERE's build dependencies" + "${KNOWHERE_DEPENDENCY_SOURCE_DEFAULT}" + "AUTO" + "BUNDLED" + "SYSTEM") + +define_option(KNOWHERE_VERBOSE_THIRDPARTY_BUILD + "Show output from ExternalProjects rather than just logging to files" ON) + +define_option(KNOWHERE_BOOST_USE_SHARED "Rely on boost shared libraries where relevant" OFF) + +define_option(KNOWHERE_BOOST_VENDORED "Use vendored Boost instead of existing Boost. \ +Note that this requires linking Boost statically" OFF) + +define_option(KNOWHERE_BOOST_HEADER_ONLY "Use only BOOST headers" OFF) + +define_option(KNOWHERE_WITH_ARROW "Build with ARROW" ON) + +define_option(KNOWHERE_WITH_LAPACK "Build with LAPACK library" ON) + +define_option(KNOWHERE_WITH_FAISS "Build with FAISS library" ON) + +define_option(KNOWHERE_WITH_FAISS_GPU_VERSION "Build with FAISS GPU version" ON) + +define_option(KNOWHERE_WITH_OPENBLAS "Build with OpenBLAS library" ON) + +#---------------------------------------------------------------------- +if(MSVC) + set_option_category("MSVC") + + define_option(MSVC_LINK_VERBOSE + "Pass verbose linking options when linking libraries and executables" + OFF) + + define_option(KNOWHERE_USE_STATIC_CRT "Build KNOWHERE with statically linked CRT" OFF) +endif() + +#---------------------------------------------------------------------- +set_option_category("Test and benchmark") + +if (BUILD_UNIT_TEST) + define_option(KNOWHERE_BUILD_TESTS "Build the KNOWHERE googletest unit tests" ON) +else() + define_option(KNOWHERE_BUILD_TESTS "Build the KNOWHERE googletest unit tests" OFF) +endif(BUILD_UNIT_TEST) + +#---------------------------------------------------------------------- +macro(config_summary) + message(STATUS "---------------------------------------------------------------------") + message(STATUS "KNOWHERE version: ${KNOWHERE_VERSION}") + message(STATUS) + message(STATUS "Build configuration summary:") + + message(STATUS " Generator: ${CMAKE_GENERATOR}") + message(STATUS " Build type: ${CMAKE_BUILD_TYPE}") + message(STATUS " Source directory: ${CMAKE_CURRENT_SOURCE_DIR}") + if(${CMAKE_EXPORT_COMPILE_COMMANDS}) + message( + STATUS " Compile commands: ${CMAKE_CURRENT_BINARY_DIR}/compile_commands.json") + endif() + + foreach(category ${KNOWHERE_OPTION_CATEGORIES}) + + message(STATUS) + message(STATUS "${category} options:") + + set(option_names ${KNOWHERE_${category}_OPTION_NAMES}) + + set(max_value_length 0) + foreach(name ${option_names}) + string(LENGTH "\"${${name}}\"" value_length) + if(${max_value_length} LESS ${value_length}) + set(max_value_length ${value_length}) + endif() + endforeach() + + foreach(name ${option_names}) + if("${${name}_OPTION_TYPE}" STREQUAL "string") + set(value "\"${${name}}\"") + else() + set(value "${${name}}") + endif() + + set(default ${${name}_OPTION_DEFAULT}) + set(description ${${name}_OPTION_DESCRIPTION}) + string(LENGTH ${description} description_length) + if(${description_length} LESS 70) + string( + SUBSTRING + " " + ${description_length} -1 description_padding) + else() + set(description_padding " + ") + endif() + + set(comment "[${name}]") + + if("${value}" STREQUAL "${default}") + set(comment "[default] ${comment}") + endif() + + if(NOT ("${${name}_OPTION_ENUM}" STREQUAL "")) + set(comment "${comment} [${${name}_OPTION_ENUM}]") + endif() + + string( + SUBSTRING "${value} " + 0 ${max_value_length} value) + + message(STATUS " ${description} ${description_padding} ${value} ${comment}") + endforeach() + + endforeach() + +endmacro() diff --git a/cpp/src/core/cmake/ThirdPartyPackages.cmake b/cpp/src/core/cmake/ThirdPartyPackages.cmake new file mode 100644 index 0000000000..981e1bd558 --- /dev/null +++ b/cpp/src/core/cmake/ThirdPartyPackages.cmake @@ -0,0 +1,1017 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. + +set(KNOWHERE_THIRDPARTY_DEPENDENCIES + + ARROW + BOOST + FAISS + GTest + LAPACK + OpenBLAS + ) + +message(STATUS "Using ${KNOWHERE_DEPENDENCY_SOURCE} approach to find dependencies") + +# For each dependency, set dependency source to global default, if unset +foreach(DEPENDENCY ${KNOWHERE_THIRDPARTY_DEPENDENCIES}) + if("${${DEPENDENCY}_SOURCE}" STREQUAL "") + set(${DEPENDENCY}_SOURCE ${KNOWHERE_DEPENDENCY_SOURCE}) + endif() +endforeach() + +macro(build_dependency DEPENDENCY_NAME) + if("${DEPENDENCY_NAME}" STREQUAL "ARROW") + build_arrow() + elseif("${DEPENDENCY_NAME}" STREQUAL "LAPACK") + build_lapack() + elseif ("${DEPENDENCY_NAME}" STREQUAL "GTest") + build_gtest() + elseif ("${DEPENDENCY_NAME}" STREQUAL "OpenBLAS") + build_openblas() + elseif("${DEPENDENCY_NAME}" STREQUAL "FAISS") + build_faiss() + else() + message(FATAL_ERROR "Unknown thirdparty dependency to build: ${DEPENDENCY_NAME}") + endif () +endmacro() + +macro(resolve_dependency DEPENDENCY_NAME) + if (${DEPENDENCY_NAME}_SOURCE STREQUAL "AUTO") + #message(STATUS "Finding ${DEPENDENCY_NAME} package") +# find_package(${DEPENDENCY_NAME} QUIET) +# if (NOT ${DEPENDENCY_NAME}_FOUND) + #message(STATUS "${DEPENDENCY_NAME} package not found") + build_dependency(${DEPENDENCY_NAME}) +# endif () + elseif (${DEPENDENCY_NAME}_SOURCE STREQUAL "BUNDLED") + build_dependency(${DEPENDENCY_NAME}) + elseif (${DEPENDENCY_NAME}_SOURCE STREQUAL "SYSTEM") + find_package(${DEPENDENCY_NAME} REQUIRED) + endif () +endmacro() + +# ---------------------------------------------------------------------- +# Identify OS +if (UNIX) + if (APPLE) + set (CMAKE_OS_NAME "osx" CACHE STRING "Operating system name" FORCE) + else (APPLE) + ## Check for Debian GNU/Linux ________________ + find_file (DEBIAN_FOUND debian_version debconf.conf + PATHS /etc + ) + if (DEBIAN_FOUND) + set (CMAKE_OS_NAME "debian" CACHE STRING "Operating system name" FORCE) + endif (DEBIAN_FOUND) + ## Check for Fedora _________________________ + find_file (FEDORA_FOUND fedora-release + PATHS /etc + ) + if (FEDORA_FOUND) + set (CMAKE_OS_NAME "fedora" CACHE STRING "Operating system name" FORCE) + endif (FEDORA_FOUND) + ## Check for RedHat _________________________ + find_file (REDHAT_FOUND redhat-release inittab.RH + PATHS /etc + ) + if (REDHAT_FOUND) + set (CMAKE_OS_NAME "redhat" CACHE STRING "Operating system name" FORCE) + endif (REDHAT_FOUND) + ## Extra check for Ubuntu ____________________ + if (DEBIAN_FOUND) + ## At its core Ubuntu is a Debian system, with + ## a slightly altered configuration; hence from + ## a first superficial inspection a system will + ## be considered as Debian, which signifies an + ## extra check is required. + find_file (UBUNTU_EXTRA legal issue + PATHS /etc + ) + if (UBUNTU_EXTRA) + ## Scan contents of file + file (STRINGS ${UBUNTU_EXTRA} UBUNTU_FOUND + REGEX Ubuntu + ) + ## Check result of string search + if (UBUNTU_FOUND) + set (CMAKE_OS_NAME "ubuntu" CACHE STRING "Operating system name" FORCE) + set (DEBIAN_FOUND FALSE) + endif (UBUNTU_FOUND) + endif (UBUNTU_EXTRA) + endif (DEBIAN_FOUND) + endif (APPLE) +endif (UNIX) + + +# ---------------------------------------------------------------------- +# thirdparty directory +set(THIRDPARTY_DIR "${CMAKE_SOURCE_DIR}/thirdparty") + +# ---------------------------------------------------------------------- +# JFrog +if(NOT DEFINED USE_JFROG_CACHE) + set(USE_JFROG_CACHE "OFF") +endif() +if(USE_JFROG_CACHE STREQUAL "ON") + set(JFROG_ARTFACTORY_CACHE_URL "http://192.168.1.201:80/artifactory/generic-local/milvus/thirdparty/cache/${CMAKE_OS_NAME}/${KNOWHERE_BUILD_ARCH}/${BUILD_TYPE}") + set(JFROG_USER_NAME "test") + set(JFROG_PASSWORD "Fantast1c") + set(THIRDPARTY_PACKAGE_CACHE "${THIRDPARTY_DIR}/cache") +endif() + +macro(resolve_dependency DEPENDENCY_NAME) + if (${DEPENDENCY_NAME}_SOURCE STREQUAL "AUTO") + #disable find_package for now + build_dependency(${DEPENDENCY_NAME}) + elseif (${DEPENDENCY_NAME}_SOURCE STREQUAL "BUNDLED") + build_dependency(${DEPENDENCY_NAME}) + elseif (${DEPENDENCY_NAME}_SOURCE STREQUAL "SYSTEM") + find_package(${DEPENDENCY_NAME} REQUIRED) + endif () +endmacro() + +# ---------------------------------------------------------------------- +# ExternalProject options + +string(TOUPPER ${CMAKE_BUILD_TYPE} UPPERCASE_BUILD_TYPE) + +set(EP_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${UPPERCASE_BUILD_TYPE}}") +set(EP_C_FLAGS "${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_${UPPERCASE_BUILD_TYPE}}") + +if(NOT MSVC) + # Set -fPIC on all external projects + set(EP_CXX_FLAGS "${EP_CXX_FLAGS} -fPIC") + set(EP_C_FLAGS "${EP_C_FLAGS} -fPIC") +endif() + +# CC/CXX environment variables are captured on the first invocation of the +# builder (e.g make or ninja) instead of when CMake is invoked into to build +# directory. This leads to issues if the variables are exported in a subshell +# and the invocation of make/ninja is in distinct subshell without the same +# environment (CC/CXX). +set(EP_COMMON_TOOLCHAIN -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} + -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}) + +if(CMAKE_AR) + set(EP_COMMON_TOOLCHAIN ${EP_COMMON_TOOLCHAIN} -DCMAKE_AR=${CMAKE_AR}) +endif() + +if(CMAKE_RANLIB) + set(EP_COMMON_TOOLCHAIN ${EP_COMMON_TOOLCHAIN} -DCMAKE_RANLIB=${CMAKE_RANLIB}) +endif() + +# External projects are still able to override the following declarations. +# cmake command line will favor the last defined variable when a duplicate is +# encountered. This requires that `EP_COMMON_CMAKE_ARGS` is always the first +# argument. +set(EP_COMMON_CMAKE_ARGS + ${EP_COMMON_TOOLCHAIN} + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + -DCMAKE_C_FLAGS=${EP_C_FLAGS} + -DCMAKE_C_FLAGS_${UPPERCASE_BUILD_TYPE}=${EP_C_FLAGS} + -DCMAKE_CXX_FLAGS=${EP_CXX_FLAGS} + -DCMAKE_CXX_FLAGS_${UPPERCASE_BUILD_TYPE}=${EP_CXX_FLAGS}) + +if(NOT KNOWHERE_VERBOSE_THIRDPARTY_BUILD) + set(EP_LOG_OPTIONS LOG_CONFIGURE 1 LOG_BUILD 1 LOG_INSTALL 1 LOG_DOWNLOAD 1) +else() + set(EP_LOG_OPTIONS) +endif() + +# Ensure that a default make is set +if("${MAKE}" STREQUAL "") + if(NOT MSVC) + find_program(MAKE make) + endif() +endif() + +set(MAKE_BUILD_ARGS "-j8") + +## Using make -j in sub-make is fragile +## see discussion https://github.com/apache/KNOWHERE/pull/2779 +#if(${CMAKE_GENERATOR} MATCHES "Makefiles") +# set(MAKE_BUILD_ARGS "") +#else() +# # limit the maximum number of jobs for ninja +# set(MAKE_BUILD_ARGS "-j4") +#endif() + +# ---------------------------------------------------------------------- +# Find pthreads + +set(THREADS_PREFER_PTHREAD_FLAG ON) +find_package(Threads REQUIRED) + +# ---------------------------------------------------------------------- +# Versions and URLs for toolchain builds, which also can be used to configure +# offline builds + +# Read toolchain versions from cpp/thirdparty/versions.txt +file(STRINGS "${THIRDPARTY_DIR}/versions.txt" TOOLCHAIN_VERSIONS_TXT) +foreach(_VERSION_ENTRY ${TOOLCHAIN_VERSIONS_TXT}) + # Exclude comments + if(NOT _VERSION_ENTRY MATCHES "^[^#][A-Za-z0-9-_]+_VERSION=") + continue() + endif() + + string(REGEX MATCH "^[^=]*" _LIB_NAME ${_VERSION_ENTRY}) + string(REPLACE "${_LIB_NAME}=" "" _LIB_VERSION ${_VERSION_ENTRY}) + + # Skip blank or malformed lines + if(${_LIB_VERSION} STREQUAL "") + continue() + endif() + + # For debugging + #message(STATUS "${_LIB_NAME}: ${_LIB_VERSION}") + + set(${_LIB_NAME} "${_LIB_VERSION}") +endforeach() + +if(DEFINED ENV{KNOWHERE_BOOST_URL}) + set(BOOST_SOURCE_URL "$ENV{KNOWHERE_BOOST_URL}") +else() + string(REPLACE "." "_" BOOST_VERSION_UNDERSCORES ${BOOST_VERSION}) + set(BOOST_SOURCE_URL + "https://dl.bintray.com/boostorg/release/${BOOST_VERSION}/source/boost_${BOOST_VERSION_UNDERSCORES}.tar.gz" + ) +endif() + +if(DEFINED ENV{KNOWHERE_FAISS_URL}) + set(FAISS_SOURCE_URL "$ENV{KNOWHERE_FAISS_URL}") +else() + set(FAISS_SOURCE_URL "http://192.168.1.105:6060/jinhai/faiss/-/archive/${FAISS_VERSION}/faiss-${FAISS_VERSION}.tar.gz") +# set(FAISS_SOURCE_URL "https://github.com/facebookresearch/faiss/archive/${FAISS_VERSION}.tar.gz") +# set(FAISS_SOURCE_URL "${CMAKE_SOURCE_DIR}/thirdparty/faiss-1.5.3") + message(STATUS ${FAISS_SOURCE_URL}) +endif() +set(FAISS_MD5 "a589663865a8558205533c8ac414278c") + +if(DEFINED ENV{KNOWHERE_ARROW_URL}) + set(ARROW_SOURCE_URL "$ENV{KNOWHERE_ARROW_URL}") +else() + set(ARROW_SOURCE_URL + "https://github.com/apache/arrow.git" + ) +endif() + +if (DEFINED ENV{KNOWHERE_GTEST_URL}) + set(GTEST_SOURCE_URL "$ENV{KNOWHERE_GTEST_URL}") +else () + set(GTEST_SOURCE_URL + "https://github.com/google/googletest/archive/release-${GTEST_VERSION}.tar.gz") +endif() +set(GTEST_MD5 "2e6fbeb6a91310a16efe181886c59596") + +if(DEFINED ENV{KNOWHERE_LAPACK_URL}) + set(LAPACK_SOURCE_URL "$ENV{KNOWHERE_LAPACK_URL}") +else() + set(LAPACK_SOURCE_URL "https://github.com/Reference-LAPACK/lapack/archive/${LAPACK_VERSION}.tar.gz") +endif() +set(LAPACK_MD5 "96591affdbf58c450d45c1daa540dbd2") + +if (DEFINED ENV{KNOWHERE_OPENBLAS_URL}) + set(OPENBLAS_SOURCE_URL "$ENV{KNOWHERE_OPENBLAS_URL}") +else () + set(OPENBLAS_SOURCE_URL + "https://github.com/xianyi/OpenBLAS/archive/${OPENBLAS_VERSION}.tar.gz") +endif() +set(OPENBLAS_MD5 "8a110a25b819a4b94e8a9580702b6495") + +# ---------------------------------------------------------------------- +# ARROW + +macro(build_arrow) + message(STATUS "Building Apache ARROW-${ARROW_VERSION} from source") + set(ARROW_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/arrow_ep-prefix/src/arrow_ep/cpp") + set(ARROW_STATIC_LIB_NAME arrow) +# set(PARQUET_STATIC_LIB_NAME parquet) + # set(ARROW_CUDA_STATIC_LIB_NAME arrow_cuda) + set(ARROW_STATIC_LIB + "${ARROW_PREFIX}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}${ARROW_STATIC_LIB_NAME}${CMAKE_STATIC_LIBRARY_SUFFIX}" + ) +# set(PARQUET_STATIC_LIB +# "${ARROW_PREFIX}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}${PARQUET_STATIC_LIB_NAME}${CMAKE_STATIC_LIBRARY_SUFFIX}" +# ) + # set(ARROW_CUDA_STATIC_LIB + # "${ARROW_PREFIX}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}${ARROW_CUDA_STATIC_LIB_NAME}${CMAKE_STATIC_LIBRARY_SUFFIX}" + # ) + set(ARROW_INCLUDE_DIR "${ARROW_PREFIX}/include") + + set(ARROW_CMAKE_ARGS + ${EP_COMMON_CMAKE_ARGS} + # "-DARROW_THRIFT_URL=${THRIFT_SOURCE_URL}" + #"env ARROW_THRIFT_URL=${THRIFT_SOURCE_URL}" + -DARROW_BUILD_STATIC=ON + -DARROW_BUILD_SHARED=OFF + -DARROW_PARQUET=OFF + -DARROW_USE_GLOG=OFF + -DCMAKE_INSTALL_PREFIX=${ARROW_PREFIX} + "-DCMAKE_LIBRARY_PATH=${CUDA_TOOLKIT_ROOT_DIR}/lib64/stubs" + -DCMAKE_BUILD_TYPE=Release + -DARROW_DEPENDENCY_SOURCE=BUNDLED) #Build all arrow dependencies from source instead of calling find_package first + + # set($ENV{ARROW_THRIFT_URL} ${THRIFT_SOURCE_URL}) + + if(USE_JFROG_CACHE STREQUAL "ON") + execute_process(COMMAND sh -c "git ls-remote --heads --tags ${ARROW_SOURCE_URL} ${ARROW_VERSION} | cut -f 1" OUTPUT_VARIABLE ARROW_LAST_COMMIT_ID) + if(${ARROW_LAST_COMMIT_ID} MATCHES "^[^#][a-z0-9]+") + string(MD5 ARROW_COMBINE_MD5 "${ARROW_LAST_COMMIT_ID}") + set(ARROW_CACHE_PACKAGE_NAME "arrow_${ARROW_COMBINE_MD5}.tar.gz") + set(ARROW_CACHE_URL "${JFROG_ARTFACTORY_CACHE_URL}/${ARROW_CACHE_PACKAGE_NAME}") + set(ARROW_CACHE_PACKAGE_PATH "${THIRDPARTY_PACKAGE_CACHE}/${ARROW_CACHE_PACKAGE_NAME}") + + execute_process(COMMAND wget -q --method HEAD ${ARROW_CACHE_URL} RESULT_VARIABLE return_code) + message(STATUS "Check the remote file ${ARROW_CACHE_URL}. return code = ${return_code}") + if (NOT return_code EQUAL 0) + externalproject_add(arrow_ep + GIT_REPOSITORY + ${ARROW_SOURCE_URL} + GIT_TAG + ${ARROW_VERSION} + GIT_SHALLOW + TRUE + SOURCE_SUBDIR + cpp + ${EP_LOG_OPTIONS} + CMAKE_ARGS + ${ARROW_CMAKE_ARGS} + BUILD_COMMAND + ${MAKE} + ${MAKE_BUILD_ARGS} + INSTALL_COMMAND + ${MAKE} install + BUILD_BYPRODUCTS + "${ARROW_STATIC_LIB}" + ) + + ExternalProject_Create_Cache(arrow_ep ${ARROW_CACHE_PACKAGE_PATH} "${CMAKE_CURRENT_BINARY_DIR}/arrow_ep-prefix" ${JFROG_USER_NAME} ${JFROG_PASSWORD} ${ARROW_CACHE_URL}) + else() + file(DOWNLOAD ${ARROW_CACHE_URL} ${ARROW_CACHE_PACKAGE_PATH} STATUS status) + list(GET status 0 status_code) + message(STATUS "DOWNLOADING FROM ${ARROW_CACHE_URL} TO ${ARROW_CACHE_PACKAGE_PATH}. STATUS = ${status_code}") + if (status_code EQUAL 0) + ExternalProject_Use_Cache(arrow_ep ${ARROW_CACHE_PACKAGE_PATH} ${CMAKE_CURRENT_BINARY_DIR}) + endif() + endif() + else() + message(FATAL_ERROR "The last commit ID of \"${ARROW_SOURCE_URL}\" repository don't match!") + endif() + else() + externalproject_add(arrow_ep + GIT_REPOSITORY + ${ARROW_SOURCE_URL} + GIT_TAG + ${ARROW_VERSION} + GIT_SHALLOW + TRUE + SOURCE_SUBDIR + cpp + ${EP_LOG_OPTIONS} + CMAKE_ARGS + ${ARROW_CMAKE_ARGS} + BUILD_COMMAND + ${MAKE} + ${MAKE_BUILD_ARGS} + INSTALL_COMMAND + ${MAKE} install + BUILD_BYPRODUCTS + "${ARROW_STATIC_LIB}" + ) + endif() + + file(MAKE_DIRECTORY "${ARROW_PREFIX}/include") + add_library(arrow STATIC IMPORTED) + set_target_properties(arrow + PROPERTIES IMPORTED_LOCATION "${ARROW_STATIC_LIB}" + INTERFACE_INCLUDE_DIRECTORIES "${ARROW_INCLUDE_DIR}") + # INTERFACE_LINK_LIBRARIES thrift) + add_dependencies(arrow arrow_ep) + + set(JEMALLOC_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/arrow_ep-prefix/src/arrow_ep-build/jemalloc_ep-prefix/src/jemalloc_ep") + + add_custom_command(TARGET arrow_ep POST_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory ${ARROW_PREFIX}/lib/ + COMMAND ${CMAKE_COMMAND} -E copy ${JEMALLOC_PREFIX}/lib/libjemalloc_pic.a ${ARROW_PREFIX}/lib/ + DEPENDS ${JEMALLOC_PREFIX}/lib/libjemalloc_pic.a) + +endmacro() + +if(KNOWHERE_WITH_ARROW) + + resolve_dependency(ARROW) + + link_directories(SYSTEM ${ARROW_PREFIX}/lib/) + include_directories(SYSTEM ${ARROW_INCLUDE_DIR}) +endif() + +# ---------------------------------------------------------------------- +# Add Boost dependencies (code adapted from Apache Kudu (incubating)) + +set(Boost_USE_MULTITHREADED ON) +if(MSVC AND KNOWHERE_USE_STATIC_CRT) + set(Boost_USE_STATIC_RUNTIME ON) +endif() +set(Boost_ADDITIONAL_VERSIONS + "1.70.0" + "1.70" + "1.69.0" + "1.69" + "1.68.0" + "1.68" + "1.67.0" + "1.67" + "1.66.0" + "1.66" + "1.65.0" + "1.65" + "1.64.0" + "1.64" + "1.63.0" + "1.63" + "1.62.0" + "1.61" + "1.61.0" + "1.62" + "1.60.0" + "1.60") + +# TODO +if(KNOWHERE_BOOST_VENDORED) +# system thread serialization wserialization regex + set(BOOST_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/boost_ep-prefix/src/boost_ep") + set(BOOST_LIB_DIR "${BOOST_PREFIX}/stage/lib") + set(BOOST_BUILD_LINK "static") + set(BOOST_STATIC_SYSTEM_LIBRARY + "${BOOST_LIB_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}boost_system${CMAKE_STATIC_LIBRARY_SUFFIX}" + ) + set(BOOST_STATIC_FILESYSTEM_LIBRARY + "${BOOST_LIB_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}boost_filesystem${CMAKE_STATIC_LIBRARY_SUFFIX}" + ) + set(BOOST_STATIC_SERIALIZATION_LIBRARY + "${BOOST_LIB_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}boost_serialization${CMAKE_STATIC_LIBRARY_SUFFIX}" + ) + set(BOOST_STATIC_WSERIALIZATION_LIBRARY + "${BOOST_LIB_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}boost_wserialization${CMAKE_STATIC_LIBRARY_SUFFIX}" + ) + set(BOOST_STATIC_REGEX_LIBRARY + "${BOOST_LIB_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}boost_regex${CMAKE_STATIC_LIBRARY_SUFFIX}" + ) + set(BOOST_STATIC_THREAD_LIBRARY + "${BOOST_LIB_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}boost_thread${CMAKE_STATIC_LIBRARY_SUFFIX}" + ) + set(BOOST_SYSTEM_LIBRARY boost_system_static) + set(BOOST_FILESYSTEM_LIBRARY boost_filesystem_static) + set(BOOST_SERIALIZATION_LIBRARY boost_serialization_static) + set(BOOST_WSERIALIZATION_LIBRARY boost_wserialization_static) + set(BOOST_REGEX_LIBRARY boost_regex_static) + set(BOOST_THREAD_LIBRARY boost_thread_static) + + if(KNOWHERE_BOOST_HEADER_ONLY) + set(BOOST_BUILD_PRODUCTS) + set(BOOST_CONFIGURE_COMMAND "") + set(BOOST_BUILD_COMMAND "") + else() + set(BOOST_BUILD_PRODUCTS ${BOOST_STATIC_SYSTEM_LIBRARY} + ${BOOST_STATIC_FILESYSTEM_LIBRARY} ${BOOST_STATIC_SERIALIZATION_LIBRARY} + ${BOOST_STATIC_WSERIALIZATION_LIBRARY} ${BOOST_STATIC_REGEX_LIBRARY} + ${BOOST_STATIC_THREAD_LIBRARY}) + set(BOOST_CONFIGURE_COMMAND "./bootstrap.sh" "--prefix=${BOOST_PREFIX}" + "--with-libraries=filesystem,serialization,wserialization,system,thread,regex") + if("${CMAKE_BUILD_TYPE}" STREQUAL "DEBUG") + set(BOOST_BUILD_VARIANT "debug") + else() + set(BOOST_BUILD_VARIANT "release") + endif() + set(BOOST_BUILD_COMMAND + "./b2" + "link=${BOOST_BUILD_LINK}" + "variant=${BOOST_BUILD_VARIANT}" + "cxxflags=-fPIC") + + add_thirdparty_lib(boost_system STATIC_LIB "${BOOST_STATIC_SYSTEM_LIBRARY}") + + add_thirdparty_lib(boost_filesystem STATIC_LIB "${BOOST_STATIC_FILESYSTEM_LIBRARY}") + + add_thirdparty_lib(boost_serialization STATIC_LIB "${BOOST_STATIC_SERIALIZATION_LIBRARY}") + + add_thirdparty_lib(boost_wserialization STATIC_LIB "${BOOST_STATIC_WSERIALIZATION_LIBRARY}") + + add_thirdparty_lib(boost_regex STATIC_LIB "${BOOST_STATIC_REGEX_LIBRARY}") + + add_thirdparty_lib(boost_thread STATIC_LIB "${BOOST_STATIC_THREAD_LIBRARY}") + + set(KNOWHERE_BOOST_LIBS ${BOOST_SYSTEM_LIBRARY} ${BOOST_FILESYSTEM_LIBRARY} ${BOOST_SERIALIZATION_LIBRARY} + ${BOOST_WSERIALIZATION_LIBRARY} ${BOOST_REGEX_LIBRARY} ${BOOST_THREAD_LIBRARY}) + endif() + externalproject_add(boost_ep + URL + ${BOOST_SOURCE_URL} + BUILD_BYPRODUCTS + ${BOOST_BUILD_PRODUCTS} + BUILD_IN_SOURCE + 1 + CONFIGURE_COMMAND + ${BOOST_CONFIGURE_COMMAND} + BUILD_COMMAND + ${BOOST_BUILD_COMMAND} + INSTALL_COMMAND + "" + ${EP_LOG_OPTIONS}) + set(Boost_INCLUDE_DIR "${BOOST_PREFIX}") + set(Boost_INCLUDE_DIRS "${BOOST_INCLUDE_DIR}") + add_dependencies(boost_system_static boost_ep) + add_dependencies(boost_filesystem_static boost_ep) + add_dependencies(boost_serialization_static boost_ep) + add_dependencies(boost_wserialization_static boost_ep) + add_dependencies(boost_regex_static boost_ep) + add_dependencies(boost_thread_static boost_ep) + +#else() +# if(MSVC) +# # disable autolinking in boost +# add_definitions(-DBOOST_ALL_NO_LIB) +# endif() + +# if(DEFINED ENV{BOOST_ROOT} OR DEFINED BOOST_ROOT) +# # In older versions of CMake (such as 3.2), the system paths for Boost will +# # In older versions of CMake (such as 3.2), the system paths for Boost will +# # be looked in first even if we set $BOOST_ROOT or pass -DBOOST_ROOT +# set(Boost_NO_SYSTEM_PATHS ON) +# endif() + +# if(KNOWHERE_BOOST_USE_SHARED) +# # Find shared Boost libraries. +# set(Boost_USE_STATIC_LIBS OFF) +# set(BUILD_SHARED_LIBS_KEEP ${BUILD_SHARED_LIBS}) +# set(BUILD_SHARED_LIBS ON) +# +# if(MSVC) +# # force all boost libraries to dynamic link +# add_definitions(-DBOOST_ALL_DYN_LINK) +# endif() +# +# if(KNOWHERE_BOOST_HEADER_ONLY) +# find_package(Boost REQUIRED) +# else() +# find_package(Boost COMPONENTS serialization system filesystem REQUIRED) +# set(BOOST_SYSTEM_LIBRARY Boost::system) +# set(BOOST_FILESYSTEM_LIBRARY Boost::filesystem) +# set(BOOST_SERIALIZATION_LIBRARY Boost::serialization) +# set(KNOWHERE_BOOST_LIBS ${BOOST_SYSTEM_LIBRARY} ${BOOST_FILESYSTEM_LIBRARY}) +# endif() +# set(BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS_KEEP}) +# unset(BUILD_SHARED_LIBS_KEEP) +# else() +# # Find static boost headers and libs +# # TODO Differentiate here between release and debug builds +# set(Boost_USE_STATIC_LIBS ON) +# if(KNOWHERE_BOOST_HEADER_ONLY) +# find_package(Boost REQUIRED) +# else() +# find_package(Boost COMPONENTS serialization system filesystem REQUIRED) +# set(BOOST_SYSTEM_LIBRARY Boost::system) +# set(BOOST_FILESYSTEM_LIBRARY Boost::filesystem) +# set(BOOST_SERIALIZATION_LIBRARY Boost::serialization) +# set(KNOWHERE_BOOST_LIBS ${BOOST_SYSTEM_LIBRARY} ${BOOST_FILESYSTEM_LIBRARY}) +# endif() +# endif() +endif() + +#message(STATUS "Boost include dir: " ${Boost_INCLUDE_DIR}) +#message(STATUS "Boost libraries: " ${Boost_LIBRARIES}) + +include_directories(SYSTEM ${Boost_INCLUDE_DIR}) +link_directories(SYSTEM ${BOOST_LIB_DIR}) + +# ---------------------------------------------------------------------- +# OpenBLAS + +macro(build_openblas) + message(STATUS "Building OpenBLAS-${OPENBLAS_VERSION} from source") + set(OPENBLAS_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/openblas_ep-prefix/src/openblas_ep") + set(OPENBLAS_INCLUDE_DIR "${OPENBLAS_PREFIX}/include") + set(OPENBLAS_STATIC_LIB + "${OPENBLAS_PREFIX}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}openblas${CMAKE_STATIC_LIBRARY_SUFFIX}") + set(OPENBLAS_REAL_STATIC_LIB + "${OPENBLAS_PREFIX}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}openblas_haswellp-r0.3.6${CMAKE_STATIC_LIBRARY_SUFFIX}") + + if(USE_JFROG_CACHE STREQUAL "ON") + set(OPENBLAS_CACHE_PACKAGE_NAME "openblas_${OPENBLAS_MD5}.tar.gz") + set(OPENBLAS_CACHE_URL "${JFROG_ARTFACTORY_CACHE_URL}/${OPENBLAS_CACHE_PACKAGE_NAME}") + set(OPENBLAS_CACHE_PACKAGE_PATH "${THIRDPARTY_PACKAGE_CACHE}/${OPENBLAS_CACHE_PACKAGE_NAME}") + + execute_process(COMMAND wget -q --method HEAD ${OPENBLAS_CACHE_URL} RESULT_VARIABLE return_code) + message(STATUS "Check the remote file ${OPENBLAS_CACHE_URL}. return code = ${return_code}") + if (NOT return_code EQUAL 0) + externalproject_add(openblas_ep + URL + ${OPENBLAS_SOURCE_URL} + ${EP_LOG_OPTIONS} + CONFIGURE_COMMAND + "" + BUILD_IN_SOURCE + 1 + BUILD_COMMAND + ${MAKE} + ${MAKE_BUILD_ARGS} + INSTALL_COMMAND + ${MAKE} + PREFIX=${OPENBLAS_PREFIX} + install + BUILD_BYPRODUCTS + ${OPENBLAS_STATIC_LIB}) + + ExternalProject_Create_Cache(openblas_ep ${OPENBLAS_CACHE_PACKAGE_PATH} "${CMAKE_CURRENT_BINARY_DIR}/openblas_ep-prefix" ${JFROG_USER_NAME} ${JFROG_PASSWORD} ${OPENBLAS_CACHE_URL}) + else() + file(DOWNLOAD ${OPENBLAS_CACHE_URL} ${OPENBLAS_CACHE_PACKAGE_PATH} STATUS status) + list(GET status 0 status_code) + message(STATUS "DOWNLOADING FROM ${OPENBLAS_CACHE_URL} TO ${OPENBLAS_CACHE_PACKAGE_PATH}. STATUS = ${status_code}") + if (status_code EQUAL 0) + ExternalProject_Use_Cache(openblas_ep ${OPENBLAS_CACHE_PACKAGE_PATH} ${CMAKE_CURRENT_BINARY_DIR}) + endif() + endif() + else() + externalproject_add(openblas_ep + URL + ${OPENBLAS_SOURCE_URL} + ${EP_LOG_OPTIONS} + CONFIGURE_COMMAND + "" + BUILD_IN_SOURCE + 1 + BUILD_COMMAND + ${MAKE} + ${MAKE_BUILD_ARGS} + INSTALL_COMMAND + ${MAKE} + PREFIX=${OPENBLAS_PREFIX} + install + BUILD_BYPRODUCTS + ${OPENBLAS_STATIC_LIB}) + endif() + + file(MAKE_DIRECTORY "${OPENBLAS_INCLUDE_DIR}") + add_library(openblas STATIC IMPORTED) + set_target_properties( + openblas + PROPERTIES IMPORTED_LOCATION "${OPENBLAS_STATIC_LIB}" + INTERFACE_INCLUDE_DIRECTORIES "${OPENBLAS_INCLUDE_DIR}") + + add_dependencies(openblas openblas_ep) +endmacro() + +#if(KNOWHERE_WITH_OPENBLAS) +# resolve_dependency(OpenBLAS) +# +# get_target_property(OPENBLAS_INCLUDE_DIR openblas INTERFACE_INCLUDE_DIRECTORIES) +# include_directories(SYSTEM "${OPENBLAS_INCLUDE_DIR}") +# link_directories(SYSTEM ${OPENBLAS_PREFIX}/lib) +#endif() + +# ---------------------------------------------------------------------- +# LAPACK + +macro(build_lapack) + message(STATUS "Building LAPACK-${LAPACK_VERSION} from source") + set(LAPACK_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/lapack_ep-prefix/src/lapack_ep") + set(LAPACK_INCLUDE_DIR "${LAPACK_PREFIX}/include") + set(LAPACK_STATIC_LIB + "${LAPACK_PREFIX}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}lapack${CMAKE_STATIC_LIBRARY_SUFFIX}") + set(BLAS_STATIC_LIB + "${LAPACK_PREFIX}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}blas${CMAKE_STATIC_LIBRARY_SUFFIX}") + + set(LAPACK_CMAKE_ARGS + ${EP_COMMON_CMAKE_ARGS} + "-DCMAKE_INSTALL_PREFIX=${LAPACK_PREFIX}" + -DCMAKE_INSTALL_LIBDIR=lib) + + if(USE_JFROG_CACHE STREQUAL "ON") + set(LAPACK_CACHE_PACKAGE_NAME "lapack_${LAPACK_MD5}.tar.gz") + set(LAPACK_CACHE_URL "${JFROG_ARTFACTORY_CACHE_URL}/${LAPACK_CACHE_PACKAGE_NAME}") + set(LAPACK_CACHE_PACKAGE_PATH "${THIRDPARTY_PACKAGE_CACHE}/${LAPACK_CACHE_PACKAGE_NAME}") + + execute_process(COMMAND wget -q --method HEAD ${LAPACK_CACHE_URL} RESULT_VARIABLE return_code) + message(STATUS "Check the remote file ${LAPACK_CACHE_URL}. return code = ${return_code}") + if (NOT return_code EQUAL 0) + externalproject_add(lapack_ep + URL + ${LAPACK_SOURCE_URL} + ${EP_LOG_OPTIONS} + CMAKE_ARGS + ${LAPACK_CMAKE_ARGS} + BUILD_COMMAND + ${MAKE} + ${MAKE_BUILD_ARGS} + BUILD_BYPRODUCTS + ${LAPACK_STATIC_LIB}) + + ExternalProject_Create_Cache(lapack_ep ${LAPACK_CACHE_PACKAGE_PATH} "${CMAKE_CURRENT_BINARY_DIR}/lapack_ep-prefix" ${JFROG_USER_NAME} ${JFROG_PASSWORD} ${LAPACK_CACHE_URL}) + else() + file(DOWNLOAD ${LAPACK_CACHE_URL} ${LAPACK_CACHE_PACKAGE_PATH} STATUS status) + list(GET status 0 status_code) + message(STATUS "DOWNLOADING FROM ${LAPACK_CACHE_URL} TO ${LAPACK_CACHE_PACKAGE_PATH}. STATUS = ${status_code}") + if (status_code EQUAL 0) + ExternalProject_Use_Cache(lapack_ep ${LAPACK_CACHE_PACKAGE_PATH} ${CMAKE_CURRENT_BINARY_DIR}) + endif() + endif() + else() + externalproject_add(lapack_ep + URL + ${LAPACK_SOURCE_URL} + ${EP_LOG_OPTIONS} + CMAKE_ARGS + ${LAPACK_CMAKE_ARGS} + BUILD_COMMAND + ${MAKE} + ${MAKE_BUILD_ARGS} + BUILD_BYPRODUCTS + ${LAPACK_STATIC_LIB}) + endif() + + file(MAKE_DIRECTORY "${LAPACK_INCLUDE_DIR}") + add_library(lapack STATIC IMPORTED) + set_target_properties( + lapack + PROPERTIES IMPORTED_LOCATION "${LAPACK_STATIC_LIB}" + INTERFACE_INCLUDE_DIRECTORIES "${LAPACK_INCLUDE_DIR}") + + add_dependencies(lapack lapack_ep) +endmacro() + +#if(KNOWHERE_WITH_LAPACK) +# resolve_dependency(LAPACK) +# +# get_target_property(LAPACK_INCLUDE_DIR lapack INTERFACE_INCLUDE_DIRECTORIES) +# include_directories(SYSTEM "${LAPACK_INCLUDE_DIR}") +# link_directories(SYSTEM ${LAPACK_PREFIX}/lib) +#endif() + +# ---------------------------------------------------------------------- +# Google gtest + +macro(build_gtest) + message(STATUS "Building gtest-${GTEST_VERSION} from source") + set(GTEST_VENDORED TRUE) + set(GTEST_CMAKE_CXX_FLAGS "${EP_CXX_FLAGS}") + + if(APPLE) + set(GTEST_CMAKE_CXX_FLAGS + ${GTEST_CMAKE_CXX_FLAGS} + -DGTEST_USE_OWN_TR1_TUPLE=1 + -Wno-unused-value + -Wno-ignored-attributes) + endif() + + set(GTEST_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/googletest_ep-prefix/src/googletest_ep") + set(GTEST_INCLUDE_DIR "${GTEST_PREFIX}/include") + set(GTEST_STATIC_LIB + "${GTEST_PREFIX}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}gtest${CMAKE_STATIC_LIBRARY_SUFFIX}") + set(GTEST_MAIN_STATIC_LIB + "${GTEST_PREFIX}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}gtest_main${CMAKE_STATIC_LIBRARY_SUFFIX}") + + set(GTEST_CMAKE_ARGS + ${EP_COMMON_CMAKE_ARGS} + "-DCMAKE_INSTALL_PREFIX=${GTEST_PREFIX}" + "-DCMAKE_INSTALL_LIBDIR=lib" + -DCMAKE_CXX_FLAGS=${GTEST_CMAKE_CXX_FLAGS} + -DCMAKE_BUILD_TYPE=Release) + + set(GMOCK_INCLUDE_DIR "${GTEST_PREFIX}/include") + set(GMOCK_STATIC_LIB + "${GTEST_PREFIX}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}gmock${CMAKE_STATIC_LIBRARY_SUFFIX}" + ) + + + if(USE_JFROG_CACHE STREQUAL "ON") + set(GTEST_CACHE_PACKAGE_NAME "googletest_${GTEST_MD5}.tar.gz") + set(GTEST_CACHE_URL "${JFROG_ARTFACTORY_CACHE_URL}/${GTEST_CACHE_PACKAGE_NAME}") + set(GTEST_CACHE_PACKAGE_PATH "${THIRDPARTY_PACKAGE_CACHE}/${GTEST_CACHE_PACKAGE_NAME}") + + execute_process(COMMAND wget -q --method HEAD ${GTEST_CACHE_URL} RESULT_VARIABLE return_code) + message(STATUS "Check the remote file ${GTEST_CACHE_URL}. return code = ${return_code}") + if (NOT return_code EQUAL 0) + ExternalProject_Add(googletest_ep + URL + ${GTEST_SOURCE_URL} + BUILD_COMMAND + ${MAKE} + ${MAKE_BUILD_ARGS} + BUILD_BYPRODUCTS + ${GTEST_STATIC_LIB} + ${GTEST_MAIN_STATIC_LIB} + ${GMOCK_STATIC_LIB} + CMAKE_ARGS + ${GTEST_CMAKE_ARGS} + ${EP_LOG_OPTIONS}) + + ExternalProject_Create_Cache(googletest_ep ${GTEST_CACHE_PACKAGE_PATH} "${CMAKE_CURRENT_BINARY_DIR}/googletest_ep-prefix" ${JFROG_USER_NAME} ${JFROG_PASSWORD} ${GTEST_CACHE_URL}) + else() + file(DOWNLOAD ${GTEST_CACHE_URL} ${GTEST_CACHE_PACKAGE_PATH} STATUS status) + list(GET status 0 status_code) + message(STATUS "DOWNLOADING FROM ${GTEST_CACHE_URL} TO ${GTEST_CACHE_PACKAGE_PATH}. STATUS = ${status_code}") + if (status_code EQUAL 0) + ExternalProject_Use_Cache(googletest_ep ${GTEST_CACHE_PACKAGE_PATH} ${CMAKE_CURRENT_BINARY_DIR}) + endif() + endif() + else() + ExternalProject_Add(googletest_ep + URL + ${GTEST_SOURCE_URL} + BUILD_COMMAND + ${MAKE} + ${MAKE_BUILD_ARGS} + BUILD_BYPRODUCTS + ${GTEST_STATIC_LIB} + ${GTEST_MAIN_STATIC_LIB} + ${GMOCK_STATIC_LIB} + CMAKE_ARGS + ${GTEST_CMAKE_ARGS} + ${EP_LOG_OPTIONS}) + endif() + + # The include directory must exist before it is referenced by a target. + file(MAKE_DIRECTORY "${GTEST_INCLUDE_DIR}") + + add_library(gtest STATIC IMPORTED) + set_target_properties(gtest + PROPERTIES IMPORTED_LOCATION "${GTEST_STATIC_LIB}" + INTERFACE_INCLUDE_DIRECTORIES "${GTEST_INCLUDE_DIR}") + + add_library(gtest_main STATIC IMPORTED) + set_target_properties(gtest_main + PROPERTIES IMPORTED_LOCATION "${GTEST_MAIN_STATIC_LIB}" + INTERFACE_INCLUDE_DIRECTORIES "${GTEST_INCLUDE_DIR}") + + add_library(gmock STATIC IMPORTED) + set_target_properties(gmock + PROPERTIES IMPORTED_LOCATION "${GMOCK_STATIC_LIB}" + INTERFACE_INCLUDE_DIRECTORIES "${GTEST_INCLUDE_DIR}") + + add_dependencies(gtest googletest_ep) + add_dependencies(gtest_main googletest_ep) + add_dependencies(gmock googletest_ep) + +endmacro() + +if (KNOWHERE_BUILD_TESTS) + #message(STATUS "Resolving gtest dependency") + resolve_dependency(GTest) + + if(NOT GTEST_VENDORED) + endif() + + # TODO: Don't use global includes but rather target_include_directories + get_target_property(GTEST_INCLUDE_DIR gtest INTERFACE_INCLUDE_DIRECTORIES) + link_directories(SYSTEM "${GTEST_PREFIX}/lib") + include_directories(SYSTEM ${GTEST_INCLUDE_DIR}) +endif() + +# ---------------------------------------------------------------------- +# FAISS + +macro(build_faiss) + message(STATUS "Building FAISS-${FAISS_VERSION} from source") + set(FAISS_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/faiss_ep-prefix/src/faiss_ep") + set(FAISS_INCLUDE_DIR "${FAISS_PREFIX}/include") + set(FAISS_STATIC_LIB + "${FAISS_PREFIX}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}faiss${CMAKE_STATIC_LIBRARY_SUFFIX}") + + # add_custom_target(faiss_dependencies) + # add_dependencies(faiss_dependencies openblas_ep) + # add_dependencies(faiss_dependencies openblas) + # get_target_property(FAISS_OPENBLAS_LIB_DIR openblas IMPORTED_LOCATION) + # get_filename_component(FAISS_OPENBLAS_LIB "${FAISS_OPENBLAS_LIB_DIR}" DIRECTORY) + + set(FAISS_CONFIGURE_ARGS + "--prefix=${FAISS_PREFIX}" + "CFLAGS=${EP_C_FLAGS}" + "CXXFLAGS=${EP_CXX_FLAGS}" + "LDFLAGS=-L${OPENBLAS_PREFIX}/lib -L${LAPACK_PREFIX}/lib -lopenblas -llapack" + --without-python) + + # if(OPENBLAS_STATIC_LIB) + # set(OPENBLAS_LIBRARY ${OPENBLAS_STATIC_LIB}) + # else() + # set(OPENBLAS_LIBRARY ${OPENBLAS_SHARED_LIB}) + # endif() + # set(FAISS_DEPENDENCIES ${FAISS_DEPENDENCIES} ${OPENBLAS_LIBRARY}) + + if(${KNOWHERE_WITH_FAISS_GPU_VERSION} STREQUAL "ON") + set(FAISS_CONFIGURE_ARGS ${FAISS_CONFIGURE_ARGS} + "--with-cuda=${CUDA_TOOLKIT_ROOT_DIR}" + "--with-cuda-arch=-gencode=arch=compute_60,code=sm_60 -gencode=arch=compute_61,code=sm_61 -gencode=arch=compute_70,code=sm_70 -gencode=arch=compute_75,code=sm_75" + ) + else() + set(FAISS_CONFIGURE_ARGS ${FAISS_CONFIGURE_ARGS} --without-cuda) + endif() + + if(USE_JFROG_CACHE STREQUAL "ON") +# Check_Last_Modify("${CMAKE_SOURCE_DIR}/thirdparty/faiss_cache_check_lists.txt" "${CMAKE_SOURCE_DIR}" FAISS_LAST_MODIFIED_COMMIT_ID) + string(MD5 FAISS_COMBINE_MD5 "${FAISS_MD5}${LAPACK_MD5}${OPENBLAS_MD5}") + string(MD5 FAISS_COMBINE_MD5 "${FAISS_LAST_MODIFIED_COMMIT_ID}${LAPACK_MD5}${OPENBLAS_MD5}") + set(FAISS_CACHE_PACKAGE_NAME "faiss_${FAISS_COMBINE_MD5}.tar.gz") + set(FAISS_CACHE_URL "${JFROG_ARTFACTORY_CACHE_URL}/${FAISS_CACHE_PACKAGE_NAME}") + set(FAISS_CACHE_PACKAGE_PATH "${THIRDPARTY_PACKAGE_CACHE}/${FAISS_CACHE_PACKAGE_NAME}") + + execute_process(COMMAND wget -q --method HEAD ${FAISS_CACHE_URL} RESULT_VARIABLE return_code) + message(STATUS "Check the remote file ${FAISS_CACHE_URL}. return code = ${return_code}") + if (NOT return_code EQUAL 0) + externalproject_add(faiss_ep + URL + ${FAISS_SOURCE_URL} + ${EP_LOG_OPTIONS} + CONFIGURE_COMMAND + "./configure" + ${FAISS_CONFIGURE_ARGS} + BUILD_COMMAND + ${MAKE} ${MAKE_BUILD_ARGS} all + BUILD_IN_SOURCE + 1 + INSTALL_COMMAND + ${MAKE} install + BUILD_BYPRODUCTS + ${FAISS_STATIC_LIB}) + + ExternalProject_Add_StepDependencies(faiss_ep build openblas_ep lapack_ep) + + ExternalProject_Create_Cache(faiss_ep ${FAISS_CACHE_PACKAGE_PATH} "${CMAKE_CURRENT_BINARY_DIR}/faiss_ep-prefix" ${JFROG_USER_NAME} ${JFROG_PASSWORD} ${FAISS_CACHE_URL}) + else() + file(DOWNLOAD ${FAISS_CACHE_URL} ${FAISS_CACHE_PACKAGE_PATH} STATUS status) + list(GET status 0 status_code) + message(STATUS "DOWNLOADING FROM ${FAISS_CACHE_URL} TO ${FAISS_CACHE_PACKAGE_PATH}. STATUS = ${status_code}") + if (status_code EQUAL 0) + ExternalProject_Use_Cache(faiss_ep ${FAISS_CACHE_PACKAGE_PATH} ${CMAKE_CURRENT_BINARY_DIR}) + endif() + endif() + else() + externalproject_add(faiss_ep + URL + ${FAISS_SOURCE_URL} + ${EP_LOG_OPTIONS} + CONFIGURE_COMMAND + "./configure" + ${FAISS_CONFIGURE_ARGS} + BUILD_COMMAND + ${MAKE} ${MAKE_BUILD_ARGS} all + BUILD_IN_SOURCE + 1 + INSTALL_COMMAND + ${MAKE} install + BUILD_BYPRODUCTS + ${FAISS_STATIC_LIB}) + + ExternalProject_Add_StepDependencies(faiss_ep build openblas_ep lapack_ep) + endif() + + file(MAKE_DIRECTORY "${FAISS_INCLUDE_DIR}") + add_library(faiss STATIC IMPORTED) + set_target_properties( + faiss + PROPERTIES IMPORTED_LOCATION "${FAISS_STATIC_LIB}" + INTERFACE_INCLUDE_DIRECTORIES "${FAISS_INCLUDE_DIR}" + INTERFACE_LINK_LIBRARIES "openblas;lapack" ) + + add_dependencies(faiss faiss_ep) + #add_dependencies(faiss openblas_ep) + #add_dependencies(faiss lapack_ep) + #target_link_libraries(faiss ${OPENBLAS_PREFIX}/lib) + #target_link_libraries(faiss ${LAPACK_PREFIX}/lib) + +endmacro() + +if(KNOWHERE_WITH_FAISS) + + resolve_dependency(OpenBLAS) + get_target_property(OPENBLAS_INCLUDE_DIR openblas INTERFACE_INCLUDE_DIRECTORIES) + include_directories(SYSTEM "${OPENBLAS_INCLUDE_DIR}") + link_directories(SYSTEM ${OPENBLAS_PREFIX}/lib) + + resolve_dependency(LAPACK) + get_target_property(LAPACK_INCLUDE_DIR lapack INTERFACE_INCLUDE_DIRECTORIES) + include_directories(SYSTEM "${LAPACK_INCLUDE_DIR}") + link_directories(SYSTEM "${LAPACK_PREFIX}/lib") + + resolve_dependency(FAISS) + get_target_property(FAISS_INCLUDE_DIR faiss INTERFACE_INCLUDE_DIRECTORIES) + include_directories(SYSTEM "${FAISS_INCLUDE_DIR}") +# include_directories(SYSTEM "${CMAKE_CURRENT_BINARY_DIR}/faiss_ep-prefix/src/") +# link_directories(SYSTEM ${FAISS_PREFIX}/) + link_directories(SYSTEM ${FAISS_PREFIX}/lib/) +# link_directories(SYSTEM ${FAISS_PREFIX}/gpu/) +endif() diff --git a/cpp/src/core/include/knowhere/adapter/arrow.h b/cpp/src/core/include/knowhere/adapter/arrow.h new file mode 100644 index 0000000000..338ab691df --- /dev/null +++ b/cpp/src/core/include/knowhere/adapter/arrow.h @@ -0,0 +1,18 @@ + +#pragma once + +#include +#include + + +namespace zilliz { +namespace knowhere { + +ArrayPtr +CopyArray(const ArrayPtr &origin); + +SchemaPtr +CopySchema(const SchemaPtr &origin); + +} // namespace knowhere +} // namespace zilliz diff --git a/cpp/src/core/include/knowhere/adapter/faiss_adopt.h b/cpp/src/core/include/knowhere/adapter/faiss_adopt.h new file mode 100644 index 0000000000..26a005122e --- /dev/null +++ b/cpp/src/core/include/knowhere/adapter/faiss_adopt.h @@ -0,0 +1,20 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 上海赜睿信息科技有限公司(Zilliz) - All Rights Reserved +// Unauthorized copying of this file, via any medium is strictly prohibited. +// Proprietary and confidential. +//////////////////////////////////////////////////////////////////////////////// + +#pragma once + +namespace zilliz { +namespace knowhere { + +#define GETTENSOR(dataset) \ + auto tensor = dataset->tensor()[0]; \ + auto p_data = tensor->raw_data(); \ + auto dim = tensor->shape()[1]; \ + auto rows = tensor->shape()[0]; \ + + +} +} \ No newline at end of file diff --git a/cpp/src/core/include/knowhere/adapter/sptag.h b/cpp/src/core/include/knowhere/adapter/sptag.h new file mode 100644 index 0000000000..08c4a625ee --- /dev/null +++ b/cpp/src/core/include/knowhere/adapter/sptag.h @@ -0,0 +1,24 @@ +#pragma once + +#include +#include +#include + + +namespace zilliz { +namespace knowhere { + +std::shared_ptr +ConvertToVectorSet(const DatasetPtr &dataset); + +std::shared_ptr +ConvertToMetadataSet(const DatasetPtr &dataset); + +std::vector +ConvertToQueryResult(const DatasetPtr &dataset, const Config &config); + +DatasetPtr +ConvertToDataset(std::vector query_results); + +} // namespace knowhere +} // namespace zilliz diff --git a/cpp/src/core/include/knowhere/adapter/structure.h b/cpp/src/core/include/knowhere/adapter/structure.h new file mode 100644 index 0000000000..e0478ed38e --- /dev/null +++ b/cpp/src/core/include/knowhere/adapter/structure.h @@ -0,0 +1,42 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 上海赜睿信息科技有限公司(Zilliz) - All Rights Reserved +// Unauthorized copying of this file, via any medium is strictly prohibited. +// Proprietary and confidential. +//////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include +#include + + +namespace zilliz { +namespace knowhere { + +extern ArrayPtr +ConstructInt64ArraySmart(uint8_t *data, int64_t size); + +extern ArrayPtr +ConstructFloatArraySmart(uint8_t *data, int64_t size); + +extern TensorPtr +ConstructFloatTensorSmart(uint8_t *data, int64_t size, std::vector shape); + +extern ArrayPtr +ConstructInt64Array(uint8_t *data, int64_t size); + +extern ArrayPtr +ConstructFloatArray(uint8_t *data, int64_t size); + +extern TensorPtr +ConstructFloatTensor(uint8_t *data, int64_t size, std::vector shape); + +extern FieldPtr +ConstructInt64Field(const std::string &name); + +extern FieldPtr +ConstructFloatField(const std::string &name); + + +} +} diff --git a/cpp/src/core/include/knowhere/common/array.h b/cpp/src/core/include/knowhere/common/array.h new file mode 100644 index 0000000000..f3d0310596 --- /dev/null +++ b/cpp/src/core/include/knowhere/common/array.h @@ -0,0 +1,35 @@ +#pragma once + +#include "arrow/array.h" +#include "knowhere/common/schema.h" + + +namespace zilliz { +namespace knowhere { + +using ArrayData = arrow::ArrayData; +using ArrayDataPtr = std::shared_ptr; + +using Array = arrow::Array; +using ArrayPtr = std::shared_ptr; + +using BooleanArray = arrow::BooleanArray; +using BooleanArrayPtr = std::shared_ptr; + +template +using NumericArray = arrow::NumericArray; +template +using NumericArrayPtr = std::shared_ptr>; + +using BinaryArray = arrow::BinaryArray; +using BinaryArrayPtr = std::shared_ptr; + +using FixedSizeBinaryArray = arrow::FixedSizeBinaryArray; +using FixedSizeBinaryArrayPtr = std::shared_ptr; + +using Decimal128Array = arrow::Decimal128Array; +using Decimal128ArrayPtr = std::shared_ptr; + + +} // namespace knowhere +} // namespace zilliz diff --git a/cpp/src/core/include/knowhere/common/binary_set.h b/cpp/src/core/include/knowhere/common/binary_set.h new file mode 100644 index 0000000000..b83d96dfe4 --- /dev/null +++ b/cpp/src/core/include/knowhere/common/binary_set.h @@ -0,0 +1,62 @@ +#pragma once + +#include +#include +#include +#include + +#include "knowhere/common/id.h" + + +namespace zilliz { +namespace knowhere { + + +struct Binary { + ID id; + std::shared_ptr data; + int64_t size = 0; +}; +using BinaryPtr = std::shared_ptr; + + +class BinarySet { + public: + BinaryPtr + GetByName(const std::string &name) const { + return binary_map_.at(name); + } + + void + Append(const std::string &name, BinaryPtr binary) { + binary_map_[name] = std::move(binary); + } + + void + Append(const std::string &name, std::shared_ptr data, int64_t size) { + auto binary = std::make_shared(); + binary->data = data; + binary->size = size; + binary_map_[name] = std::move(binary); + } + + //void + //Append(const std::string &name, void *data, int64_t size, ID id) { + // Binary binary; + // binary.data = data; + // binary.size = size; + // binary.id = id; + // binary_map_[name] = binary; + //} + + void clear() { + binary_map_.clear(); + } + + public: + std::map binary_map_; +}; + + +} // namespace knowhere +} // namespace zilliz diff --git a/cpp/src/core/include/knowhere/common/buffer.h b/cpp/src/core/include/knowhere/common/buffer.h new file mode 100644 index 0000000000..44867e760a --- /dev/null +++ b/cpp/src/core/include/knowhere/common/buffer.h @@ -0,0 +1,45 @@ +#pragma once + +#include +#include "arrow/buffer.h" + + +namespace zilliz { +namespace knowhere { + +using Buffer = arrow::Buffer; +using BufferPtr = std::shared_ptr; +using MutableBuffer = arrow::MutableBuffer; +using MutableBufferPtr = std::shared_ptr; + +namespace internal { + +struct BufferDeleter { + void operator()(Buffer *buffer) { + free((void *) buffer->data()); + } +}; + +} +inline BufferPtr +MakeBufferSmart(uint8_t *data, const int64_t size) { + return BufferPtr(new Buffer(data, size), internal::BufferDeleter()); +} + +inline MutableBufferPtr +MakeMutableBufferSmart(uint8_t *data, const int64_t size) { + return MutableBufferPtr(new MutableBuffer(data, size), internal::BufferDeleter()); +} + +inline BufferPtr +MakeBuffer(uint8_t *data, const int64_t size) { + return std::make_shared(data, size); +} + +inline MutableBufferPtr +MakeMutableBuffer(uint8_t *data, const int64_t size) { + return std::make_shared(data, size); +} + +} // namespace knowhere +} // namespace zilliz diff --git a/cpp/src/core/include/knowhere/common/config.h b/cpp/src/core/include/knowhere/common/config.h new file mode 100644 index 0000000000..3a3fee1219 --- /dev/null +++ b/cpp/src/core/include/knowhere/common/config.h @@ -0,0 +1,14 @@ +#pragma once + +#include + + +namespace zilliz { +namespace knowhere { + + +using Config = jsoncons::json; + + +} // namespace knowhere +} // namespace zilliz diff --git a/cpp/src/core/include/knowhere/common/dataset.h b/cpp/src/core/include/knowhere/common/dataset.h new file mode 100644 index 0000000000..ee1d6e5100 --- /dev/null +++ b/cpp/src/core/include/knowhere/common/dataset.h @@ -0,0 +1,122 @@ +#pragma once + +#include +#include +#include "knowhere/common/array.h" +#include "knowhere/common/buffer.h" +#include "knowhere/common/tensor.h" +#include "knowhere/common/schema.h" +#include "knowhere/common/config.h" +#include "knowhere/adapter/arrow.h" + + +namespace zilliz { +namespace knowhere { + +class Dataset; + +using DatasetPtr = std::shared_ptr; + +class Dataset { + public: + Dataset() = default; + + Dataset(std::vector &&array, SchemaPtr array_schema, + std::vector &&tensor, SchemaPtr tensor_schema) + : array_(std::move(array)), + array_schema_(std::move(array_schema)), + tensor_(std::move(tensor)), + tensor_schema_(std::move(tensor_schema)) {} + + Dataset(std::vector array, SchemaPtr array_schema) + : array_(std::move(array)), array_schema_(std::move(array_schema)) {} + + Dataset(std::vector tensor, SchemaPtr tensor_schema) + : tensor_(std::move(tensor)), tensor_schema_(std::move(tensor_schema)) {} + + Dataset(const Dataset &) = delete; + Dataset &operator=(const Dataset &) = delete; + + DatasetPtr + Clone() { + auto dataset = std::make_shared(); + + std::vector clone_array; + for (auto &array : array_) { + clone_array.emplace_back(CopyArray(array)); + } + dataset->set_array(clone_array); + + std::vector clone_tensor; + for (auto &tensor : tensor_) { + auto buffer = tensor->data(); + std::shared_ptr copy_buffer; + // TODO: checkout copy success; + buffer->Copy(0, buffer->size(), ©_buffer); + auto copy = std::make_shared(tensor->type(), copy_buffer, tensor->shape()); + clone_tensor.emplace_back(copy); + } + dataset->set_tensor(clone_tensor); + + if (array_schema_) + dataset->set_array_schema(CopySchema(array_schema_)); + if (tensor_schema_) + dataset->set_tensor_schema(CopySchema(tensor_schema_)); + + return dataset; + } + + public: + const std::vector & + array() const { return array_; } + + void + set_array(std::vector array) { + array_ = std::move(array); + } + + const std::vector & + tensor() const { return tensor_; } + + void + set_tensor(std::vector tensor) { + tensor_ = std::move(tensor); + } + + SchemaConstPtr + array_schema() const { return array_schema_; } + + void + set_array_schema(SchemaPtr array_schema) { + array_schema_ = std::move(array_schema); + } + + SchemaConstPtr + tensor_schema() const { return tensor_schema_; } + + void + set_tensor_schema(SchemaPtr tensor_schema) { + tensor_schema_ = std::move(tensor_schema); + } + + //const Config & + //meta() const { return meta_; } + + //void + //set_meta(Config meta) { + // meta_ = std::move(meta); + //} + + private: + SchemaPtr array_schema_; + SchemaPtr tensor_schema_; + std::vector array_; + std::vector tensor_; + //Config meta_; +}; + +using DatasetPtr = std::shared_ptr; + + +} // namespace knowhere +} // namespace zilliz diff --git a/cpp/src/core/include/knowhere/common/device_type.h b/cpp/src/core/include/knowhere/common/device_type.h new file mode 100644 index 0000000000..09fa362643 --- /dev/null +++ b/cpp/src/core/include/knowhere/common/device_type.h @@ -0,0 +1,10 @@ +#pragma once + + +namespace zilliz { +namespace sched { +namespace master { + +} // namespace master +} // namespace sched +} // namespace zilliz diff --git a/cpp/src/core/include/knowhere/common/error.h b/cpp/src/core/include/knowhere/common/error.h new file mode 100644 index 0000000000..ba7b5cf315 --- /dev/null +++ b/cpp/src/core/include/knowhere/common/error.h @@ -0,0 +1,40 @@ +#pragma once + +#include +#include "zlibrary/error/error.h" + + +namespace zilliz { +namespace knowhere { + +using Error = zilliz::lib::ErrorCode; + +constexpr Error STORE_SUCCESS = zilliz::lib::SUCCESS_CODE; + +constexpr Error ERROR_CODE_BASE = 0x36000; +constexpr Error ERROR_CODE_END = 0x37000; + +constexpr Error +ToGlobalErrorCode(const Error error_code) { + return zilliz::lib::ToGlobalErrorCode(error_code, ERROR_CODE_BASE); +} + +class Exception : public zilliz::lib::Exception { + public: + Exception(const Error error_code, + const std::string &message = nullptr) + : zilliz::lib::Exception(error_code, "KNOWHERE", message) {} +}; + +constexpr Error UNEXPECTED = ToGlobalErrorCode(0x001); +constexpr Error UNSUPPORTED = ToGlobalErrorCode(0x002); +constexpr Error NULL_POINTER = ToGlobalErrorCode(0x003); +constexpr Error OVERFLOW = ToGlobalErrorCode(0x004); +constexpr Error INVALID_ARGUMENT = ToGlobalErrorCode(0x005); +constexpr Error UNSUPPORTED_TYPE = ToGlobalErrorCode(0x006); + + +} // namespace store +} // namespace zilliz + +using Error = zilliz::store::Error; diff --git a/cpp/src/core/include/knowhere/common/exception.h b/cpp/src/core/include/knowhere/common/exception.h new file mode 100644 index 0000000000..ea80f5657e --- /dev/null +++ b/cpp/src/core/include/knowhere/common/exception.h @@ -0,0 +1,45 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 上海赜睿信息科技有限公司(Zilliz) - All Rights Reserved +// Unauthorized copying of this file, via any medium is strictly prohibited. +// Proprietary and confidential. +//////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include +#include + + +namespace zilliz { +namespace knowhere { + +class KnowhereException : public std::exception { + public: + explicit KnowhereException(const std::string &msg); + + KnowhereException(const std::string &msg, const char *funName, + const char *file, int line); + + const char *what() const noexcept override; + + std::string msg; +}; + + +#define KNOWHERE_THROW_MSG(MSG)\ +do {\ + throw KnowhereException(MSG, __PRETTY_FUNCTION__, __FILE__, __LINE__);\ +} while (false) + +#define KNOHERE_THROW_FORMAT(FMT, ...)\ + do { \ + std::string __s;\ + int __size = snprintf(nullptr, 0, FMT, __VA_ARGS__);\ + __s.resize(__size + 1);\ + snprintf(&__s[0], __s.size(), FMT, __VA_ARGS__);\ + throw faiss::FaissException(__s, __PRETTY_FUNCTION__, __FILE__, __LINE__);\ + } while (false) + + +} +} \ No newline at end of file diff --git a/cpp/src/core/include/knowhere/common/id.h b/cpp/src/core/include/knowhere/common/id.h new file mode 100644 index 0000000000..dc823e6e22 --- /dev/null +++ b/cpp/src/core/include/knowhere/common/id.h @@ -0,0 +1,42 @@ +#pragma once + +//#include "zcommon/id/id.h" +//using ID = zilliz::common::ID; + +#include +#include + +namespace zilliz { +namespace knowhere { + + + +class ID { + public: + constexpr static int64_t kIDSize = 20; + + public: + const int32_t * + data() const { return content_; } + + int32_t * + mutable_data() { return content_; } + + bool + IsValid() const; + + std::string + ToString() const; + + bool + operator==(const ID &that) const; + + bool + operator<(const ID &that) const; + + protected: + int32_t content_[5] = {}; +}; + +} // namespace knowhere +} // namespace zilliz diff --git a/cpp/src/core/include/knowhere/common/schema.h b/cpp/src/core/include/knowhere/common/schema.h new file mode 100644 index 0000000000..fe87721470 --- /dev/null +++ b/cpp/src/core/include/knowhere/common/schema.h @@ -0,0 +1,21 @@ +#pragma once + +#include +#include "arrow/type.h" + + +namespace zilliz { +namespace knowhere { + + +using DataType = arrow::DataType; +using Field = arrow::Field; +using FieldPtr = std::shared_ptr; +using Schema = arrow::Schema; +using SchemaPtr = std::shared_ptr; +using SchemaConstPtr = std::shared_ptr; + + + +} // namespace knowhere +} // namespace zilliz diff --git a/cpp/src/core/include/knowhere/common/tensor.h b/cpp/src/core/include/knowhere/common/tensor.h new file mode 100644 index 0000000000..93b7642cd1 --- /dev/null +++ b/cpp/src/core/include/knowhere/common/tensor.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include "arrow/tensor.h" + + +namespace zilliz { +namespace knowhere { + + +using Tensor = arrow::Tensor; +using TensorPtr = std::shared_ptr; + + +} // namespace knowhere +} // namespace zilliz diff --git a/cpp/src/core/include/knowhere/common/timer.h b/cpp/src/core/include/knowhere/common/timer.h new file mode 100644 index 0000000000..680d984d19 --- /dev/null +++ b/cpp/src/core/include/knowhere/common/timer.h @@ -0,0 +1,41 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 上海赜睿信息科技有限公司(Zilliz) - All Rights Reserved +// Unauthorized copying of this file, via any medium is strictly prohibited. +// Proprietary and confidential. +//////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include +#include + +namespace zilliz { +namespace knowhere { + +class TimeRecorder { + using stdclock = std::chrono::high_resolution_clock; + + public: + TimeRecorder(const std::string &header, + int64_t log_level = 0); + + ~TimeRecorder();//trace = 0, debug = 1, info = 2, warn = 3, error = 4, critical = 5 + + double RecordSection(const std::string &msg); + + double ElapseFromBegin(const std::string &msg); + + static std::string GetTimeSpanStr(double span); + + private: + void PrintTimeRecord(const std::string &msg, double span); + + private: + std::string header_; + stdclock::time_point start_; + stdclock::time_point last_; + int64_t log_level_; +}; + +} +} diff --git a/cpp/src/core/include/knowhere/index/index.h b/cpp/src/core/include/knowhere/index/index.h new file mode 100644 index 0000000000..40f3a8d5c0 --- /dev/null +++ b/cpp/src/core/include/knowhere/index/index.h @@ -0,0 +1,49 @@ +#pragma once + +#include +#include "knowhere/common/binary_set.h" +#include "knowhere/common/dataset.h" +#include "knowhere/index/index_type.h" +#include "knowhere/index/index_model.h" +#include "knowhere/index/preprocessor/preprocessor.h" + + +namespace zilliz { +namespace knowhere { + + +class Index { + public: + virtual BinarySet + Serialize() = 0; + + virtual void + Load(const BinarySet &index_binary) = 0; + + // @throw + virtual DatasetPtr + Search(const DatasetPtr &dataset, const Config &config) = 0; + + public: + IndexType + idx_type() const { return idx_type_; } + + void + set_idx_type(IndexType idx_type) { idx_type_ = idx_type; } + + virtual void + set_preprocessor(PreprocessorPtr preprocessor) {} + + virtual void + set_index_model(IndexModelPtr model) {} + + private: + IndexType idx_type_; +}; + + +using IndexPtr = std::shared_ptr; + + +} // namespace knowhere +} // namespace zilliz diff --git a/cpp/src/core/include/knowhere/index/index_model.h b/cpp/src/core/include/knowhere/index/index_model.h new file mode 100644 index 0000000000..4b3a4e439c --- /dev/null +++ b/cpp/src/core/include/knowhere/index/index_model.h @@ -0,0 +1,24 @@ +#pragma once + +#include +#include "knowhere/common/binary_set.h" + +namespace zilliz { +namespace knowhere { + + +class IndexModel { + public: + virtual BinarySet + Serialize() = 0; + + virtual void + Load(const BinarySet &binary) = 0; +}; + +using IndexModelPtr = std::shared_ptr; + + + +} // namespace knowhere +} // namespace zilliz diff --git a/cpp/src/core/include/knowhere/index/index_type.h b/cpp/src/core/include/knowhere/index/index_type.h new file mode 100644 index 0000000000..c7f9e39057 --- /dev/null +++ b/cpp/src/core/include/knowhere/index/index_type.h @@ -0,0 +1,17 @@ +#pragma once + + +namespace zilliz { +namespace knowhere { + + +enum class IndexType { + kUnknown = 0, + kVecIdxBegin = 100, + kVecIVFFlat = kVecIdxBegin, + kVecIdxEnd, +}; + + +} // namespace knowhere +} // namespace zilliz diff --git a/cpp/src/core/include/knowhere/index/preprocessor/normalize.h b/cpp/src/core/include/knowhere/index/preprocessor/normalize.h new file mode 100644 index 0000000000..1d871b580d --- /dev/null +++ b/cpp/src/core/include/knowhere/index/preprocessor/normalize.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include "preprocessor.h" + + +namespace zilliz { +namespace knowhere { + +class NormalizePreprocessor : public Preprocessor { + public: + DatasetPtr + Preprocess(const DatasetPtr &input) override; + + private: + + void + Normalize(float *arr, int64_t dimension); +}; + + +using NormalizePreprocessorPtr = std::shared_ptr; + + +} // namespace knowhere +} // namespace zilliz diff --git a/cpp/src/core/include/knowhere/index/preprocessor/preprocessor.h b/cpp/src/core/include/knowhere/index/preprocessor/preprocessor.h new file mode 100644 index 0000000000..368276e513 --- /dev/null +++ b/cpp/src/core/include/knowhere/index/preprocessor/preprocessor.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include "knowhere/common/dataset.h" + + +namespace zilliz { +namespace knowhere { + + +class Preprocessor { + public: + virtual DatasetPtr + Preprocess(const DatasetPtr &input) = 0; +}; + + +using PreprocessorPtr = std::shared_ptr; + + +} // namespace knowhere +} // namespace zilliz diff --git a/cpp/src/core/include/knowhere/index/vector_index/cloner.h b/cpp/src/core/include/knowhere/index/vector_index/cloner.h new file mode 100644 index 0000000000..008954c34a --- /dev/null +++ b/cpp/src/core/include/knowhere/index/vector_index/cloner.h @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright 上海赜睿信息科技有限公司(Zilliz) - All Rights Reserved + * Unauthorized copying of this file, via any medium is strictly prohibited. + * Proprietary and confidential. + ******************************************************************************/ + +#pragma once + +#include "vector_index.h" + + +namespace zilliz { +namespace knowhere { + +// TODO(linxj): rename CopyToGpu +extern VectorIndexPtr +CopyCpuToGpu(const VectorIndexPtr &index, const int64_t &device_id, const Config &config); + +extern VectorIndexPtr +CopyGpuToCpu(const VectorIndexPtr &index, const Config &config); + +} +} \ No newline at end of file diff --git a/cpp/src/core/include/knowhere/index/vector_index/cpu_kdt_rng.h b/cpp/src/core/include/knowhere/index/vector_index/cpu_kdt_rng.h new file mode 100644 index 0000000000..a00d6afe58 --- /dev/null +++ b/cpp/src/core/include/knowhere/index/vector_index/cpu_kdt_rng.h @@ -0,0 +1,70 @@ +#pragma once + +#include +#include +#include "knowhere/index/vector_index/vector_index.h" +#include "knowhere/index/index_model.h" +#include + + +namespace zilliz { +namespace knowhere { + + +class CPUKDTRNG : public VectorIndex { + public: + CPUKDTRNG() { + index_ptr_ = SPTAG::VectorIndex::CreateInstance(SPTAG::IndexAlgoType::KDT, + SPTAG::VectorValueType::Float); + index_ptr_->SetParameter("DistCalcMethod", "L2"); + } + + public: + BinarySet + Serialize() override; + VectorIndexPtr Clone() override; + void + Load(const BinarySet &index_array) override; + + public: + PreprocessorPtr + BuildPreprocessor(const DatasetPtr &dataset, const Config &config) override; + int64_t Count() override; + int64_t Dimension() override; + + IndexModelPtr + Train(const DatasetPtr &dataset, const Config &config) override; + + void + Add(const DatasetPtr &dataset, const Config &config) override; + + DatasetPtr + Search(const DatasetPtr &dataset, const Config &config) override; + void Seal() override; + private: + void + SetParameters(const Config &config); + + private: + PreprocessorPtr preprocessor_; + std::shared_ptr index_ptr_; +}; + +using CPUKDTRNGPtr = std::shared_ptr; + +class CPUKDTRNGIndexModel : public IndexModel { + public: + BinarySet + Serialize() override; + + void + Load(const BinarySet &binary) override; + + private: + std::shared_ptr index_; +}; + +using CPUKDTRNGIndexModelPtr = std::shared_ptr; + +} // namespace knowhere +} // namespace zilliz diff --git a/cpp/src/core/include/knowhere/index/vector_index/definitions.h b/cpp/src/core/include/knowhere/index/vector_index/definitions.h new file mode 100644 index 0000000000..9904597584 --- /dev/null +++ b/cpp/src/core/include/knowhere/index/vector_index/definitions.h @@ -0,0 +1,14 @@ +#pragma once + +#include + + +namespace zilliz { +namespace knowhere { + +#define META_ROWS ("rows") +#define META_DIM ("dimension") +#define META_K ("k") + +} // namespace knowhere +} // namespace zilliz diff --git a/cpp/src/core/include/knowhere/index/vector_index/gpu_ivf.h b/cpp/src/core/include/knowhere/index/vector_index/gpu_ivf.h new file mode 100644 index 0000000000..f6f13ad1f7 --- /dev/null +++ b/cpp/src/core/include/knowhere/index/vector_index/gpu_ivf.h @@ -0,0 +1,132 @@ +#pragma once + +#include + +#include "ivf.h" + + +namespace zilliz { +namespace knowhere { + +class FaissGpuResourceMgr { + public: + struct DeviceParams { + int64_t temp_mem_size = 0; + int64_t pinned_mem_size = 0; + int64_t resource_num = 2; + }; + + public: + using ResPtr = std::shared_ptr; + using ResWPtr = std::weak_ptr; + + static FaissGpuResourceMgr & + GetInstance(); + + void + AllocateTempMem(ResPtr &res, const int64_t& device_id, const int64_t& size); + + void + InitDevice(int64_t device_id, + int64_t pin_mem_size = 0, + int64_t temp_mem_size = 0, + int64_t res_num = 2); + + void InitResource(); + + ResPtr GetRes(const int64_t &device_id, const int64_t& alloc_size = 0); + + void MoveToInuse(const int64_t &device_id, const ResPtr& res); + void MoveToIdle(const int64_t &device_id, const ResPtr& res); + + protected: + bool is_init = false; + + std::mutex mutex_; + std::map devices_params_; + std::map> in_use_; + std::map> idle_; +}; + +class ResScope { + public: + ResScope(const int64_t device_id,std::shared_ptr &res) : resource(res), device_id(device_id) { + FaissGpuResourceMgr::GetInstance().MoveToInuse(device_id, resource); + } + + ~ResScope() { + resource->noTempMemory(); + FaissGpuResourceMgr::GetInstance().MoveToIdle(device_id, resource); + } + + private: + std::shared_ptr resource; + int64_t device_id; +}; + +class GPUIndex { + public: + explicit GPUIndex(const int &device_id) : gpu_id_(device_id) {}; + + virtual VectorIndexPtr CopyGpuToCpu(const Config &config) = 0; + virtual VectorIndexPtr CopyGpuToGpu(const int64_t &device_id, const Config &config) = 0; + + void SetGpuDevice(const int &gpu_id); + const int64_t &GetGpuDevice(); + + protected: + int64_t gpu_id_; +}; + +class GPUIVF : public IVF, public GPUIndex { + public: + explicit GPUIVF(const int &device_id) : IVF(), GPUIndex(device_id) {} + explicit GPUIVF(std::shared_ptr index, const int64_t &device_id) + : IVF(std::move(index)), GPUIndex(device_id) {}; + IndexModelPtr Train(const DatasetPtr &dataset, const Config &config) override; + void set_index_model(IndexModelPtr model) override; + //DatasetPtr Search(const DatasetPtr &dataset, const Config &config) override; + VectorIndexPtr CopyGpuToCpu(const Config &config) override; + VectorIndexPtr CopyGpuToGpu(const int64_t &device_id, const Config &config) override; + VectorIndexPtr Clone() final; + + // TODO(linxj): Deprecated + virtual IVFIndexPtr Copy_index_gpu_to_cpu(); + + protected: + void search_impl(int64_t n, + const float *data, + int64_t k, + float *distances, + int64_t *labels, + const Config &cfg) override; + BinarySet SerializeImpl() override; + void LoadImpl(const BinarySet &index_binary) override; +}; + +class GPUIVFSQ : public GPUIVF { + public: + explicit GPUIVFSQ(const int &device_id) : GPUIVF(device_id) {} + explicit GPUIVFSQ(std::shared_ptr index, const int64_t& device_id) : GPUIVF(std::move(index),device_id) {}; + IndexModelPtr Train(const DatasetPtr &dataset, const Config &config) override; + + public: + VectorIndexPtr CopyGpuToCpu(const Config &config) override; +}; + +class GPUIVFPQ : public GPUIVF { + public: + explicit GPUIVFPQ(const int &device_id) : GPUIVF(device_id) {} + IndexModelPtr Train(const DatasetPtr &dataset, const Config &config) override; + + public: + VectorIndexPtr CopyGpuToCpu(const Config &config) override; + + protected: + // TODO(linxj): remove GenParams. + std::shared_ptr GenParams(const Config &config) override; +}; + + +} // namespace knowhere +} // namespace zilliz diff --git a/cpp/src/core/include/knowhere/index/vector_index/idmap.h b/cpp/src/core/include/knowhere/index/vector_index/idmap.h new file mode 100644 index 0000000000..cea8aeab97 --- /dev/null +++ b/cpp/src/core/include/knowhere/index/vector_index/idmap.h @@ -0,0 +1,59 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 上海赜睿信息科技有限公司(Zilliz) - All Rights Reserved +// Unauthorized copying of this file, via any medium is strictly prohibited. +// Proprietary and confidential. +//////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "ivf.h" +#include "gpu_ivf.h" + + +namespace zilliz { +namespace knowhere { + +class IDMAP : public VectorIndex, public BasicIndex { + public: + IDMAP() : BasicIndex(nullptr) {}; + explicit IDMAP(std::shared_ptr index) : BasicIndex(std::move(index)) {}; + BinarySet Serialize() override; + void Load(const BinarySet &index_binary) override; + void Train(const Config &config); + DatasetPtr Search(const DatasetPtr &dataset, const Config &config) override; + int64_t Count() override; + VectorIndexPtr Clone() override; + int64_t Dimension() override; + void Add(const DatasetPtr &dataset, const Config &config) override; + VectorIndexPtr CopyCpuToGpu(const int64_t &device_id, const Config &config); + void Seal() override; + + virtual float *GetRawVectors(); + virtual int64_t *GetRawIds(); + + protected: + std::mutex mutex_; +}; + +using IDMAPPtr = std::shared_ptr; + +class GPUIDMAP : public IDMAP, public GPUIndex { + public: + explicit GPUIDMAP(std::shared_ptr index, const int64_t &device_id) + : IDMAP(std::move(index)), GPUIndex(device_id) {} + + VectorIndexPtr CopyGpuToCpu(const Config &config) override; + float *GetRawVectors() override; + int64_t *GetRawIds() override; + VectorIndexPtr Clone() override; + VectorIndexPtr CopyGpuToGpu(const int64_t &device_id, const Config &config) override; + + protected: + BinarySet SerializeImpl() override; + void LoadImpl(const BinarySet &index_binary) override; +}; + +using GPUIDMAPPtr = std::shared_ptr; + +} +} diff --git a/cpp/src/core/include/knowhere/index/vector_index/ivf.h b/cpp/src/core/include/knowhere/index/vector_index/ivf.h new file mode 100644 index 0000000000..36f292d9e5 --- /dev/null +++ b/cpp/src/core/include/knowhere/index/vector_index/ivf.h @@ -0,0 +1,145 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 上海赜睿信息科技有限公司(Zilliz) - All Rights Reserved +// Unauthorized copying of this file, via any medium is strictly prohibited. +// Proprietary and confidential. +//////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include +#include + +#include +#include +#include + +#include "knowhere/index/vector_index/vector_index.h" + + +namespace zilliz { +namespace knowhere { + +class BasicIndex { + protected: + explicit BasicIndex(std::shared_ptr index); + virtual BinarySet SerializeImpl(); + virtual void LoadImpl(const BinarySet &index_binary); + virtual void + SealImpl(); + + protected: + std::shared_ptr index_ = nullptr; +}; + +using Graph = std::vector>; + +class IVF : public VectorIndex, protected BasicIndex { + public: + IVF() : BasicIndex(nullptr) {}; + explicit IVF(std::shared_ptr index) : BasicIndex(std::move(index)) {} + VectorIndexPtr Clone() override;; + IndexModelPtr Train(const DatasetPtr &dataset, const Config &config) override; + void set_index_model(IndexModelPtr model) override; + void Add(const DatasetPtr &dataset, const Config &config) override; + void AddWithoutIds(const DatasetPtr &dataset, const Config &config); + DatasetPtr Search(const DatasetPtr &dataset, const Config &config) override; + void GenGraph(const int64_t &k, Graph &graph, const DatasetPtr &dataset, const Config &config); + BinarySet Serialize() override; + void Load(const BinarySet &index_binary) override; + int64_t Count() override; + int64_t Dimension() override; + + void + Seal() override; + + virtual VectorIndexPtr CopyCpuToGpu(const int64_t &device_id, const Config &config); + + + protected: + virtual std::shared_ptr GenParams(const Config &config); + + virtual VectorIndexPtr Clone_impl(const std::shared_ptr &index); + + virtual void search_impl(int64_t n, + const float *data, + int64_t k, + float *distances, + int64_t *labels, + const Config &cfg); + + protected: + std::mutex mutex_; +}; + +using IVFIndexPtr = std::shared_ptr; + +class IVFSQ : public IVF { + public: + explicit IVFSQ(std::shared_ptr index) : IVF(std::move(index)) {} + IVFSQ() = default; + IndexModelPtr Train(const DatasetPtr &dataset, const Config &config) override; + VectorIndexPtr CopyCpuToGpu(const int64_t &device_id, const Config &config) override; + protected: + VectorIndexPtr Clone_impl(const std::shared_ptr &index) override; +}; + +class IVFPQ : public IVF { + public: + explicit IVFPQ(std::shared_ptr index) : IVF(std::move(index)) {} + IVFPQ() = default; + IndexModelPtr Train(const DatasetPtr &dataset, const Config &config) override; + protected: + std::shared_ptr GenParams(const Config &config) override; + VectorIndexPtr Clone_impl(const std::shared_ptr &index) override; +}; + + +//class OPQIVFPQ : public IVFPQ { +// public: +// PreprocessorPtr BuildPreprocessor(const Dataset &dataset, const Config &config) override; +//}; + + +class GPUIVF; + + +struct MemoryIOWriter : public faiss::IOWriter { + uint8_t *data_ = nullptr; + size_t total = 0; + size_t rp = 0; + + size_t operator()(const void *ptr, size_t size, size_t nitems) override; +}; + + +struct MemoryIOReader : public faiss::IOReader { + uint8_t *data_; + size_t rp = 0; + size_t total = 0; + + size_t operator()(void *ptr, size_t size, size_t nitems) override; + +}; + + +class IVFIndexModel : public IndexModel, public BasicIndex { + friend IVF; + friend GPUIVF; + + public: + explicit IVFIndexModel(std::shared_ptr index); + IVFIndexModel() : BasicIndex(nullptr) {}; + BinarySet Serialize() override; + protected: + void SealImpl() override; + public: + void Load(const BinarySet &binary) override; + + protected: + std::mutex mutex_; +}; + +using IVFIndexModelPtr = std::shared_ptr; + +} +} \ No newline at end of file diff --git a/cpp/src/core/include/knowhere/index/vector_index/kdt_parameters.h b/cpp/src/core/include/knowhere/index/vector_index/kdt_parameters.h new file mode 100644 index 0000000000..6f2d631d42 --- /dev/null +++ b/cpp/src/core/include/knowhere/index/vector_index/kdt_parameters.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include + + +namespace zilliz { +namespace knowhere { + +using KDTParameter = std::pair; + +class KDTParameterManagement { + public: + const std::vector & + GetKDTParameters(); + + public: + static KDTParameterManagement & + GetInstance() { + static KDTParameterManagement instance; + return instance; + } + + KDTParameterManagement(const KDTParameterManagement &) = delete; + KDTParameterManagement &operator=(const KDTParameterManagement &) = delete; + private: + KDTParameterManagement(); + + private: + std::vector kdt_parameters_; +}; + +} // namespace knowhere +} // namespace zilliz diff --git a/cpp/src/core/include/knowhere/index/vector_index/nsg/neighbor.h b/cpp/src/core/include/knowhere/index/vector_index/nsg/neighbor.h new file mode 100644 index 0000000000..40281d2d6d --- /dev/null +++ b/cpp/src/core/include/knowhere/index/vector_index/nsg/neighbor.h @@ -0,0 +1,51 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 上海赜睿信息科技有限公司(Zilliz) - All Rights Reserved +// Unauthorized copying of this file, via any medium is strictly prohibited. +// Proprietary and confidential. +//////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include + + +namespace zilliz { +namespace knowhere { +namespace algo { + +using node_t = int64_t; + +// TODO: search use simple neighbor +struct Neighbor { + node_t id; // offset of node in origin data + float distance; + bool has_explored; + + Neighbor() = default; + explicit Neighbor(node_t id, float distance, bool f) : id{id}, distance{distance}, has_explored(f) {} + + explicit Neighbor(node_t id, float distance) : id{id}, distance{distance}, has_explored(false) {} + + inline bool operator<(const Neighbor &other) const { + return distance < other.distance; + } +}; + +//struct SimpleNeighbor { +// node_t id; // offset of node in origin data +// float distance; +// +// SimpleNeighbor() = default; +// explicit SimpleNeighbor(node_t id, float distance) : id{id}, distance{distance}{} +// +// inline bool operator<(const Neighbor &other) const { +// return distance < other.distance; +// } +//}; + +typedef std::lock_guard LockGuard; + + +} +} +} \ No newline at end of file diff --git a/cpp/src/core/include/knowhere/index/vector_index/nsg/nsg.h b/cpp/src/core/include/knowhere/index/vector_index/nsg/nsg.h new file mode 100644 index 0000000000..080bfec043 --- /dev/null +++ b/cpp/src/core/include/knowhere/index/vector_index/nsg/nsg.h @@ -0,0 +1,147 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 上海赜睿信息科技有限公司(Zilliz) - All Rights Reserved +// Unauthorized copying of this file, via any medium is strictly prohibited. +// Proprietary and confidential. +//////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include +#include +#include + +#include +#include "neighbor.h" + + +namespace zilliz { +namespace knowhere { +namespace algo { + + +using node_t = int64_t; + +enum class MetricType { + METRIC_INNER_PRODUCT = 0, + METRIC_L2 = 1, +}; + +struct BuildParams { + size_t search_length; + size_t out_degree; + size_t candidate_pool_size; +}; + +struct SearchParams { + size_t search_length; +}; + +using Graph = std::vector>; + +class NsgIndex { + public: + size_t dimension; + size_t ntotal; // totabl nb of indexed vectors + MetricType metric_type; // L2 | IP + + float *ori_data_; + long *ids_; // TODO: support different type + Graph nsg; // final graph + Graph knng; // reset after build + + node_t navigation_point; // offset of node in origin data + + bool is_trained = false; + + /* + * build and search parameter + */ + size_t search_length; + size_t candidate_pool_size; // search deepth in fullset + size_t out_degree; + + public: + explicit NsgIndex(const size_t &dimension, + const size_t &n, + MetricType metric = MetricType::METRIC_L2); + + NsgIndex() = default; + + virtual ~NsgIndex(); + + void SetKnnGraph(Graph &knng); + + virtual void Build_with_ids(size_t nb, + const float *data, + const long *ids, + const BuildParams ¶meters); + + void Search(const float *query, + const unsigned &nq, + const unsigned &dim, + const unsigned &k, + float *dist, + long *ids, + SearchParams ¶ms); + + // Not support yet. + //virtual void Add() = 0; + //virtual void Add_with_ids() = 0; + //virtual void Delete() = 0; + //virtual void Delete_with_ids() = 0; + //virtual void Rebuild(size_t nb, + // const float *data, + // const long *ids, + // const Parameters ¶meters) = 0; + //virtual void Build(size_t nb, + // const float *data, + // const BuildParam ¶meters); + + protected: + virtual void InitNavigationPoint(); + + // link specify + void GetNeighbors(const float *query, + std::vector &resset, + std::vector &fullset, + boost::dynamic_bitset<> &has_calculated_dist); + + // FindUnconnectedNode + void GetNeighbors(const float *query, + std::vector &resset, + std::vector &fullset); + + // search and navigation-point + void GetNeighbors(const float *query, + std::vector &resset, + Graph &graph, + SearchParams *param = nullptr); + + void Link(); + + void SyncPrune(size_t q, + std::vector &pool, + boost::dynamic_bitset<> &has_calculated, + float *cut_graph_dist + ); + + void SelectEdge(unsigned &cursor, + std::vector &sort_pool, + std::vector &result, + bool limit = false); + + void InterInsert(unsigned n, std::vector &mutex_vec, float *dist); + + void CheckConnectivity(); + + void DFS(size_t root, boost::dynamic_bitset<> &flags, int64_t &count); + + void FindUnconnectedNode(boost::dynamic_bitset<> &flags, int64_t &root); + + private: + void GetKnnGraphFromFile(); +}; + +} +} +} diff --git a/cpp/src/core/include/knowhere/index/vector_index/nsg/nsg.i b/cpp/src/core/include/knowhere/index/vector_index/nsg/nsg.i new file mode 100644 index 0000000000..d66dc49029 --- /dev/null +++ b/cpp/src/core/include/knowhere/index/vector_index/nsg/nsg.i @@ -0,0 +1,15 @@ +%module nsg +%{ +#define SWIG_FILE_WITH_INIT +#include + +/* Include the header in the wrapper code */ +#include "nsg.h" + + +%} + + +/* Parse the header file */ +%include "index.h" + diff --git a/cpp/src/core/include/knowhere/index/vector_index/nsg/nsg_io.h b/cpp/src/core/include/knowhere/index/vector_index/nsg/nsg_io.h new file mode 100644 index 0000000000..5f20e715c7 --- /dev/null +++ b/cpp/src/core/include/knowhere/index/vector_index/nsg/nsg_io.h @@ -0,0 +1,22 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 上海赜睿信息科技有限公司(Zilliz) - All Rights Reserved +// Unauthorized copying of this file, via any medium is strictly prohibited. +// Proprietary and confidential. +//////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "nsg.h" +#include "knowhere/index/vector_index/ivf.h" + + +namespace zilliz { +namespace knowhere { +namespace algo { + +extern void write_index(NsgIndex* index, MemoryIOWriter& writer); +extern NsgIndex* read_index(MemoryIOReader& reader); + +} +} +} diff --git a/cpp/src/core/include/knowhere/index/vector_index/nsg_index.h b/cpp/src/core/include/knowhere/index/vector_index/nsg_index.h new file mode 100644 index 0000000000..21896fac49 --- /dev/null +++ b/cpp/src/core/include/knowhere/index/vector_index/nsg_index.h @@ -0,0 +1,41 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 上海赜睿信息科技有限公司(Zilliz) - All Rights Reserved +// Unauthorized copying of this file, via any medium is strictly prohibited. +// Proprietary and confidential. +//////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "knowhere/index/vector_index/vector_index.h" + + +namespace zilliz { +namespace knowhere { + +namespace algo { +class NsgIndex; +} + +class NSG : public VectorIndex { + public: + explicit NSG(const int64_t& gpu_num):gpu_(gpu_num){} + NSG() = default; + + IndexModelPtr Train(const DatasetPtr &dataset, const Config &config) override; + DatasetPtr Search(const DatasetPtr &dataset, const Config &config) override; + void Add(const DatasetPtr &dataset, const Config &config) override; + BinarySet Serialize() override; + void Load(const BinarySet &index_binary) override; + int64_t Count() override; + int64_t Dimension() override; + VectorIndexPtr Clone() override; + void Seal() override; + private: + std::shared_ptr index_; + int64_t gpu_; +}; + +using NSGIndexPtr = std::shared_ptr(); + +} +} diff --git a/cpp/src/core/include/knowhere/index/vector_index/vector_index.h b/cpp/src/core/include/knowhere/index/vector_index/vector_index.h new file mode 100644 index 0000000000..1618bc01bb --- /dev/null +++ b/cpp/src/core/include/knowhere/index/vector_index/vector_index.h @@ -0,0 +1,45 @@ +#pragma once + + +#include +#include "knowhere/common/config.h" +#include "knowhere/common/dataset.h" +#include "knowhere/index/index.h" +#include "knowhere/index/preprocessor/preprocessor.h" + + +namespace zilliz { +namespace knowhere { + +class VectorIndex; +using VectorIndexPtr = std::shared_ptr; + + +class VectorIndex : public Index { + public: + virtual PreprocessorPtr + BuildPreprocessor(const DatasetPtr &dataset, const Config &config) { return nullptr; } + + virtual IndexModelPtr + Train(const DatasetPtr &dataset, const Config &config) { return nullptr; } + + virtual void + Add(const DatasetPtr &dataset, const Config &config) = 0; + + virtual void + Seal() = 0; + + virtual VectorIndexPtr + Clone() = 0; + + virtual int64_t + Count() = 0; + + virtual int64_t + Dimension() = 0; +}; + + + +} // namespace knowhere +} // namespace zilliz diff --git a/cpp/src/core/src/CMakeLists.txt b/cpp/src/core/src/CMakeLists.txt new file mode 100644 index 0000000000..5b119f8b2b --- /dev/null +++ b/cpp/src/core/src/CMakeLists.txt @@ -0,0 +1,139 @@ +set(TBB_DIR ${CMAKE_SOURCE_DIR}/thirdparty/tbb) +set(TBB_LIBRARIES ${TBB_DIR}/libtbb.so) +include_directories(${TBB_DIR}/include) + +include_directories(${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES}) +link_directories(${CUDA_TOOLKIT_ROOT_DIR}/lib64) + +include_directories(${CMAKE_SOURCE_DIR}/include) +include_directories(${CMAKE_SOURCE_DIR}/thirdparty) +include_directories(${CMAKE_SOURCE_DIR}/thirdparty/SPTAG/AnnService) +include_directories(${CMAKE_SOURCE_DIR}/thirdparty/jsoncons-0.126.0/include) + +set(SPTAG_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../thirdparty/SPTAG) +file(GLOB HDR_FILES + ${SPTAG_SOURCE_DIR}/AnnService/inc/Core/*.h + ${SPTAG_SOURCE_DIR}/AnnService/inc/Core/Common/*.h + ${SPTAG_SOURCE_DIR}/AnnService/inc/Core/BKT/*.h + ${SPTAG_SOURCE_DIR}/AnnService/inc/Core/KDT/*.h + ${SPTAG_SOURCE_DIR}/AnnService/inc/Helper/*.h) +file(GLOB SRC_FILES + ${SPTAG_SOURCE_DIR}/AnnService/src/Core/*.cpp + ${SPTAG_SOURCE_DIR}/AnnService/src/Core/Common/*.cpp + ${SPTAG_SOURCE_DIR}/AnnService/src/Core/BKT/*.cpp + ${SPTAG_SOURCE_DIR}/AnnService/src/Core/KDT/*.cpp + ${SPTAG_SOURCE_DIR}/AnnService/src/Helper/*.cpp) + +#add_library(SPTAGLib SHARED ${SRC_FILES} ${HDR_FILES}) +#target_link_libraries(SPTAGLib ${TBB_LIBRARIES}) +add_library(SPTAGLibStatic STATIC ${SRC_FILES} ${HDR_FILES}) + +set(external_srcs + knowhere/adapter/sptag.cpp + knowhere/adapter/structure.cpp + knowhere/adapter/arrow.cpp + knowhere/common/exception.cpp + knowhere/common/timer.cpp + ) + +set(index_srcs + knowhere/index/preprocessor/normalize.cpp + knowhere/index/vector_index/cpu_kdt_rng.cpp + knowhere/index/vector_index/idmap.cpp + knowhere/index/vector_index/ivf.cpp + knowhere/index/vector_index/gpu_ivf.cpp + knowhere/index/vector_index/kdt_parameters.cpp + knowhere/index/vector_index/nsg_index.cpp + knowhere/index/vector_index/nsg/nsg.cpp + knowhere/index/vector_index/nsg/nsg_io.cpp + knowhere/index/vector_index/nsg/utils.cpp + knowhere/index/vector_index/cloner.cpp + ) + +set(depend_libs +# libtcmalloc.a + SPTAGLibStatic + ${TBB_LIBRARIES} + faiss + openblas + lapack + arrow + jemalloc_pic + cudart + cublas + gomp + gfortran + pthread + ) + +add_library( + knowhere STATIC + ${external_srcs} + ${index_srcs} +) +#target_compile_options(knowhere PUBLIC "-fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-free") + +target_link_libraries( + knowhere + ${depend_libs} +) + +#add_library( +# knowhereS SHARED +# ${external_srcs} +# ${index_srcs} +#) +# +#target_link_libraries( +# knowhereS +## ${TBB_LIBRARIES} +# ${depend_libs} +#) + +INSTALL(TARGETS + knowhere + SPTAGLibStatic + DESTINATION + lib) + +INSTALL(FILES + ${ARROW_STATIC_LIB} +# ${PARQUET_STATIC_LIB} + ${ARROW_PREFIX}/lib/libjemalloc_pic.a + ${FAISS_STATIC_LIB} + ${LAPACK_STATIC_LIB} + ${BLAS_STATIC_LIB} + DESTINATION + lib + ) + +INSTALL(FILES ${OPENBLAS_REAL_STATIC_LIB} + RENAME "libopenblas.a" + DESTINATION lib + ) + +INSTALL(FILES ${CMAKE_SOURCE_DIR}/thirdparty/tbb/libtbb.so.2 +# RENAME "libtbb.so.2" + DESTINATION lib + ) +INSTALL(FILES ${CMAKE_SOURCE_DIR}/thirdparty/tbb/libtbb.so +# RENAME "libtbb.so" + DESTINATION lib + ) + +INSTALL(DIRECTORY + ${CMAKE_SOURCE_DIR}/include/knowhere + ${CMAKE_SOURCE_DIR}/thirdparty/jsoncons-0.126.0/include/jsoncons + ${CMAKE_SOURCE_DIR}/thirdparty/jsoncons-0.126.0/include/jsoncons_ext + ${ARROW_INCLUDE_DIR}/arrow +# ${ARROW_INCLUDE_DIR}/parquet + ${FAISS_PREFIX}/include/faiss + ${OPENBLAS_INCLUDE_DIR}/ + ${CMAKE_SOURCE_DIR}/thirdparty/tbb/include/tbb + DESTINATION + include) + +INSTALL(DIRECTORY + ${SPTAG_SOURCE_DIR}/AnnService/inc/ + DESTINATION + include/SPTAG/AnnService/inc) diff --git a/cpp/src/core/src/knowhere/adapter/arrow.cpp b/cpp/src/core/src/knowhere/adapter/arrow.cpp new file mode 100644 index 0000000000..c70c584278 --- /dev/null +++ b/cpp/src/core/src/knowhere/adapter/arrow.cpp @@ -0,0 +1,39 @@ + +#include "knowhere/adapter/arrow.h" + +namespace zilliz { +namespace knowhere { + +ArrayPtr +CopyArray(const ArrayPtr &origin) { + ArrayPtr copy = nullptr; + auto copy_data = origin->data()->Copy(); + switch (origin->type_id()) { +#define DEFINE_TYPE(type, clazz) \ + case arrow::Type::type: { \ + copy = std::make_shared(copy_data); \ + } + DEFINE_TYPE(BOOL, BooleanArray) + DEFINE_TYPE(BINARY, BinaryArray) + DEFINE_TYPE(FIXED_SIZE_BINARY, FixedSizeBinaryArray) + DEFINE_TYPE(DECIMAL, Decimal128Array) + DEFINE_TYPE(FLOAT, NumericArray) + DEFINE_TYPE(INT64, NumericArray) + default:break; + } + return copy; +} + +SchemaPtr +CopySchema(const SchemaPtr &origin) { + std::vector> fields; + for (auto &field : origin->fields()) { + auto copy = std::make_shared(field->name(), field->type(),field->nullable(), nullptr); + fields.emplace_back(copy); + } + return std::make_shared(std::move(fields)); +} + + +} // namespace knowhere +} // namespace zilliz diff --git a/cpp/src/core/src/knowhere/adapter/sptag.cpp b/cpp/src/core/src/knowhere/adapter/sptag.cpp new file mode 100644 index 0000000000..a724a27d91 --- /dev/null +++ b/cpp/src/core/src/knowhere/adapter/sptag.cpp @@ -0,0 +1,116 @@ + +#include "knowhere/index/vector_index/definitions.h" +#include "knowhere/adapter/sptag.h" +#include "knowhere/adapter/structure.h" + + +namespace zilliz { +namespace knowhere { + + +std::shared_ptr +ConvertToMetadataSet(const DatasetPtr &dataset) { + auto array = dataset->array()[0]; + auto elems = array->length(); + + auto p_data = array->data()->GetValues(1, 0); + auto p_offset = (int64_t *) malloc(sizeof(int64_t) * elems); + for (auto i = 0; i <= elems; ++i) + p_offset[i] = i * 8; + + std::shared_ptr metaset(new SPTAG::MemMetadataSet( + SPTAG::ByteArray((std::uint8_t *) p_data, elems * sizeof(int64_t), false), + SPTAG::ByteArray((std::uint8_t *) p_offset, elems * sizeof(int64_t), true), + elems)); + + + return metaset; +} + +std::shared_ptr +ConvertToVectorSet(const DatasetPtr &dataset) { + auto tensor = dataset->tensor()[0]; + + auto p_data = tensor->raw_mutable_data(); + auto dimension = tensor->shape()[1]; + auto rows = tensor->shape()[0]; + auto num_bytes = tensor->size() * sizeof(float); + + SPTAG::ByteArray byte_array(p_data, num_bytes, false); + + auto vectorset = std::make_shared(byte_array, + SPTAG::VectorValueType::Float, + dimension, + rows); + return vectorset; +} + +std::vector +ConvertToQueryResult(const DatasetPtr &dataset, const Config &config) { + auto tensor = dataset->tensor()[0]; + + auto p_data = (float *) tensor->raw_mutable_data(); + auto dimension = tensor->shape()[1]; + auto rows = tensor->shape()[0]; + + auto k = config[META_K].as(); + std::vector query_results(rows, SPTAG::QueryResult(nullptr, k, true)); + for (auto i = 0; i < rows; ++i) { + query_results[i].SetTarget(&p_data[i * dimension]); + } + + return query_results; +} + +DatasetPtr +ConvertToDataset(std::vector query_results) { + auto k = query_results[0].GetResultNum(); + auto elems = query_results.size() * k; + + auto p_id = (int64_t *) malloc(sizeof(int64_t) * elems); + auto p_dist = (float *) malloc(sizeof(float) * elems); + // TODO: throw if malloc failed. + +#pragma omp parallel for + for (auto i = 0; i < query_results.size(); ++i) { + auto results = query_results[i].GetResults(); + auto num_result = query_results[i].GetResultNum(); + for (auto j = 0; j < num_result; ++j) { +// p_id[i * k + j] = results[j].VID; + p_id[i * k + j] = *(int64_t *) query_results[i].GetMetadata(j).Data(); + p_dist[i * k + j] = results[j].Dist; + } + } + + auto id_buf = MakeMutableBufferSmart((uint8_t *) p_id, sizeof(int64_t) * elems); + auto dist_buf = MakeMutableBufferSmart((uint8_t *) p_dist, sizeof(float) * elems); + + // TODO: magic + std::vector id_bufs{nullptr, id_buf}; + std::vector dist_bufs{nullptr, dist_buf}; + + auto int64_type = std::make_shared(); + auto float_type = std::make_shared(); + + auto id_array_data = arrow::ArrayData::Make(int64_type, elems, id_bufs); + auto dist_array_data = arrow::ArrayData::Make(float_type, elems, dist_bufs); +// auto id_array_data = std::make_shared(int64_type, sizeof(int64_t) * elems, id_bufs); +// auto dist_array_data = std::make_shared(float_type, sizeof(float) * elems, dist_bufs); + +// auto ids = ConstructInt64Array((uint8_t*)p_id, sizeof(int64_t) * elems); +// auto dists = ConstructFloatArray((uint8_t*)p_dist, sizeof(float) * elems); + + auto ids = std::make_shared>(id_array_data); + auto dists = std::make_shared>(dist_array_data); + std::vector array{ids, dists}; + + auto field_id = std::make_shared("id", std::make_shared()); + auto field_dist = std::make_shared("dist", std::make_shared()); + std::vector fields{field_id, field_dist}; + auto schema = std::make_shared(fields); + + return std::make_shared(array, schema); +} + +} // namespace knowhere +} // namespace zilliz diff --git a/cpp/src/core/src/knowhere/adapter/structure.cpp b/cpp/src/core/src/knowhere/adapter/structure.cpp new file mode 100644 index 0000000000..c78b1f125d --- /dev/null +++ b/cpp/src/core/src/knowhere/adapter/structure.cpp @@ -0,0 +1,76 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 上海赜睿信息科技有限公司(Zilliz) - All Rights Reserved +// Unauthorized copying of this file, via any medium is strictly prohibited. +// Proprietary and confidential. +//////////////////////////////////////////////////////////////////////////////// + +#include "knowhere/adapter/structure.h" + + +namespace zilliz { +namespace knowhere { + +ArrayPtr +ConstructInt64ArraySmart(uint8_t *data, int64_t size) { + // TODO: magic + std::vector id_buf{nullptr, MakeMutableBufferSmart(data, size)}; + auto type = std::make_shared(); + auto id_array_data = arrow::ArrayData::Make(type, size / sizeof(int64_t), id_buf); + return std::make_shared>(id_array_data); +} + +ArrayPtr +ConstructFloatArraySmart(uint8_t *data, int64_t size) { + // TODO: magic + std::vector id_buf{nullptr, MakeMutableBufferSmart(data, size)}; + auto type = std::make_shared(); + auto id_array_data = arrow::ArrayData::Make(type, size / sizeof(float), id_buf); + return std::make_shared>(id_array_data); +} + +TensorPtr +ConstructFloatTensorSmart(uint8_t *data, int64_t size, std::vector shape) { + auto buffer = MakeMutableBufferSmart(data, size); + auto float_type = std::make_shared(); + return std::make_shared(float_type, buffer, shape); +} + +ArrayPtr +ConstructInt64Array(uint8_t *data, int64_t size) { + // TODO: magic + std::vector id_buf{nullptr, MakeMutableBuffer(data, size)}; + auto type = std::make_shared(); + auto id_array_data = arrow::ArrayData::Make(type, size / sizeof(int64_t), id_buf); + return std::make_shared>(id_array_data); +} + +ArrayPtr +ConstructFloatArray(uint8_t *data, int64_t size) { + // TODO: magic + std::vector id_buf{nullptr, MakeMutableBuffer(data, size)}; + auto type = std::make_shared(); + auto id_array_data = arrow::ArrayData::Make(type, size / sizeof(float), id_buf); + return std::make_shared>(id_array_data); +} + +TensorPtr +ConstructFloatTensor(uint8_t *data, int64_t size, std::vector shape) { + auto buffer = MakeMutableBuffer(data, size); + auto float_type = std::make_shared(); + return std::make_shared(float_type, buffer, shape); +} + +FieldPtr +ConstructInt64Field(const std::string &name) { + auto type = std::make_shared(); + return std::make_shared(name, type); +} + + +FieldPtr +ConstructFloatField(const std::string &name) { + auto type = std::make_shared(); + return std::make_shared(name, type); +} +} +} diff --git a/cpp/src/core/src/knowhere/common/exception.cpp b/cpp/src/core/src/knowhere/common/exception.cpp new file mode 100644 index 0000000000..aec8c03650 --- /dev/null +++ b/cpp/src/core/src/knowhere/common/exception.cpp @@ -0,0 +1,29 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 上海赜睿信息科技有限公司(Zilliz) - All Rights Reserved +// Unauthorized copying of this file, via any medium is strictly prohibited. +// Proprietary and confidential. +//////////////////////////////////////////////////////////////////////////////// + +#include "knowhere/common/exception.h" +#include + +namespace zilliz { +namespace knowhere { + + +KnowhereException::KnowhereException(const std::string &msg):msg(msg) {} + +KnowhereException::KnowhereException(const std::string &m, const char *funcName, const char *file, int line) { + int size = snprintf(nullptr, 0, "Error in %s at %s:%d: %s", + funcName, file, line, m.c_str()); + msg.resize(size + 1); + snprintf(&msg[0], msg.size(), "Error in %s at %s:%d: %s", + funcName, file, line, m.c_str()); +} + +const char *KnowhereException::what() const noexcept { + return msg.c_str(); +} + +} +} \ No newline at end of file diff --git a/cpp/src/core/src/knowhere/common/timer.cpp b/cpp/src/core/src/knowhere/common/timer.cpp new file mode 100644 index 0000000000..01e62b2425 --- /dev/null +++ b/cpp/src/core/src/knowhere/common/timer.cpp @@ -0,0 +1,93 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 上海赜睿信息科技有限公司(Zilliz) - All Rights Reserved +// Unauthorized copying of this file, via any medium is strictly prohibited. +// Proprietary and confidential. +//////////////////////////////////////////////////////////////////////////////// + +#include // TODO(linxj): using Log instead + +#include "knowhere/common/timer.h" + +namespace zilliz { +namespace knowhere { + +TimeRecorder::TimeRecorder(const std::string &header, + int64_t log_level) : + header_(header), + log_level_(log_level) { + start_ = last_ = stdclock::now(); +} + +TimeRecorder::~TimeRecorder() { +} + +std::string +TimeRecorder::GetTimeSpanStr(double span) { + std::string str_sec = std::to_string(span * 0.000001) + ((span > 1000000) ? " seconds" : " second"); + std::string str_ms = std::to_string(span * 0.001) + " ms"; + + return str_sec + " [" + str_ms + "]"; +} + +void +TimeRecorder::PrintTimeRecord(const std::string &msg, double span) { + std::string str_log; + if (!header_.empty()) str_log += header_ + ": "; + str_log += msg; + str_log += " ("; + str_log += TimeRecorder::GetTimeSpanStr(span); + str_log += ")"; + + switch (log_level_) { + case 0: { + std::cout << str_log << std::endl; + break; + } + //case 1: { + // SERVER_LOG_DEBUG << str_log; + // break; + //} + //case 2: { + // SERVER_LOG_INFO << str_log; + // break; + //} + //case 3: { + // SERVER_LOG_WARNING << str_log; + // break; + //} + //case 4: { + // SERVER_LOG_ERROR << str_log; + // break; + //} + //case 5: { + // SERVER_LOG_FATAL << str_log; + // break; + //} + //default: { + // SERVER_LOG_INFO << str_log; + // break; + //} + } +} + +double +TimeRecorder::RecordSection(const std::string &msg) { + stdclock::time_point curr = stdclock::now(); + double span = (std::chrono::duration(curr - last_)).count(); + last_ = curr; + + PrintTimeRecord(msg, span); + return span; +} + +double +TimeRecorder::ElapseFromBegin(const std::string &msg) { + stdclock::time_point curr = stdclock::now(); + double span = (std::chrono::duration(curr - start_)).count(); + + PrintTimeRecord(msg, span); + return span; +} + +} +} \ No newline at end of file diff --git a/cpp/src/core/src/knowhere/index/preprocessor/normalize.cpp b/cpp/src/core/src/knowhere/index/preprocessor/normalize.cpp new file mode 100644 index 0000000000..a26854347e --- /dev/null +++ b/cpp/src/core/src/knowhere/index/preprocessor/normalize.cpp @@ -0,0 +1,42 @@ + +#include "knowhere/index/vector_index/definitions.h" +#include "knowhere/common/config.h" +#include "knowhere/index/preprocessor/normalize.h" + + +namespace zilliz { +namespace knowhere { + +DatasetPtr +NormalizePreprocessor::Preprocess(const DatasetPtr &dataset) { + // TODO: wrap dataset->tensor + auto tensor = dataset->tensor()[0]; + auto p_data = (float *)tensor->raw_mutable_data(); + auto dimension = tensor->shape()[1]; + auto rows = tensor->shape()[0]; + +#pragma omp parallel for + for (auto i = 0; i < rows; ++i) { + Normalize(&(p_data[i * dimension]), dimension); + } +} + +void +NormalizePreprocessor::Normalize(float *arr, int64_t dimension) { + double vector_length = 0; + for (auto j = 0; j < dimension; j++) { + double val = arr[j]; + vector_length += val * val; + } + vector_length = std::sqrt(vector_length); + if (vector_length < 1e-6) { + auto val = (float) (1.0 / std::sqrt((double) dimension)); + for (int j = 0; j < dimension; j++) arr[j] = val; + } else { + for (int j = 0; j < dimension; j++) arr[j] = (float) (arr[j] / vector_length); + } +} + +} // namespace knowhere +} // namespace zilliz + diff --git a/cpp/src/core/src/knowhere/index/vector_index/cloner.cpp b/cpp/src/core/src/knowhere/index/vector_index/cloner.cpp new file mode 100644 index 0000000000..7fd0df6664 --- /dev/null +++ b/cpp/src/core/src/knowhere/index/vector_index/cloner.cpp @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright 上海赜睿信息科技有限公司(Zilliz) - All Rights Reserved + * Unauthorized copying of this file, via any medium is strictly prohibited. + * Proprietary and confidential. + ******************************************************************************/ + +#include "knowhere/common/exception.h" +#include "knowhere/index/vector_index/cloner.h" +#include "knowhere/index/vector_index/ivf.h" +#include "knowhere/index/vector_index/gpu_ivf.h" +#include "knowhere/index/vector_index/idmap.h" + + +namespace zilliz { +namespace knowhere { + +VectorIndexPtr CopyGpuToCpu(const VectorIndexPtr &index, const Config &config) { + if (auto device_index = std::dynamic_pointer_cast(index)) { + return device_index->CopyGpuToCpu(config); + } else { + KNOWHERE_THROW_MSG("index type is not gpuindex"); + } +} + +VectorIndexPtr CopyCpuToGpu(const VectorIndexPtr &index, const int64_t &device_id, const Config &config) { + if (auto device_index = std::dynamic_pointer_cast(index)) { + return device_index->CopyGpuToGpu(device_id, config); + } + + if (auto cpu_index = std::dynamic_pointer_cast(index)) { + return cpu_index->CopyCpuToGpu(device_id, config); + //KNOWHERE_THROW_MSG("IVFSQ not support tranfer to gpu"); + } else if (auto cpu_index = std::dynamic_pointer_cast(index)) { + KNOWHERE_THROW_MSG("IVFPQ not support tranfer to gpu"); + } else if (auto cpu_index = std::dynamic_pointer_cast(index)) { + return cpu_index->CopyCpuToGpu(device_id, config); + } else if (auto cpu_index = std::dynamic_pointer_cast(index)) { + return cpu_index->CopyCpuToGpu(device_id, config); + } else { + KNOWHERE_THROW_MSG("this index type not support tranfer to gpu"); + } +} + +} +} diff --git a/cpp/src/core/src/knowhere/index/vector_index/cpu_kdt_rng.cpp b/cpp/src/core/src/knowhere/index/vector_index/cpu_kdt_rng.cpp new file mode 100644 index 0000000000..de885941e4 --- /dev/null +++ b/cpp/src/core/src/knowhere/index/vector_index/cpu_kdt_rng.cpp @@ -0,0 +1,155 @@ + +#include +#include +#include +#include + + +#undef mkdir + +#include "knowhere/index/vector_index/cpu_kdt_rng.h" +#include "knowhere/index/vector_index/definitions.h" +#include "knowhere/index/preprocessor/normalize.h" +#include "knowhere/index/vector_index/kdt_parameters.h" +#include "knowhere/adapter/sptag.h" +#include "knowhere/common/exception.h" + + +namespace zilliz { +namespace knowhere { + +BinarySet +CPUKDTRNG::Serialize() { + std::vector index_blobs; + std::vector index_len; + index_ptr_->SaveIndexToMemory(index_blobs, index_len); + BinarySet binary_set; + + auto sample = std::make_shared(); + sample.reset(static_cast(index_blobs[0])); + auto tree = std::make_shared(); + tree.reset(static_cast(index_blobs[1])); + auto graph = std::make_shared(); + graph.reset(static_cast(index_blobs[2])); + auto metadata = std::make_shared(); + metadata.reset(static_cast(index_blobs[3])); + + binary_set.Append("samples", sample, index_len[0]); + binary_set.Append("tree", tree, index_len[1]); + binary_set.Append("graph", graph, index_len[2]); + binary_set.Append("metadata", metadata, index_len[3]); + return binary_set; +} + +void +CPUKDTRNG::Load(const BinarySet &binary_set) { + std::vector index_blobs; + + auto samples = binary_set.GetByName("samples"); + index_blobs.push_back(samples->data.get()); + + auto tree = binary_set.GetByName("tree"); + index_blobs.push_back(tree->data.get()); + + auto graph = binary_set.GetByName("graph"); + index_blobs.push_back(graph->data.get()); + + auto metadata = binary_set.GetByName("metadata"); + index_blobs.push_back(metadata->data.get()); + + index_ptr_->LoadIndexFromMemory(index_blobs); +} + +PreprocessorPtr +CPUKDTRNG::BuildPreprocessor(const DatasetPtr &dataset, const Config &config) { + return std::make_shared(); +} + +IndexModelPtr +CPUKDTRNG::Train(const DatasetPtr &origin, const Config &train_config) { + SetParameters(train_config); + DatasetPtr dataset = origin->Clone(); + + if (index_ptr_->GetDistCalcMethod() == SPTAG::DistCalcMethod::Cosine + && preprocessor_) { + preprocessor_->Preprocess(dataset); + } + + auto vectorset = ConvertToVectorSet(dataset); + auto metaset = ConvertToMetadataSet(dataset); + index_ptr_->BuildIndex(vectorset, metaset); + + // TODO: return IndexModelPtr + return nullptr; +} + +void +CPUKDTRNG::Add(const DatasetPtr &origin, const Config &add_config) { + SetParameters(add_config); + DatasetPtr dataset = origin->Clone(); + + if (index_ptr_->GetDistCalcMethod() == SPTAG::DistCalcMethod::Cosine + && preprocessor_) { + preprocessor_->Preprocess(dataset); + } + + auto vectorset = ConvertToVectorSet(dataset); + auto metaset = ConvertToMetadataSet(dataset); + index_ptr_->AddIndex(vectorset, metaset); +} + +void +CPUKDTRNG::SetParameters(const Config &config) { + for (auto ¶ : KDTParameterManagement::GetInstance().GetKDTParameters()) { + auto value = config.get_with_default(para.first, para.second); + index_ptr_->SetParameter(para.first, value); + } +} + +DatasetPtr +CPUKDTRNG::Search(const DatasetPtr &dataset, const Config &config) { + SetParameters(config); + auto tensor = dataset->tensor()[0]; + auto p = (float *) tensor->raw_mutable_data(); + for (auto i = 0; i < 10; ++i) { + for (auto j = 0; j < 10; ++j) { + std::cout << p[i * 10 + j] << " "; + } + std::cout << std::endl; + } + std::vector query_results = ConvertToQueryResult(dataset, config); + +#pragma omp parallel for + for (auto i = 0; i < query_results.size(); ++i) { + auto target = (float *) query_results[i].GetTarget(); + std::cout << target[0] << ", " << target[1] << ", " << target[2] << std::endl; + index_ptr_->SearchIndex(query_results[i]); + } + + return ConvertToDataset(query_results); +} + +int64_t CPUKDTRNG::Count() { + index_ptr_->GetNumSamples(); +} +int64_t CPUKDTRNG::Dimension() { + index_ptr_->GetFeatureDim(); +} + +VectorIndexPtr CPUKDTRNG::Clone() { + KNOWHERE_THROW_MSG("not support"); +} + +void CPUKDTRNG::Seal() { + // do nothing +} + +// TODO(linxj): +BinarySet +CPUKDTRNGIndexModel::Serialize() {} + +void +CPUKDTRNGIndexModel::Load(const BinarySet &binary) {} + +} // namespace knowhere +} // namespace zilliz diff --git a/cpp/src/core/src/knowhere/index/vector_index/gpu_ivf.cpp b/cpp/src/core/src/knowhere/index/vector_index/gpu_ivf.cpp new file mode 100644 index 0000000000..01c4908511 --- /dev/null +++ b/cpp/src/core/src/knowhere/index/vector_index/gpu_ivf.cpp @@ -0,0 +1,309 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 上海赜睿信息科技有限公司(Zilliz) - All Rights Reserved +// Unauthorized copying of this file, via any medium is strictly prohibited. +// Proprietary and confidential. +//////////////////////////////////////////////////////////////////////////////// + + +#include +#include +#include +#include +#include +#include +#include + + +#include "knowhere/common/exception.h" +#include "knowhere/index/vector_index/cloner.h" +#include "knowhere/adapter/faiss_adopt.h" +#include "knowhere/index/vector_index/gpu_ivf.h" + + +namespace zilliz { +namespace knowhere { + +IndexModelPtr GPUIVF::Train(const DatasetPtr &dataset, const Config &config) { + auto nlist = config["nlist"].as(); + auto gpu_device = config.get_with_default("gpu_id", gpu_id_); + auto metric_type = config["metric_type"].as_string() == "L2" ? + faiss::METRIC_L2 : faiss::METRIC_INNER_PRODUCT; + + GETTENSOR(dataset) + + // TODO(linxj): use device_id + auto res = FaissGpuResourceMgr::GetInstance().GetRes(gpu_device); + ResScope rs(gpu_device, res); + faiss::gpu::GpuIndexIVFFlat device_index(res.get(), dim, nlist, metric_type); + device_index.train(rows, (float *) p_data); + + std::shared_ptr host_index = nullptr; + host_index.reset(faiss::gpu::index_gpu_to_cpu(&device_index)); + + return std::make_shared(host_index); +} + +void GPUIVF::set_index_model(IndexModelPtr model) { + std::lock_guard lk(mutex_); + + auto host_index = std::static_pointer_cast(model); + if (auto res = FaissGpuResourceMgr::GetInstance().GetRes(gpu_id_)) { + ResScope rs(gpu_id_, res); + auto device_index = faiss::gpu::index_cpu_to_gpu(res.get(), gpu_id_, host_index->index_.get()); + index_.reset(device_index); + } else { + KNOWHERE_THROW_MSG("load index model error, can't get gpu_resource"); + } +} + +BinarySet GPUIVF::SerializeImpl() { + if (!index_ || !index_->is_trained) { + KNOWHERE_THROW_MSG("index not initialize or trained"); + } + + try { + MemoryIOWriter writer; + { + faiss::Index *index = index_.get(); + faiss::Index *host_index = faiss::gpu::index_gpu_to_cpu(index); + + SealImpl(); + + faiss::write_index(host_index, &writer); + delete host_index; + } + auto data = std::make_shared(); + data.reset(writer.data_); + + BinarySet res_set; + res_set.Append("IVF", data, writer.rp); + + return res_set; + } catch (std::exception &e) { + KNOWHERE_THROW_MSG(e.what()); + } +} + +void GPUIVF::LoadImpl(const BinarySet &index_binary) { + auto binary = index_binary.GetByName("IVF"); + MemoryIOReader reader; + { + reader.total = binary->size; + reader.data_ = binary->data.get(); + + faiss::Index *index = faiss::read_index(&reader); + + if (auto res = FaissGpuResourceMgr::GetInstance().GetRes(gpu_id_)) { + ResScope rs(gpu_id_, res); + auto device_index = faiss::gpu::index_cpu_to_gpu(res.get(), gpu_id_, index); + index_.reset(device_index); + } else { + KNOWHERE_THROW_MSG("Load error, can't get gpu resource"); + } + + delete index; + } +} + +IVFIndexPtr GPUIVF::Copy_index_gpu_to_cpu() { + std::lock_guard lk(mutex_); + + faiss::Index *device_index = index_.get(); + faiss::Index *host_index = faiss::gpu::index_gpu_to_cpu(device_index); + + std::shared_ptr new_index; + new_index.reset(host_index); + return std::make_shared(new_index); +} + +void GPUIVF::search_impl(int64_t n, + const float *data, + int64_t k, + float *distances, + int64_t *labels, + const Config &cfg) { + if (auto device_index = std::static_pointer_cast(index_)) { + auto nprobe = cfg.get_with_default("nprobe", size_t(1)); + + std::lock_guard lk(mutex_); + device_index->setNumProbes(nprobe); + device_index->search(n, (float *) data, k, distances, labels); + } +} + +VectorIndexPtr GPUIVF::CopyGpuToCpu(const Config &config) { + std::lock_guard lk(mutex_); + + faiss::Index *device_index = index_.get(); + faiss::Index *host_index = faiss::gpu::index_gpu_to_cpu(device_index); + + std::shared_ptr new_index; + new_index.reset(host_index); + return std::make_shared(new_index); +} + +VectorIndexPtr GPUIVF::Clone() { + auto cpu_idx = CopyGpuToCpu(Config()); + return ::zilliz::knowhere::CopyCpuToGpu(cpu_idx, gpu_id_, Config()); +} + +VectorIndexPtr GPUIVF::CopyGpuToGpu(const int64_t &device_id, const Config &config) { + auto host_index = CopyGpuToCpu(config); + return std::static_pointer_cast(host_index)->CopyCpuToGpu(device_id, config); +} + +IndexModelPtr GPUIVFPQ::Train(const DatasetPtr &dataset, const Config &config) { + auto nlist = config["nlist"].as(); + auto M = config["M"].as(); // number of subquantizers(subvectors) + auto nbits = config["nbits"].as();// number of bit per subvector index + auto gpu_num = config.get_with_default("gpu_id", gpu_id_); + auto metric_type = config["metric_type"].as_string() == "L2" ? + faiss::METRIC_L2 : faiss::METRIC_L2; // IP not support. + + GETTENSOR(dataset) + + // TODO(linxj): set device here. + faiss::gpu::StandardGpuResources res; + faiss::gpu::GpuIndexIVFPQ device_index(&res, dim, nlist, M, nbits, metric_type); + device_index.train(rows, (float *) p_data); + + std::shared_ptr host_index = nullptr; + host_index.reset(faiss::gpu::index_gpu_to_cpu(&device_index)); + + return std::make_shared(host_index); +} + +std::shared_ptr GPUIVFPQ::GenParams(const Config &config) { + auto params = std::make_shared(); + params->nprobe = config.get_with_default("nprobe", size_t(1)); + //params->scan_table_threshold = 0; + //params->polysemous_ht = 0; + //params->max_codes = 0; + + return params; +} + +VectorIndexPtr GPUIVFPQ::CopyGpuToCpu(const Config &config) { + KNOWHERE_THROW_MSG("not support yet"); +} + +IndexModelPtr GPUIVFSQ::Train(const DatasetPtr &dataset, const Config &config) { + auto nlist = config["nlist"].as(); + auto nbits = config["nbits"].as(); // TODO(linxj): gpu only support SQ4 SQ8 SQ16 + auto gpu_num = config.get_with_default("gpu_id", gpu_id_); + auto metric_type = config["metric_type"].as_string() == "L2" ? + faiss::METRIC_L2 : faiss::METRIC_INNER_PRODUCT; + + GETTENSOR(dataset) + + std::stringstream index_type; + index_type << "IVF" << nlist << "," << "SQ" << nbits; + auto build_index = faiss::index_factory(dim, index_type.str().c_str(), metric_type); + + faiss::gpu::StandardGpuResources res; + auto device_index = faiss::gpu::index_cpu_to_gpu(&res, gpu_num, build_index); + device_index->train(rows, (float *) p_data); + + std::shared_ptr host_index = nullptr; + host_index.reset(faiss::gpu::index_gpu_to_cpu(device_index)); + + delete device_index; + delete build_index; + + return std::make_shared(host_index); +} + +VectorIndexPtr GPUIVFSQ::CopyGpuToCpu(const Config &config) { + std::lock_guard lk(mutex_); + + faiss::Index *device_index = index_.get(); + faiss::Index *host_index = faiss::gpu::index_gpu_to_cpu(device_index); + + std::shared_ptr new_index; + new_index.reset(host_index); + return std::make_shared(new_index); +} + +FaissGpuResourceMgr &FaissGpuResourceMgr::GetInstance() { + static FaissGpuResourceMgr instance; + return instance; +} + +void FaissGpuResourceMgr::AllocateTempMem(std::shared_ptr &res, + const int64_t &device_id, + const int64_t &size) { + if (size) { + res->setTempMemory(size); + } + else { + auto search = devices_params_.find(device_id); + if (search != devices_params_.end()) { + res->setTempMemory(search->second.temp_mem_size); + } + // else do nothing. allocate when use. + } +} + +void FaissGpuResourceMgr::InitDevice(int64_t device_id, + int64_t pin_mem_size, + int64_t temp_mem_size, + int64_t res_num) { + DeviceParams params; + params.pinned_mem_size = pin_mem_size; + params.temp_mem_size = temp_mem_size; + params.resource_num = res_num; + + devices_params_.emplace(device_id, params); +} + +void FaissGpuResourceMgr::InitResource() { + for(auto& device : devices_params_) { + auto& resource_vec = idle_[device.first]; + + for (int i = 0; i < device.second.resource_num; ++i) { + auto res = std::make_shared(); + res->noTempMemory(); + resource_vec.push_back(res); + } + } +} + +std::shared_ptr FaissGpuResourceMgr::GetRes(const int64_t &device_id, + const int64_t &alloc_size) { + std::lock_guard lk(mutex_); + + if (!is_init) { + InitResource(); + is_init = true; + } + + auto search = idle_.find(device_id); + if (search != idle_.end()) { + auto res = search->second.back(); + AllocateTempMem(res, device_id, alloc_size); + + search->second.pop_back(); + return res; + } +} + +void FaissGpuResourceMgr::MoveToInuse(const int64_t &device_id, const std::shared_ptr &res) { + std::lock_guard lk(mutex_); + in_use_[device_id].push_back(res); +} + +void FaissGpuResourceMgr::MoveToIdle(const int64_t &device_id, const std::shared_ptr &res) { + std::lock_guard lk(mutex_); + idle_[device_id].push_back(res); +} + +void GPUIndex::SetGpuDevice(const int &gpu_id) { + gpu_id_ = gpu_id; +} + +const int64_t &GPUIndex::GetGpuDevice() { + return gpu_id_; +} + +} +} diff --git a/cpp/src/core/src/knowhere/index/vector_index/idmap.cpp b/cpp/src/core/src/knowhere/index/vector_index/idmap.cpp new file mode 100644 index 0000000000..0f4823dd6a --- /dev/null +++ b/cpp/src/core/src/knowhere/index/vector_index/idmap.cpp @@ -0,0 +1,231 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 上海赜睿信息科技有限公司(Zilliz) - All Rights Reserved +// Unauthorized copying of this file, via any medium is strictly prohibited. +// Proprietary and confidential. +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include + + +#include "knowhere/common/exception.h" +#include "knowhere/adapter/faiss_adopt.h" +#include "knowhere/index/vector_index/idmap.h" + + +namespace zilliz { +namespace knowhere { + +BinarySet IDMAP::Serialize() { + if (!index_) { + KNOWHERE_THROW_MSG("index not initialize"); + } + + std::lock_guard lk(mutex_); + return SerializeImpl(); +} + +void IDMAP::Load(const BinarySet &index_binary) { + std::lock_guard lk(mutex_); + LoadImpl(index_binary); +} + +DatasetPtr IDMAP::Search(const DatasetPtr &dataset, const Config &config) { + if (!index_) { + KNOWHERE_THROW_MSG("index not initialize"); + } + + auto k = config["k"].as(); + + GETTENSOR(dataset) + + // TODO(linxj): handle malloc exception + auto elems = rows * k; + auto res_ids = (int64_t *) malloc(sizeof(int64_t) * elems); + auto res_dis = (float *) malloc(sizeof(float) * elems); + + index_->search(rows, (float *) p_data, k, res_dis, res_ids); + + auto id_buf = MakeMutableBufferSmart((uint8_t *) res_ids, sizeof(int64_t) * elems); + auto dist_buf = MakeMutableBufferSmart((uint8_t *) res_dis, sizeof(float) * elems); + + // TODO: magic + std::vector id_bufs{nullptr, id_buf}; + std::vector dist_bufs{nullptr, dist_buf}; + + auto int64_type = std::make_shared(); + auto float_type = std::make_shared(); + + auto id_array_data = arrow::ArrayData::Make(int64_type, elems, id_bufs); + auto dist_array_data = arrow::ArrayData::Make(float_type, elems, dist_bufs); + + auto ids = std::make_shared>(id_array_data); + auto dists = std::make_shared>(dist_array_data); + std::vector array{ids, dists}; + + return std::make_shared(array, nullptr); +} + +void IDMAP::Add(const DatasetPtr &dataset, const Config &config) { + if (!index_) { + KNOWHERE_THROW_MSG("index not initialize"); + } + + std::lock_guard lk(mutex_); + GETTENSOR(dataset) + + // TODO: magic here. + auto array = dataset->array()[0]; + auto p_ids = array->data()->GetValues(1, 0); + + index_->add_with_ids(rows, (float *) p_data, p_ids); +} + +int64_t IDMAP::Count() { + return index_->ntotal; +} + +int64_t IDMAP::Dimension() { + return index_->d; +} + +// TODO(linxj): return const pointer +float *IDMAP::GetRawVectors() { + try { + auto file_index = dynamic_cast(index_.get()); + auto flat_index = dynamic_cast(file_index->index); + return flat_index->xb.data(); + } catch (std::exception &e) { + KNOWHERE_THROW_MSG(e.what()); + } +} + +// TODO(linxj): return const pointer +int64_t *IDMAP::GetRawIds() { + try { + auto file_index = dynamic_cast(index_.get()); + return file_index->id_map.data(); + } catch (std::exception &e) { + KNOWHERE_THROW_MSG(e.what()); + } +} + +const char* type = "IDMap,Flat"; +void IDMAP::Train(const Config &config) { + auto metric_type = config["metric_type"].as_string() == "L2" ? + faiss::METRIC_L2 : faiss::METRIC_INNER_PRODUCT; + auto dim = config["dim"].as(); + + auto index = faiss::index_factory(dim, type, metric_type); + index_.reset(index); +} + +VectorIndexPtr IDMAP::Clone() { + std::lock_guard lk(mutex_); + + auto clone_index = faiss::clone_index(index_.get()); + std::shared_ptr new_index; + new_index.reset(clone_index); + return std::make_shared(new_index); +} + +VectorIndexPtr IDMAP::CopyCpuToGpu(const int64_t &device_id, const Config &config) { + if (auto res = FaissGpuResourceMgr::GetInstance().GetRes(device_id)){ + ResScope rs(device_id, res); + auto gpu_index = faiss::gpu::index_cpu_to_gpu(res.get(), device_id, index_.get()); + + std::shared_ptr device_index; + device_index.reset(gpu_index); + return std::make_shared(device_index, device_id); + } else { + KNOWHERE_THROW_MSG("CopyCpuToGpu Error, can't get gpu_resource"); + } +} + +void IDMAP::Seal() { + // do nothing +} + +VectorIndexPtr GPUIDMAP::CopyGpuToCpu(const Config &config) { + std::lock_guard lk(mutex_); + + faiss::Index *device_index = index_.get(); + faiss::Index *host_index = faiss::gpu::index_gpu_to_cpu(device_index); + + std::shared_ptr new_index; + new_index.reset(host_index); + return std::make_shared(new_index); +} + +VectorIndexPtr GPUIDMAP::Clone() { + auto cpu_idx = CopyGpuToCpu(Config()); + + if (auto idmap = std::dynamic_pointer_cast(cpu_idx)){ + return idmap->CopyCpuToGpu(gpu_id_, Config()); + } + else { + KNOWHERE_THROW_MSG("IndexType not Support GpuClone"); + } +} + +BinarySet GPUIDMAP::SerializeImpl() { + try { + MemoryIOWriter writer; + { + faiss::Index *index = index_.get(); + faiss::Index *host_index = faiss::gpu::index_gpu_to_cpu(index); + + faiss::write_index(host_index, &writer); + delete host_index; + } + auto data = std::make_shared(); + data.reset(writer.data_); + + BinarySet res_set; + res_set.Append("IVF", data, writer.rp); + + return res_set; + } catch (std::exception &e) { + KNOWHERE_THROW_MSG(e.what()); + } +} + +void GPUIDMAP::LoadImpl(const BinarySet &index_binary) { + auto binary = index_binary.GetByName("IVF"); + MemoryIOReader reader; + { + reader.total = binary->size; + reader.data_ = binary->data.get(); + + faiss::Index *index = faiss::read_index(&reader); + + if (auto res = FaissGpuResourceMgr::GetInstance().GetRes(gpu_id_) ){ + ResScope rs(gpu_id_, res); + auto device_index = faiss::gpu::index_cpu_to_gpu(res.get(), gpu_id_, index); + index_.reset(device_index); + } else { + KNOWHERE_THROW_MSG("Load error, can't get gpu resource"); + } + + delete index; + } +} + +VectorIndexPtr GPUIDMAP::CopyGpuToGpu(const int64_t &device_id, const Config &config) { + auto cpu_index = CopyGpuToCpu(config); + return std::static_pointer_cast(cpu_index)->CopyCpuToGpu(device_id, config); +} + +float *GPUIDMAP::GetRawVectors() { + KNOWHERE_THROW_MSG("Not support"); +} + +int64_t *GPUIDMAP::GetRawIds() { + KNOWHERE_THROW_MSG("Not support"); +} + +} +} diff --git a/cpp/src/core/src/knowhere/index/vector_index/ivf.cpp b/cpp/src/core/src/knowhere/index/vector_index/ivf.cpp new file mode 100644 index 0000000000..439e8c8ddb --- /dev/null +++ b/cpp/src/core/src/knowhere/index/vector_index/ivf.cpp @@ -0,0 +1,402 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 上海赜睿信息科技有限公司(Zilliz) - All Rights Reserved +// Unauthorized copying of this file, via any medium is strictly prohibited. +// Proprietary and confidential. +//////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "knowhere/common/exception.h" +#include "knowhere/index/vector_index/ivf.h" +#include "knowhere/adapter/faiss_adopt.h" +#include "knowhere/index/vector_index/gpu_ivf.h" + + +namespace zilliz { +namespace knowhere { + + +IndexModelPtr IVF::Train(const DatasetPtr &dataset, const Config &config) { + auto nlist = config["nlist"].as(); + auto metric_type = config["metric_type"].as_string() == "L2" ? + faiss::METRIC_L2 : faiss::METRIC_INNER_PRODUCT; + + GETTENSOR(dataset) + + faiss::Index *coarse_quantizer = new faiss::IndexFlatL2(dim); + auto index = std::make_shared(coarse_quantizer, dim, nlist, metric_type); + index->train(rows, (float *) p_data); + + // TODO: override here. train return model or not. + return std::make_shared(index); +} + + +void IVF::Add(const DatasetPtr &dataset, const Config &config) { + if (!index_ || !index_->is_trained) { + KNOWHERE_THROW_MSG("index not initialize or trained"); + } + + std::lock_guard lk(mutex_); + GETTENSOR(dataset) + + // TODO: magic here. + auto array = dataset->array()[0]; + auto p_ids = array->data()->GetValues(1, 0); + index_->add_with_ids(rows, (float *) p_data, p_ids); +} + +void IVF::AddWithoutIds(const DatasetPtr &dataset, const Config &config) { + if (!index_ || !index_->is_trained) { + KNOWHERE_THROW_MSG("index not initialize or trained"); + } + + std::lock_guard lk(mutex_); + GETTENSOR(dataset) + + index_->add(rows, (float *) p_data); +} + +BinarySet IVF::Serialize() { + if (!index_ || !index_->is_trained) { + KNOWHERE_THROW_MSG("index not initialize or trained"); + } + + std::lock_guard lk(mutex_); + Seal(); + return SerializeImpl(); +} + +void IVF::Load(const BinarySet &index_binary) { + std::lock_guard lk(mutex_); + LoadImpl(index_binary); +} + +DatasetPtr IVF::Search(const DatasetPtr &dataset, const Config &config) { + if (!index_ || !index_->is_trained) { + KNOWHERE_THROW_MSG("index not initialize or trained"); + } + + auto k = config["k"].as(); + + GETTENSOR(dataset) + + // TODO(linxj): handle malloc exception + auto elems = rows * k; + auto res_ids = (int64_t *) malloc(sizeof(int64_t) * elems); + auto res_dis = (float *) malloc(sizeof(float) * elems); + + search_impl(rows, (float*) p_data, k, res_dis, res_ids, config); + //faiss::ivflib::search_with_parameters(index_.get(), + // rows, + // (float *) p_data, + // k, + // res_dis, + // res_ids, + // params.get()); + + auto id_buf = MakeMutableBufferSmart((uint8_t *) res_ids, sizeof(int64_t) * elems); + auto dist_buf = MakeMutableBufferSmart((uint8_t *) res_dis, sizeof(float) * elems); + + // TODO: magic + std::vector id_bufs{nullptr, id_buf}; + std::vector dist_bufs{nullptr, dist_buf}; + + auto int64_type = std::make_shared(); + auto float_type = std::make_shared(); + + auto id_array_data = arrow::ArrayData::Make(int64_type, elems, id_bufs); + auto dist_array_data = arrow::ArrayData::Make(float_type, elems, dist_bufs); + + auto ids = std::make_shared>(id_array_data); + auto dists = std::make_shared>(dist_array_data); + std::vector array{ids, dists}; + + return std::make_shared(array, nullptr); +} + +void IVF::set_index_model(IndexModelPtr model) { + std::lock_guard lk(mutex_); + + auto rel_model = std::static_pointer_cast(model); + + // Deep copy here. + index_.reset(faiss::clone_index(rel_model->index_.get())); +} + +std::shared_ptr IVF::GenParams(const Config &config) { + auto params = std::make_shared(); + params->nprobe = config.get_with_default("nprobe", size_t(1)); + //params->max_codes = config.get_with_default("max_codes", size_t(0)); + + return params; +} + +int64_t IVF::Count() { + return index_->ntotal; +} + +int64_t IVF::Dimension() { + return index_->d; +} + +void IVF::GenGraph(const int64_t &k, Graph &graph, const DatasetPtr &dataset, const Config &config) { + GETTENSOR(dataset) + + auto ntotal = Count(); + + auto batch_size = 100; + auto tail_batch_size = ntotal % batch_size; + auto batch_search_count = ntotal / batch_size; + auto total_search_count = tail_batch_size == 0 ? batch_search_count : batch_search_count + 1; + + std::vector res_dis(k * batch_size); + graph.resize(ntotal); + Graph res_vec(total_search_count); + for (int i = 0; i < total_search_count; ++i) { + auto b_size = i == total_search_count - 1 && tail_batch_size != 0 ? tail_batch_size : batch_size; + + auto &res = res_vec[i]; + res.resize(k * b_size); + + auto xq = p_data + batch_size * dim * i; + search_impl(b_size, (float*)xq, k, res_dis.data(), res.data(), config); + + int tmp = 0; + for (int j = 0; j < b_size; ++j) { + auto &node = graph[batch_size * i + j]; + node.resize(k); + for (int m = 0; m < k && tmp < k * b_size; ++m, ++tmp) { + // TODO(linxj): avoid memcopy here. + node[m] = res[tmp]; + } + } + } +} + +void IVF::search_impl(int64_t n, + const float *data, + int64_t k, + float *distances, + int64_t *labels, + const Config &cfg) { + auto params = GenParams(cfg); + faiss::ivflib::search_with_parameters(index_.get(), n, (float *) data, k, distances, labels, params.get()); +} + +VectorIndexPtr IVF::CopyCpuToGpu(const int64_t& device_id, const Config &config) { + if (auto res = FaissGpuResourceMgr::GetInstance().GetRes(device_id)){ + ResScope rs(device_id, res); + auto gpu_index = faiss::gpu::index_cpu_to_gpu(res.get(), device_id, index_.get()); + + std::shared_ptr device_index; + device_index.reset(gpu_index); + return std::make_shared(device_index, device_id); + } else { + KNOWHERE_THROW_MSG("CopyCpuToGpu Error, can't get gpu_resource"); + } +} + +VectorIndexPtr IVF::Clone() { + std::lock_guard lk(mutex_); + + auto clone_index = faiss::clone_index(index_.get()); + std::shared_ptr new_index; + new_index.reset(clone_index); + return Clone_impl(new_index); +} + +VectorIndexPtr IVF::Clone_impl(const std::shared_ptr &index) { + return std::make_shared(index); +} + +void IVF::Seal() { + if (!index_ || !index_->is_trained) { + KNOWHERE_THROW_MSG("index not initialize or trained"); + } + SealImpl(); +} + + +IVFIndexModel::IVFIndexModel(std::shared_ptr index) : BasicIndex(std::move(index)) {} + +BinarySet IVFIndexModel::Serialize() { + if (!index_ || !index_->is_trained) { + KNOWHERE_THROW_MSG("indexmodel not initialize or trained"); + } + std::lock_guard lk(mutex_); + return SerializeImpl(); +} + +void IVFIndexModel::Load(const BinarySet &binary_set) { + std::lock_guard lk(mutex_); + LoadImpl(binary_set); +} + +void IVFIndexModel::SealImpl() { + // do nothing +} + +IndexModelPtr IVFSQ::Train(const DatasetPtr &dataset, const Config &config) { + auto nlist = config["nlist"].as(); + auto nbits = config["nbits"].as(); // TODO(linxj): only support SQ4 SQ6 SQ8 SQ16 + auto metric_type = config["metric_type"].as_string() == "L2" ? + faiss::METRIC_L2 : faiss::METRIC_INNER_PRODUCT; + + GETTENSOR(dataset) + + std::stringstream index_type; + index_type << "IVF" << nlist << "," << "SQ" << nbits; + auto build_index = faiss::index_factory(dim, index_type.str().c_str(), metric_type); + build_index->train(rows, (float *) p_data); + + std::shared_ptr ret_index; + ret_index.reset(build_index); + return std::make_shared(ret_index); +} + +VectorIndexPtr IVFSQ::Clone_impl(const std::shared_ptr &index) { + return std::make_shared(index); +} + +VectorIndexPtr IVFSQ::CopyCpuToGpu(const int64_t &device_id, const Config &config) { + if (auto res = FaissGpuResourceMgr::GetInstance().GetRes(device_id)){ + ResScope rs(device_id, res); + faiss::gpu::GpuClonerOptions option; + option.allInGpu = true; + + auto gpu_index = faiss::gpu::index_cpu_to_gpu(res.get(), device_id, index_.get(), &option); + + std::shared_ptr device_index; + device_index.reset(gpu_index); + return std::make_shared(device_index, device_id); + } else { + KNOWHERE_THROW_MSG("CopyCpuToGpu Error, can't get gpu_resource"); + } +} + +IndexModelPtr IVFPQ::Train(const DatasetPtr &dataset, const Config &config) { + auto nlist = config["nlist"].as(); + auto M = config["M"].as(); // number of subquantizers(subvector) + auto nbits = config["nbits"].as();// number of bit per subvector index + auto metric_type = config["metric_type"].as_string() == "L2" ? + faiss::METRIC_L2 : faiss::METRIC_INNER_PRODUCT; + + GETTENSOR(dataset) + + faiss::Index *coarse_quantizer = new faiss::IndexFlat(dim, metric_type); + auto index = std::make_shared(coarse_quantizer, dim, nlist, M, nbits); + index->train(rows, (float *) p_data); + + return std::make_shared(index); +} + +std::shared_ptr IVFPQ::GenParams(const Config &config) { + auto params = std::make_shared(); + params->nprobe = config.get_with_default("nprobe", size_t(1)); + //params->scan_table_threshold = 0; + //params->polysemous_ht = 0; + //params->max_codes = 0; + + return params; +} + +VectorIndexPtr IVFPQ::Clone_impl(const std::shared_ptr &index) { + return std::make_shared(index); +} + +BasicIndex::BasicIndex(std::shared_ptr index) : index_(std::move(index)) {} + +BinarySet BasicIndex::SerializeImpl() { + try { + faiss::Index *index = index_.get(); + + SealImpl(); + + MemoryIOWriter writer; + faiss::write_index(index, &writer); + auto data = std::make_shared(); + data.reset(writer.data_); + + BinarySet res_set; + // TODO(linxj): use virtual func Name() instead of raw string. + res_set.Append("IVF", data, writer.rp); + return res_set; + } catch (std::exception &e) { + KNOWHERE_THROW_MSG(e.what()); + } +} + +void BasicIndex::LoadImpl(const BinarySet &index_binary) { + auto binary = index_binary.GetByName("IVF"); + + MemoryIOReader reader; + reader.total = binary->size; + reader.data_ = binary->data.get(); + + faiss::Index *index = faiss::read_index(&reader); + + index_.reset(index); +} + +void BasicIndex::SealImpl() { +//#ifdef ZILLIZ_FAISS + faiss::Index *index = index_.get(); + auto idx = dynamic_cast(index); + if (idx != nullptr) { + idx->to_readonly(); + } +//#endif +} + +// TODO(linxj): Get From Config File +static size_t magic_num = 2; +size_t MemoryIOWriter::operator()(const void *ptr, size_t size, size_t nitems) { + auto total_need = size * nitems + rp; + + if (!data_) { // data == nullptr + total = total_need * magic_num; + rp = size * nitems; + data_ = new uint8_t[total]; + memcpy((void *) (data_), ptr, rp); + } + + if (total_need > total) { + total = total_need * magic_num; + auto new_data = new uint8_t[total]; + memcpy((void *) new_data, (void *) data_, rp); + delete data_; + data_ = new_data; + + memcpy((void *) (data_ + rp), ptr, size * nitems); + rp = total_need; + } else { + memcpy((void *) (data_ + rp), ptr, size * nitems); + rp = total_need; + } + + return nitems; +} + +size_t MemoryIOReader::operator()(void *ptr, size_t size, size_t nitems) { + if (rp >= total) return 0; + size_t nremain = (total - rp) / size; + if (nremain < nitems) nitems = nremain; + memcpy(ptr, (void *) (data_ + rp), size * nitems); + rp += size * nitems; + return nitems; +} + + +} +} diff --git a/cpp/src/core/src/knowhere/index/vector_index/kdt_parameters.cpp b/cpp/src/core/src/knowhere/index/vector_index/kdt_parameters.cpp new file mode 100644 index 0000000000..9f62b5d3a2 --- /dev/null +++ b/cpp/src/core/src/knowhere/index/vector_index/kdt_parameters.cpp @@ -0,0 +1,41 @@ + +#include +#include "knowhere/index/vector_index/kdt_parameters.h" + + +namespace zilliz { +namespace knowhere { + +const std::vector & +KDTParameterManagement::GetKDTParameters() { + return kdt_parameters_; +} + +KDTParameterManagement::KDTParameterManagement() { + kdt_parameters_ = std::vector{ + {"KDTNumber", "1"}, + {"NumTopDimensionKDTSplit", "5"}, + {"NumSamplesKDTSplitConsideration", "100"}, + + {"TPTNumber", "32"}, + {"TPTLeafSize", "2000"}, + {"NumTopDimensionTPTSplit", "5"}, + + {"NeighborhoodSize", "32"}, + {"GraphNeighborhoodScale", "2"}, + {"GraphCEFScale", "2"}, + {"RefineIterations", "0"}, + {"CEF", "1000"}, + {"MaxCheckForRefineGraph", "10000"}, + + {"NumberOfThreads", "1"}, + + {"MaxCheck", "8192"}, + {"ThresholdOfNumberOfContinuousNoBetterPropagation", "3"}, + {"NumberOfInitialDynamicPivots", "50"}, + {"NumberOfOtherDynamicPivots", "4"}, + }; +} + +} // namespace knowhere +} // namespace zilliz diff --git a/cpp/src/core/src/knowhere/index/vector_index/nsg/index_io.h b/cpp/src/core/src/knowhere/index/vector_index/nsg/index_io.h new file mode 100644 index 0000000000..0e32622f15 --- /dev/null +++ b/cpp/src/core/src/knowhere/index/vector_index/nsg/index_io.h @@ -0,0 +1,20 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 上海赜睿信息科技有限公司(Zilliz) - All Rights Reserved +// Unauthorized copying of this file, via any medium is strictly prohibited. +// Proprietary and confidential. +//////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "knowhere/index/vector_index/nsg/nsg.h" + +namespace zilliz { +namespace knowhere { +namespace algo { + +void read_from_file(NsgIndex* index, const char *filename); +void write_to_file(NsgIndex* index, const char *filename); + +} +} +} diff --git a/cpp/src/core/src/knowhere/index/vector_index/nsg/nsg.cpp b/cpp/src/core/src/knowhere/index/vector_index/nsg/nsg.cpp new file mode 100644 index 0000000000..8f9d041013 --- /dev/null +++ b/cpp/src/core/src/knowhere/index/vector_index/nsg/nsg.cpp @@ -0,0 +1,752 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 上海赜睿信息科技有限公司(Zilliz) - All Rights Reserved +// Unauthorized copying of this file, via any medium is strictly prohibited. +// Proprietary and confidential. +//////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include + +#include "knowhere/index/vector_index/nsg/nsg.h" +#include "knowhere/common/exception.h" +#include "knowhere/common/timer.h" +#include "utils.h" + +// TODO: enable macro +//#include + + +namespace zilliz { +namespace knowhere { +namespace algo { + + +NsgIndex::NsgIndex(const size_t &dimension, const size_t &n, MetricType metric) + : dimension(dimension), ntotal(n), metric_type(metric) { +} + +NsgIndex::~NsgIndex() { + delete[] ori_data_; + delete[] ids_; +} + +//void NsgIndex::Build(size_t nb, const float *data, const BuildParam ¶meters) { +//} +void NsgIndex::Build_with_ids(size_t nb, const float *data, const long *ids, const BuildParams ¶meters) { + TimeRecorder rc("NSG"); + + ntotal = nb; + ori_data_ = new float[ntotal * dimension]; + ids_ = new long[ntotal]; + memcpy((void *) ori_data_, (void *) data, sizeof(float) * ntotal * dimension); + memcpy((void *) ids_, (void *) ids, sizeof(long) * ntotal); + + search_length = parameters.search_length; + out_degree = parameters.out_degree; + candidate_pool_size = parameters.candidate_pool_size; + + InitNavigationPoint(); + rc.RecordSection("init"); + + Link(); + rc.RecordSection("Link"); + + //>> Debug code + ///// + //int count = 0; + //for (int i = 0; i < ntotal; ++i) { + // count += nsg[i].size(); + //} + ///// + + CheckConnectivity(); + rc.RecordSection("Connect"); + + //>> Debug code + /// + int total_degree = 0; + for (int i = 0; i < ntotal; ++i) { + total_degree += nsg[i].size(); + } + std::cout << "graph physical size: " << total_degree * sizeof(node_t) / 1024 / 1024; + std::cout << "average degree: " << total_degree / ntotal; + ///// + + is_trained = true; +} + +void NsgIndex::InitNavigationPoint() { + // calculate the center of vectors + auto center = new float[dimension]; + memset(center, 0, sizeof(float) * dimension); + + for (size_t i = 0; i < ntotal; i++) { + for (size_t j = 0; j < dimension; j++) { + center[j] += ori_data_[i * dimension + j]; + } + } + for (size_t j = 0; j < dimension; j++) { + center[j] /= ntotal; + } + + // select navigation point + std::vector resset, fullset; + navigation_point = rand() % ntotal; // random initialize navigating point + + //>> Debug code + ///// + //navigation_point = drand48(); + ///// + + GetNeighbors(center, resset, knng); + navigation_point = resset[0].id; + + //>> Debug code + ///// + //std::cout << "ep: " << navigation_point << std::endl; + ///// + + //>> Debug code + ///// + //float r1 = calculate(center, ori_data_ + navigation_point * dimension, dimension); + //assert(r1 == resset[0].distance); + ///// +} + +// Specify Link +void NsgIndex::GetNeighbors(const float *query, + std::vector &resset, + std::vector &fullset, + boost::dynamic_bitset<> &has_calculated_dist) { + auto &graph = knng; + size_t buffer_size = search_length; + + if (buffer_size > ntotal) { + // TODO: throw exception here. + } + + std::vector init_ids; + + { + /* + * copy navigation-point neighbor, pick random node if less than buffer size + */ + size_t count = 0; + + // Get all neighbors + for (size_t i = 0; i < graph[navigation_point].size(); ++i) { + init_ids.push_back(graph[navigation_point][i]); + has_calculated_dist[init_ids[i]] = true; + ++count; + } + while (count < buffer_size) { + node_t id = rand() % ntotal; + if (has_calculated_dist[id]) continue; // duplicate id + init_ids.push_back(id); + ++count; + has_calculated_dist[id] = true; + } + } + + { + resset.resize(init_ids.size()); + + // init resset and sort by distance + for (size_t i = 0; i < init_ids.size(); ++i) { + node_t id = init_ids[i]; + + if (id >= ntotal) { + KNOWHERE_THROW_MSG("Build Index Error, id > ntotal"); + continue; + } + + float dist = calculate(ori_data_ + dimension * id, query, dimension); + resset[i] = Neighbor(id, dist, false); + + ///////////// difference from other GetNeighbors /////////////// + fullset.push_back(resset[i]); + /////////////////////////////////////// + } + std::sort(resset.begin(), resset.end()); // sort by distance + + //search nearest neighbor + size_t cursor = 0; + while (cursor < buffer_size) { + size_t nearest_updated_pos = buffer_size; + + if (!resset[cursor].has_explored) { + resset[cursor].has_explored = true; + + node_t start_pos = resset[cursor].id; + auto &wait_for_search_node_vec = graph[start_pos]; + for (size_t i = 0; i < wait_for_search_node_vec.size(); ++i) { + node_t id = wait_for_search_node_vec[i]; + if (has_calculated_dist[id]) continue; + has_calculated_dist[id] = true; + + float + dist = calculate(query, ori_data_ + dimension * id, dimension); + Neighbor nn(id, dist, false); + fullset.push_back(nn); + + if (dist >= resset[buffer_size - 1].distance) continue; + + size_t pos = InsertIntoPool(resset.data(), buffer_size, nn); // replace with a closer node + if (pos < nearest_updated_pos) nearest_updated_pos = pos; + + //assert(buffer_size + 1 >= resset.size()); + if (buffer_size + 1 < resset.size()) ++buffer_size; + } + } + if (cursor >= nearest_updated_pos) { + cursor = nearest_updated_pos; // re-search from new pos + } else ++cursor; + } + } +} + +// FindUnconnectedNode +void NsgIndex::GetNeighbors(const float *query, std::vector &resset, std::vector &fullset) { + auto &graph = nsg; + size_t buffer_size = search_length; + + if (buffer_size > ntotal) { + // TODO: throw exception here. + } + + std::vector init_ids; + boost::dynamic_bitset<> has_calculated_dist{ntotal, 0}; // TODO: ? + + { + /* + * copy navigation-point neighbor, pick random node if less than buffer size + */ + size_t count = 0; + + // Get all neighbors + for (size_t i = 0; i < graph[navigation_point].size(); ++i) { + init_ids.push_back(graph[navigation_point][i]); + has_calculated_dist[init_ids[i]] = true; + ++count; + } + while (count < buffer_size) { + node_t id = rand() % ntotal; + if (has_calculated_dist[id]) continue; // duplicate id + init_ids.push_back(id); + ++count; + has_calculated_dist[id] = true; + } + } + + { + resset.resize(init_ids.size()); + + // init resset and sort by distance + for (size_t i = 0; i < init_ids.size(); ++i) { + node_t id = init_ids[i]; + + if (id >= ntotal) { + KNOWHERE_THROW_MSG("Build Index Error, id > ntotal"); + continue; + } + + float dist = calculate(ori_data_ + id * dimension, query, dimension); + resset[i] = Neighbor(id, dist, false); + } + std::sort(resset.begin(), resset.end()); // sort by distance + + // search nearest neighbor + size_t cursor = 0; + while (cursor < buffer_size) { + size_t nearest_updated_pos = buffer_size; + + if (!resset[cursor].has_explored) { + resset[cursor].has_explored = true; + + node_t start_pos = resset[cursor].id; + auto &wait_for_search_node_vec = graph[start_pos]; + for (size_t i = 0; i < wait_for_search_node_vec.size(); ++i) { + node_t id = wait_for_search_node_vec[i]; + if (has_calculated_dist[id]) continue; + has_calculated_dist[id] = true; + + float + dist = calculate(ori_data_ + dimension * id, query, dimension); + Neighbor nn(id, dist, false); + fullset.push_back(nn); + + if (dist >= resset[buffer_size - 1].distance) continue; + + size_t pos = InsertIntoPool(resset.data(), buffer_size, nn); // replace with a closer node + if (pos < nearest_updated_pos) nearest_updated_pos = pos; + + //assert(buffer_size + 1 >= resset.size()); + if (buffer_size + 1 < resset.size()) ++buffer_size; // trick + } + } + if (cursor >= nearest_updated_pos) { + cursor = nearest_updated_pos; // re-search from new pos + } else ++cursor; + } + } +} + +void NsgIndex::GetNeighbors(const float *query, + std::vector &resset, + Graph &graph, + SearchParams *params) { + size_t &buffer_size = params ? params->search_length : search_length; + + if (buffer_size > ntotal) { + // TODO: throw exception here. + } + + std::vector init_ids; + boost::dynamic_bitset<> has_calculated_dist{ntotal, 0}; + + { + /* + * copy navigation-point neighbor, pick random node if less than buffer size + */ + size_t count = 0; + + // Get all neighbors + for (size_t i = 0; i < graph[navigation_point].size(); ++i) { + init_ids.push_back(graph[navigation_point][i]); + has_calculated_dist[init_ids[i]] = true; + ++count; + } + while (count < buffer_size) { + node_t id = rand() % ntotal; + if (has_calculated_dist[id]) continue; // duplicate id + init_ids.push_back(id); + ++count; + has_calculated_dist[id] = true; + } + } + + { + resset.resize(init_ids.size()); + + // init resset and sort by distance + for (size_t i = 0; i < init_ids.size(); ++i) { + node_t id = init_ids[i]; + + //assert(id < ntotal); + if (id >= ntotal) { + KNOWHERE_THROW_MSG("Build Index Error, id > ntotal"); + continue; + } + + float dist = calculate(ori_data_ + id * dimension, query, dimension); + resset[i] = Neighbor(id, dist, false); + } + std::sort(resset.begin(), resset.end()); // sort by distance + + //>> Debug code + ///// + //for (int j = 0; j < buffer_size; ++j) { + // std::cout << "resset_id: " << resset[j].id << ", resset_dist: " << resset[j].distance << std::endl; + //} + ///// + + // search nearest neighbor + size_t cursor = 0; + while (cursor < buffer_size) { + size_t nearest_updated_pos = buffer_size; + + if (!resset[cursor].has_explored) { + resset[cursor].has_explored = true; + + node_t start_pos = resset[cursor].id; + auto &wait_for_search_node_vec = graph[start_pos]; + for (size_t i = 0; i < wait_for_search_node_vec.size(); ++i) { + node_t id = wait_for_search_node_vec[i]; + if (has_calculated_dist[id]) continue; + has_calculated_dist[id] = true; + + float + dist = calculate(query, ori_data_ + dimension * id, dimension); + + if (dist >= resset[buffer_size - 1].distance) continue; + ///////////// difference from other GetNeighbors /////////////// + Neighbor nn(id, dist, false); + /////////////////////////////////////// + + size_t pos = InsertIntoPool(resset.data(), buffer_size, nn); // replace with a closer node + if (pos < nearest_updated_pos) nearest_updated_pos = pos; + + //>> Debug code + ///// + //std::cout << "pos: " << pos << ", nn: " << nn.id << ":" << nn.distance << ", nup: " << nearest_updated_pos << std::endl; + ///// + + + // trick: avoid search query search_length < init_ids.size() ... + if (buffer_size + 1 < resset.size()) ++buffer_size; + } + } + if (cursor >= nearest_updated_pos) { + cursor = nearest_updated_pos; // re-search from new pos + } else ++cursor; + } + } +} + +void NsgIndex::Link() { + auto cut_graph_dist = new float[ntotal * out_degree]; + nsg.resize(ntotal); + +#pragma omp parallel + { + std::vector fullset; + std::vector temp; + boost::dynamic_bitset<> flags{ntotal, 0}; // TODO: ? +#pragma omp for schedule(dynamic, 100) + for (size_t n = 0; n < ntotal; ++n) { + fullset.clear(); + flags.reset(); + GetNeighbors(ori_data_ + dimension * n, temp, fullset, flags); + + //>> Debug code + ///// + //float r1 = calculate(ori_data_ + n * dimension, ori_data_ + temp[0].id * dimension, dimension); + //assert(r1 == temp[0].distance); + ///// + SyncPrune(n, fullset, flags, cut_graph_dist); + } + } + + //>> Debug code + ///// + //auto bak_nsg = nsg; + ///// + + knng.clear(); + knng.shrink_to_fit(); + + std::vector mutex_vec(ntotal); + +#pragma omp for schedule(dynamic, 100) + for (unsigned n = 0; n < ntotal; ++n) { + InterInsert(n, mutex_vec, cut_graph_dist); + } + delete[] cut_graph_dist; + + //>> Debug code + ///// + //int count = 0; + //for (int i = 0; i < ntotal; ++i) { + // if (bak_nsg[i].size() != nsg[i].size()) { + // //count += nsg[i].size() - bak_nsg[i].size(); + // count += nsg[i].size(); + // } + //} + ///// + + for (int i = 0; i < ntotal; ++i) { + nsg[i].shrink_to_fit(); + } +} + +void NsgIndex::SyncPrune(size_t n, + std::vector &pool, + boost::dynamic_bitset<> &has_calculated, + float *cut_graph_dist) { + // avoid lose nearest neighbor in knng + for (size_t i = 0; i < knng[n].size(); ++i) { + auto id = knng[n][i]; + if (has_calculated[id]) continue; + float dist = calculate(ori_data_ + dimension * n, + ori_data_ + dimension * id, dimension); + pool.emplace_back(Neighbor(id, dist, true)); + } + + // sort and find closest node + unsigned cursor = 0; + std::sort(pool.begin(), pool.end()); + std::vector result; + if (pool[cursor].id == n) cursor++; + result.push_back(pool[cursor]); // init result with nearest neighbor + + SelectEdge(cursor, pool, result, true); + + // filling the cut_graph + auto &des_id_pool = nsg[n]; + float *des_dist_pool = cut_graph_dist + n * out_degree; + for (size_t i = 0; i < result.size(); ++i) { + des_id_pool.push_back(result[i].id); + des_dist_pool[i] = result[i].distance; + } + if (result.size() < out_degree) { + des_dist_pool[result.size()] = -1; + } + //>> Optimize: reserve id_pool capacity +} + +//>> Optimize: remove read-lock +void NsgIndex::InterInsert(unsigned n, std::vector &mutex_vec, float *cut_graph_dist) { + auto ¤t = n; + + auto &neighbor_id_pool = nsg[current]; + float *neighbor_dist_pool = cut_graph_dist + current * out_degree; + for (size_t i = 0; i < out_degree; ++i) { + if (neighbor_dist_pool[i] == -1) break; + + size_t current_neighbor = neighbor_id_pool[i]; // center's neighbor id + auto &nsn_id_pool = nsg[current_neighbor]; // nsn => neighbor's neighbor + float *nsn_dist_pool = cut_graph_dist + current_neighbor * out_degree; + + std::vector wait_for_link_pool; // maintain candidate neighbor of the current neighbor. + int duplicate = false; + { + LockGuard lk(mutex_vec[current_neighbor]); + for (int j = 0; j < out_degree; ++j) { + if (nsn_dist_pool[j] == -1) break; + + // 保证至少有一条边能连回来 + if (n == nsn_id_pool[j]) { + duplicate = true; + break; + } + + Neighbor nsn(nsn_id_pool[j], nsn_dist_pool[j]); + wait_for_link_pool.push_back(nsn); + } + } + if (duplicate) continue; + + // original: (neighbor) <------- (current) + // after: (neighbor) -------> (current) + // current node as a neighbor of its neighbor + Neighbor current_as_neighbor(n, neighbor_dist_pool[i]); + wait_for_link_pool.push_back(current_as_neighbor); + + // re-selectEdge if candidate neighbor num > out_degree + if (wait_for_link_pool.size() > out_degree) { + std::vector result; + + unsigned start = 0; + std::sort(wait_for_link_pool.begin(), wait_for_link_pool.end()); + result.push_back(wait_for_link_pool[start]); + + SelectEdge(start, wait_for_link_pool, result); + + { + LockGuard lk(mutex_vec[current_neighbor]); + for (int j = 0; j < result.size(); ++j) { + nsn_id_pool[j] = result[j].id; + nsn_dist_pool[j] = result[j].distance; + } + } + } else { + LockGuard lk(mutex_vec[current_neighbor]); + for (int j = 0; j < out_degree; ++j) { + if (nsn_dist_pool[j] == -1) { + nsn_id_pool.push_back(current_as_neighbor.id); + nsn_dist_pool[j] = current_as_neighbor.distance; + if (j + 1 < out_degree) nsn_dist_pool[j + 1] = -1; + break; + } + } + } + + } +} + +void NsgIndex::SelectEdge(unsigned &cursor, + std::vector &sort_pool, + std::vector &result, + bool limit) { + auto &pool = sort_pool; + + /* + * edge selection + * + * search in pool and search deepth is under candidate_pool_size + * max result size equal to out_degress + */ + size_t search_deepth = limit ? candidate_pool_size : pool.size(); + while (result.size() < out_degree && cursor < search_deepth && (++cursor) < pool.size()) { + auto &p = pool[cursor]; + bool should_link = true; + for (size_t t = 0; t < result.size(); ++t) { + float dist = calculate(ori_data_ + dimension * result[t].id, + ori_data_ + dimension * p.id, dimension); + + if (dist < p.distance) { + should_link = false; + break; + } + } + if (should_link) result.push_back(p); + } +} + +void NsgIndex::CheckConnectivity() { + auto root = navigation_point; + boost::dynamic_bitset<> has_linked{ntotal, 0}; + int64_t linked_count = 0; + + while (linked_count < ntotal) { + DFS(root, has_linked, linked_count); + if (linked_count >= ntotal) break; + FindUnconnectedNode(has_linked, root); + } +} + +void NsgIndex::DFS(size_t root, boost::dynamic_bitset<> &has_linked, int64_t &linked_count) { + size_t start = root; + std::stack s; + s.push(root); + if (!has_linked[root]) { + linked_count++; // not link + has_linked[root] = true; // link start... + } + + while (!s.empty()) { + size_t next = ntotal + 1; + + for (unsigned i = 0; i < nsg[start].size(); i++) { + if (has_linked[nsg[start][i]] == false) // if not link + { + next = nsg[start][i]; + break; + } + } + if (next == (ntotal + 1)) { + s.pop(); + if (s.empty()) break; + start = s.top(); + continue; + } + start = next; + has_linked[start] = true; + s.push(start); + ++linked_count; + } +} + +void NsgIndex::FindUnconnectedNode(boost::dynamic_bitset<> &has_linked, int64_t &root) { + // find any of unlinked-node + size_t id = ntotal; + for (size_t i = 0; i < ntotal; i++) { // find not link + if (has_linked[i] == false) { + id = i; + break; + } + } + + if (id == ntotal) return; // No Unlinked Node + + // search unlinked-node's neighbor + std::vector tmp, pool; + GetNeighbors(ori_data_ + dimension * id, tmp, pool); + std::sort(pool.begin(), pool.end()); + + size_t found = 0; + for (size_t i = 0; i < pool.size(); i++) { // find nearest neighbor and add unlinked-node as its neighbor + if (has_linked[pool[i].id]) { + root = pool[i].id; + found = 1; + break; + } + } + if (found == 0) { + while (true) { // random a linked-node and add unlinked-node as its neighbor + size_t rid = rand() % ntotal; + if (has_linked[rid]) { + root = rid; + break; + } + } + } + nsg[root].push_back(id); +} + + +void NsgIndex::Search(const float *query, + const unsigned &nq, + const unsigned &dim, + const unsigned &k, + float *dist, + long *ids, + SearchParams ¶ms) { + std::vector> resset(nq); + + TimeRecorder rc("search"); + if (nq == 1) { + GetNeighbors(query, resset[0], nsg, ¶ms); + } else{ + //#pragma omp parallel for schedule(dynamic, 50) + #pragma omp parallel for + for (int i = 0; i < nq; ++i) { + // TODO(linxj): when to use openmp + auto single_query = query + i * dim; + GetNeighbors(single_query, resset[i], nsg, ¶ms); + } + } + rc.ElapseFromBegin("cost"); + + for (int i = 0; i < nq; ++i) { + for (int j = 0; j < k; ++j) { + //ids[i * k + j] = resset[i][j].id; + + // Fix(linxj): bug, reset[i][j] out of range + ids[i * k + j] = ids_[resset[i][j].id]; + dist[i * k + j] = resset[i][j].distance; + } + } + + //>> Debug: test single insert + //int x_0 = resset[0].size(); + //for (int l = 0; l < resset[0].size(); ++l) { + // resset[0].pop_back(); + //} + //resset.clear(); + + //ProfilerStart("xx.prof"); + //std::vector resset; + //GetNeighbors(query, resset, nsg, ¶ms); + //for (int i = 0; i < k; ++i) { + // ids[i] = resset[i].id; + //dist[i] = resset[i].distance; + //} + //ProfilerStop(); +} + +void NsgIndex::SetKnnGraph(Graph &g) { + knng = std::move(g); +} + +void NsgIndex::GetKnnGraphFromFile() { + //std::string filename = "/home/zilliz/opt/workspace/wook/efanna_graph/tests/sift.1M.50NN.graph"; + std::string filename = "/home/zilliz/opt/workspace/wook/efanna_graph/tests/sift.50NN.graph"; + + std::ifstream in(filename, std::ios::binary); + unsigned k; + in.read((char *) &k, sizeof(unsigned)); + in.seekg(0, std::ios::end); + std::ios::pos_type ss = in.tellg(); + size_t fsize = (size_t) ss; + size_t num = (unsigned) (fsize / (k + 1) / 4); + in.seekg(0, std::ios::beg); + + knng.resize(num); + knng.reserve(num); + unsigned kk = (k + 3) / 4 * 4; + for (size_t i = 0; i < num; i++) { + in.seekg(4, std::ios::cur); + knng[i].resize(k); + knng[i].reserve(kk); + in.read((char *) knng[i].data(), k * sizeof(unsigned)); + } + in.close(); +} + +} +} +} diff --git a/cpp/src/core/src/knowhere/index/vector_index/nsg/nsg_io.cpp b/cpp/src/core/src/knowhere/index/vector_index/nsg/nsg_io.cpp new file mode 100644 index 0000000000..e9854236bc --- /dev/null +++ b/cpp/src/core/src/knowhere/index/vector_index/nsg/nsg_io.cpp @@ -0,0 +1,59 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 上海赜睿信息科技有限公司(Zilliz) - All Rights Reserved +// Unauthorized copying of this file, via any medium is strictly prohibited. +// Proprietary and confidential. +//////////////////////////////////////////////////////////////////////////////// + +#include + +#include "knowhere/index/vector_index/nsg/nsg_io.h" + + +namespace zilliz { +namespace knowhere { +namespace algo { + +void write_index(NsgIndex *index, MemoryIOWriter &writer) { + writer(&index->ntotal, sizeof(index->ntotal), 1); + writer(&index->dimension, sizeof(index->dimension), 1); + writer(&index->navigation_point, sizeof(index->navigation_point), 1); + writer(index->ori_data_, sizeof(float) * index->ntotal * index->dimension, 1); + writer(index->ids_, sizeof(long) * index->ntotal, 1); + + for (unsigned i = 0; i < index->ntotal; ++i) { + auto neighbor_num = (node_t) index->nsg[i].size(); + writer(&neighbor_num, sizeof(node_t), 1); + writer(index->nsg[i].data(), neighbor_num * sizeof(node_t), 1); + } +} + +NsgIndex *read_index(MemoryIOReader &reader) { + size_t ntotal; + size_t dimension; + reader(&ntotal, sizeof(size_t), 1); + reader(&dimension, sizeof(size_t), 1); + auto index = new NsgIndex(dimension, ntotal); + reader(&index->navigation_point, sizeof(index->navigation_point), 1); + + index->ori_data_ = new float[index->ntotal * index->dimension]; + index->ids_ = new long[index->ntotal]; + reader(index->ori_data_, sizeof(float) * index->ntotal * index->dimension, 1); + reader(index->ids_, sizeof(long) * index->ntotal, 1); + + index->nsg.reserve(index->ntotal); + index->nsg.resize(index->ntotal); + node_t neighbor_num; + for (unsigned i = 0; i < index->ntotal; ++i) { + reader(&neighbor_num, sizeof(node_t), 1); + index->nsg[i].reserve(neighbor_num); + index->nsg[i].resize(neighbor_num); + reader(index->nsg[i].data(), neighbor_num * sizeof(node_t), 1); + } + + index->is_trained = true; + return index; +} + +} +} +} diff --git a/cpp/src/core/src/knowhere/index/vector_index/nsg/utils.cpp b/cpp/src/core/src/knowhere/index/vector_index/nsg/utils.cpp new file mode 100644 index 0000000000..4be8aece02 --- /dev/null +++ b/cpp/src/core/src/knowhere/index/vector_index/nsg/utils.cpp @@ -0,0 +1,166 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 上海赜睿信息科技有限公司(Zilliz) - All Rights Reserved +// Unauthorized copying of this file, via any medium is strictly prohibited. +// Proprietary and confidential. +//////////////////////////////////////////////////////////////////////////////// + +#include +#include + +#include "utils.h" + + +namespace zilliz { +namespace knowhere { +namespace algo { + +// TODO: impl search && insert && return insert pos. why not just find and swap? +int InsertIntoPool(Neighbor *addr, unsigned K, Neighbor nn) { + //>> Fix: Add assert + for (int i = 0; i < K; ++i) { + assert(addr[i].id != nn.id); + } + + // find the location to insert + int left = 0, right = K - 1; + if (addr[left].distance > nn.distance) { + //>> Fix: memmove overflow, dump when vector deconstruct + memmove((char *) &addr[left + 1], &addr[left], (K - 1) * sizeof(Neighbor)); + addr[left] = nn; + return left; + } + if (addr[right].distance < nn.distance) { + addr[K] = nn; + return K; + } + while (left < right - 1) { + int mid = (left + right) / 2; + if (addr[mid].distance > nn.distance) + right = mid; + else + left = mid; + } + //check equal ID + + while (left > 0) { + if (addr[left].distance < nn.distance) // pos is right + break; + if (addr[left].id == nn.id) + return K + 1; + left--; + } + if (addr[left].id == nn.id || addr[right].id == nn.id) + return K + 1; + + //>> Fix: memmove overflow, dump when vector deconstruct + memmove((char *) &addr[right + 1], &addr[right], (K - 1 - right) * sizeof(Neighbor)); + addr[right] = nn; + return right; +} + +// TODO: support L2 / IP +float calculate(const float *a, const float *b, unsigned size) { + float result = 0; + +#ifdef __GNUC__ +#ifdef __AVX__ + +#define AVX_L2SQR(addr1, addr2, dest, tmp1, tmp2) \ + tmp1 = _mm256_loadu_ps(addr1);\ + tmp2 = _mm256_loadu_ps(addr2);\ + tmp1 = _mm256_sub_ps(tmp1, tmp2); \ + tmp1 = _mm256_mul_ps(tmp1, tmp1); \ + dest = _mm256_add_ps(dest, tmp1); + + __m256 sum; + __m256 l0, l1; + __m256 r0, r1; + unsigned D = (size + 7) & ~7U; + unsigned DR = D % 16; + unsigned DD = D - DR; + const float *l = a; + const float *r = b; + const float *e_l = l + DD; + const float *e_r = r + DD; + float unpack[8] __attribute__ ((aligned (32))) = {0, 0, 0, 0, 0, 0, 0, 0}; + + sum = _mm256_loadu_ps(unpack); + if (DR) { AVX_L2SQR(e_l, e_r, sum, l0, r0); } + + for (unsigned i = 0; i < DD; i += 16, l += 16, r += 16) { + AVX_L2SQR(l, r, sum, l0, r0); + AVX_L2SQR(l + 8, r + 8, sum, l1, r1); + } + _mm256_storeu_ps(unpack, sum); + result = unpack[0] + unpack[1] + unpack[2] + unpack[3] + unpack[4] + unpack[5] + unpack[6] + unpack[7]; + +#else +#ifdef __SSE2__ +#define SSE_L2SQR(addr1, addr2, dest, tmp1, tmp2) \ + tmp1 = _mm_load_ps(addr1);\ + tmp2 = _mm_load_ps(addr2);\ + tmp1 = _mm_sub_ps(tmp1, tmp2); \ + tmp1 = _mm_mul_ps(tmp1, tmp1); \ + dest = _mm_add_ps(dest, tmp1); + + __m128 sum; + __m128 l0, l1, l2, l3; + __m128 r0, r1, r2, r3; + unsigned D = (size + 3) & ~3U; + unsigned DR = D % 16; + unsigned DD = D - DR; + const float *l = a; + const float *r = b; + const float *e_l = l + DD; + const float *e_r = r + DD; + float unpack[4] __attribute__ ((aligned (16))) = {0, 0, 0, 0}; + + sum = _mm_load_ps(unpack); + switch (DR) { + case 12:SSE_L2SQR(e_l + 8, e_r + 8, sum, l2, r2); + case 8:SSE_L2SQR(e_l + 4, e_r + 4, sum, l1, r1); + case 4:SSE_L2SQR(e_l, e_r, sum, l0, r0); + default:break; + } + for (unsigned i = 0; i < DD; i += 16, l += 16, r += 16) { + SSE_L2SQR(l, r, sum, l0, r0); + SSE_L2SQR(l + 4, r + 4, sum, l1, r1); + SSE_L2SQR(l + 8, r + 8, sum, l2, r2); + SSE_L2SQR(l + 12, r + 12, sum, l3, r3); + } + _mm_storeu_ps(unpack, sum); + result += unpack[0] + unpack[1] + unpack[2] + unpack[3]; + +//nomal distance +#else + + float diff0, diff1, diff2, diff3; + const float* last = a + size; + const float* unroll_group = last - 3; + + /* Process 4 items with each loop for efficiency. */ + while (a < unroll_group) { + diff0 = a[0] - b[0]; + diff1 = a[1] - b[1]; + diff2 = a[2] - b[2]; + diff3 = a[3] - b[3]; + result += diff0 * diff0 + diff1 * diff1 + diff2 * diff2 + diff3 * diff3; + a += 4; + b += 4; + } + /* Process last 0-3 pixels. Not needed for standard vector lengths. */ + while (a < last) { + diff0 = *a++ - *b++; + result += diff0 * diff0; + } +#endif +#endif +#endif + + return result; +} + + +} +} +} \ No newline at end of file diff --git a/cpp/src/core/src/knowhere/index/vector_index/nsg/utils.h b/cpp/src/core/src/knowhere/index/vector_index/nsg/utils.h new file mode 100644 index 0000000000..4d9dbbbda3 --- /dev/null +++ b/cpp/src/core/src/knowhere/index/vector_index/nsg/utils.h @@ -0,0 +1,27 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 上海赜睿信息科技有限公司(Zilliz) - All Rights Reserved +// Unauthorized copying of this file, via any medium is strictly prohibited. +// Proprietary and confidential. +//////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include +#include + +#include + +#include "knowhere/index/vector_index/nsg/nsg.h" +#include "knowhere/common/config.h" + + +namespace zilliz { +namespace knowhere { +namespace algo { + +extern int InsertIntoPool(Neighbor *addr, unsigned K, Neighbor nn); +extern float calculate(const float *a, const float *b, unsigned size); + +} +} +} diff --git a/cpp/src/core/src/knowhere/index/vector_index/nsg_index.cpp b/cpp/src/core/src/knowhere/index/vector_index/nsg_index.cpp new file mode 100644 index 0000000000..aa56b81382 --- /dev/null +++ b/cpp/src/core/src/knowhere/index/vector_index/nsg_index.cpp @@ -0,0 +1,157 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 上海赜睿信息科技有限公司(Zilliz) - All Rights Reserved +// Unauthorized copying of this file, via any medium is strictly prohibited. +// Proprietary and confidential. +//////////////////////////////////////////////////////////////////////////////// + +#include "knowhere/index/vector_index/nsg_index.h" +#include "knowhere/index/vector_index/nsg/nsg.h" +#include "knowhere/index/vector_index/nsg/nsg_io.h" +#include "knowhere/index/vector_index/idmap.h" +#include "knowhere/index/vector_index/ivf.h" +#include "knowhere/index/vector_index/gpu_ivf.h" +#include "knowhere/adapter/faiss_adopt.h" +#include "knowhere/common/exception.h" +#include "knowhere/common/timer.h" + + +namespace zilliz { +namespace knowhere { + +BinarySet NSG::Serialize() { + if (!index_ || !index_->is_trained) { + KNOWHERE_THROW_MSG("index not initialize or trained"); + } + + try { + algo::NsgIndex *index = index_.get(); + + MemoryIOWriter writer; + algo::write_index(index, writer); + auto data = std::make_shared(); + data.reset(writer.data_); + + BinarySet res_set; + res_set.Append("NSG", data, writer.total); + return res_set; + } catch (std::exception &e) { + KNOWHERE_THROW_MSG(e.what()); + } +} + +void NSG::Load(const BinarySet &index_binary) { + try { + auto binary = index_binary.GetByName("NSG"); + + MemoryIOReader reader; + reader.total = binary->size; + reader.data_ = binary->data.get(); + + auto index = algo::read_index(reader); + index_.reset(index); + } catch (std::exception &e) { + KNOWHERE_THROW_MSG(e.what()); + } +} + +DatasetPtr NSG::Search(const DatasetPtr &dataset, const Config &config) { + if (!index_ || !index_->is_trained) { + KNOWHERE_THROW_MSG("index not initialize or trained"); + } + + // Required + // if not found throw exception here. + auto k = config["k"].as(); + auto search_length = config.get_with_default("search_length", 30); + + GETTENSOR(dataset) + + auto elems = rows * k; + auto res_ids = (int64_t *) malloc(sizeof(int64_t) * elems); + auto res_dis = (float *) malloc(sizeof(float) * elems); + + // TODO(linxj): get from config + algo::SearchParams s_params; + s_params.search_length = search_length; + index_->Search((float *) p_data, rows, dim, k, res_dis, res_ids, s_params); + + auto id_buf = MakeMutableBufferSmart((uint8_t *) res_ids, sizeof(int64_t) * elems); + auto dist_buf = MakeMutableBufferSmart((uint8_t *) res_dis, sizeof(float) * elems); + + // TODO: magic + std::vector id_bufs{nullptr, id_buf}; + std::vector dist_bufs{nullptr, dist_buf}; + + auto int64_type = std::make_shared(); + auto float_type = std::make_shared(); + + auto id_array_data = arrow::ArrayData::Make(int64_type, elems, id_bufs); + auto dist_array_data = arrow::ArrayData::Make(float_type, elems, dist_bufs); + + auto ids = std::make_shared>(id_array_data); + auto dists = std::make_shared>(dist_array_data); + std::vector array{ids, dists}; + + return std::make_shared(array, nullptr); +} + +IndexModelPtr NSG::Train(const DatasetPtr &dataset, const Config &config) { + TimeRecorder rc("Interface"); + + auto metric_type = config["metric_type"].as_string(); + if (metric_type != "L2") { KNOWHERE_THROW_MSG("NSG not support this kind of metric type");} + + // TODO(linxj): dev IndexFactory, support more IndexType + auto preprocess_index = std::make_shared(0); + //auto preprocess_index = std::make_shared(); + auto model = preprocess_index->Train(dataset, config); + preprocess_index->set_index_model(model); + preprocess_index->AddWithoutIds(dataset, config); + rc.RecordSection("build ivf"); + + auto k = config["knng"].as(); + Graph knng; + preprocess_index->GenGraph(k, knng, dataset, config); + rc.RecordSection("build knng"); + + GETTENSOR(dataset) + auto array = dataset->array()[0]; + auto p_ids = array->data()->GetValues(1, 0); + + algo::BuildParams b_params; + b_params.candidate_pool_size = config["candidate_pool_size"].as(); + b_params.out_degree = config["out_degree"].as(); + b_params.search_length = config["search_length"].as(); + + index_ = std::make_shared(dim, rows); + index_->SetKnnGraph(knng); + index_->Build_with_ids(rows, (float *) p_data, (long *) p_ids, b_params); + rc.RecordSection("build nsg"); + rc.ElapseFromBegin("total cost"); + return nullptr; // TODO(linxj): support serialize +} + +void NSG::Add(const DatasetPtr &dataset, const Config &config) { + // TODO(linxj): support incremental index. + + //KNOWHERE_THROW_MSG("Not support yet"); +} + +int64_t NSG::Count() { + return index_->ntotal; +} + +int64_t NSG::Dimension() { + return index_->dimension; +} +VectorIndexPtr NSG::Clone() { + KNOWHERE_THROW_MSG("not support"); +} + +void NSG::Seal() { + // do nothing +} + +} +} + diff --git a/cpp/src/core/test/CMakeLists.txt b/cpp/src/core/test/CMakeLists.txt new file mode 100644 index 0000000000..fbbf151264 --- /dev/null +++ b/cpp/src/core/test/CMakeLists.txt @@ -0,0 +1,79 @@ +include_directories(${CMAKE_SOURCE_DIR}/thirdparty) +include_directories(${CMAKE_SOURCE_DIR}/thirdparty/SPTAG/AnnService) +include_directories(${CMAKE_SOURCE_DIR}/include) +include_directories(${CMAKE_SOURCE_DIR}/thirdparty/jsoncons-0.126.0/include) +include_directories(/usr/local/cuda/include) +link_directories(/usr/local/cuda/lib64) +link_directories(${CMAKE_SOURCE_DIR}/thirdparty/tbb) + +set(unittest_libs + gtest gmock gtest_main gmock_main) + +set(depend_libs + faiss openblas lapack + arrow jemalloc_pic + tbb + ) + +set(basic_libs + cudart cublas + gomp gfortran pthread + ) + + +# +#<<<<<<<<<< +set(ivf_srcs + ${CMAKE_SOURCE_DIR}/src/knowhere/index/vector_index/ivf.cpp + ${CMAKE_SOURCE_DIR}/src/knowhere/index/vector_index/gpu_ivf.cpp + ${CMAKE_SOURCE_DIR}/src/knowhere/index/vector_index/cloner.cpp + ${CMAKE_SOURCE_DIR}/src/knowhere/index/vector_index/idmap.cpp + ${CMAKE_SOURCE_DIR}/src/knowhere/adapter/structure.cpp + ${CMAKE_SOURCE_DIR}/src/knowhere/common/exception.cpp + ${CMAKE_SOURCE_DIR}/src/knowhere/common/timer.cpp + utils.cpp + ) +add_executable(test_ivf test_ivf.cpp ${ivf_srcs}) +target_link_libraries(test_ivf ${depend_libs} ${unittest_libs} ${basic_libs}) +#<<<<<<<<<< + +# +#<<<<<<<<<< +set(idmap_srcs + ${CMAKE_SOURCE_DIR}/src/knowhere/index/vector_index/idmap.cpp + ${CMAKE_SOURCE_DIR}/src/knowhere/index/vector_index/ivf.cpp + ${CMAKE_SOURCE_DIR}/src/knowhere/index/vector_index/cloner.cpp + ${CMAKE_SOURCE_DIR}/src/knowhere/index/vector_index/gpu_ivf.cpp + ${CMAKE_SOURCE_DIR}/src/knowhere/adapter/structure.cpp + ${CMAKE_SOURCE_DIR}/src/knowhere/common/exception.cpp + ${CMAKE_SOURCE_DIR}/src/knowhere/common/timer.cpp + utils.cpp + ) +add_executable(test_idmap test_idmap.cpp ${idmap_srcs}) +target_link_libraries(test_idmap ${depend_libs} ${unittest_libs} ${basic_libs}) +#<<<<<<<<<< + + +# +#<<<<<<<<<< +set(kdt_srcs + ${CMAKE_SOURCE_DIR}/src/knowhere/index/preprocessor/normalize.cpp + ${CMAKE_SOURCE_DIR}/src/knowhere/index/vector_index/kdt_parameters.cpp + ${CMAKE_SOURCE_DIR}/src/knowhere/index/vector_index/cpu_kdt_rng.cpp + ${CMAKE_SOURCE_DIR}/src/knowhere/adapter/structure.cpp + ${CMAKE_SOURCE_DIR}/src/knowhere/adapter/sptag.cpp + ${CMAKE_SOURCE_DIR}/src/knowhere/common/exception.cpp + ${CMAKE_SOURCE_DIR}/src/knowhere/adapter/arrow.cpp + ${CMAKE_SOURCE_DIR}/src/knowhere/common/timer.cpp + utils.cpp + ) +add_executable(test_kdt test_kdt.cpp ${kdt_srcs}) +target_link_libraries(test_kdt + SPTAGLibStatic + ${depend_libs} ${unittest_libs} ${basic_libs}) +#<<<<<<<<<< + + +add_subdirectory(faiss_ori) +add_subdirectory(test_nsg) + diff --git a/cpp/src/core/test/SPTAG.cpp b/cpp/src/core/test/SPTAG.cpp new file mode 100644 index 0000000000..3dfea0f088 --- /dev/null +++ b/cpp/src/core/test/SPTAG.cpp @@ -0,0 +1,36 @@ + +#include +#include +#include +#include "SPTAG/AnnService/inc/Core/Common.h" +#include "SPTAG/AnnService/inc/Core/VectorIndex.h" + + +int +main(int argc, char *argv[]) { + using namespace SPTAG; + const int d = 128; + const int n = 100; + + auto p_data = new float[n * d]; + + auto index = VectorIndex::CreateInstance(IndexAlgoType::KDT, VectorValueType::Float); + + std::random_device rd; + std::mt19937 mt(rd()); + std::uniform_real_distribution dist(1.0, 2.0); + + for (auto i = 0; i < n; i++) { + for (auto j = 0; j < d; j++) { + p_data[i * d + j] = dist(mt) - 1; + } + } + std::cout << "generate random n * d finished."; + ByteArray data((uint8_t *) p_data, n * d * sizeof(float), true); + + auto vectorset = std::make_shared(data, VectorValueType::Float, d, n); + index->BuildIndex(vectorset, nullptr); + + std::cout << index->GetFeatureDim(); +} + diff --git a/cpp/src/core/test/faiss_ori/CMakeLists.txt b/cpp/src/core/test/faiss_ori/CMakeLists.txt new file mode 100644 index 0000000000..a6b20a2373 --- /dev/null +++ b/cpp/src/core/test/faiss_ori/CMakeLists.txt @@ -0,0 +1,26 @@ +include_directories(${CMAKE_SOURCE_DIR}/thirdparty) +include_directories(${CMAKE_SOURCE_DIR}/include) +include_directories(/usr/local/cuda/include) +link_directories(/usr/local/cuda/lib64) +link_directories(${CMAKE_SOURCE_DIR}/thirdparty/tbb) + +set(unittest_libs + gtest gmock gtest_main gmock_main) + +set(depend_libs + faiss openblas lapack + arrow jemalloc_pic + tbb + ) + +set(basic_libs + cudart cublas + gomp gfortran pthread + ) + + +# +#<<<<<<<<<< +add_executable(test_gpu gpuresource_test.cpp) +target_link_libraries(test_gpu ${depend_libs} ${unittest_libs} ${basic_libs}) +#<<<<<<<<<< diff --git a/cpp/src/core/test/faiss_ori/gpuresource_test.cpp b/cpp/src/core/test/faiss_ori/gpuresource_test.cpp new file mode 100644 index 0000000000..f88ad3e111 --- /dev/null +++ b/cpp/src/core/test/faiss_ori/gpuresource_test.cpp @@ -0,0 +1,166 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 上海赜睿信息科技有限公司(Zilliz) - All Rights Reserved +// Unauthorized copying of this file, via any medium is strictly prohibited. +// Proprietary and confidential. +//////////////////////////////////////////////////////////////////////////////// +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +using namespace std::chrono_literals; + +class TestGpuRes { + public: + TestGpuRes() { + res_ = new faiss::gpu::StandardGpuResources; + } + ~TestGpuRes() { + delete res_; + delete index_; + } + std::shared_ptr Do() { + int d = 128; // dimension + int nb = 100000; // database size + int nq = 100; // nb of queries + int nlist = 1638; + + float *xb = new float[d * nb]; + float *xq = new float[d * nq]; + + for (int i = 0; i < nb; i++) { + for (int j = 0; j < d; j++) + xb[d * i + j] = drand48(); + xb[d * i] += i / 1000.; + } + + for (int i = 0; i < nq; i++) { + for (int j = 0; j < d; j++) + xq[d * i + j] = drand48(); + xq[d * i] += i / 1000.; + } + + index_ = new faiss::gpu::GpuIndexIVFFlat(res_, d, nlist, faiss::METRIC_L2); + index_->train(nb, xb); + index_->add(nb, xb); + + std::shared_ptr host_index = nullptr; + host_index.reset(faiss::gpu::index_gpu_to_cpu(index_)); + return host_index; + } + private: + faiss::gpu::GpuResources *res_ = nullptr; + faiss::Index *index_ = nullptr; +}; + +TEST(gpuresource, resource) { + TestGpuRes t; + t.Do(); +} + +TEST(test, resource_re) { + int d = 128; // dimension + int nb = 1000000; // database size + int nq = 100; // nb of queries + int nlist = 16384; + int k = 100; + + float *xb = new float[d * nb]; + float *xq = new float[d * nq]; + + for (int i = 0; i < nb; i++) { + for (int j = 0; j < d; j++) + xb[d * i + j] = drand48(); + xb[d * i] += i / 1000.; + } + + for (int i = 0; i < nq; i++) { + for (int j = 0; j < d; j++) + xq[d * i + j] = drand48(); + xq[d * i] += i / 1000.; + } + + auto elems = nq * k; + auto res_ids = (int64_t *) malloc(sizeof(int64_t) * elems); + auto res_dis = (float *) malloc(sizeof(float) * elems); + + faiss::gpu::StandardGpuResources res; + auto cpu_index = faiss::index_factory(d, "IVF16384, Flat"); + auto device_index = faiss::gpu::index_cpu_to_gpu(&res, 0, cpu_index); + device_index->train(nb, xb); + device_index->add(nb, xb); + auto new_index = faiss::gpu::index_gpu_to_cpu(device_index); + + delete device_index; + + std::cout << "start clone" << std::endl; + auto load = [&] { + std::cout << "start" << std::endl; + faiss::gpu::StandardGpuResources res; + //res.noTempMemory(); + for (int l = 0; l < 100; ++l) { + auto x = faiss::gpu::index_cpu_to_gpu(&res, 1, new_index); + delete x; + } + std::cout << "load finish" << std::endl; + }; + + auto search = [&] { + faiss::gpu::StandardGpuResources res; + auto device_index = faiss::gpu::index_cpu_to_gpu(&res, 1, new_index); + std::cout << "search start" << std::endl; + for (int l = 0; l < 10000; ++l) { + device_index->search(nq,xq,10, res_dis, res_ids); + } + std::cout << "search finish" << std::endl; + delete device_index; + delete cpu_index; + }; + + load(); + search(); + std::thread t1(search); + std::this_thread::sleep_for(1s); + std::thread t2(load); + t1.join(); + t2.join(); + std::cout << "finish clone" << std::endl; + + //std::this_thread::sleep_for(5s); + // + //auto device_index_2 = faiss::gpu::index_cpu_to_gpu(&res, 1, cpu_index); + //device_index->train(nb, xb); + //device_index->add(nb, xb); + + //std::cout << "finish clone" << std::endl; + //std::this_thread::sleep_for(5s); + + //std::this_thread::sleep_for(2s); + //std::cout << "start clone" << std::endl; + //auto new_index = faiss::clone_index(device_index); + //std::cout << "start search" << std::endl; + //new_index->search(nq, xq, k, res_dis, res_ids); + + //std::cout << "start clone" << std::endl; + //{ + // faiss::gpu::StandardGpuResources res; + // auto cpu_index = faiss::index_factory(d, "IVF1638, Flat"); + // auto device_index = faiss::gpu::index_cpu_to_gpu(&res, 1, cpu_index); + // device_index->train(nb, xb); + // device_index->add(nb, xb); + // std::cout << "finish clone" << std::endl; + // delete device_index; + // delete cpu_index; + // std::cout << "finish clone" << std::endl; + //} + // + //std::cout << "finish clone" << std::endl; +} diff --git a/cpp/src/core/test/kdtree.cpp b/cpp/src/core/test/kdtree.cpp new file mode 100644 index 0000000000..0b63e657e1 --- /dev/null +++ b/cpp/src/core/test/kdtree.cpp @@ -0,0 +1,134 @@ + +#include +#include +#include "knowhere/index/vector_index/cpu_kdt_rng.h" +#include "knowhere/index/vector_index/definitions.h" +#include "knowhere/adapter/sptag.h" +#include "knowhere/adapter/structure.h" + + +using namespace zilliz::knowhere; + +DatasetPtr +generate_dataset(int64_t n, int64_t d, int64_t base) { + auto elems = n * d; + auto p_data = (float *) malloc(elems * sizeof(float)); + auto p_id = (int64_t *) malloc(elems * sizeof(int64_t)); + assert(p_data != nullptr && p_id != nullptr); + + for (auto i = 0; i < n; ++i) { + for (auto j = 0; j < d; ++j) { + p_data[i * d + j] = float(base + i); + } + p_id[i] = i; + } + + std::vector shape{n, d}; + auto tensor = ConstructFloatTensorSmart((uint8_t *) p_data, elems * sizeof(float), shape); + std::vector tensors{tensor}; + std::vector tensor_fields{ConstructFloatField("data")}; + auto tensor_schema = std::make_shared(tensor_fields); + + auto id_array = ConstructInt64ArraySmart((uint8_t *) p_id, n * sizeof(int64_t)); + std::vector arrays{id_array}; + std::vector array_fields{ConstructInt64Field("id")}; + auto array_schema = std::make_shared(tensor_fields); + + auto dataset = std::make_shared(std::move(arrays), array_schema, + std::move(tensors), tensor_schema); + + return dataset; +} + +DatasetPtr +generate_queries(int64_t n, int64_t d, int64_t k, int64_t base) { + size_t size = sizeof(float) * n * d; + auto v = (float *) malloc(size); + // TODO: check malloc + for (auto i = 0; i < n; ++i) { + for (auto j = 0; j < d; ++j) { + v[i * d + j] = float(base + i); + } + } + + std::vector data; + auto buffer = MakeMutableBufferSmart((uint8_t *) v, size); + std::vector shape{n, d}; + auto float_type = std::make_shared(); + auto tensor = std::make_shared(float_type, buffer, shape); + data.push_back(tensor); + + Config meta; + meta[META_ROWS] = int64_t (n); + meta[META_DIM] = int64_t (d); + meta[META_K] = int64_t (k); + + auto type = std::make_shared(); + auto field = std::make_shared("data", type); + std::vector fields{field}; + auto schema = std::make_shared(fields); + + return std::make_shared(data, schema); +} + + +int +main(int argc, char *argv[]) { + auto kdt_index = std::make_shared(); + + const auto d = 10; + const auto k = 3; + const auto nquery = 10; + + // ID [0, 99] + auto train = generate_dataset(100, d, 0); + // ID [100] + auto base = generate_dataset(1, d, 0); + auto queries = generate_queries(nquery, d, k, 0); + + // Build Preprocessor + auto preprocessor = kdt_index->BuildPreprocessor(train, Config()); + + // Set Preprocessor + kdt_index->set_preprocessor(preprocessor); + + Config train_config; + train_config["TPTNumber"] = "64"; + // Train + kdt_index->Train(train, train_config); + + // Add + kdt_index->Add(base, Config()); + + auto binary = kdt_index->Serialize(); + auto new_index = std::make_shared(); + new_index->Load(binary); +// auto new_index = kdt_index; + + Config search_config; + search_config[META_K] = int64_t (k); + + // Search + auto result = new_index->Search(queries, search_config); + + // Print Result + { + auto ids = result->array()[0]; + auto dists = result->array()[1]; + + std::stringstream ss_id; + std::stringstream ss_dist; + for (auto i = 0; i < nquery; i++) { + for (auto j = 0; j < k; ++j) { + ss_id << *ids->data()->GetValues(1, i * k + j) << " "; + ss_dist << *dists->data()->GetValues(1, i * k + j) << " "; + } + ss_id << std::endl; + ss_dist << std::endl; + } + std::cout << "id\n" << ss_id.str() << std::endl; + std::cout << "dist\n" << ss_dist.str() << std::endl; + } +} + + diff --git a/cpp/src/core/test/sift.50NN.graph b/cpp/src/core/test/sift.50NN.graph new file mode 100644 index 0000000000..bf7ba7555d Binary files /dev/null and b/cpp/src/core/test/sift.50NN.graph differ diff --git a/cpp/src/core/test/siftsmall_base.fvecs b/cpp/src/core/test/siftsmall_base.fvecs new file mode 100644 index 0000000000..e3b90ae1ee Binary files /dev/null and b/cpp/src/core/test/siftsmall_base.fvecs differ diff --git a/cpp/src/core/test/test_idmap.cpp b/cpp/src/core/test/test_idmap.cpp new file mode 100644 index 0000000000..7b7e771953 --- /dev/null +++ b/cpp/src/core/test/test_idmap.cpp @@ -0,0 +1,171 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 上海赜睿信息科技有限公司(Zilliz) - All Rights Reserved +// Unauthorized copying of this file, via any medium is strictly prohibited. +// Proprietary and confidential. +//////////////////////////////////////////////////////////////////////////////// + +#include + +#include +#include + +#include "knowhere/index/vector_index/idmap.h" +#include "knowhere/adapter/structure.h" +#include "knowhere/index/vector_index/cloner.h" + +#include "utils.h" + + +using namespace zilliz::knowhere; + +class IDMAPTest : public DataGen, public ::testing::Test { + protected: + void SetUp() override { + Init_with_default(); + index_ = std::make_shared(); + } + protected: + IDMAPPtr index_ = nullptr; +}; + +void AssertAnns(const DatasetPtr &result, + const int &nq, + const int &k) { + auto ids = result->array()[0]; + for (auto i = 0; i < nq; i++) { + EXPECT_EQ(i, *(ids->data()->GetValues(1, i * k))); + } +} + +void PrintResult(const DatasetPtr &result, + const int &nq, + const int &k) { + auto ids = result->array()[0]; + auto dists = result->array()[1]; + + std::stringstream ss_id; + std::stringstream ss_dist; + for (auto i = 0; i < 10; i++) { + for (auto j = 0; j < k; ++j) { + ss_id << *(ids->data()->GetValues(1, i * k + j)) << " "; + ss_dist << *(dists->data()->GetValues(1, i * k + j)) << " "; + } + ss_id << std::endl; + ss_dist << std::endl; + } + std::cout << "id\n" << ss_id.str() << std::endl; + std::cout << "dist\n" << ss_dist.str() << std::endl; +} + +TEST_F(IDMAPTest, idmap_basic) { + assert(!xb.empty()); + Config Default_cfg; + + index_->Train(Config::object{{"dim", dim}, {"metric_type", "L2"}}); + index_->Add(base_dataset, Default_cfg); + EXPECT_EQ(index_->Count(), nb); + EXPECT_EQ(index_->Dimension(), dim); + assert(index_->GetRawVectors() != nullptr); + assert(index_->GetRawIds() != nullptr); + auto result = index_->Search(query_dataset, Config::object{{"k", k}}); + AssertAnns(result, nq, k); + PrintResult(result, nq, k); + + auto binaryset = index_->Serialize(); + auto new_index = std::make_shared(); + new_index->Load(binaryset); + auto re_result = index_->Search(query_dataset, Config::object{{"k", k}}); + AssertAnns(re_result, nq, k); + PrintResult(re_result, nq, k); +} + +TEST_F(IDMAPTest, idmap_serialize) { + auto serialize = [](const std::string &filename, BinaryPtr &bin, uint8_t *ret) { + FileIOWriter writer(filename); + writer(static_cast(bin->data.get()), bin->size); + + FileIOReader reader(filename); + reader(ret, bin->size); + }; + + { + // serialize index + index_->Train(Config::object{{"dim", dim}, {"metric_type", "L2"}}); + index_->Add(base_dataset, Config()); + auto re_result = index_->Search(query_dataset, Config::object{{"k", k}}); + AssertAnns(re_result, nq, k); + PrintResult(re_result, nq, k); + EXPECT_EQ(index_->Count(), nb); + EXPECT_EQ(index_->Dimension(), dim); + auto binaryset = index_->Serialize(); + auto bin = binaryset.GetByName("IVF"); + + std::string filename = "/tmp/idmap_test_serialize.bin"; + auto load_data = new uint8_t[bin->size]; + serialize(filename, bin, load_data); + + binaryset.clear(); + auto data = std::make_shared(); + data.reset(load_data); + binaryset.Append("IVF", data, bin->size); + + index_->Load(binaryset); + EXPECT_EQ(index_->Count(), nb); + EXPECT_EQ(index_->Dimension(), dim); + auto result = index_->Search(query_dataset, Config::object{{"k", k}}); + AssertAnns(result, nq, k); + PrintResult(result, nq, k); + } +} + +TEST_F(IDMAPTest, copy_test) { + assert(!xb.empty()); + Config Default_cfg; + + index_->Train(Config::object{{"dim", dim}, {"metric_type", "L2"}}); + index_->Add(base_dataset, Default_cfg); + EXPECT_EQ(index_->Count(), nb); + EXPECT_EQ(index_->Dimension(), dim); + assert(index_->GetRawVectors() != nullptr); + assert(index_->GetRawIds() != nullptr); + auto result = index_->Search(query_dataset, Config::object{{"k", k}}); + AssertAnns(result, nq, k); + //PrintResult(result, nq, k); + + { + // clone + auto clone_index = index_->Clone(); + auto clone_result = clone_index->Search(query_dataset, Config::object{{"k", k}}); + AssertAnns(clone_result, nq, k); + } + + { + // cpu to gpu + static int64_t device_id = 0; + FaissGpuResourceMgr::GetInstance().InitDevice(0); + FaissGpuResourceMgr::GetInstance().InitDevice(1); + + auto clone_index = CopyCpuToGpu(index_, device_id, Config()); + auto clone_result = clone_index->Search(query_dataset, Config::object{{"k", k}}); + AssertAnns(clone_result, nq, k); + //assert(std::static_pointer_cast(clone_index)->GetRawVectors() != nullptr); + //assert(std::static_pointer_cast(clone_index)->GetRawIds() != nullptr); + auto clone_gpu_idx = clone_index->Clone(); + auto clone_gpu_res = clone_gpu_idx->Search(query_dataset, Config::object{{"k", k}}); + AssertAnns(clone_gpu_res, nq, k); + + // gpu to cpu + auto host_index = CopyGpuToCpu(clone_index, Config()); + auto host_result = host_index->Search(query_dataset, Config::object{{"k", k}}); + AssertAnns(host_result, nq, k); + assert(std::static_pointer_cast(host_index)->GetRawVectors() != nullptr); + assert(std::static_pointer_cast(host_index)->GetRawIds() != nullptr); + + // gpu to gpu + auto device_index = CopyCpuToGpu(index_, 1, Config()); + auto device_result = device_index->Search(query_dataset, Config::object{{"k", k}}); + AssertAnns(device_result, nq, k); + //assert(std::static_pointer_cast(device_index)->GetRawVectors() != nullptr); + //assert(std::static_pointer_cast(device_index)->GetRawIds() != nullptr); + } +} diff --git a/cpp/src/core/test/test_ivf.cpp b/cpp/src/core/test/test_ivf.cpp new file mode 100644 index 0000000000..fc9ab653f6 --- /dev/null +++ b/cpp/src/core/test/test_ivf.cpp @@ -0,0 +1,346 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 上海赜睿信息科技有限公司(Zilliz) - All Rights Reserved +// Unauthorized copying of this file, via any medium is strictly prohibited. +// Proprietary and confidential. +//////////////////////////////////////////////////////////////////////////////// + +#include + +#include +#include + +#include "knowhere/index/vector_index/gpu_ivf.h" +#include "knowhere/index/vector_index/ivf.h" +#include "knowhere/adapter/structure.h" +#include "knowhere/index/vector_index/cloner.h" +#include "knowhere/common/exception.h" +#include "knowhere/common/timer.h" + +#include "utils.h" + + +using namespace zilliz::knowhere; + +using ::testing::TestWithParam; +using ::testing::Values; +using ::testing::Combine; + +static int device_id = 1; +IVFIndexPtr IndexFactory(const std::string &type) { + if (type == "IVF") { + return std::make_shared(); + } else if (type == "IVFPQ") { + return std::make_shared(); + } else if (type == "GPUIVF") { + return std::make_shared(device_id); + } else if (type == "GPUIVFPQ") { + return std::make_shared(device_id); + } else if (type == "IVFSQ") { + return std::make_shared(); + } else if (type == "GPUIVFSQ") { + return std::make_shared(device_id); + } +} + +class IVFTest + : public DataGen, public TestWithParam<::std::tuple> { + protected: + void SetUp() override { + std::tie(index_type, preprocess_cfg, train_cfg, add_cfg, search_cfg) = GetParam(); + //Init_with_default(); + Generate(128, 1000000/5, 10); + index_ = IndexFactory(index_type); + FaissGpuResourceMgr::GetInstance().InitDevice(device_id); + } + + protected: + std::string index_type; + Config preprocess_cfg; + Config train_cfg; + Config add_cfg; + Config search_cfg; + IVFIndexPtr index_ = nullptr; +}; + + +INSTANTIATE_TEST_CASE_P(IVFParameters, IVFTest, + Values( + std::make_tuple("IVF", + Config(), + Config::object{{"nlist", 100}, {"metric_type", "L2"}}, + Config(), + Config::object{{"k", 10}}), + //std::make_tuple("IVFPQ", + // Config(), + // Config::object{{"nlist", 100}, {"M", 8}, {"nbits", 8}, {"metric_type", "L2"}}, + // Config(), + // Config::object{{"k", 10}}), + std::make_tuple("GPUIVF", + Config(), + Config::object{{"nlist", 1638}, {"gpu_id", device_id}, {"metric_type", "L2"}}, + Config(), + Config::object{{"k", 10}}), + //std::make_tuple("GPUIVFPQ", + // Config(), + // Config::object{{"gpu_id", device_id}, {"nlist", 100}, {"M", 8}, {"nbits", 8}, {"metric_type", "L2"}}, + // Config(), + // Config::object{{"k", 10}}), + std::make_tuple("IVFSQ", + Config(), + Config::object{{"nlist", 100}, {"nbits", 8}, {"metric_type", "L2"}}, + Config(), + Config::object{{"k", 10}}), + std::make_tuple("GPUIVFSQ", + Config(), + Config::object{{"gpu_id", device_id}, {"nlist", 1638}, {"nbits", 8}, {"metric_type", "L2"}}, + Config(), + Config::object{{"k", 10}}) + ) +); + +void AssertAnns(const DatasetPtr &result, + const int &nq, + const int &k) { + auto ids = result->array()[0]; + for (auto i = 0; i < nq; i++) { + EXPECT_EQ(i, *(ids->data()->GetValues(1, i * k))); + } +} + +void PrintResult(const DatasetPtr &result, + const int &nq, + const int &k) { + auto ids = result->array()[0]; + auto dists = result->array()[1]; + + std::stringstream ss_id; + std::stringstream ss_dist; + for (auto i = 0; i < 10; i++) { + for (auto j = 0; j < k; ++j) { + ss_id << *(ids->data()->GetValues(1, i * k + j)) << " "; + ss_dist << *(dists->data()->GetValues(1, i * k + j)) << " "; + } + ss_id << std::endl; + ss_dist << std::endl; + } + std::cout << "id\n" << ss_id.str() << std::endl; + std::cout << "dist\n" << ss_dist.str() << std::endl; +} + +TEST_P(IVFTest, ivf_basic) { + assert(!xb.empty()); + + auto preprocessor = index_->BuildPreprocessor(base_dataset, preprocess_cfg); + index_->set_preprocessor(preprocessor); + + auto model = index_->Train(base_dataset, train_cfg); + index_->set_index_model(model); + index_->Add(base_dataset, add_cfg); + EXPECT_EQ(index_->Count(), nb); + EXPECT_EQ(index_->Dimension(), dim); + auto result = index_->Search(query_dataset, search_cfg); + AssertAnns(result, nq, k); + //PrintResult(result, nq, k); +} + +//TEST_P(IVFTest, gpu_to_cpu) { +// if (index_type.find("GPU") == std::string::npos) { return; } +// +// // else +// assert(!xb.empty()); +// +// auto preprocessor = index_->BuildPreprocessor(base_dataset, preprocess_cfg); +// index_->set_preprocessor(preprocessor); +// +// auto model = index_->Train(base_dataset, train_cfg); +// index_->set_index_model(model); +// index_->Add(base_dataset, add_cfg); +// EXPECT_EQ(index_->Count(), nb); +// EXPECT_EQ(index_->Dimension(), dim); +// auto result = index_->Search(query_dataset, search_cfg); +// AssertAnns(result, nq, k); +// +// if (auto device_index = std::dynamic_pointer_cast(index_)) { +// auto host_index = device_index->Copy_index_gpu_to_cpu(); +// auto result = host_index->Search(query_dataset, search_cfg); +// AssertAnns(result, nq, k); +// } +//} + +TEST_P(IVFTest, ivf_serialize) { + auto serialize = [](const std::string &filename, BinaryPtr &bin, uint8_t *ret) { + FileIOWriter writer(filename); + writer(static_cast(bin->data.get()), bin->size); + + FileIOReader reader(filename); + reader(ret, bin->size); + }; + + { + // serialize index-model + auto model = index_->Train(base_dataset, train_cfg); + auto binaryset = model->Serialize(); + auto bin = binaryset.GetByName("IVF"); + + std::string filename = "/tmp/ivf_test_model_serialize.bin"; + auto load_data = new uint8_t[bin->size]; + serialize(filename, bin, load_data); + + binaryset.clear(); + auto data = std::make_shared(); + data.reset(load_data); + binaryset.Append("IVF", data, bin->size); + + model->Load(binaryset); + + index_->set_index_model(model); + index_->Add(base_dataset, add_cfg); + auto result = index_->Search(query_dataset, search_cfg); + AssertAnns(result, nq, k); + } + + { + // serialize index + auto model = index_->Train(base_dataset, train_cfg); + index_->set_index_model(model); + index_->Add(base_dataset, add_cfg); + auto binaryset = index_->Serialize(); + auto bin = binaryset.GetByName("IVF"); + + std::string filename = "/tmp/ivf_test_serialize.bin"; + auto load_data = new uint8_t[bin->size]; + serialize(filename, bin, load_data); + + binaryset.clear(); + auto data = std::make_shared(); + data.reset(load_data); + binaryset.Append("IVF", data, bin->size); + + index_->Load(binaryset); + EXPECT_EQ(index_->Count(), nb); + EXPECT_EQ(index_->Dimension(), dim); + auto result = index_->Search(query_dataset, search_cfg); + AssertAnns(result, nq, k); + } +} + +TEST_P(IVFTest, clone_test) { + assert(!xb.empty()); + + auto preprocessor = index_->BuildPreprocessor(base_dataset, preprocess_cfg); + index_->set_preprocessor(preprocessor); + + auto model = index_->Train(base_dataset, train_cfg); + index_->set_index_model(model); + index_->Add(base_dataset, add_cfg); + EXPECT_EQ(index_->Count(), nb); + EXPECT_EQ(index_->Dimension(), dim); + auto result = index_->Search(query_dataset, search_cfg); + AssertAnns(result, nq, k); + //PrintResult(result, nq, k); + + auto AssertEqual = [&] (DatasetPtr p1, DatasetPtr p2) { + auto ids_p1 = p1->array()[0]; + auto ids_p2 = p2->array()[0]; + + for (int i = 0; i < nq * k; ++i) { + EXPECT_EQ(*(ids_p2->data()->GetValues(1, i)), + *(ids_p1->data()->GetValues(1, i))); + } + }; + + { + // clone in place + std::vector support_idx_vec{"IVF", "GPUIVF", "IVFPQ", "IVFSQ", "GPUIVFSQ"}; + auto finder = std::find(support_idx_vec.cbegin(), support_idx_vec.cend(), index_type); + if (finder != support_idx_vec.cend()) { + EXPECT_NO_THROW({ + auto clone_index = index_->Clone(); + auto clone_result = clone_index->Search(query_dataset, search_cfg); + //AssertAnns(result, nq, k); + AssertEqual(result, clone_result); + std::cout << "inplace clone [" << index_type << "] success" << std::endl; + }); + } else { + EXPECT_THROW({ + std::cout << "inplace clone [" << index_type << "] failed" << std::endl; + auto clone_index = index_->Clone(); + }, KnowhereException); + } + } + + { + // copy from gpu to cpu + std::vector support_idx_vec{"GPUIVF", "GPUIVFSQ"}; + auto finder = std::find(support_idx_vec.cbegin(), support_idx_vec.cend(), index_type); + if (finder != support_idx_vec.cend()) { + EXPECT_NO_THROW({ + auto clone_index = CopyGpuToCpu(index_, Config()); + auto clone_result = clone_index->Search(query_dataset, search_cfg); + AssertEqual(result, clone_result); + std::cout << "clone G <=> C [" << index_type << "] success" << std::endl; + }); + } else { + EXPECT_THROW({ + std::cout << "clone G <=> C [" << index_type << "] failed" << std::endl; + auto clone_index = CopyGpuToCpu(index_, Config()); + }, KnowhereException); + } + } + + { + // copy to gpu + std::vector support_idx_vec{"IVF", "GPUIVF", "IVFSQ", "GPUIVFSQ"}; + auto finder = std::find(support_idx_vec.cbegin(), support_idx_vec.cend(), index_type); + if (finder != support_idx_vec.cend()) { + EXPECT_NO_THROW({ + auto clone_index = CopyCpuToGpu(index_, device_id, Config()); + auto clone_result = clone_index->Search(query_dataset, search_cfg); + AssertEqual(result, clone_result); + std::cout << "clone C <=> G [" << index_type << "] success" << std::endl; + }); + } else { + EXPECT_THROW({ + std::cout << "clone C <=> G [" << index_type << "] failed" << std::endl; + auto clone_index = CopyCpuToGpu(index_, device_id, Config()); + }, KnowhereException); + } + } +} + +TEST_P(IVFTest, seal_test) { + //FaissGpuResourceMgr::GetInstance().InitDevice(device_id); + + std::vector support_idx_vec{"GPUIVF", "GPUIVFSQ"}; + auto finder = std::find(support_idx_vec.cbegin(), support_idx_vec.cend(), index_type); + if (finder == support_idx_vec.cend()) { + return; + } + + assert(!xb.empty()); + + //index_ = std::make_shared(0); + auto preprocessor = index_->BuildPreprocessor(base_dataset, preprocess_cfg); + index_->set_preprocessor(preprocessor); + + auto model = index_->Train(base_dataset, train_cfg); + index_->set_index_model(model); + index_->Add(base_dataset, add_cfg); + EXPECT_EQ(index_->Count(), nb); + EXPECT_EQ(index_->Dimension(), dim); + auto result = index_->Search(query_dataset, search_cfg); + AssertAnns(result, nq, k); + + auto cpu_idx = CopyGpuToCpu(index_, Config()); + + TimeRecorder tc("CopyToGpu"); + CopyCpuToGpu(cpu_idx, device_id, Config()); + auto without_seal = tc.RecordSection("Without seal"); + cpu_idx->Seal(); + tc.RecordSection("seal cost"); + CopyCpuToGpu(cpu_idx, device_id, Config()); + auto with_seal = tc.RecordSection("With seal"); + ASSERT_GE(without_seal, with_seal); +} + +// TODO(linxj): Add exception test diff --git a/cpp/src/core/test/test_json.cpp b/cpp/src/core/test/test_json.cpp new file mode 100644 index 0000000000..bc4c1666ff --- /dev/null +++ b/cpp/src/core/test/test_json.cpp @@ -0,0 +1,18 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 上海赜睿信息科技有限公司(Zilliz) - All Rights Reserved +// Unauthorized copying of this file, via any medium is strictly prohibited. +// Proprietary and confidential. +//////////////////////////////////////////////////////////////////////////////// + +#include "knowhere/common/config.h" + +using namespace zilliz::knowhere; + +int main(){ + Config cfg; + + cfg["size"] = size_t(199); + auto size = cfg.get_with_default("size", 123); + auto size_2 = cfg["size"].as(); + printf("%d", size_2); +} diff --git a/cpp/src/core/test/test_kdt.cpp b/cpp/src/core/test/test_kdt.cpp new file mode 100644 index 0000000000..4236704cd8 --- /dev/null +++ b/cpp/src/core/test/test_kdt.cpp @@ -0,0 +1,162 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 上海赜睿信息科技有限公司(Zilliz) - All Rights Reserved +// Unauthorized copying of this file, via any medium is strictly prohibited. +// Proprietary and confidential. +//////////////////////////////////////////////////////////////////////////////// + +#include + +#include +#include + +#include "knowhere/index/vector_index/cpu_kdt_rng.h" +#include "knowhere/index/vector_index/definitions.h" +#include "knowhere/adapter/sptag.h" +#include "knowhere/adapter/structure.h" + +#include "utils.h" + + +using namespace zilliz::knowhere; + +using ::testing::TestWithParam; +using ::testing::Values; +using ::testing::Combine; + + +class KDTTest + : public DataGen, public TestWithParam<::std::tuple> { + protected: + void SetUp() override { + std::tie(preprocess_cfg, train_cfg, add_cfg, search_cfg) = GetParam(); + index_ = std::make_shared(); + Init_with_default(); + } + + protected: + Config preprocess_cfg; + Config train_cfg; + Config add_cfg; + Config search_cfg; + std::shared_ptr index_ = nullptr; +}; + +INSTANTIATE_TEST_CASE_P(KDTParameters, KDTTest, + Values( + std::make_tuple(Config(), + Config::object{{"TPTNumber", 1}}, + Config(), + Config::object{{"k", 10}}) + ) +); + +void AssertAnns(const DatasetPtr &result, + const int &nq, + const int &k) { + auto ids = result->array()[0]; + for (auto i = 0; i < nq; i++) { + EXPECT_EQ(i, *(ids->data()->GetValues(1, i * k))); + } +} + +void PrintResult(const DatasetPtr &result, + const int &nq, + const int &k) { + auto ids = result->array()[0]; + auto dists = result->array()[1]; + + std::stringstream ss_id; + std::stringstream ss_dist; + for (auto i = 0; i < 10; i++) { + for (auto j = 0; j < k; ++j) { + ss_id << *(ids->data()->GetValues(1, i * k + j)) << " "; + ss_dist << *(dists->data()->GetValues(1, i * k + j)) << " "; + } + ss_id << std::endl; + ss_dist << std::endl; + } + std::cout << "id\n" << ss_id.str() << std::endl; + std::cout << "dist\n" << ss_dist.str() << std::endl; +} + +// TODO(linxj): add test about count() and dimension() +TEST_P(KDTTest, kdt_basic) { + assert(!xb.empty()); + + auto preprocessor = index_->BuildPreprocessor(base_dataset, preprocess_cfg); + index_->set_preprocessor(preprocessor); + + auto model = index_->Train(base_dataset, train_cfg); + index_->set_index_model(model); + index_->Add(base_dataset, add_cfg); + auto result = index_->Search(query_dataset, search_cfg); + AssertAnns(result, nq, k); + + { + auto ids = result->array()[0]; + auto dists = result->array()[1]; + + std::stringstream ss_id; + std::stringstream ss_dist; + for (auto i = 0; i < nq; i++) { + for (auto j = 0; j < k; ++j) { + ss_id << *ids->data()->GetValues(1, i * k + j) << " "; + ss_dist << *dists->data()->GetValues(1, i * k + j) << " "; + } + ss_id << std::endl; + ss_dist << std::endl; + } + std::cout << "id\n" << ss_id.str() << std::endl; + std::cout << "dist\n" << ss_dist.str() << std::endl; + } +} + +TEST_P(KDTTest, kdt_serialize) { + assert(!xb.empty()); + + auto preprocessor = index_->BuildPreprocessor(base_dataset, preprocess_cfg); + index_->set_preprocessor(preprocessor); + + auto model = index_->Train(base_dataset, train_cfg); + //index_->Add(base_dataset, add_cfg); + auto binaryset = index_->Serialize(); + auto new_index = std::make_shared(); + new_index->Load(binaryset); + auto result = new_index->Search(query_dataset, search_cfg); + AssertAnns(result, nq, k); + PrintResult(result, nq, k); + + { + int fileno = 0; + const std::string &base_name = "/tmp/kdt_serialize_test_bin_"; + std::vector filename_list; + std::vector> meta_list; + for (auto &iter: binaryset.binary_map_) { + const std::string &filename = base_name + std::to_string(fileno); + FileIOWriter writer(filename); + writer(iter.second->data.get(), iter.second->size); + + meta_list.emplace_back(std::make_pair(iter.first, iter.second->size)); + filename_list.push_back(filename); + ++fileno; + } + + BinarySet load_data_list; + for (int i = 0; i < filename_list.size() && i < meta_list.size(); ++i) { + auto bin_size = meta_list[i].second; + FileIOReader reader(filename_list[i]); + + auto load_data = new uint8_t[bin_size]; + reader(load_data, bin_size); + auto data = std::make_shared(); + data.reset(load_data); + load_data_list.Append(meta_list[i].first, data, bin_size); + } + + auto new_index = std::make_shared(); + new_index->Load(load_data_list); + auto result = new_index->Search(query_dataset, search_cfg); + AssertAnns(result, nq, k); + PrintResult(result, nq, k); + } +} diff --git a/cpp/src/core/test/test_nsg.cpp b/cpp/src/core/test/test_nsg.cpp new file mode 100644 index 0000000000..d7e472b13e --- /dev/null +++ b/cpp/src/core/test/test_nsg.cpp @@ -0,0 +1,98 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 上海赜睿信息科技有限公司(Zilliz) - All Rights Reserved +// Unauthorized copying of this file, via any medium is strictly prohibited. +// Proprietary and confidential. +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include "index.h" + +//#include + +using namespace zilliz::knowhere; + +void load_data(std::string &filename, float *&data, unsigned &num, + unsigned &dim) { // load data with sift10K pattern + std::ifstream in(filename, std::ios::binary); + if (!in.is_open()) { + std::cout << "open file error" << std::endl; + exit(-1); + } + in.read((char *) &dim, 4); + in.seekg(0, std::ios::end); + std::ios::pos_type ss = in.tellg(); + size_t fsize = (size_t) ss; + num = (unsigned) (fsize / (dim + 1) / 4); + data = new float[(size_t) num * (size_t) dim]; + + in.seekg(0, std::ios::beg); + for (size_t i = 0; i < num; i++) { + in.seekg(4, std::ios::cur); + in.read((char *) (data + i * dim), dim * 4); + } + in.close(); +} + +void test_distance() { + std::vector xb{1, 2, 3, 4}; + std::vector xq{2, 2, 3, 4}; + float r = calculate(xb.data(), xq.data(), 4); + std::cout << r << std::endl; +} + +int main() { + test_distance(); + + BuildParams params; + params.search_length = 100; + params.candidate_pool_size = 100; + params.out_degree = 50; + + float *data = nullptr; + long *ids = nullptr; + unsigned ntotal, dim; + std::string filename = "/home/zilliz/opt/workspace/wook/efanna_graph/tests/siftsmall/siftsmall_base.fvecs"; + //std::string filename = "/home/zilliz/opt/workspace/wook/efanna_graph/tests/sift/sift_base.fvecs"; + + load_data(filename, data, ntotal, dim); + assert(data); + //float x = calculate(data + dim * 0, data + dim * 62, dim); + //std::cout << x << std::endl; + + NsgIndex index(dim, ntotal); + + auto s = std::chrono::high_resolution_clock::now(); + index.Build_with_ids(ntotal, data, ids, params); + auto e = std::chrono::high_resolution_clock::now(); + std::chrono::duration diff = e - s; + std::cout << "indexing time: " << diff.count() << "\n"; + + + int k = 10; + int nq = 1000; + SearchParams s_params; + s_params.search_length = 50; + auto dist = new float[nq*k]; + auto ids_b = new long[nq*k]; + s = std::chrono::high_resolution_clock::now(); + //ProfilerStart("xx.prof"); + index.Search(data, nq, dim, k, dist, ids_b, s_params); + //ProfilerStop(); + e = std::chrono::high_resolution_clock::now(); + diff = e - s; + std::cout << "search time: " << diff.count() << "\n"; + + for (int i = 0; i < k; ++i) { + std::cout << "id " << ids_b[i] << std::endl; + //std::cout << "dist " << dist[i] << std::endl; + } + + delete[] dist; + delete[] ids_b; + + return 0; +} + + diff --git a/cpp/src/core/test/test_nsg/CMakeLists.txt b/cpp/src/core/test/test_nsg/CMakeLists.txt new file mode 100644 index 0000000000..bd2db8072c --- /dev/null +++ b/cpp/src/core/test/test_nsg/CMakeLists.txt @@ -0,0 +1,48 @@ +############################## +include_directories(/usr/local/include/gperftools) +link_directories(/usr/local/lib) + +#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-free") +add_definitions(-std=c++11 -O3 -lboost -march=native -Wall -DINFO) + +find_package(OpenMP) +if (OPENMP_FOUND) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") +else () + message(FATAL_ERROR "no OpenMP supprot") +endif () +message(${OpenMP_CXX_FLAGS}) + +include_directories(${CMAKE_SOURCE_DIR}/src/knowhere/index/vector_index/nsg) +#include_directories(/home/zilliz/opt/app/pyenv/versions/3.6.8/include/python3.6m) +#include_directories(/home/zilliz/opt/app/pyenv/versions/3.6.8/envs/megasearch_testframework_dev/lib/python3.6/site-packages/numpy/core/include) + +aux_source_directory(${CMAKE_SOURCE_DIR}/src/knowhere/index/vector_index/nsg nsg_src) + +#add_library(nsg_raw SHARED ${nsg_src}) +#target_link_libraries(nsg_raw +# gomp) + +set(interface_src + ${CMAKE_SOURCE_DIR}/src/knowhere/index/vector_index/ivf.cpp + ${CMAKE_SOURCE_DIR}/src/knowhere/index/vector_index/gpu_ivf.cpp + ${CMAKE_SOURCE_DIR}/src/knowhere/index/vector_index/nsg_index.cpp + ${CMAKE_SOURCE_DIR}/src/knowhere/adapter/structure.cpp + ${CMAKE_SOURCE_DIR}/src/knowhere/common/exception.cpp + ${CMAKE_SOURCE_DIR}/src/knowhere/common/timer.cpp + ../utils.cpp + ) + +add_executable(test_nsg + test_nsg.cpp + ${interface_src} + ${nsg_src} + ) +#target_link_libraries(test_nsg +# # libprofiler.so +## -ltcmalloc +## gomp +# ) +target_link_libraries(test_nsg ${depend_libs} ${unittest_libs} ${basic_libs}) +############################## \ No newline at end of file diff --git a/cpp/src/core/test/test_nsg/test_nsg.cpp b/cpp/src/core/test/test_nsg/test_nsg.cpp new file mode 100644 index 0000000000..54ffa07848 --- /dev/null +++ b/cpp/src/core/test/test_nsg/test_nsg.cpp @@ -0,0 +1,82 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 上海赜睿信息科技有限公司(Zilliz) - All Rights Reserved +// Unauthorized copying of this file, via any medium is strictly prohibited. +// Proprietary and confidential. +//////////////////////////////////////////////////////////////////////////////// + +#include +#include + +#include "knowhere/index/vector_index/nsg_index.h" +#include "knowhere/index/vector_index/nsg/nsg_io.h" + +#include "../utils.h" + + +using namespace zilliz::knowhere; +using ::testing::TestWithParam; +using ::testing::Values; +using ::testing::Combine; + +class NSGInterfaceTest : public DataGen, public TestWithParam<::std::tuple> { + protected: + void SetUp() override { + //Init_with_default(); + Generate(256, 1000000, 1); + index_ = std::make_shared(); + std::tie(train_cfg, search_cfg) = GetParam(); + } + + protected: + std::shared_ptr index_; + Config train_cfg; + Config search_cfg; +}; + +INSTANTIATE_TEST_CASE_P(NSGparameters, NSGInterfaceTest, + Values(std::make_tuple( + // search length > out_degree + Config::object{{"nlist", 16384}, {"nprobe", 50}, {"knng", 100}, {"metric_type", "L2"}, + {"search_length", 60}, {"out_degree", 70}, {"candidate_pool_size", 500}}, + Config::object{{"k", 20}, {"search_length", 30}})) +); + +void AssertAnns(const DatasetPtr &result, + const int &nq, + const int &k) { + auto ids = result->array()[0]; + for (auto i = 0; i < nq; i++) { + EXPECT_EQ(i, *(ids->data()->GetValues(1, i * k))); + } +} + +TEST_P(NSGInterfaceTest, basic_test) { + assert(!xb.empty()); + + auto model = index_->Train(base_dataset, train_cfg); + auto result = index_->Search(query_dataset, search_cfg); + AssertAnns(result, nq, k); + + auto binaryset = index_->Serialize(); + auto new_index = std::make_shared(); + new_index->Load(binaryset); + auto new_result = new_index->Search(query_dataset, Config::object{{"k", k}}); + AssertAnns(result, nq, k); + + { + //std::cout << "k = 1" << std::endl; + //new_index->Search(GenQuery(1), Config::object{{"k", 1}}); + //new_index->Search(GenQuery(10), Config::object{{"k", 1}}); + //new_index->Search(GenQuery(100), Config::object{{"k", 1}}); + //new_index->Search(GenQuery(1000), Config::object{{"k", 1}}); + //new_index->Search(GenQuery(10000), Config::object{{"k", 1}}); + + //std::cout << "k = 5" << std::endl; + //new_index->Search(GenQuery(1), Config::object{{"k", 5}}); + //new_index->Search(GenQuery(20), Config::object{{"k", 5}}); + //new_index->Search(GenQuery(100), Config::object{{"k", 5}}); + //new_index->Search(GenQuery(300), Config::object{{"k", 5}}); + //new_index->Search(GenQuery(500), Config::object{{"k", 5}}); + } +} + diff --git a/cpp/src/core/test/utils.cpp b/cpp/src/core/test/utils.cpp new file mode 100644 index 0000000000..5c007aac28 --- /dev/null +++ b/cpp/src/core/test/utils.cpp @@ -0,0 +1,131 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 上海赜睿信息科技有限公司(Zilliz) - All Rights Reserved +// Unauthorized copying of this file, via any medium is strictly prohibited. +// Proprietary and confidential. +//////////////////////////////////////////////////////////////////////////////// + +#include "utils.h" + + +void DataGen::Init_with_default() { + Generate(dim, nb, nq); +} + +void DataGen::Generate(const int &dim, const int &nb, const int &nq) { + this->nb = nb; + this->nq = nq; + this->dim = dim; + + GenAll(dim, nb, xb, ids, nq, xq); + assert(xb.size() == dim * nb); + assert(xq.size() == dim * nq); + + base_dataset = generate_dataset(nb, dim, xb.data(), ids.data()); + query_dataset = generate_query_dataset(nq, dim, xq.data()); + +} +zilliz::knowhere::DatasetPtr DataGen::GenQuery(const int &nq) { + xq.resize(nq * dim); + for (size_t i = 0; i < nq * dim; ++i) { + xq[i] = xb[i]; + } + return generate_query_dataset(nq, dim, xq.data()); +} + +void GenAll(const int64_t dim, + const int64_t &nb, + std::vector &xb, + std::vector &ids, + const int64_t &nq, + std::vector &xq) { + xb.resize(nb * dim); + xq.resize(nq * dim); + ids.resize(nb); + GenAll(dim, nb, xb.data(), ids.data(), nq, xq.data()); +} + +void GenAll(const int64_t &dim, + const int64_t &nb, + float *xb, + int64_t *ids, + const int64_t &nq, + float *xq) { + GenBase(dim, nb, xb, ids); + for (size_t i = 0; i < nq * dim; ++i) { + xq[i] = xb[i]; + } +} + +void GenBase(const int64_t &dim, + const int64_t &nb, + float *xb, + int64_t *ids) { + for (auto i = 0; i < nb; ++i) { + for (auto j = 0; j < dim; ++j) { + //p_data[i * d + j] = float(base + i); + xb[i * dim + j] = drand48(); + } + xb[dim * i] += i / 1000.; + ids[i] = i; + } +} + +FileIOReader::FileIOReader(const std::string &fname) { + name = fname; + fs = std::fstream(name, std::ios::in | std::ios::binary); +} + +FileIOReader::~FileIOReader() { + fs.close(); +} + +size_t FileIOReader::operator()(void *ptr, size_t size) { + fs.read(reinterpret_cast(ptr), size); + return size; +} + +FileIOWriter::FileIOWriter(const std::string &fname) { + name = fname; + fs = std::fstream(name, std::ios::out | std::ios::binary); +} + +FileIOWriter::~FileIOWriter() { + fs.close(); +} + +size_t FileIOWriter::operator()(void *ptr, size_t size) { + fs.write(reinterpret_cast(ptr), size); + return size; +} + +using namespace zilliz::knowhere; + +DatasetPtr +generate_dataset(int64_t nb, int64_t dim, float *xb, long *ids) { + std::vector shape{nb, dim}; + auto tensor = ConstructFloatTensor((uint8_t *) xb, nb * dim * sizeof(float), shape); + std::vector tensors{tensor}; + std::vector tensor_fields{ConstructFloatField("data")}; + auto tensor_schema = std::make_shared(tensor_fields); + + auto id_array = ConstructInt64Array((uint8_t *) ids, nb * sizeof(int64_t)); + std::vector arrays{id_array}; + std::vector array_fields{ConstructInt64Field("id")}; + auto array_schema = std::make_shared(tensor_fields); + + auto dataset = std::make_shared(std::move(arrays), array_schema, + std::move(tensors), tensor_schema); + return dataset; +} + +DatasetPtr +generate_query_dataset(int64_t nb, int64_t dim, float *xb) { + std::vector shape{nb, dim}; + auto tensor = ConstructFloatTensor((uint8_t *) xb, nb * dim * sizeof(float), shape); + std::vector tensors{tensor}; + std::vector tensor_fields{ConstructFloatField("data")}; + auto tensor_schema = std::make_shared(tensor_fields); + + auto dataset = std::make_shared(std::move(tensors), tensor_schema); + return dataset; +} diff --git a/cpp/src/core/test/utils.h b/cpp/src/core/test/utils.h new file mode 100644 index 0000000000..ca56fedb2c --- /dev/null +++ b/cpp/src/core/test/utils.h @@ -0,0 +1,79 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 上海赜睿信息科技有限公司(Zilliz) - All Rights Reserved +// Unauthorized copying of this file, via any medium is strictly prohibited. +// Proprietary and confidential. +//////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include +#include +#include +#include + +#include "knowhere/adapter/structure.h" + +class DataGen { + protected: + void Init_with_default(); + + void Generate(const int &dim, const int &nb, const int &nq); + + zilliz::knowhere::DatasetPtr GenQuery(const int&nq); + + protected: + int nb = 10000; + int nq = 10; + int dim = 64; + int k = 10; + std::vector xb; + std::vector xq; + std::vector ids; + zilliz::knowhere::DatasetPtr base_dataset = nullptr; + zilliz::knowhere::DatasetPtr query_dataset = nullptr; +}; + + +extern void GenAll(const int64_t dim, + const int64_t &nb, + std::vector &xb, + std::vector &ids, + const int64_t &nq, + std::vector &xq); + +extern void GenAll(const int64_t &dim, + const int64_t &nb, + float *xb, + int64_t *ids, + const int64_t &nq, + float *xq); + +extern void GenBase(const int64_t &dim, + const int64_t &nb, + float *xb, + int64_t *ids); + +zilliz::knowhere::DatasetPtr +generate_dataset(int64_t nb, int64_t dim, float *xb, long *ids); + +zilliz::knowhere::DatasetPtr +generate_query_dataset(int64_t nb, int64_t dim, float *xb); + +struct FileIOWriter { + std::fstream fs; + std::string name; + + FileIOWriter(const std::string &fname); + ~FileIOWriter(); + size_t operator()(void *ptr, size_t size); +}; + +struct FileIOReader { + std::fstream fs; + std::string name; + + FileIOReader(const std::string &fname); + ~FileIOReader(); + size_t operator()(void *ptr, size_t size); +}; + diff --git a/cpp/src/core/thirdparty/SPTAG/.github/ISSUE_TEMPLATE/bug_report.md b/cpp/src/core/thirdparty/SPTAG/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000000..b735373365 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,35 @@ +--- +name: Bug report +about: Create a report to help us improve + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Version [e.g. 22] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Browser [e.g. stock browser, safari] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/cpp/src/core/thirdparty/SPTAG/.github/ISSUE_TEMPLATE/feature_request.md b/cpp/src/core/thirdparty/SPTAG/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000000..066b2d920a --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,17 @@ +--- +name: Feature request +about: Suggest an idea for this project + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/cpp/src/core/thirdparty/SPTAG/.gitignore b/cpp/src/core/thirdparty/SPTAG/.gitignore new file mode 100644 index 0000000000..9b51454741 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/.gitignore @@ -0,0 +1,93 @@ +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf +/.vs/SPTAG/v14 +/AnnService/x64 +/obj/x64_Release +/PythonWrapper/x64/Release +/x64/Release +/SPTAG.VC.db +/SPTAG.VC.VC.opendb +/AnnService/CoreLibrary.vcxproj.user +/AnnService/IndexBuilder.vcxproj.user +/AnnService/Server.vcxproj.user +/AnnService/SocketLib.vcxproj.user +/PythonWrapper/PythonCore.vcxproj.user +/build +/PythonWrapper/inc/ClientInterface_wrap.cxx +/PythonWrapper/inc/CoreInterface_wrap.cxx +/PythonWrapper/inc/SPTAG.py +/PythonWrapper/inc/SPTAGClient.py +/ipch/TEST-4fb66b42 +/obj/x64_Debug +/x64/Debug +/packages +/Search/Search.vcxproj.user +/AnnService/IndexSearcher.vcxproj.user +/Wrappers/inc/SWIGTYPE_p_RemoteSearchResult.java +/Wrappers/inc/SWIGTYPE_p_QueryResult.java +/Wrappers/inc/SPTAGJNI.java +/Wrappers/inc/SPTAGClientJNI.java +/Wrappers/inc/SPTAGClient.py +/Wrappers/inc/SPTAGClient.java +/Wrappers/inc/SPTAG.py +/Wrappers/inc/SPTAG.java +/Wrappers/inc/CoreInterface_pwrap.cpp +/Wrappers/inc/CoreInterface_jwrap.cpp +/Wrappers/inc/ClientInterface_pwrap.cpp +/Wrappers/inc/ClientInterface_jwrap.cpp +/Wrappers/inc/AnnIndex.java +/Wrappers/inc/AnnClient.java +/AnnService.users - Copy.props +/.vs +Release/ +Debug/ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService.users.props b/cpp/src/core/thirdparty/SPTAG/AnnService.users.props new file mode 100644 index 0000000000..e65231357f --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService.users.props @@ -0,0 +1,18 @@ + + + + + + + $(SystemVersionDef) %(AdditionalOptions) + + + + + $(SolutionDir)\$(Platform)\$(Configuration)\ + $(SolutionDir)\$(Platform)\$(Configuration)\ + + + + + diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/Aggregator.vcxproj b/cpp/src/core/thirdparty/SPTAG/AnnService/Aggregator.vcxproj new file mode 100644 index 0000000000..4e5514f057 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/Aggregator.vcxproj @@ -0,0 +1,178 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {D7F09A63-BDCA-4F6C-A864-8551D1FE447A} + Aggregator + 8.1 + + + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + $(SolutionDir)obj\$(Platform)_$(Configuration)\$(ProjectName)\ + $(ProjectDir);$(IncludePath) + $(OutAppDir) + $(OutLibDir);$(LibraryPath) + + + false + + + + Level3 + Disabled + true + true + _MBCS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + Guard + ProgramDatabase + + + CoreLibrary.lib;SocketLib.lib;%(AdditionalDependencies) + /guard:cf + %(AdditionalOptions) + + + + + Level3 + Disabled + true + true + + + CoreLibrary.lib;SocketLib.lib;%(AdditionalDependencies) + + + + + Level3 + MaxSpeed + true + true + true + true + + + true + true + CoreLibrary.lib;SocketLib.lib;%(AdditionalDependencies) + + + + + Level3 + MaxSpeed + true + true + true + true + _MBCS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + true + true + CoreLibrary.lib;SocketLib.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/Aggregator.vcxproj.filters b/cpp/src/core/thirdparty/SPTAG/AnnService/Aggregator.vcxproj.filters new file mode 100644 index 0000000000..de08faca3f --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/Aggregator.vcxproj.filters @@ -0,0 +1,44 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/CMakeLists.txt b/cpp/src/core/thirdparty/SPTAG/AnnService/CMakeLists.txt new file mode 100644 index 0000000000..4c1abe0189 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/CMakeLists.txt @@ -0,0 +1,44 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +file(GLOB HDR_FILES ${PROJECT_SOURCE_DIR}/AnnService/inc/Core/*.h ${PROJECT_SOURCE_DIR}/AnnService/inc/Core/Common/*.h ${PROJECT_SOURCE_DIR}/AnnService/inc/Core/BKT/*.h ${PROJECT_SOURCE_DIR}/AnnService/inc/Core/KDT/*.h ${PROJECT_SOURCE_DIR}/AnnService/inc/Helper/*.h) +file(GLOB SRC_FILES ${PROJECT_SOURCE_DIR}/AnnService/src/Core/*.cpp ${PROJECT_SOURCE_DIR}/AnnService/src/Core/Common/*.cpp ${PROJECT_SOURCE_DIR}/AnnService/src/Core/BKT/*.cpp ${PROJECT_SOURCE_DIR}/AnnService/src/Core/KDT/*.cpp ${PROJECT_SOURCE_DIR}/AnnService/src/Helper/*.cpp) + +include_directories(${PROJECT_SOURCE_DIR}/AnnService) + +add_library (SPTAGLib SHARED ${SRC_FILES} ${HDR_FILES}) +target_link_libraries (SPTAGLib ${TBB_LIBRARIES}) +add_library (SPTAGLibStatic STATIC ${SRC_FILES} ${HDR_FILES}) +set_target_properties(SPTAGLibStatic PROPERTIES OUTPUT_NAME SPTAGLib) + +file(GLOB SERVER_HDR_FILES ${HDR_FILES} ${PROJECT_SOURCE_DIR}/AnnService/inc/Server/*.h ${PROJECT_SOURCE_DIR}/AnnService/inc/Socket/*.h) +file(GLOB SERVER_FILES ${SRC_FILES} ${PROJECT_SOURCE_DIR}/AnnService/src/Server/*.cpp ${PROJECT_SOURCE_DIR}/AnnService/src/Socket/*.cpp) +add_executable (server ${SERVER_FILES} ${SERVER_HDR_FILES}) +target_link_libraries(server ${Boost_LIBRARIES} ${TBB_LIBRARIES}) + +file(GLOB CLIENT_HDR_FILES ${HDR_FILES} ${PROJECT_SOURCE_DIR}/AnnService/inc/Client/*.h ${PROJECT_SOURCE_DIR}/AnnService/inc/Socket/*.h) +file(GLOB CLIENT_FILES ${SRC_FILES} ${PROJECT_SOURCE_DIR}/AnnService/src/Client/*.cpp ${PROJECT_SOURCE_DIR}/AnnService/src/Socket/*.cpp) +add_executable (client ${CLIENT_FILES} ${CLIENT_HDR_FILES}) +target_link_libraries(client ${Boost_LIBRARIES} ${TBB_LIBRARIES}) + +file(GLOB AGG_HDR_FILES ${HDR_FILES} ${PROJECT_SOURCE_DIR}/AnnService/inc/Aggregator/*.h ${PROJECT_SOURCE_DIR}/AnnService/inc/Socket/*.h) +file(GLOB AGG_FILES ${SRC_FILES} ${PROJECT_SOURCE_DIR}/AnnService/src/Aggregator/*.cpp ${PROJECT_SOURCE_DIR}/AnnService/src/Socket/*.cpp) +add_executable (aggregator ${AGG_FILES} ${AGG_HDR_FILES}) +target_link_libraries(aggregator ${Boost_LIBRARIES} ${TBB_LIBRARIES}) + +file(GLOB BUILDER_HDR_FILES ${HDR_FILES} ${PROJECT_SOURCE_DIR}/AnnService/inc/IndexBuilder/*.h ${PROJECT_SOURCE_DIR}/AnnService/inc/IndexBuilder/VectorSetReaders/*.h) +file(GLOB BUILDER_FILES ${SRC_FILES} ${PROJECT_SOURCE_DIR}/AnnService/src/IndexBuilder/*.cpp ${PROJECT_SOURCE_DIR}/AnnService/src/IndexBuilder/VectorSetReaders/*.cpp) +add_executable (indexbuilder ${BUILDER_FILES} ${BUILDER_HDR_FILES}) +target_link_libraries(indexbuilder ${Boost_LIBRARIES} ${TBB_LIBRARIES}) + +file(GLOB SEARCHER_FILES ${SRC_FILES} ${PROJECT_SOURCE_DIR}/AnnService/src/IndexSearcher/*.cpp) +add_executable (indexsearcher ${SEARCHER_FILES} ${HDR_FILES}) +target_link_libraries(indexsearcher ${Boost_LIBRARIES} ${TBB_LIBRARIES}) + +install(TARGETS SPTAGLib SPTAGLibStatic server client aggregator indexbuilder indexsearcher + RUNTIME DESTINATION bin + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib) + +install(DIRECTORY inc DESTINATION include/sptag + FILES_MATCHING PATTERN "*.h") \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/Client.vcxproj b/cpp/src/core/thirdparty/SPTAG/AnnService/Client.vcxproj new file mode 100644 index 0000000000..34cb9def7a --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/Client.vcxproj @@ -0,0 +1,145 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {A89D70C3-C53B-42DE-A5CE-9A472540F5CB} + Client + 8.1 + + + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + $(SolutionDir)obj\$(Platform)_$(Configuration)\$(ProjectName)\ + $(ProjectDir);$(IncludePath) + $(OutAppDir) + $(OutLibDir);$(LibraryPath) + + + false + + + + CoreLibrary.lib;SocketLib.lib;%(AdditionalDependencies) + + + + + CoreLibrary.lib;SocketLib.lib;%(AdditionalDependencies) + + + + + CoreLibrary.lib;SocketLib.lib;%(AdditionalDependencies) + /guard:cf %(AdditionalOptions) + + + Guard + ProgramDatabase + _MBCS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + + + CoreLibrary.lib;SocketLib.lib;%(AdditionalDependencies) + + + _MBCS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + + + + + + + + + + + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/Client.vcxproj.filters b/cpp/src/core/thirdparty/SPTAG/AnnService/Client.vcxproj.filters new file mode 100644 index 0000000000..31d84bd1d5 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/Client.vcxproj.filters @@ -0,0 +1,32 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/CoreLibrary.vcxproj b/cpp/src/core/thirdparty/SPTAG/AnnService/CoreLibrary.vcxproj new file mode 100644 index 0000000000..a0e884b3df --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/CoreLibrary.vcxproj @@ -0,0 +1,193 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {C2BC5FDE-C853-4F3D-B7E4-2C9B5524DDF9} + CoreLibrary + 8.1 + CoreLibrary + + + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + StaticLibrary + true + v140 + MultiByte + + + StaticLibrary + false + v140 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + $(IncludePath);$(ProjectDir) + + + $(SolutionDir)obj\$(Platform)_$(Configuration)\$(ProjectName)\ + $(OutLibDir) + + + + Level3 + Disabled + true + true + /Zc:twoPhase- %(AdditionalOptions) + + + + + Level3 + Disabled + true + true + true + _MBCS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + Guard + ProgramDatabase + + + + + Level3 + MaxSpeed + true + true + true + true + /Zc:twoPhase- %(AdditionalOptions) + + + true + true + + + + + Level3 + MaxSpeed + true + true + true + true + true + _MBCS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/CoreLibrary.vcxproj.filters b/cpp/src/core/thirdparty/SPTAG/AnnService/CoreLibrary.vcxproj.filters new file mode 100644 index 0000000000..c411e8cef5 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/CoreLibrary.vcxproj.filters @@ -0,0 +1,178 @@ + + + + + {c260e4c4-ec44-4d50-941f-078454da2a89} + + + {c7b9ab49-a99f-4eb4-b8ab-61f0730b9a89} + + + {a306a099-8e3f-433d-b065-9d99433f422e} + + + {33f272c5-907e-4848-bbd7-4340fe44f511} + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {47ec2958-e880-4c1a-b663-04fc48c799af} + + + {10d17e5e-9ad2-4000-96d4-83b616480b97} + + + {23fdeb31-9052-47d1-8edb-9b47c4b02707} + + + {6dff7b24-66ea-40b4-b408-d8fe264a6caa} + + + {b0f1e81d-ca05-426e-bffa-75513a52ca6b} + + + {774592a9-40aa-4342-a4af-b711a1cc4d52} + + + {8fb36afb-73ed-4c3d-8c9b-c3581d80c5d1} + + + + + Header Files\Core + + + Header Files\Core + + + Header Files\Core + + + Header Files\Core + + + Header Files\Core + + + Header Files\Core\BKT + + + Header Files\Helper + + + Header Files\Helper + + + Header Files\Helper + + + Header Files\Core + + + Header Files\Core + + + Header Files\Helper + + + Header Files\Helper + + + Header Files\Helper + + + Header Files\Core\BKT + + + Header Files\Core\Common + + + Header Files\Core\Common + + + Header Files\Core\Common + + + Header Files\Core\Common + + + Header Files\Core\Common + + + Header Files\Core\Common + + + Header Files\Core\Common + + + Header Files\Core\Common + + + Header Files\Core\KDT + + + Header Files\Core\KDT + + + Header Files\Core\Common + + + Header Files\Core\Common + + + Header Files\Core\Common + + + Header Files\Core\Common + + + Header Files\Core\Common + + + + + Source Files\Core + + + Source Files\Core + + + Source Files\Core\Common + + + Source Files\Helper + + + Source Files\Helper + + + Source Files\Core + + + Source Files\Core + + + Source Files\Helper + + + Source Files\Helper + + + Source Files\Helper + + + Source Files\Core\BKT + + + Source Files\Core\KDT + + + Source Files\Core\Common + + + + + + \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/IndexBuilder.vcxproj b/cpp/src/core/thirdparty/SPTAG/AnnService/IndexBuilder.vcxproj new file mode 100644 index 0000000000..931f301e10 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/IndexBuilder.vcxproj @@ -0,0 +1,179 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {F492F794-E78B-4B1F-A556-5E045B9163D5} + IndexBuilder + 8.1 + + + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + + + + + + + + + + + + + + + + + + $(SolutionDir)obj\$(Platform)_$(Configuration)\$(ProjectName)\ + $(ProjectDir);$(IncludePath) + $(OutAppDir) + $(OutLibDir);$(LibraryPath) + + + false + + + + CoreLibrary.lib;%(AdditionalDependencies) + + + + + Level3 + MaxSpeed + true + true + true + true + _MBCS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + + + true + true + + + + + Level3 + Disabled + true + true + + + + + Level3 + Disabled + true + true + _MBCS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + Guard + ProgramDatabase + true + + + /guard:cf %(AdditionalOptions) + + + + + Level3 + MaxSpeed + true + true + true + true + + + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + + \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/IndexBuilder.vcxproj.filters b/cpp/src/core/thirdparty/SPTAG/AnnService/IndexBuilder.vcxproj.filters new file mode 100644 index 0000000000..dcd29861c4 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/IndexBuilder.vcxproj.filters @@ -0,0 +1,50 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {cf68b421-6a65-44f2-bf43-438b13940d7d} + + + {41ac91f9-6b6d-4341-8791-12f672d6ad5c} + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files\VectorSetReaders + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files\VectorSetReaders + + + Source Files + + + \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/IndexSearcher.vcxproj b/cpp/src/core/thirdparty/SPTAG/AnnService/IndexSearcher.vcxproj new file mode 100644 index 0000000000..9cd6418959 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/IndexSearcher.vcxproj @@ -0,0 +1,172 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {97615D3B-9FA0-469E-B229-95A91A5087E0} + IndexSearcher + 8.1 + IndexSearcher + + + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + + + + + + + + + + + + + + + + + + $(SolutionDir)obj\$(Platform)_$(Configuration)\$(ProjectName)\ + $(ProjectDir);$(SolutionDir)AnnService\;$(IncludePath) + $(OutLibDir);$(LibraryPath) + $(OutAppDir) + + + false + + + + CoreLibrary.lib;%(AdditionalDependencies) + + + + + Level3 + MaxSpeed + true + true + true + true + _MBCS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + + + true + true + + + + + Level3 + Disabled + true + true + + + + + Level3 + Disabled + true + true + _MBCS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + Guard + ProgramDatabase + true + + + /guard:cf %(AdditionalOptions) + + + + + Level3 + MaxSpeed + true + true + true + true + + + true + true + + + + + + + + Designer + + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + + \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/IndexSearcher.vcxproj.filters b/cpp/src/core/thirdparty/SPTAG/AnnService/IndexSearcher.vcxproj.filters new file mode 100644 index 0000000000..82f7700c53 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/IndexSearcher.vcxproj.filters @@ -0,0 +1,25 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + + + + \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/Server.vcxproj b/cpp/src/core/thirdparty/SPTAG/AnnService/Server.vcxproj new file mode 100644 index 0000000000..c2336176ee --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/Server.vcxproj @@ -0,0 +1,155 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {E28B1222-8BEA-4A92-8FE0-088EBDAA7FE0} + Server + 8.1 + + + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + $(SolutionDir)obj\$(Platform)_$(Configuration)\$(ProjectName)\ + $(ProjectDir);$(IncludePath) + $(OutAppDir) + $(OutLibDir);$(LibraryPath) + + + false + + + + CoreLibrary.lib;SocketLib.lib;%(AdditionalDependencies) + + + + + CoreLibrary.lib;SocketLib.lib;%(AdditionalDependencies) + + + + + CoreLibrary.lib;SocketLib.lib;%(AdditionalDependencies) + /guard:cf %(AdditionalOptions) + + + _MBCS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + Guard + ProgramDatabase + + + + + CoreLibrary.lib;SocketLib.lib;%(AdditionalDependencies) + + + _MBCS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + + \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/Server.vcxproj.filters b/cpp/src/core/thirdparty/SPTAG/AnnService/Server.vcxproj.filters new file mode 100644 index 0000000000..da95d13f40 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/Server.vcxproj.filters @@ -0,0 +1,56 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/SocketLib.vcxproj b/cpp/src/core/thirdparty/SPTAG/AnnService/SocketLib.vcxproj new file mode 100644 index 0000000000..84f968fa0a --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/SocketLib.vcxproj @@ -0,0 +1,123 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {F9A72303-6381-4C80-86FF-606A2F6F7B96} + SocketLib + 8.1 + + + + StaticLibrary + true + v140 + MultiByte + + + StaticLibrary + false + v140 + true + MultiByte + + + StaticLibrary + true + v140 + MultiByte + + + StaticLibrary + false + v140 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + + $(ProjectDir);$(IncludePath) + $(SolutionDir)obj\$(Platform)_$(Configuration)\$(ProjectName)\ + $(OutLibDir)\ + + + + Guard + ProgramDatabase + _MBCS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + + + _MBCS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/SocketLib.vcxproj.filters b/cpp/src/core/thirdparty/SPTAG/AnnService/SocketLib.vcxproj.filters new file mode 100644 index 0000000000..5aa20f3bbf --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/SocketLib.vcxproj.filters @@ -0,0 +1,65 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Aggregator/AggregatorContext.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Aggregator/AggregatorContext.h new file mode 100644 index 0000000000..60c86137be --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Aggregator/AggregatorContext.h @@ -0,0 +1,67 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_AGGREGATOR_AGGREGATORCONTEXT_H_ +#define _SPTAG_AGGREGATOR_AGGREGATORCONTEXT_H_ + +#include "inc/Socket/Common.h" +#include "AggregatorSettings.h" + +#include +#include +#include + +namespace SPTAG +{ +namespace Aggregator +{ + +enum RemoteMachineStatus : uint8_t +{ + Disconnected = 0, + + Connecting, + + Connected +}; + + +struct RemoteMachine +{ + RemoteMachine(); + + std::string m_address; + + std::string m_port; + + Socket::ConnectionID m_connectionID; + + std::atomic m_status; +}; + +class AggregatorContext +{ +public: + AggregatorContext(const std::string& p_filePath); + + ~AggregatorContext(); + + bool IsInitialized() const; + + const std::vector>& GetRemoteServers() const; + + const std::shared_ptr& GetSettings() const; + +private: + std::vector> m_remoteServers; + + std::shared_ptr m_settings; + + bool m_initialized; +}; + +} // namespace Aggregator +} // namespace AnnService + + +#endif // _SPTAG_AGGREGATOR_AGGREGATORCONTEXT_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Aggregator/AggregatorExecutionContext.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Aggregator/AggregatorExecutionContext.h new file mode 100644 index 0000000000..12948a218a --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Aggregator/AggregatorExecutionContext.h @@ -0,0 +1,53 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_AGGREGATOR_AGGREGATOREXECUTIONCONTEXT_H_ +#define _SPTAG_AGGREGATOR_AGGREGATOREXECUTIONCONTEXT_H_ + +#include "inc/Socket/RemoteSearchQuery.h" +#include "inc/Socket/Packet.h" + +#include +#include + +namespace SPTAG +{ +namespace Aggregator +{ + +typedef std::shared_ptr AggregatorResult; + +class AggregatorExecutionContext +{ +public: + AggregatorExecutionContext(std::size_t p_totalServerNumber, + Socket::PacketHeader p_requestHeader); + + ~AggregatorExecutionContext(); + + std::size_t GetServerNumber() const; + + AggregatorResult& GetResult(std::size_t p_num); + + const Socket::PacketHeader& GetRequestHeader() const; + + bool IsCompletedAfterFinsh(std::uint32_t p_finishedCount); + +private: + std::atomic m_unfinishedCount; + + std::vector m_results; + + Socket::PacketHeader m_requestHeader; + +}; + + + + +} // namespace Aggregator +} // namespace AnnService + + +#endif // _SPTAG_AGGREGATOR_AGGREGATOREXECUTIONCONTEXT_H_ + diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Aggregator/AggregatorService.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Aggregator/AggregatorService.h new file mode 100644 index 0000000000..4d864aa5f0 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Aggregator/AggregatorService.h @@ -0,0 +1,88 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_AGGREGATOR_AGGREGATORSERVICE_H_ +#define _SPTAG_AGGREGATOR_AGGREGATORSERVICE_H_ + +#include "AggregatorContext.h" +#include "AggregatorExecutionContext.h" +#include "inc/Socket/Server.h" +#include "inc/Socket/Client.h" +#include "inc/Socket/ResourceManager.h" + +#include + +#include +#include +#include +#include + +namespace SPTAG +{ +namespace Aggregator +{ + +class AggregatorService +{ +public: + AggregatorService(); + + ~AggregatorService(); + + bool Initialize(); + + void Run(); + +private: + + void StartClient(); + + void StartListen(); + + void WaitForShutdown(); + + void ConnectToPendingServers(); + + void AddToPendingServers(std::shared_ptr p_remoteServer); + + void SearchRequestHanlder(Socket::ConnectionID p_localConnectionID, Socket::Packet p_packet); + + void SearchResponseHanlder(Socket::ConnectionID p_localConnectionID, Socket::Packet p_packet); + + void AggregateResults(std::shared_ptr p_exectionContext); + + std::shared_ptr GetContext(); + +private: + typedef std::function AggregatorCallback; + + std::shared_ptr m_aggregatorContext; + + std::shared_ptr m_socketServer; + + std::shared_ptr m_socketClient; + + bool m_initalized; + + std::unique_ptr m_threadPool; + + boost::asio::io_context m_ioContext; + + boost::asio::signal_set m_shutdownSignals; + + std::vector> m_pendingConnectServers; + + std::mutex m_pendingConnectServersMutex; + + boost::asio::deadline_timer m_pendingConnectServersTimer; + + Socket::ResourceManager m_aggregatorCallbackManager; +}; + + + +} // namespace Aggregator +} // namespace AnnService + + +#endif // _SPTAG_AGGREGATOR_AGGREGATORSERVICE_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Aggregator/AggregatorSettings.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Aggregator/AggregatorSettings.h new file mode 100644 index 0000000000..cb1e9fe7f7 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Aggregator/AggregatorSettings.h @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_AGGREGATOR_AGGREGATORSETTINGS_H_ +#define _SPTAG_AGGREGATOR_AGGREGATORSETTINGS_H_ + +#include "../Core/Common.h" + +#include + +namespace SPTAG +{ +namespace Aggregator +{ + +struct AggregatorSettings +{ + AggregatorSettings(); + + std::string m_listenAddr; + + std::string m_listenPort; + + std::uint32_t m_searchTimeout; + + SizeType m_threadNum; + + SizeType m_socketThreadNum; +}; + + + + +} // namespace Aggregator +} // namespace AnnService + + +#endif // _SPTAG_AGGREGATOR_AGGREGATORSETTINGS_H_ + diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Client/ClientWrapper.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Client/ClientWrapper.h new file mode 100644 index 0000000000..d96a67061e --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Client/ClientWrapper.h @@ -0,0 +1,80 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_CLIENT_CLIENTWRAPPER_H_ +#define _SPTAG_CLIENT_CLIENTWRAPPER_H_ + +#include "inc/Socket/Client.h" +#include "inc/Socket/RemoteSearchQuery.h" +#include "inc/Socket/ResourceManager.h" +#include "Options.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace SPTAG +{ +namespace Client +{ + +class ClientWrapper +{ +public: + typedef std::function Callback; + + ClientWrapper(const ClientOptions& p_options); + + ~ClientWrapper(); + + void SendQueryAsync(const Socket::RemoteQuery& p_query, + Callback p_callback, + const ClientOptions& p_options); + + void WaitAllFinished(); + + bool IsAvailable() const; + +private: + typedef std::pair ConnectionPair; + + Socket::PacketHandlerMapPtr GetHandlerMap(); + + void DecreaseUnfnishedJobCount(); + + const ConnectionPair& GetConnection(); + + void SearchResponseHanlder(Socket::ConnectionID p_localConnectionID, Socket::Packet p_packet); + + void HandleDeadConnection(Socket::ConnectionID p_cid); + +private: + ClientOptions m_options; + + std::unique_ptr m_client; + + std::atomic m_unfinishedJobCount; + + std::atomic_bool m_isWaitingFinish; + + std::condition_variable m_waitingQueue; + + std::mutex m_waitingMutex; + + std::vector m_connections; + + std::atomic m_spinCountOfConnection; + + Socket::ResourceManager m_callbackManager; +}; + + +} // namespace Socket +} // namespace SPTAG + +#endif // _SPTAG_CLIENT_OPTIONS_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Client/Options.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Client/Options.h new file mode 100644 index 0000000000..062061f042 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Client/Options.h @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_CLIENT_OPTIONS_H_ +#define _SPTAG_CLIENT_OPTIONS_H_ + +#include "inc/Helper/ArgumentsParser.h" + +#include +#include +#include + +namespace SPTAG +{ +namespace Client +{ + +class ClientOptions : public Helper::ArgumentsParser +{ +public: + ClientOptions(); + + virtual ~ClientOptions(); + + std::string m_serverAddr; + + std::string m_serverPort; + + // in milliseconds. + std::uint32_t m_searchTimeout; + + std::uint32_t m_threadNum; + + std::uint32_t m_socketThreadNum; + +}; + + +} // namespace Socket +} // namespace SPTAG + +#endif // _SPTAG_CLIENT_OPTIONS_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/BKT/Index.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/BKT/Index.h new file mode 100644 index 0000000000..fde5b8ec88 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/BKT/Index.h @@ -0,0 +1,112 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_BKT_INDEX_H_ +#define _SPTAG_BKT_INDEX_H_ + +#include "../Common.h" +#include "../VectorIndex.h" + +#include "../Common/CommonUtils.h" +#include "../Common/DistanceUtils.h" +#include "../Common/QueryResultSet.h" +#include "../Common/Dataset.h" +#include "../Common/WorkSpace.h" +#include "../Common/WorkSpacePool.h" +#include "../Common/RelativeNeighborhoodGraph.h" +#include "../Common/BKTree.h" +#include "inc/Helper/SimpleIniReader.h" +#include "inc/Helper/StringConvert.h" + +#include +#include +#include + +namespace SPTAG +{ + + namespace Helper + { + class IniReader; + } + + namespace BKT + { + template + class Index : public VectorIndex + { + private: + // data points + COMMON::Dataset m_pSamples; + + // BKT structures. + COMMON::BKTree m_pTrees; + + // Graph structure + COMMON::RelativeNeighborhoodGraph m_pGraph; + + std::string m_sBKTFilename; + std::string m_sGraphFilename; + std::string m_sDataPointsFilename; + + std::mutex m_dataLock; // protect data and graph + tbb::concurrent_unordered_set m_deletedID; + std::unique_ptr m_workSpacePool; + + int m_iNumberOfThreads; + DistCalcMethod m_iDistCalcMethod; + float(*m_fComputeDistance)(const T* pX, const T* pY, int length); + + int m_iMaxCheck; + int m_iThresholdOfNumberOfContinuousNoBetterPropagation; + int m_iNumberOfInitialDynamicPivots; + int m_iNumberOfOtherDynamicPivots; + public: + Index() + { +#define DefineBKTParameter(VarName, VarType, DefaultValue, RepresentStr) \ + VarName = DefaultValue; \ + +#include "inc/Core/BKT/ParameterDefinitionList.h" +#undef DefineBKTParameter + + m_fComputeDistance = COMMON::DistanceCalcSelector(m_iDistCalcMethod); + } + + ~Index() {} + + inline int GetNumSamples() const { return m_pSamples.R(); } + inline int GetFeatureDim() const { return m_pSamples.C(); } + + inline int GetCurrMaxCheck() const { return m_iMaxCheck; } + inline int GetNumThreads() const { return m_iNumberOfThreads; } + inline DistCalcMethod GetDistCalcMethod() const { return m_iDistCalcMethod; } + inline IndexAlgoType GetIndexAlgoType() const { return IndexAlgoType::BKT; } + inline VectorValueType GetVectorValueType() const { return GetEnumValueType(); } + + inline float ComputeDistance(const void* pX, const void* pY) const { return m_fComputeDistance((const T*)pX, (const T*)pY, m_pSamples.C()); } + inline const void* GetSample(const int idx) const { return (void*)m_pSamples[idx]; } + + ErrorCode BuildIndex(const void* p_data, int p_vectorNum, int p_dimension); + + ErrorCode SaveIndexToMemory(std::vector& p_indexBlobs, std::vector& p_indexBlobsLen); + ErrorCode LoadIndexFromMemory(const std::vector& p_indexBlobs); + + ErrorCode SaveIndex(const std::string& p_folderPath, std::ofstream& p_configout); + ErrorCode LoadIndex(const std::string& p_folderPath, Helper::IniReader& p_reader); + ErrorCode SearchIndex(QueryResult &p_query) const; + ErrorCode AddIndex(const void* p_vectors, int p_vectorNum, int p_dimension); + ErrorCode DeleteIndex(const void* p_vectors, int p_vectorNum); + + ErrorCode SetParameter(const char* p_param, const char* p_value); + std::string GetParameter(const char* p_param) const; + + private: + ErrorCode RefineIndex(const std::string& p_folderPath); + void SearchIndexWithDeleted(COMMON::QueryResultSet &p_query, COMMON::WorkSpace &p_space, const tbb::concurrent_unordered_set &p_deleted) const; + void SearchIndexWithoutDeleted(COMMON::QueryResultSet &p_query, COMMON::WorkSpace &p_space) const; + }; + } // namespace BKT +} // namespace SPTAG + +#endif // _SPTAG_BKT_INDEX_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/BKT/ParameterDefinitionList.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/BKT/ParameterDefinitionList.h new file mode 100644 index 0000000000..7ad17fcbb1 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/BKT/ParameterDefinitionList.h @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifdef DefineBKTParameter + +// DefineBKTParameter(VarName, VarType, DefaultValue, RepresentStr) +DefineBKTParameter(m_sBKTFilename, std::string, std::string("tree.bin"), "TreeFilePath") +DefineBKTParameter(m_sGraphFilename, std::string, std::string("graph.bin"), "GraphFilePath") +DefineBKTParameter(m_sDataPointsFilename, std::string, std::string("vectors.bin"), "VectorFilePath") + +DefineBKTParameter(m_pTrees.m_iTreeNumber, int, 1L, "BKTNumber") +DefineBKTParameter(m_pTrees.m_iBKTKmeansK, int, 32L, "BKTKmeansK") +DefineBKTParameter(m_pTrees.m_iBKTLeafSize, int, 8L, "BKTLeafSize") +DefineBKTParameter(m_pTrees.m_iSamples, int, 1000L, "Samples") + + +DefineBKTParameter(m_pGraph.m_iTPTNumber, int, 32L, "TpTreeNumber") +DefineBKTParameter(m_pGraph.m_iTPTLeafSize, int, 2000L, "TPTLeafSize") +DefineBKTParameter(m_pGraph.m_numTopDimensionTPTSplit, int, 5L, "NumTopDimensionTpTreeSplit") + +DefineBKTParameter(m_pGraph.m_iNeighborhoodSize, int, 32L, "NeighborhoodSize") +DefineBKTParameter(m_pGraph.m_iNeighborhoodScale, int, 2L, "GraphNeighborhoodScale") +DefineBKTParameter(m_pGraph.m_iCEFScale, int, 2L, "GraphCEFScale") +DefineBKTParameter(m_pGraph.m_iRefineIter, int, 0L, "RefineIterations") +DefineBKTParameter(m_pGraph.m_iCEF, int, 1000L, "CEF") +DefineBKTParameter(m_pGraph.m_iMaxCheckForRefineGraph, int, 10000L, "MaxCheckForRefineGraph") + +DefineBKTParameter(m_iNumberOfThreads, int, 1L, "NumberOfThreads") +DefineBKTParameter(m_iDistCalcMethod, SPTAG::DistCalcMethod, SPTAG::DistCalcMethod::Cosine, "DistCalcMethod") + +DefineBKTParameter(m_iMaxCheck, int, 8192L, "MaxCheck") +DefineBKTParameter(m_iThresholdOfNumberOfContinuousNoBetterPropagation, int, 3L, "ThresholdOfNumberOfContinuousNoBetterPropagation") +DefineBKTParameter(m_iNumberOfInitialDynamicPivots, int, 50L, "NumberOfInitialDynamicPivots") +DefineBKTParameter(m_iNumberOfOtherDynamicPivots, int, 4L, "NumberOfOtherDynamicPivots") + +#endif diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common.h new file mode 100644 index 0000000000..91c6239b32 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common.h @@ -0,0 +1,166 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_CORE_COMMONDEFS_H_ +#define _SPTAG_CORE_COMMONDEFS_H_ + +#include +#include +#include +#include +#include +#include +#include + +#ifndef _MSC_VER +#include +#include +#define FolderSep '/' +#define mkdir(a) mkdir(a, ACCESSPERMS) +inline bool direxists(const char* path) { + struct stat info; + return stat(path, &info) == 0 && (info.st_mode & S_IFDIR); +} +inline bool fileexists(const char* path) { + struct stat info; + return stat(path, &info) == 0 && (info.st_mode & S_IFDIR) == 0; +} +template +inline T min(T a, T b) { + return a < b ? a : b; +} +template +inline T max(T a, T b) { + return a > b ? a : b; +} + +#ifndef _rotl +#define _rotl(x, n) (((x) << (n)) | ((x) >> (32-(n)))) +#endif + +#else +#define WIN32_LEAN_AND_MEAN +#include +#include +#define FolderSep '\\' +#define mkdir(a) CreateDirectory(a, NULL) +inline bool direxists(const char* path) { + auto dwAttr = GetFileAttributes((LPCSTR)path); + return (dwAttr != INVALID_FILE_ATTRIBUTES) && (dwAttr & FILE_ATTRIBUTE_DIRECTORY); +} +inline bool fileexists(const char* path) { + auto dwAttr = GetFileAttributes((LPCSTR)path); + return (dwAttr != INVALID_FILE_ATTRIBUTES) && (dwAttr & FILE_ATTRIBUTE_DIRECTORY) == 0; +} +#endif + +namespace SPTAG +{ + +typedef std::uint32_t SizeType; + +const float MinDist = (std::numeric_limits::min)(); +const float MaxDist = (std::numeric_limits::max)(); +const float Epsilon = 0.000000001f; + +class MyException : public std::exception +{ +private: + std::string Exp; +public: + MyException(std::string e) { Exp = e; } +#ifdef _MSC_VER + const char* what() const { return Exp.c_str(); } +#else + const char* what() const noexcept { return Exp.c_str(); } +#endif +}; + +// Type of number index. +typedef std::int32_t IndexType; +static_assert(std::is_integral::value, "IndexType must be integral type."); + + +enum class ErrorCode : std::uint16_t +{ +#define DefineErrorCode(Name, Value) Name = Value, +#include "DefinitionList.h" +#undef DefineErrorCode + + Undefined +}; +static_assert(static_cast(ErrorCode::Undefined) != 0, "Empty ErrorCode!"); + + +enum class DistCalcMethod : std::uint8_t +{ +#define DefineDistCalcMethod(Name) Name, +#include "DefinitionList.h" +#undef DefineDistCalcMethod + + Undefined +}; +static_assert(static_cast(DistCalcMethod::Undefined) != 0, "Empty DistCalcMethod!"); + + +enum class VectorValueType : std::uint8_t +{ +#define DefineVectorValueType(Name, Type) Name, +#include "DefinitionList.h" +#undef DefineVectorValueType + + Undefined +}; +static_assert(static_cast(VectorValueType::Undefined) != 0, "Empty VectorValueType!"); + + +enum class IndexAlgoType : std::uint8_t +{ +#define DefineIndexAlgo(Name) Name, +#include "DefinitionList.h" +#undef DefineIndexAlgo + + Undefined +}; +static_assert(static_cast(IndexAlgoType::Undefined) != 0, "Empty IndexAlgoType!"); + + +template +constexpr VectorValueType GetEnumValueType() +{ + return VectorValueType::Undefined; +} + + +#define DefineVectorValueType(Name, Type) \ +template<> \ +constexpr VectorValueType GetEnumValueType() \ +{ \ + return VectorValueType::Name; \ +} \ + +#include "DefinitionList.h" +#undef DefineVectorValueType + + +inline std::size_t GetValueTypeSize(VectorValueType p_valueType) +{ + switch (p_valueType) + { +#define DefineVectorValueType(Name, Type) \ + case VectorValueType::Name: \ + return sizeof(Type); \ + +#include "DefinitionList.h" +#undef DefineVectorValueType + + default: + break; + } + + return 0; +} + +} // namespace SPTAG + +#endif // _SPTAG_CORE_COMMONDEFS_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common/BKTree.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common/BKTree.h new file mode 100644 index 0000000000..366ca08499 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common/BKTree.h @@ -0,0 +1,492 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_COMMON_BKTREE_H_ +#define _SPTAG_COMMON_BKTREE_H_ + +#include +#include +#include +#include + +#include "../VectorIndex.h" + +#include "CommonUtils.h" +#include "QueryResultSet.h" +#include "WorkSpace.h" + +#pragma warning(disable:4996) // 'fopen': This function or variable may be unsafe. Consider using fopen_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. + +namespace SPTAG +{ + namespace COMMON + { + // node type for storing BKT + struct BKTNode + { + int centerid; + int childStart; + int childEnd; + + BKTNode(int cid = -1) : centerid(cid), childStart(-1), childEnd(-1) {} + }; + + template + struct KmeansArgs { + int _K; + int _D; + int _T; + T* centers; + int* counts; + float* newCenters; + int* newCounts; + char* label; + int* clusterIdx; + float* clusterDist; + T* newTCenters; + + KmeansArgs(int k, int dim, int datasize, int threadnum) : _K(k), _D(dim), _T(threadnum) { + centers = new T[k * dim]; + counts = new int[k]; + newCenters = new float[threadnum * k * dim]; + newCounts = new int[threadnum * k]; + label = new char[datasize]; + clusterIdx = new int[threadnum * k]; + clusterDist = new float[threadnum * k]; + newTCenters = new T[k * dim]; + } + + ~KmeansArgs() { + delete[] centers; + delete[] counts; + delete[] newCenters; + delete[] newCounts; + delete[] label; + delete[] clusterIdx; + delete[] clusterDist; + delete[] newTCenters; + } + + inline void ClearCounts() { + memset(newCounts, 0, sizeof(int) * _T * _K); + } + + inline void ClearCenters() { + memset(newCenters, 0, sizeof(float) * _T * _K * _D); + } + + inline void ClearDists(float dist) { + for (int i = 0; i < _T * _K; i++) { + clusterIdx[i] = -1; + clusterDist[i] = dist; + } + } + + void Shuffle(std::vector& indices, int first, int last) { + int* pos = new int[_K]; + pos[0] = first; + for (int k = 1; k < _K; k++) pos[k] = pos[k - 1] + newCounts[k - 1]; + + for (int k = 0; k < _K; k++) { + if (newCounts[k] == 0) continue; + int i = pos[k]; + while (newCounts[k] > 0) { + int swapid = pos[(int)(label[i])] + newCounts[(int)(label[i])] - 1; + newCounts[(int)(label[i])]--; + std::swap(indices[i], indices[swapid]); + std::swap(label[i], label[swapid]); + } + while (indices[i] != clusterIdx[k]) i++; + std::swap(indices[i], indices[pos[k] + counts[k] - 1]); + } + delete[] pos; + } + }; + + class BKTree + { + public: + BKTree(): m_iTreeNumber(1), m_iBKTKmeansK(32), m_iBKTLeafSize(8), m_iSamples(1000) {} + + BKTree(BKTree& other): m_iTreeNumber(other.m_iTreeNumber), + m_iBKTKmeansK(other.m_iBKTKmeansK), + m_iBKTLeafSize(other.m_iBKTLeafSize), + m_iSamples(other.m_iSamples) {} + ~BKTree() {} + + inline const BKTNode& operator[](int index) const { return m_pTreeRoots[index]; } + inline BKTNode& operator[](int index) { return m_pTreeRoots[index]; } + + inline int size() const { return (int)m_pTreeRoots.size(); } + + inline const std::unordered_map& GetSampleMap() const { return m_pSampleCenterMap; } + + template + void BuildTrees(VectorIndex* index, std::vector* indices = nullptr) + { + struct BKTStackItem { + int index, first, last; + BKTStackItem(int index_, int first_, int last_) : index(index_), first(first_), last(last_) {} + }; + std::stack ss; + + std::vector localindices; + if (indices == nullptr) { + localindices.resize(index->GetNumSamples()); + for (int i = 0; i < index->GetNumSamples(); i++) localindices[i] = i; + } + else { + localindices.assign(indices->begin(), indices->end()); + } + KmeansArgs args(m_iBKTKmeansK, index->GetFeatureDim(), (int)localindices.size(), omp_get_num_threads()); + + m_pSampleCenterMap.clear(); + for (char i = 0; i < m_iTreeNumber; i++) + { + std::random_shuffle(localindices.begin(), localindices.end()); + + m_pTreeStart.push_back((int)m_pTreeRoots.size()); + m_pTreeRoots.push_back(BKTNode((int)localindices.size())); + std::cout << "Start to build BKTree " << i + 1 << std::endl; + + ss.push(BKTStackItem(m_pTreeStart[i], 0, (int)localindices.size())); + while (!ss.empty()) { + BKTStackItem item = ss.top(); ss.pop(); + int newBKTid = (int)m_pTreeRoots.size(); + m_pTreeRoots[item.index].childStart = newBKTid; + if (item.last - item.first <= m_iBKTLeafSize) { + for (int j = item.first; j < item.last; j++) { + m_pTreeRoots.push_back(BKTNode(localindices[j])); + } + } + else { // clustering the data into BKTKmeansK clusters + int numClusters = KmeansClustering(index, localindices, item.first, item.last, args); + if (numClusters <= 1) { + int end = min(item.last + 1, (int)localindices.size()); + std::sort(localindices.begin() + item.first, localindices.begin() + end); + m_pTreeRoots[item.index].centerid = localindices[item.first]; + m_pTreeRoots[item.index].childStart = -m_pTreeRoots[item.index].childStart; + for (int j = item.first + 1; j < end; j++) { + m_pTreeRoots.push_back(BKTNode(localindices[j])); + m_pSampleCenterMap[localindices[j]] = m_pTreeRoots[item.index].centerid; + } + m_pSampleCenterMap[-1 - m_pTreeRoots[item.index].centerid] = item.index; + } + else { + for (int k = 0; k < m_iBKTKmeansK; k++) { + if (args.counts[k] == 0) continue; + m_pTreeRoots.push_back(BKTNode(localindices[item.first + args.counts[k] - 1])); + if (args.counts[k] > 1) ss.push(BKTStackItem(newBKTid++, item.first, item.first + args.counts[k] - 1)); + item.first += args.counts[k]; + } + } + } + m_pTreeRoots[item.index].childEnd = (int)m_pTreeRoots.size(); + } + std::cout << i + 1 << " BKTree built, " << m_pTreeRoots.size() - m_pTreeStart[i] << " " << localindices.size() << std::endl; + } + } + + bool SaveTrees(void **pKDTMemFile, int64_t &len) const + { + int treeNodeSize = (int)m_pTreeRoots.size(); + + size_t size = sizeof(int) + + sizeof(int) * m_iTreeNumber + + sizeof(int) + + sizeof(BKTNode) * treeNodeSize; + char *mem = (char*)malloc(size); + if (mem == NULL) return false; + + auto ptr = mem; + *(int*)ptr = m_iTreeNumber; + ptr += sizeof(int); + + memcpy(ptr, m_pTreeStart.data(), sizeof(int) * m_iTreeNumber); + ptr += sizeof(int) * m_iTreeNumber; + + *(int*)ptr = treeNodeSize; + ptr += sizeof(int); + + memcpy(ptr, m_pTreeRoots.data(), sizeof(BKTNode) * treeNodeSize); + *pKDTMemFile = mem; + len = size; + + return true; + } + + bool SaveTrees(std::string sTreeFileName) const + { + std::cout << "Save BKT to " << sTreeFileName << std::endl; + FILE *fp = fopen(sTreeFileName.c_str(), "wb"); + if (fp == NULL) return false; + + fwrite(&m_iTreeNumber, sizeof(int), 1, fp); + fwrite(m_pTreeStart.data(), sizeof(int), m_iTreeNumber, fp); + int treeNodeSize = (int)m_pTreeRoots.size(); + fwrite(&treeNodeSize, sizeof(int), 1, fp); + fwrite(m_pTreeRoots.data(), sizeof(BKTNode), treeNodeSize, fp); + fclose(fp); + std::cout << "Save BKT (" << m_iTreeNumber << "," << treeNodeSize << ") Finish!" << std::endl; + return true; + } + + bool LoadTrees(char* pBKTMemFile) + { + m_iTreeNumber = *((int*)pBKTMemFile); + pBKTMemFile += sizeof(int); + m_pTreeStart.resize(m_iTreeNumber); + memcpy(m_pTreeStart.data(), pBKTMemFile, sizeof(int) * m_iTreeNumber); + pBKTMemFile += sizeof(int)*m_iTreeNumber; + + int treeNodeSize = *((int*)pBKTMemFile); + pBKTMemFile += sizeof(int); + m_pTreeRoots.resize(treeNodeSize); + memcpy(m_pTreeRoots.data(), pBKTMemFile, sizeof(BKTNode) * treeNodeSize); + return true; + } + + bool LoadTrees(std::string sTreeFileName) + { + std::cout << "Load BKT From " << sTreeFileName << std::endl; + FILE *fp = fopen(sTreeFileName.c_str(), "rb"); + if (fp == NULL) return false; + + fread(&m_iTreeNumber, sizeof(int), 1, fp); + m_pTreeStart.resize(m_iTreeNumber); + fread(m_pTreeStart.data(), sizeof(int), m_iTreeNumber, fp); + + int treeNodeSize; + fread(&treeNodeSize, sizeof(int), 1, fp); + m_pTreeRoots.resize(treeNodeSize); + fread(m_pTreeRoots.data(), sizeof(BKTNode), treeNodeSize, fp); + fclose(fp); + std::cout << "Load BKT (" << m_iTreeNumber << "," << treeNodeSize << ") Finish!" << std::endl; + return true; + } + + template + void InitSearchTrees(const VectorIndex* p_index, const COMMON::QueryResultSet &p_query, COMMON::WorkSpace &p_space) const + { + for (char i = 0; i < m_iTreeNumber; i++) { + const BKTNode& node = m_pTreeRoots[m_pTreeStart[i]]; + if (node.childStart < 0) { + p_space.m_SPTQueue.insert(COMMON::HeapCell(m_pTreeStart[i], p_index->ComputeDistance((const void*)p_query.GetTarget(), p_index->GetSample(node.centerid)))); + } + else { + for (int begin = node.childStart; begin < node.childEnd; begin++) { + int index = m_pTreeRoots[begin].centerid; + p_space.m_SPTQueue.insert(COMMON::HeapCell(begin, p_index->ComputeDistance((const void*)p_query.GetTarget(), p_index->GetSample(index)))); + } + } + } + } + + template + void SearchTrees(const VectorIndex* p_index, const COMMON::QueryResultSet &p_query, + COMMON::WorkSpace &p_space, const int p_limits) const + { + do + { + COMMON::HeapCell bcell = p_space.m_SPTQueue.pop(); + const BKTNode& tnode = m_pTreeRoots[bcell.node]; + if (tnode.childStart < 0) { + if (!p_space.CheckAndSet(tnode.centerid)) { + p_space.m_iNumberOfCheckedLeaves++; + p_space.m_NGQueue.insert(COMMON::HeapCell(tnode.centerid, bcell.distance)); + } + if (p_space.m_iNumberOfCheckedLeaves >= p_limits) break; + } + else { + if (!p_space.CheckAndSet(tnode.centerid)) { + p_space.m_NGQueue.insert(COMMON::HeapCell(tnode.centerid, bcell.distance)); + } + for (int begin = tnode.childStart; begin < tnode.childEnd; begin++) { + int index = m_pTreeRoots[begin].centerid; + p_space.m_SPTQueue.insert(COMMON::HeapCell(begin, p_index->ComputeDistance((const void*)p_query.GetTarget(), p_index->GetSample(index)))); + } + } + } while (!p_space.m_SPTQueue.empty()); + } + + private: + + template + float KmeansAssign(VectorIndex* p_index, + std::vector& indices, + const int first, const int last, KmeansArgs& args, const bool updateCenters) const { + float currDist = 0; + int threads = omp_get_num_threads(); + float lambda = (updateCenters) ? COMMON::Utils::GetBase() * COMMON::Utils::GetBase() / (100.0f * (last - first)) : 0.0f; + int subsize = (last - first - 1) / threads + 1; + +#pragma omp parallel for + for (int tid = 0; tid < threads; tid++) + { + int istart = first + tid * subsize; + int iend = min(first + (tid + 1) * subsize, last); + int *inewCounts = args.newCounts + tid * m_iBKTKmeansK; + float *inewCenters = args.newCenters + tid * m_iBKTKmeansK * p_index->GetFeatureDim(); + int * iclusterIdx = args.clusterIdx + tid * m_iBKTKmeansK; + float * iclusterDist = args.clusterDist + tid * m_iBKTKmeansK; + float idist = 0; + for (int i = istart; i < iend; i++) { + int clusterid = 0; + float smallestDist = MaxDist; + for (int k = 0; k < m_iBKTKmeansK; k++) { + float dist = p_index->ComputeDistance(p_index->GetSample(indices[i]), (const void*)(args.centers + k*p_index->GetFeatureDim())) + lambda*args.counts[k]; + if (dist > -MaxDist && dist < smallestDist) { + clusterid = k; smallestDist = dist; + } + } + args.label[i] = clusterid; + inewCounts[clusterid]++; + idist += smallestDist; + if (updateCenters) { + const T* v = (const T*)p_index->GetSample(indices[i]); + float* center = inewCenters + clusterid*p_index->GetFeatureDim(); + for (int j = 0; j < p_index->GetFeatureDim(); j++) center[j] += v[j]; + if (smallestDist > iclusterDist[clusterid]) { + iclusterDist[clusterid] = smallestDist; + iclusterIdx[clusterid] = indices[i]; + } + } + else { + if (smallestDist <= iclusterDist[clusterid]) { + iclusterDist[clusterid] = smallestDist; + iclusterIdx[clusterid] = indices[i]; + } + } + } + COMMON::Utils::atomic_float_add(&currDist, idist); + } + + for (int i = 1; i < threads; i++) { + for (int k = 0; k < m_iBKTKmeansK; k++) + args.newCounts[k] += args.newCounts[i*m_iBKTKmeansK + k]; + } + + if (updateCenters) { + for (int i = 1; i < threads; i++) { + float* currCenter = args.newCenters + i*m_iBKTKmeansK*p_index->GetFeatureDim(); + for (int j = 0; j < m_iBKTKmeansK * p_index->GetFeatureDim(); j++) args.newCenters[j] += currCenter[j]; + } + + int maxcluster = 0; + for (int k = 1; k < m_iBKTKmeansK; k++) if (args.newCounts[maxcluster] < args.newCounts[k]) maxcluster = k; + + int maxid = maxcluster; + for (int tid = 1; tid < threads; tid++) { + if (args.clusterDist[maxid] < args.clusterDist[tid * m_iBKTKmeansK + maxcluster]) maxid = tid * m_iBKTKmeansK + maxcluster; + } + if (args.clusterIdx[maxid] < 0 || args.clusterIdx[maxid] >= p_index->GetNumSamples()) + std::cout << "first:" << first << " last:" << last << " maxcluster:" << maxcluster << "(" << args.newCounts[maxcluster] << ") Error maxid:" << maxid << " dist:" << args.clusterDist[maxid] << std::endl; + maxid = args.clusterIdx[maxid]; + + for (int k = 0; k < m_iBKTKmeansK; k++) { + T* TCenter = args.newTCenters + k * p_index->GetFeatureDim(); + if (args.newCounts[k] == 0) { + //int nextid = Utils::rand_int(last, first); + //while (args.label[nextid] != maxcluster) nextid = Utils::rand_int(last, first); + int nextid = maxid; + std::memcpy(TCenter, p_index->GetSample(nextid), sizeof(T)*p_index->GetFeatureDim()); + } + else { + float* currCenters = args.newCenters + k * p_index->GetFeatureDim(); + for (int j = 0; j < p_index->GetFeatureDim(); j++) currCenters[j] /= args.newCounts[k]; + + if (p_index->GetDistCalcMethod() == DistCalcMethod::Cosine) { + COMMON::Utils::Normalize(currCenters, p_index->GetFeatureDim(), COMMON::Utils::GetBase()); + } + for (int j = 0; j < p_index->GetFeatureDim(); j++) TCenter[j] = (T)(currCenters[j]); + } + } + } + else { + for (int i = 1; i < threads; i++) { + for (int k = 0; k < m_iBKTKmeansK; k++) { + if (args.clusterIdx[i*m_iBKTKmeansK + k] != -1 && args.clusterDist[i*m_iBKTKmeansK + k] <= args.clusterDist[k]) { + args.clusterDist[k] = args.clusterDist[i*m_iBKTKmeansK + k]; + args.clusterIdx[k] = args.clusterIdx[i*m_iBKTKmeansK + k]; + } + } + } + } + return currDist; + } + + template + int KmeansClustering(VectorIndex* p_index, + std::vector& indices, const int first, const int last, KmeansArgs& args) const { + int iterLimit = 100; + + int batchEnd = min(first + m_iSamples, last); + float currDiff, currDist, minClusterDist = MaxDist; + for (int numKmeans = 0; numKmeans < 3; numKmeans++) { + for (int k = 0; k < m_iBKTKmeansK; k++) { + int randid = COMMON::Utils::rand_int(last, first); + std::memcpy(args.centers + k*p_index->GetFeatureDim(), p_index->GetSample(indices[randid]), sizeof(T)*p_index->GetFeatureDim()); + } + args.ClearCounts(); + currDist = KmeansAssign(p_index, indices, first, batchEnd, args, false); + if (currDist < minClusterDist) { + minClusterDist = currDist; + memcpy(args.newTCenters, args.centers, sizeof(T)*m_iBKTKmeansK*p_index->GetFeatureDim()); + memcpy(args.counts, args.newCounts, sizeof(int) * m_iBKTKmeansK); + } + } + + minClusterDist = MaxDist; + int noImprovement = 0; + for (int iter = 0; iter < iterLimit; iter++) { + std::memcpy(args.centers, args.newTCenters, sizeof(T)*m_iBKTKmeansK*p_index->GetFeatureDim()); + std::random_shuffle(indices.begin() + first, indices.begin() + last); + + args.ClearCenters(); + args.ClearCounts(); + args.ClearDists(-MaxDist); + currDist = KmeansAssign(p_index, indices, first, batchEnd, args, true); + memcpy(args.counts, args.newCounts, sizeof(int)*m_iBKTKmeansK); + + currDiff = 0; + for (int k = 0; k < m_iBKTKmeansK; k++) { + currDiff += p_index->ComputeDistance((const void*)(args.centers + k*p_index->GetFeatureDim()), (const void*)(args.newTCenters + k*p_index->GetFeatureDim())); + } + + if (currDist < minClusterDist) { + noImprovement = 0; + minClusterDist = currDist; + } + else { + noImprovement++; + } + if (currDiff < 1e-3 || noImprovement >= 5) break; + } + + args.ClearCounts(); + args.ClearDists(MaxDist); + currDist = KmeansAssign(p_index, indices, first, last, args, false); + memcpy(args.counts, args.newCounts, sizeof(int)*m_iBKTKmeansK); + + int numClusters = 0; + for (int i = 0; i < m_iBKTKmeansK; i++) if (args.counts[i] > 0) numClusters++; + + if (numClusters <= 1) { + //if (last - first > 1) std::cout << "large cluster:" << last - first << " dist:" << currDist << std::endl; + return numClusters; + } + args.Shuffle(indices, first, last); + return numClusters; + } + + private: + std::vector m_pTreeStart; + std::vector m_pTreeRoots; + std::unordered_map m_pSampleCenterMap; + + public: + int m_iTreeNumber, m_iBKTKmeansK, m_iBKTLeafSize, m_iSamples; + }; + } +} +#endif diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common/CommonUtils.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common/CommonUtils.h new file mode 100644 index 0000000000..ca5ed83fca --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common/CommonUtils.h @@ -0,0 +1,178 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_COMMON_COMMONUTILS_H_ +#define _SPTAG_COMMON_COMMONUTILS_H_ + +#include "../Common.h" + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#define PREFETCH + +#ifndef _MSC_VER +#include +#include +#include +#include + +#define InterlockedCompareExchange(a,b,c) __sync_val_compare_and_swap(a, c, b) +#define Sleep(a) usleep(a * 1000) +#define strtok_s(a, b, c) strtok_r(a, b, c) +#endif + +namespace SPTAG +{ + namespace COMMON + { + class Utils { + public: + static int rand_int(int high = RAND_MAX, int low = 0) // Generates a random int value. + { + return low + (int)(float(high - low)*(std::rand() / (RAND_MAX + 1.0))); + } + + static inline float atomic_float_add(volatile float* ptr, const float operand) + { + union { + volatile long iOld; + float fOld; + }; + union { + long iNew; + float fNew; + }; + + while (true) { + iOld = *(volatile long *)ptr; + fNew = fOld + operand; + if (InterlockedCompareExchange((long *)ptr, iNew, iOld) == iOld) { + return fNew; + } + } + } + + static double GetVector(char* cstr, const char* sep, std::vector& arr, int& NumDim) { + char* current; + char* context = NULL; + + int i = 0; + double sum = 0; + arr.clear(); + current = strtok_s(cstr, sep, &context); + while (current != NULL && (i < NumDim || NumDim < 0)) { + try { + float val = (float)atof(current); + arr.push_back(val); + } + catch (std::exception e) { + std::cout << "Exception:" << e.what() << std::endl; + return -2; + } + + sum += arr[i] * arr[i]; + current = strtok_s(NULL, sep, &context); + i++; + } + + if (NumDim < 0) NumDim = i; + if (i < NumDim) return -2; + return std::sqrt(sum); + } + + template + static void Normalize(T* arr, int col, int base) { + double vecLen = 0; + for (int j = 0; j < col; j++) { + double val = arr[j]; + vecLen += val * val; + } + vecLen = std::sqrt(vecLen); + if (vecLen < 1e-6) { + T val = (T)(1.0 / std::sqrt((double)col) * base); + for (int j = 0; j < col; j++) arr[j] = val; + } + else { + for (int j = 0; j < col; j++) arr[j] = (T)(arr[j] / vecLen * base); + } + } + + static size_t ProcessLine(std::string& currentLine, std::vector& arr, int& D, int base, DistCalcMethod distCalcMethod) { + size_t index; + double vecLen; + if (currentLine.length() == 0 || (index = currentLine.find_last_of("\t")) == std::string::npos || (vecLen = GetVector(const_cast(currentLine.c_str() + index + 1), "|", arr, D)) < -1) { + std::cout << "Parse vector error: " + currentLine << std::endl; + //throw MyException("Error in parsing data " + currentLine); + return -1; + } + if (distCalcMethod == DistCalcMethod::Cosine) { + Normalize(arr.data(), D, base); + } + return index; + } + + template + static void PrepareQuerys(std::ifstream& inStream, std::vector& qString, std::vector>& Query, int& NumQuery, int& NumDim, DistCalcMethod distCalcMethod, int base) { + std::string currentLine; + std::vector arr; + int i = 0; + size_t index; + while ((NumQuery < 0 || i < NumQuery) && !inStream.eof()) { + std::getline(inStream, currentLine); + if (currentLine.length() <= 1 || (index = ProcessLine(currentLine, arr, NumDim, base, distCalcMethod)) < 0) { + continue; + } + qString.push_back(currentLine.substr(0, index)); + if (Query.size() < i + 1) Query.push_back(std::vector(NumDim, 0)); + + for (int j = 0; j < NumDim; j++) Query[i][j] = (T)arr[j]; + i++; + } + NumQuery = i; + std::cout << "Load data: (" << NumQuery << ", " << NumDim << ")" << std::endl; + } + + template + static inline int GetBase() { + if (GetEnumValueType() != VectorValueType::Float) { + return (int)(std::numeric_limits::max)(); + } + return 1; + } + + static inline void AddNeighbor(int idx, float dist, int *neighbors, float *dists, int size) + { + size--; + if (dist < dists[size] || (dist == dists[size] && idx < neighbors[size])) + { + int nb; + for (nb = 0; nb <= size && neighbors[nb] != idx; nb++); + + if (nb > size) + { + nb = size; + while (nb > 0 && (dist < dists[nb - 1] || (dist == dists[nb - 1] && idx < neighbors[nb - 1]))) + { + dists[nb] = dists[nb - 1]; + neighbors[nb] = neighbors[nb - 1]; + nb--; + } + dists[nb] = dist; + neighbors[nb] = idx; + } + } + } + }; + } +} + +#endif // _SPTAG_COMMON_COMMONUTILS_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common/DataUtils.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common/DataUtils.h new file mode 100644 index 0000000000..affc4687da --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common/DataUtils.h @@ -0,0 +1,290 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_COMMON_DATAUTILS_H_ +#define _SPTAG_COMMON_DATAUTILS_H_ + +#include +#include +#include "CommonUtils.h" +#include "../../Helper/CommonHelper.h" + +namespace SPTAG +{ + namespace COMMON + { + const int bufsize = 1024 * 1024 * 1024; + + class DataUtils { + public: + template + static void ProcessTSVData(int id, int threadbase, std::uint64_t blocksize, + std::string filename, std::string outfile, std::string outmetafile, std::string outmetaindexfile, + std::atomic_int& numSamples, int& D, DistCalcMethod distCalcMethod) { + std::ifstream inputStream(filename); + if (!inputStream.is_open()) { + std::cerr << "unable to open file " + filename << std::endl; + throw MyException("unable to open file " + filename); + exit(1); + } + std::ofstream outputStream, metaStream_out, metaStream_index; + outputStream.open(outfile + std::to_string(id + threadbase), std::ofstream::binary); + metaStream_out.open(outmetafile + std::to_string(id + threadbase), std::ofstream::binary); + metaStream_index.open(outmetaindexfile + std::to_string(id + threadbase), std::ofstream::binary); + if (!outputStream.is_open() || !metaStream_out.is_open() || !metaStream_index.is_open()) { + std::cerr << "unable to open output file " << outfile << " " << outmetafile << " " << outmetaindexfile << std::endl; + throw MyException("unable to open output files"); + exit(1); + } + + std::vector arr; + std::vector sample; + + int base = 1; + if (distCalcMethod == DistCalcMethod::Cosine) { + base = Utils::GetBase(); + } + std::uint64_t writepos = 0; + int sampleSize = 0; + std::uint64_t totalread = 0; + std::streamoff startpos = id * blocksize; + +#ifndef _MSC_VER + int enter_size = 1; +#else + int enter_size = 1; +#endif + std::string currentLine; + size_t index; + inputStream.seekg(startpos, std::ifstream::beg); + if (id != 0) { + std::getline(inputStream, currentLine); + totalread += currentLine.length() + enter_size; + } + std::cout << "Begin thread " << id << " begin at:" << (startpos + totalread) << std::endl; + while (!inputStream.eof() && totalread <= blocksize) { + std::getline(inputStream, currentLine); + if (currentLine.length() <= enter_size || (index = Utils::ProcessLine(currentLine, arr, D, base, distCalcMethod)) < 0) { + totalread += currentLine.length() + enter_size; + continue; + } + sample.resize(D); + for (int j = 0; j < D; j++) sample[j] = (T)arr[j]; + + outputStream.write((char *)(sample.data()), sizeof(T)*D); + metaStream_index.write((char *)&writepos, sizeof(std::uint64_t)); + metaStream_out.write(currentLine.c_str(), index); + + writepos += index; + sampleSize += 1; + totalread += currentLine.length() + enter_size; + } + metaStream_index.write((char *)&writepos, sizeof(std::uint64_t)); + metaStream_index.write((char *)&sampleSize, sizeof(int)); + inputStream.close(); + outputStream.close(); + metaStream_out.close(); + metaStream_index.close(); + + numSamples.fetch_add(sampleSize); + + std::cout << "Finish Thread[" << id << ", " << sampleSize << "] at:" << (startpos + totalread) << std::endl; + } + + static void MergeData(int threadbase, std::string outfile, std::string outmetafile, std::string outmetaindexfile, + std::atomic_int& numSamples, int D) { + std::ifstream inputStream; + std::ofstream outputStream; + char * buf = new char[bufsize]; + std::uint64_t * offsets; + int partSamples; + int metaSamples = 0; + std::uint64_t lastoff = 0; + + outputStream.open(outfile, std::ofstream::binary); + outputStream.write((char *)&numSamples, sizeof(int)); + outputStream.write((char *)&D, sizeof(int)); + for (int i = 0; i < threadbase; i++) { + std::string file = outfile + std::to_string(i); + inputStream.open(file, std::ifstream::binary); + while (!inputStream.eof()) { + inputStream.read(buf, bufsize); + outputStream.write(buf, inputStream.gcount()); + } + inputStream.close(); + remove(file.c_str()); + } + outputStream.close(); + + outputStream.open(outmetafile, std::ofstream::binary); + for (int i = 0; i < threadbase; i++) { + std::string file = outmetafile + std::to_string(i); + inputStream.open(file, std::ifstream::binary); + while (!inputStream.eof()) { + inputStream.read(buf, bufsize); + outputStream.write(buf, inputStream.gcount()); + } + inputStream.close(); + remove(file.c_str()); + } + outputStream.close(); + delete[] buf; + + outputStream.open(outmetaindexfile, std::ofstream::binary); + outputStream.write((char *)&numSamples, sizeof(int)); + for (int i = 0; i < threadbase; i++) { + std::string file = outmetaindexfile + std::to_string(i); + inputStream.open(file, std::ifstream::binary); + + inputStream.seekg(-((long long)sizeof(int)), inputStream.end); + inputStream.read((char *)&partSamples, sizeof(int)); + offsets = new std::uint64_t[partSamples + 1]; + + inputStream.seekg(0, inputStream.beg); + inputStream.read((char *)offsets, sizeof(std::uint64_t)*(partSamples + 1)); + inputStream.close(); + remove(file.c_str()); + + for (int j = 0; j < partSamples + 1; j++) + offsets[j] += lastoff; + outputStream.write((char *)offsets, sizeof(std::uint64_t)*partSamples); + + lastoff = offsets[partSamples]; + metaSamples += partSamples; + delete[] offsets; + } + outputStream.write((char *)&lastoff, sizeof(std::uint64_t)); + outputStream.close(); + + std::cout << "numSamples:" << numSamples << " metaSamples:" << metaSamples << " D:" << D << std::endl; + } + + static bool MergeIndex(const std::string& p_vectorfile1, const std::string& p_metafile1, const std::string& p_metaindexfile1, + const std::string& p_vectorfile2, const std::string& p_metafile2, const std::string& p_metaindexfile2) { + std::ifstream inputStream1, inputStream2; + std::ofstream outputStream; + char * buf = new char[bufsize]; + int R1, R2, C1, C2; + +#define MergeVector(inputStream, vectorFile, R, C) \ + inputStream.open(vectorFile, std::ifstream::binary); \ + if (!inputStream.is_open()) { \ + std::cout << "Cannot open vector file: " << vectorFile <<"!" << std::endl; \ + return false; \ + } \ + inputStream.read((char *)&(R), sizeof(int)); \ + inputStream.read((char *)&(C), sizeof(int)); \ + + MergeVector(inputStream1, p_vectorfile1, R1, C1) + MergeVector(inputStream2, p_vectorfile2, R2, C2) +#undef MergeVector + if (C1 != C2) { + inputStream1.close(); inputStream2.close(); + std::cout << "Vector dimensions are not the same!" << std::endl; + return false; + } + R1 += R2; + outputStream.open(p_vectorfile1 + "_tmp", std::ofstream::binary); + outputStream.write((char *)&R1, sizeof(int)); + outputStream.write((char *)&C1, sizeof(int)); + while (!inputStream1.eof()) { + inputStream1.read(buf, bufsize); + outputStream.write(buf, inputStream1.gcount()); + } + while (!inputStream2.eof()) { + inputStream2.read(buf, bufsize); + outputStream.write(buf, inputStream2.gcount()); + } + inputStream1.close(); inputStream2.close(); + outputStream.close(); + + if (p_metafile1 != "" && p_metafile2 != "") { + outputStream.open(p_metafile1 + "_tmp", std::ofstream::binary); +#define MergeMeta(inputStream, metaFile) \ + inputStream.open(metaFile, std::ifstream::binary); \ + if (!inputStream.is_open()) { \ + std::cout << "Cannot open meta file: " << metaFile << "!" << std::endl; \ + return false; \ + } \ + while (!inputStream.eof()) { \ + inputStream.read(buf, bufsize); \ + outputStream.write(buf, inputStream.gcount()); \ + } \ + inputStream.close(); \ + + MergeMeta(inputStream1, p_metafile1) + MergeMeta(inputStream2, p_metafile2) +#undef MergeMeta + outputStream.close(); + delete[] buf; + + + std::uint64_t * offsets; + int partSamples; + std::uint64_t lastoff = 0; + outputStream.open(p_metaindexfile1 + "_tmp", std::ofstream::binary); + outputStream.write((char *)&R1, sizeof(int)); +#define MergeMetaIndex(inputStream, metaIndexFile) \ + inputStream.open(metaIndexFile, std::ifstream::binary); \ + if (!inputStream.is_open()) { \ + std::cout << "Cannot open meta index file: " << metaIndexFile << "!" << std::endl; \ + return false; \ + } \ + inputStream.read((char *)&partSamples, sizeof(int)); \ + offsets = new std::uint64_t[partSamples + 1]; \ + inputStream.read((char *)offsets, sizeof(std::uint64_t)*(partSamples + 1)); \ + inputStream.close(); \ + for (int j = 0; j < partSamples + 1; j++) offsets[j] += lastoff; \ + outputStream.write((char *)offsets, sizeof(std::uint64_t)*partSamples); \ + lastoff = offsets[partSamples]; \ + delete[] offsets; \ + + MergeMetaIndex(inputStream1, p_metaindexfile1) + MergeMetaIndex(inputStream2, p_metaindexfile2) +#undef MergeMetaIndex + outputStream.write((char *)&lastoff, sizeof(std::uint64_t)); + outputStream.close(); + + rename((p_metafile1 + "_tmp").c_str(), p_metafile1.c_str()); + rename((p_metaindexfile1 + "_tmp").c_str(), p_metaindexfile1.c_str()); + } + rename((p_vectorfile1 + "_tmp").c_str(), p_vectorfile1.c_str()); + + std::cout << "Merged -> numSamples:" << R1 << " D:" << C1 << std::endl; + return true; + } + + template + static void ParseData(std::string filenames, std::string outfile, std::string outmetafile, std::string outmetaindexfile, + int threadnum, DistCalcMethod distCalcMethod) { + omp_set_num_threads(threadnum); + + std::atomic_int numSamples = { 0 }; + int D = -1; + + int threadbase = 0; + std::vector inputFileNames = Helper::StrUtils::SplitString(filenames, ","); + for (std::string inputFileName : inputFileNames) + { +#ifndef _MSC_VER + struct stat stat_buf; + stat(inputFileName.c_str(), &stat_buf); +#else + struct _stat64 stat_buf; + int res = _stat64(inputFileName.c_str(), &stat_buf); +#endif + std::uint64_t blocksize = (stat_buf.st_size + threadnum - 1) / threadnum; + +#pragma omp parallel for + for (int i = 0; i < threadnum; i++) { + ProcessTSVData(i, threadbase, blocksize, inputFileName, outfile, outmetafile, outmetaindexfile, numSamples, D, distCalcMethod); + } + threadbase += threadnum; + } + MergeData(threadbase, outfile, outmetafile, outmetaindexfile, numSamples, D); + } + }; + } +} + +#endif // _SPTAG_COMMON_DATAUTILS_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common/Dataset.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common/Dataset.h new file mode 100644 index 0000000000..b47d521d81 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common/Dataset.h @@ -0,0 +1,216 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_COMMON_DATASET_H_ +#define _SPTAG_COMMON_DATASET_H_ + +#include + +#if defined(_MSC_VER) || defined(__INTEL_COMPILER) +#include +#else +#include +#endif // defined(__GNUC__) + +#define ALIGN 32 + +#define aligned_malloc(a, b) _mm_malloc(a, b) +#define aligned_free(a) _mm_free(a) + +#pragma warning(disable:4996) // 'fopen': This function or variable may be unsafe. Consider using fopen_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. + +namespace SPTAG +{ + namespace COMMON + { + // structure to save Data and Graph + template + class Dataset + { + private: + int rows; + int cols; + bool ownData = false; + T* data = nullptr; + std::vector dataIncremental; + + public: + Dataset(): rows(0), cols(1) {} + Dataset(int rows_, int cols_, T* data_ = nullptr, bool transferOnwership_ = true) + { + Initialize(rows_, cols_, data_, transferOnwership_); + } + ~Dataset() + { + if (ownData) aligned_free(data); + } + void Initialize(int rows_, int cols_, T* data_ = nullptr, bool transferOnwership_ = true) + { + rows = rows_; + cols = cols_; + data = data_; + if (data_ == nullptr || !transferOnwership_) + { + ownData = true; + data = (T*)aligned_malloc(sizeof(T) * rows * cols, ALIGN); + if (data_ != nullptr) memcpy(data, data_, rows * cols * sizeof(T)); + else std::memset(data, -1, rows * cols * sizeof(T)); + } + } + void SetR(int R_) + { + if (R_ >= rows) + dataIncremental.resize((R_ - rows) * cols); + else + { + rows = R_; + dataIncremental.clear(); + } + } + inline int R() const { return (int)(rows + dataIncremental.size() / cols); } + inline int C() const { return cols; } + T* operator[](int index) + { + if (index >= rows) { + return dataIncremental.data() + (size_t)(index - rows)*cols; + } + return data + (size_t)index*cols; + } + + const T* operator[](int index) const + { + if (index >= rows) { + return dataIncremental.data() + (size_t)(index - rows)*cols; + } + return data + (size_t)index*cols; + } + + void AddBatch(const T* pData, int num) + { + dataIncremental.insert(dataIncremental.end(), pData, pData + num*cols); + } + + void AddBatch(int num) + { + dataIncremental.insert(dataIncremental.end(), (size_t)num*cols, T(-1)); + } + + bool Save(std::string sDataPointsFileName) + { + std::cout << "Save Data To " << sDataPointsFileName << std::endl; + FILE * fp = fopen(sDataPointsFileName.c_str(), "wb"); + if (fp == NULL) return false; + + int CR = R(); + fwrite(&CR, sizeof(int), 1, fp); + fwrite(&cols, sizeof(int), 1, fp); + + T* ptr = data; + int toWrite = rows; + while (toWrite > 0) + { + size_t write = fwrite(ptr, sizeof(T) * cols, toWrite, fp); + ptr += write * cols; + toWrite -= (int)write; + } + ptr = dataIncremental.data(); + toWrite = CR - rows; + while (toWrite > 0) + { + size_t write = fwrite(ptr, sizeof(T) * cols, toWrite, fp); + ptr += write * cols; + toWrite -= (int)write; + } + fclose(fp); + + std::cout << "Save Data (" << CR << ", " << cols << ") Finish!" << std::endl; + return true; + } + + bool Save(void **pDataPointsMemFile, int64_t &len) + { + size_t size = sizeof(int) + sizeof(int) + sizeof(T) * R() *cols; + char *mem = (char*)malloc(size); + if (mem == NULL) return false; + + int CR = R(); + + auto header = (int*)mem; + header[0] = CR; + header[1] = cols; + auto body = &mem[8]; + + memcpy(body, data, sizeof(T) * cols * rows); + body += sizeof(T) * cols * rows; + memcpy(body, dataIncremental.data(), sizeof(T) * cols * (CR - rows)); + body += sizeof(T) * cols * (CR - rows); + + *pDataPointsMemFile = mem; + len = size; + + return true; + } + + bool Load(std::string sDataPointsFileName) + { + std::cout << "Load Data From " << sDataPointsFileName << std::endl; + FILE * fp = fopen(sDataPointsFileName.c_str(), "rb"); + if (fp == NULL) return false; + + int R, C; + fread(&R, sizeof(int), 1, fp); + fread(&C, sizeof(int), 1, fp); + + Initialize(R, C); + T* ptr = data; + while (R > 0) { + size_t read = fread(ptr, sizeof(T) * C, R, fp); + ptr += read * C; + R -= (int)read; + } + fclose(fp); + std::cout << "Load Data (" << rows << ", " << cols << ") Finish!" << std::endl; + return true; + } + + // Functions for loading models from memory mapped files + bool Load(char* pDataPointsMemFile) + { + int R, C; + R = *((int*)pDataPointsMemFile); + pDataPointsMemFile += sizeof(int); + + C = *((int*)pDataPointsMemFile); + pDataPointsMemFile += sizeof(int); + + Initialize(R, C, (T*)pDataPointsMemFile); + return true; + } + + bool Refine(const std::vector& indices, std::string sDataPointsFileName) + { + std::cout << "Save Refine Data To " << sDataPointsFileName << std::endl; + FILE * fp = fopen(sDataPointsFileName.c_str(), "wb"); + if (fp == NULL) return false; + + int R = (int)(indices.size()); + fwrite(&R, sizeof(int), 1, fp); + fwrite(&cols, sizeof(int), 1, fp); + + // write point one by one in case for cache miss + for (int i = 0; i < R; i++) { + if (indices[i] < rows) + fwrite(data + (size_t)indices[i] * cols, sizeof(T) * cols, 1, fp); + else + fwrite(dataIncremental.data() + (size_t)(indices[i] - rows) * cols, sizeof(T) * cols, 1, fp); + } + fclose(fp); + + std::cout << "Save Refine Data (" << R << ", " << cols << ") Finish!" << std::endl; + return true; + } + }; + } +} + +#endif // _SPTAG_COMMON_DATASET_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common/DistanceUtils.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common/DistanceUtils.h new file mode 100644 index 0000000000..828eead752 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common/DistanceUtils.h @@ -0,0 +1,610 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_COMMON_DISTANCEUTILS_H_ +#define _SPTAG_COMMON_DISTANCEUTILS_H_ + +#include +#include + +#include "CommonUtils.h" + +#define SSE + +#ifndef _MSC_VER +#define DIFF128 diff128 +#define DIFF256 diff256 +#else +#define DIFF128 diff128.m128_f32 +#define DIFF256 diff256.m256_f32 +#endif + +namespace SPTAG +{ + namespace COMMON + { + class DistanceUtils + { + public: + static inline __m128 _mm_mul_epi8(__m128i X, __m128i Y) + { + __m128i zero = _mm_setzero_si128(); + + __m128i sign_x = _mm_cmplt_epi8(X, zero); + __m128i sign_y = _mm_cmplt_epi8(Y, zero); + + __m128i xlo = _mm_unpacklo_epi8(X, sign_x); + __m128i xhi = _mm_unpackhi_epi8(X, sign_x); + __m128i ylo = _mm_unpacklo_epi8(Y, sign_y); + __m128i yhi = _mm_unpackhi_epi8(Y, sign_y); + + return _mm_cvtepi32_ps(_mm_add_epi32(_mm_madd_epi16(xlo, ylo), _mm_madd_epi16(xhi, yhi))); + } + + static inline __m128 _mm_sqdf_epi8(__m128i X, __m128i Y) + { + __m128i zero = _mm_setzero_si128(); + + __m128i sign_x = _mm_cmplt_epi8(X, zero); + __m128i sign_y = _mm_cmplt_epi8(Y, zero); + + __m128i xlo = _mm_unpacklo_epi8(X, sign_x); + __m128i xhi = _mm_unpackhi_epi8(X, sign_x); + __m128i ylo = _mm_unpacklo_epi8(Y, sign_y); + __m128i yhi = _mm_unpackhi_epi8(Y, sign_y); + + __m128i dlo = _mm_sub_epi16(xlo, ylo); + __m128i dhi = _mm_sub_epi16(xhi, yhi); + + return _mm_cvtepi32_ps(_mm_add_epi32(_mm_madd_epi16(dlo, dlo), _mm_madd_epi16(dhi, dhi))); + } + + static inline __m128 _mm_mul_epu8(__m128i X, __m128i Y) + { + __m128i zero = _mm_setzero_si128(); + + __m128i xlo = _mm_unpacklo_epi8(X, zero); + __m128i xhi = _mm_unpackhi_epi8(X, zero); + __m128i ylo = _mm_unpacklo_epi8(Y, zero); + __m128i yhi = _mm_unpackhi_epi8(Y, zero); + + return _mm_cvtepi32_ps(_mm_add_epi32(_mm_madd_epi16(xlo, ylo), _mm_madd_epi16(xhi, yhi))); + } + + static inline __m128 _mm_sqdf_epu8(__m128i X, __m128i Y) + { + __m128i zero = _mm_setzero_si128(); + + __m128i xlo = _mm_unpacklo_epi8(X, zero); + __m128i xhi = _mm_unpackhi_epi8(X, zero); + __m128i ylo = _mm_unpacklo_epi8(Y, zero); + __m128i yhi = _mm_unpackhi_epi8(Y, zero); + + __m128i dlo = _mm_sub_epi16(xlo, ylo); + __m128i dhi = _mm_sub_epi16(xhi, yhi); + + return _mm_cvtepi32_ps(_mm_add_epi32(_mm_madd_epi16(dlo, dlo), _mm_madd_epi16(dhi, dhi))); + } + + static inline __m128 _mm_mul_epi16(__m128i X, __m128i Y) + { + return _mm_cvtepi32_ps(_mm_madd_epi16(X, Y)); + } + + static inline __m128 _mm_sqdf_epi16(__m128i X, __m128i Y) + { + __m128i zero = _mm_setzero_si128(); + + __m128i sign_x = _mm_cmplt_epi16(X, zero); + __m128i sign_y = _mm_cmplt_epi16(Y, zero); + + __m128i xlo = _mm_unpacklo_epi16(X, sign_x); + __m128i xhi = _mm_unpackhi_epi16(X, sign_x); + __m128i ylo = _mm_unpacklo_epi16(Y, sign_y); + __m128i yhi = _mm_unpackhi_epi16(Y, sign_y); + + __m128 dlo = _mm_cvtepi32_ps(_mm_sub_epi32(xlo, ylo)); + __m128 dhi = _mm_cvtepi32_ps(_mm_sub_epi32(xhi, yhi)); + + return _mm_add_ps(_mm_mul_ps(dlo, dlo), _mm_mul_ps(dhi, dhi)); + } + static inline __m128 _mm_sqdf_ps(__m128 X, __m128 Y) + { + __m128 d = _mm_sub_ps(X, Y); + return _mm_mul_ps(d, d); + } +#if defined(AVX) + static inline __m256 _mm256_mul_epi8(__m256i X, __m256i Y) + { + __m256i zero = _mm256_setzero_si256(); + + __m256i sign_x = _mm256_cmpgt_epi8(zero, X); + __m256i sign_y = _mm256_cmpgt_epi8(zero, Y); + + __m256i xlo = _mm256_unpacklo_epi8(X, sign_x); + __m256i xhi = _mm256_unpackhi_epi8(X, sign_x); + __m256i ylo = _mm256_unpacklo_epi8(Y, sign_y); + __m256i yhi = _mm256_unpackhi_epi8(Y, sign_y); + + return _mm256_cvtepi32_ps(_mm256_add_epi32(_mm256_madd_epi16(xlo, ylo), _mm256_madd_epi16(xhi, yhi))); + } + static inline __m256 _mm256_sqdf_epi8(__m256i X, __m256i Y) + { + __m256i zero = _mm256_setzero_si256(); + + __m256i sign_x = _mm256_cmpgt_epi8(zero, X); + __m256i sign_y = _mm256_cmpgt_epi8(zero, Y); + + __m256i xlo = _mm256_unpacklo_epi8(X, sign_x); + __m256i xhi = _mm256_unpackhi_epi8(X, sign_x); + __m256i ylo = _mm256_unpacklo_epi8(Y, sign_y); + __m256i yhi = _mm256_unpackhi_epi8(Y, sign_y); + + __m256i dlo = _mm256_sub_epi16(xlo, ylo); + __m256i dhi = _mm256_sub_epi16(xhi, yhi); + + return _mm256_cvtepi32_ps(_mm256_add_epi32(_mm256_madd_epi16(dlo, dlo), _mm256_madd_epi16(dhi, dhi))); + } + static inline __m256 _mm256_mul_epu8(__m256i X, __m256i Y) + { + __m256i zero = _mm256_setzero_si256(); + + __m256i xlo = _mm256_unpacklo_epi8(X, zero); + __m256i xhi = _mm256_unpackhi_epi8(X, zero); + __m256i ylo = _mm256_unpacklo_epi8(Y, zero); + __m256i yhi = _mm256_unpackhi_epi8(Y, zero); + + return _mm256_cvtepi32_ps(_mm256_add_epi32(_mm256_madd_epi16(xlo, ylo), _mm256_madd_epi16(xhi, yhi))); + } + static inline __m256 _mm256_sqdf_epu8(__m256i X, __m256i Y) + { + __m256i zero = _mm256_setzero_si256(); + + __m256i xlo = _mm256_unpacklo_epi8(X, zero); + __m256i xhi = _mm256_unpackhi_epi8(X, zero); + __m256i ylo = _mm256_unpacklo_epi8(Y, zero); + __m256i yhi = _mm256_unpackhi_epi8(Y, zero); + + __m256i dlo = _mm256_sub_epi16(xlo, ylo); + __m256i dhi = _mm256_sub_epi16(xhi, yhi); + + return _mm256_cvtepi32_ps(_mm256_add_epi32(_mm256_madd_epi16(dlo, dlo), _mm256_madd_epi16(dhi, dhi))); + } + static inline __m256 _mm256_mul_epi16(__m256i X, __m256i Y) + { + return _mm256_cvtepi32_ps(_mm256_madd_epi16(X, Y)); + } + static inline __m256 _mm256_sqdf_epi16(__m256i X, __m256i Y) + { + __m256i zero = _mm256_setzero_si256(); + + __m256i sign_x = _mm256_cmpgt_epi16(zero, X); + __m256i sign_y = _mm256_cmpgt_epi16(zero, Y); + + __m256i xlo = _mm256_unpacklo_epi16(X, sign_x); + __m256i xhi = _mm256_unpackhi_epi16(X, sign_x); + __m256i ylo = _mm256_unpacklo_epi16(Y, sign_y); + __m256i yhi = _mm256_unpackhi_epi16(Y, sign_y); + + __m256 dlo = _mm256_cvtepi32_ps(_mm256_sub_epi32(xlo, ylo)); + __m256 dhi = _mm256_cvtepi32_ps(_mm256_sub_epi32(xhi, yhi)); + + return _mm256_add_ps(_mm256_mul_ps(dlo, dlo), _mm256_mul_ps(dhi, dhi)); + } + static inline __m256 _mm256_sqdf_ps(__m256 X, __m256 Y) + { + __m256 d = _mm256_sub_ps(X, Y); + return _mm256_mul_ps(d, d); + } +#endif +/* + template + static float ComputeL2Distance(const T *pX, const T *pY, int length) + { + float diff = 0; + const T* pEnd1 = pX + length; + while (pX < pEnd1) { + float c1 = ((float)(*pX++) - (float)(*pY++)); diff += c1 * c1; + } + return diff; + } +*/ +#define REPEAT(type, ctype, delta, load, exec, acc, result) \ + { \ + type c1 = load((ctype *)(pX)); \ + type c2 = load((ctype *)(pY)); \ + pX += delta; pY += delta; \ + result = acc(result, exec(c1, c2)); \ + } \ + + static float ComputeL2Distance(const std::int8_t *pX, const std::int8_t *pY, int length) + { + const std::int8_t* pEnd32 = pX + ((length >> 5) << 5); + const std::int8_t* pEnd16 = pX + ((length >> 4) << 4); + const std::int8_t* pEnd4 = pX + ((length >> 2) << 2); + const std::int8_t* pEnd1 = pX + length; +#if defined(SSE) + __m128 diff128 = _mm_setzero_ps(); + while (pX < pEnd32) { + REPEAT(__m128i, __m128i, 16, _mm_loadu_si128, _mm_sqdf_epi8, _mm_add_ps, diff128) + REPEAT(__m128i, __m128i, 16, _mm_loadu_si128, _mm_sqdf_epi8, _mm_add_ps, diff128) + } + while (pX < pEnd16) { + REPEAT(__m128i, __m128i, 16, _mm_loadu_si128, _mm_sqdf_epi8, _mm_add_ps, diff128) + } + float diff = DIFF128[0] + DIFF128[1] + DIFF128[2] + DIFF128[3]; +#elif defined(AVX) + __m256 diff256 = _mm256_setzero_ps(); + while (pX < pEnd32) { + REPEAT(__m256i, __m256i, 32, _mm256_loadu_si256, _mm256_sqdf_epi8, _mm256_add_ps, diff256) + } + __m128 diff128 = _mm_add_ps(_mm256_castps256_ps128(diff256), _mm256_extractf128_ps(diff256, 1)); + while (pX < pEnd16) { + REPEAT(__m128i, __m128i, 16, _mm_loadu_si128, _mm_sqdf_epi8, _mm_add_ps, diff128) + } + float diff = DIFF128[0] + DIFF128[1] + DIFF128[2] + DIFF128[3]; +#else + float diff = 0; +#endif + while (pX < pEnd4) { + float c1 = ((float)(*pX++) - (float)(*pY++)); diff += c1 * c1; + c1 = ((float)(*pX++) - (float)(*pY++)); diff += c1 * c1; + c1 = ((float)(*pX++) - (float)(*pY++)); diff += c1 * c1; + c1 = ((float)(*pX++) - (float)(*pY++)); diff += c1 * c1; + } + while (pX < pEnd1) { + float c1 = ((float)(*pX++) - (float)(*pY++)); diff += c1 * c1; + } + return diff; + } + + static float ComputeL2Distance(const std::uint8_t *pX, const std::uint8_t *pY, int length) + { + const std::uint8_t* pEnd32 = pX + ((length >> 5) << 5); + const std::uint8_t* pEnd16 = pX + ((length >> 4) << 4); + const std::uint8_t* pEnd4 = pX + ((length >> 2) << 2); + const std::uint8_t* pEnd1 = pX + length; +#if defined(SSE) + __m128 diff128 = _mm_setzero_ps(); + while (pX < pEnd32) { + REPEAT(__m128i, __m128i, 16, _mm_loadu_si128, _mm_sqdf_epu8, _mm_add_ps, diff128) + REPEAT(__m128i, __m128i, 16, _mm_loadu_si128, _mm_sqdf_epu8, _mm_add_ps, diff128) + } + while (pX < pEnd16) { + REPEAT(__m128i, __m128i, 16, _mm_loadu_si128, _mm_sqdf_epu8, _mm_add_ps, diff128) + } + float diff = DIFF128[0] + DIFF128[1] + DIFF128[2] + DIFF128[3]; +#elif defined(AVX) + __m256 diff256 = _mm256_setzero_ps(); + while (pX < pEnd32) { + REPEAT(__m256i, __m256i, 32, _mm256_loadu_si256, _mm256_sqdf_epu8, _mm256_add_ps, diff256) + } + __m128 diff128 = _mm_add_ps(_mm256_castps256_ps128(diff256), _mm256_extractf128_ps(diff256, 1)); + while (pX < pEnd16) { + REPEAT(__m128i, __m128i, 16, _mm_loadu_si128, _mm_sqdf_epu8, _mm_add_ps, diff128) + } + float diff = DIFF128[0] + DIFF128[1] + DIFF128[2] + DIFF128[3]; +#else + float diff = 0; +#endif + while (pX < pEnd4) { + float c1 = ((float)(*pX++) - (float)(*pY++)); diff += c1 * c1; + c1 = ((float)(*pX++) - (float)(*pY++)); diff += c1 * c1; + c1 = ((float)(*pX++) - (float)(*pY++)); diff += c1 * c1; + c1 = ((float)(*pX++) - (float)(*pY++)); diff += c1 * c1; + } + while (pX < pEnd1) { + float c1 = ((float)(*pX++) - (float)(*pY++)); diff += c1 * c1; + } + return diff; + } + + static float ComputeL2Distance(const std::int16_t *pX, const std::int16_t *pY, int length) + { + const std::int16_t* pEnd16 = pX + ((length >> 4) << 4); + const std::int16_t* pEnd8 = pX + ((length >> 3) << 3); + const std::int16_t* pEnd4 = pX + ((length >> 2) << 2); + const std::int16_t* pEnd1 = pX + length; +#if defined(SSE) + __m128 diff128 = _mm_setzero_ps(); + while (pX < pEnd16) { + REPEAT(__m128i, __m128i, 8, _mm_loadu_si128, _mm_sqdf_epi16, _mm_add_ps, diff128) + REPEAT(__m128i, __m128i, 8, _mm_loadu_si128, _mm_sqdf_epi16, _mm_add_ps, diff128) + } + while (pX < pEnd8) { + REPEAT(__m128i, __m128i, 8, _mm_loadu_si128, _mm_sqdf_epi16, _mm_add_ps, diff128) + } + float diff = DIFF128[0] + DIFF128[1] + DIFF128[2] + DIFF128[3]; +#elif defined(AVX) + __m256 diff256 = _mm256_setzero_ps(); + while (pX < pEnd16) { + REPEAT(__m256i, __m256i, 16, _mm256_loadu_si256, _mm256_sqdf_epi16, _mm256_add_ps, diff256) + } + __m128 diff128 = _mm_add_ps(_mm256_castps256_ps128(diff256), _mm256_extractf128_ps(diff256, 1)); + while (pX < pEnd8) { + REPEAT(__m128i, __m128i, 8, _mm_loadu_si128, _mm_sqdf_epi16, _mm_add_ps, diff128) + } + float diff = DIFF128[0] + DIFF128[1] + DIFF128[2] + DIFF128[3]; +#else + float diff = 0; +#endif + while (pX < pEnd4) { + float c1 = ((float)(*pX++) - (float)(*pY++)); diff += c1 * c1; + c1 = ((float)(*pX++) - (float)(*pY++)); diff += c1 * c1; + c1 = ((float)(*pX++) - (float)(*pY++)); diff += c1 * c1; + c1 = ((float)(*pX++) - (float)(*pY++)); diff += c1 * c1; + } + + while (pX < pEnd1) { + float c1 = ((float)(*pX++) - (float)(*pY++)); diff += c1 * c1; + } + return diff; + } + + static float ComputeL2Distance(const float *pX, const float *pY, int length) + { + const float* pEnd16 = pX + ((length >> 4) << 4); + const float* pEnd4 = pX + ((length >> 2) << 2); + const float* pEnd1 = pX + length; +#if defined(SSE) + __m128 diff128 = _mm_setzero_ps(); + while (pX < pEnd16) + { + REPEAT(__m128, const float, 4, _mm_loadu_ps, _mm_sqdf_ps, _mm_add_ps, diff128) + REPEAT(__m128, const float, 4, _mm_loadu_ps, _mm_sqdf_ps, _mm_add_ps, diff128) + REPEAT(__m128, const float, 4, _mm_loadu_ps, _mm_sqdf_ps, _mm_add_ps, diff128) + REPEAT(__m128, const float, 4, _mm_loadu_ps, _mm_sqdf_ps, _mm_add_ps, diff128) + } + while (pX < pEnd4) + { + REPEAT(__m128, const float, 4, _mm_loadu_ps, _mm_sqdf_ps, _mm_add_ps, diff128) + } + float diff = DIFF128[0] + DIFF128[1] + DIFF128[2] + DIFF128[3]; +#elif defined(AVX) + __m256 diff256 = _mm256_setzero_ps(); + while (pX < pEnd16) + { + REPEAT(__m256, const float, 8, _mm256_loadu_ps, _mm256_sqdf_ps, _mm256_add_ps, diff256) + REPEAT(__m256, const float, 8, _mm256_loadu_ps, _mm256_sqdf_ps, _mm256_add_ps, diff256) + } + __m128 diff128 = _mm_add_ps(_mm256_castps256_ps128(diff256), _mm256_extractf128_ps(diff256, 1)); + while (pX < pEnd4) + { + REPEAT(__m128, const float, 4, _mm_loadu_ps, _mm_sqdf_ps, _mm_add_ps, diff128) + } + float diff = DIFF128[0] + DIFF128[1] + DIFF128[2] + DIFF128[3]; +#else + float diff = 0; + while (pX < pEnd4) { + float c1 = (*pX++) - (*pY++); diff += c1 * c1; + c1 = (*pX++) - (*pY++); diff += c1 * c1; + c1 = (*pX++) - (*pY++); diff += c1 * c1; + c1 = (*pX++) - (*pY++); diff += c1 * c1; + } +#endif + while (pX < pEnd1) { + float c1 = (*pX++) - (*pY++); diff += c1 * c1; + } + return diff; + } +/* + template + static float ComputeCosineDistance(const T *pX, const T *pY, int length) { + float diff = 0; + const T* pEnd1 = pX + length; + while (pX < pEnd1) diff += (*pX++) * (*pY++); + return 1 - diff; + } +*/ + static float ComputeCosineDistance(const std::int8_t *pX, const std::int8_t *pY, int length) { + const std::int8_t* pEnd32 = pX + ((length >> 5) << 5); + const std::int8_t* pEnd16 = pX + ((length >> 4) << 4); + const std::int8_t* pEnd4 = pX + ((length >> 2) << 2); + const std::int8_t* pEnd1 = pX + length; +#if defined(SSE) + + __m128 diff128 = _mm_setzero_ps(); + while (pX < pEnd32) { + REPEAT(__m128i, __m128i, 16, _mm_loadu_si128, _mm_mul_epi8, _mm_add_ps, diff128) + REPEAT(__m128i, __m128i, 16, _mm_loadu_si128, _mm_mul_epi8, _mm_add_ps, diff128) + } + while (pX < pEnd16) { + REPEAT(__m128i, __m128i, 16, _mm_loadu_si128, _mm_mul_epi8, _mm_add_ps, diff128) + } + float diff = DIFF128[0] + DIFF128[1] + DIFF128[2] + DIFF128[3]; +#elif defined(AVX) + __m256 diff256 = _mm256_setzero_ps(); + while (pX < pEnd32) { + REPEAT(__m256i, __m256i, 32, _mm256_loadu_si256, _mm256_mul_epi8, _mm256_add_ps, diff256) + } + __m128 diff128 = _mm_add_ps(_mm256_castps256_ps128(diff256), _mm256_extractf128_ps(diff256, 1)); + while (pX < pEnd16) { + REPEAT(__m128i, __m128i, 16, _mm_loadu_si128, _mm_mul_epi8, _mm_add_ps, diff128) + } + float diff = DIFF128[0] + DIFF128[1] + DIFF128[2] + DIFF128[3]; +#else + float diff = 0; +#endif + while (pX < pEnd4) + { + float c1 = ((float)(*pX++) * (float)(*pY++)); diff += c1; + c1 = ((float)(*pX++) * (float)(*pY++)); diff += c1; + c1 = ((float)(*pX++) * (float)(*pY++)); diff += c1; + c1 = ((float)(*pX++) * (float)(*pY++)); diff += c1; + } + while (pX < pEnd1) diff += ((float)(*pX++) * (float)(*pY++)); + return 16129 - diff; + } + + static float ComputeCosineDistance(const std::uint8_t *pX, const std::uint8_t *pY, int length) { + const std::uint8_t* pEnd32 = pX + ((length >> 5) << 5); + const std::uint8_t* pEnd16 = pX + ((length >> 4) << 4); + const std::uint8_t* pEnd4 = pX + ((length >> 2) << 2); + const std::uint8_t* pEnd1 = pX + length; +#if defined(SSE) + + __m128 diff128 = _mm_setzero_ps(); + while (pX < pEnd32) { + REPEAT(__m128i, __m128i, 16, _mm_loadu_si128, _mm_mul_epu8, _mm_add_ps, diff128) + REPEAT(__m128i, __m128i, 16, _mm_loadu_si128, _mm_mul_epu8, _mm_add_ps, diff128) + } + while (pX < pEnd16) { + REPEAT(__m128i, __m128i, 16, _mm_loadu_si128, _mm_mul_epu8, _mm_add_ps, diff128) + } + float diff = DIFF128[0] + DIFF128[1] + DIFF128[2] + DIFF128[3]; +#elif defined(AVX) + __m256 diff256 = _mm256_setzero_ps(); + while (pX < pEnd32) { + REPEAT(__m256i, __m256i, 32, _mm256_loadu_si256, _mm256_mul_epu8, _mm256_add_ps, diff256) + } + __m128 diff128 = _mm_add_ps(_mm256_castps256_ps128(diff256), _mm256_extractf128_ps(diff256, 1)); + while (pX < pEnd16) { + REPEAT(__m128i, __m128i, 16, _mm_loadu_si128, _mm_mul_epu8, _mm_add_ps, diff128) + } + float diff = DIFF128[0] + DIFF128[1] + DIFF128[2] + DIFF128[3]; +#else + float diff = 0; +#endif + while (pX < pEnd4) + { + float c1 = ((float)(*pX++) * (float)(*pY++)); diff += c1; + c1 = ((float)(*pX++) * (float)(*pY++)); diff += c1; + c1 = ((float)(*pX++) * (float)(*pY++)); diff += c1; + c1 = ((float)(*pX++) * (float)(*pY++)); diff += c1; + } + while (pX < pEnd1) diff += ((float)(*pX++) * (float)(*pY++)); + return 65025 - diff; + } + + static float ComputeCosineDistance(const std::int16_t *pX, const std::int16_t *pY, int length) { + const std::int16_t* pEnd16 = pX + ((length >> 4) << 4); + const std::int16_t* pEnd8 = pX + ((length >> 3) << 3); + const std::int16_t* pEnd4 = pX + ((length >> 2) << 2); + const std::int16_t* pEnd1 = pX + length; +#if defined(SSE) + __m128 diff128 = _mm_setzero_ps(); + while (pX < pEnd16) { + REPEAT(__m128i, __m128i, 8, _mm_loadu_si128, _mm_mul_epi16, _mm_add_ps, diff128) + REPEAT(__m128i, __m128i, 8, _mm_loadu_si128, _mm_mul_epi16, _mm_add_ps, diff128) + } + while (pX < pEnd8) { + REPEAT(__m128i, __m128i, 8, _mm_loadu_si128, _mm_mul_epi16, _mm_add_ps, diff128) + } + float diff = DIFF128[0] + DIFF128[1] + DIFF128[2] + DIFF128[3]; + +#elif defined(AVX) + __m256 diff256 = _mm256_setzero_ps(); + while (pX < pEnd16) { + REPEAT(__m256i, __m256i, 16, _mm256_loadu_si256, _mm256_mul_epi16, _mm256_add_ps, diff256) + } + __m128 diff128 = _mm_add_ps(_mm256_castps256_ps128(diff256), _mm256_extractf128_ps(diff256, 1)); + while (pX < pEnd8) { + REPEAT(__m128i, __m128i, 8, _mm_loadu_si128, _mm_mul_epi16, _mm_add_ps, diff128) + } + float diff = DIFF128[0] + DIFF128[1] + DIFF128[2] + DIFF128[3]; +#else + float diff = 0; +#endif + while (pX < pEnd4) + { + float c1 = ((float)(*pX++) * (float)(*pY++)); diff += c1; + c1 = ((float)(*pX++) * (float)(*pY++)); diff += c1; + c1 = ((float)(*pX++) * (float)(*pY++)); diff += c1; + c1 = ((float)(*pX++) * (float)(*pY++)); diff += c1; + } + + while (pX < pEnd1) diff += ((float)(*pX++) * (float)(*pY++)); + return 1073676289 - diff; + } + + static float ComputeCosineDistance(const float *pX, const float *pY, int length) { + const float* pEnd16 = pX + ((length >> 4) << 4); + const float* pEnd4 = pX + ((length >> 2) << 2); + const float* pEnd1 = pX + length; +#if defined(SSE) + __m128 diff128 = _mm_setzero_ps(); + while (pX < pEnd16) + { + REPEAT(__m128, const float, 4, _mm_loadu_ps, _mm_mul_ps, _mm_add_ps, diff128) + REPEAT(__m128, const float, 4, _mm_loadu_ps, _mm_mul_ps, _mm_add_ps, diff128) + REPEAT(__m128, const float, 4, _mm_loadu_ps, _mm_mul_ps, _mm_add_ps, diff128) + REPEAT(__m128, const float, 4, _mm_loadu_ps, _mm_mul_ps, _mm_add_ps, diff128) + } + while (pX < pEnd4) + { + REPEAT(__m128, const float, 4, _mm_loadu_ps, _mm_mul_ps, _mm_add_ps, diff128) + } + float diff = DIFF128[0] + DIFF128[1] + DIFF128[2] + DIFF128[3]; + +#elif defined(AVX) + __m256 diff256 = _mm256_setzero_ps(); + while (pX < pEnd16) + { + REPEAT(__m256, const float, 8, _mm256_loadu_ps, _mm256_mul_ps, _mm256_add_ps, diff256) + REPEAT(__m256, const float, 8, _mm256_loadu_ps, _mm256_mul_ps, _mm256_add_ps, diff256) + } + __m128 diff128 = _mm_add_ps(_mm256_castps256_ps128(diff256), _mm256_extractf128_ps(diff256, 1)); + while (pX < pEnd4) + { + REPEAT(__m128, const float, 4, _mm_loadu_ps, _mm_mul_ps, _mm_add_ps, diff128) + } + float diff = DIFF128[0] + DIFF128[1] + DIFF128[2] + DIFF128[3]; +#else + float diff = 0; + while (pX < pEnd4) + { + float c1 = (*pX++) * (*pY++); diff += c1; + c1 = (*pX++) * (*pY++); diff += c1; + c1 = (*pX++) * (*pY++); diff += c1; + c1 = (*pX++) * (*pY++); diff += c1; + } +#endif + while (pX < pEnd1) diff += (*pX++) * (*pY++); + return 1 - diff; + } + + template + static inline float ComputeDistance(const T *p1, const T *p2, int length, SPTAG::DistCalcMethod distCalcMethod) + { + if (distCalcMethod == SPTAG::DistCalcMethod::L2) + return ComputeL2Distance(p1, p2, length); + + return ComputeCosineDistance(p1, p2, length); + } + + static inline float ConvertCosineSimilarityToDistance(float cs) + { + // Cosine similarity is in [-1, 1], the higher the value, the closer are the two vectors. + // However, the tree is built and searched based on "distance" between two vectors, that's >=0. The smaller the value, the closer are the two vectors. + // So we do a linear conversion from a cosine similarity to a distance value. + return 1 - cs; //[1, 3] + } + + static inline float ConvertDistanceBackToCosineSimilarity(float d) + { + return 1 - d; + } + }; + + + template + float (*DistanceCalcSelector(SPTAG::DistCalcMethod p_method)) (const T*, const T*, int) + { + switch (p_method) + { + case SPTAG::DistCalcMethod::Cosine: + return &(DistanceUtils::ComputeCosineDistance); + + case SPTAG::DistCalcMethod::L2: + return &(DistanceUtils::ComputeL2Distance); + + default: + break; + } + + return nullptr; + } + } +} + +#endif // _SPTAG_COMMON_DISTANCEUTILS_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common/FineGrainedLock.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common/FineGrainedLock.h new file mode 100644 index 0000000000..d8bfbaa9fe --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common/FineGrainedLock.h @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_COMMON_FINEGRAINEDLOCK_H_ +#define _SPTAG_COMMON_FINEGRAINEDLOCK_H_ + +#include +#include +#include + +namespace SPTAG +{ + namespace COMMON + { + class FineGrainedLock { + public: + FineGrainedLock() {} + ~FineGrainedLock() { + for (int i = 0; i < locks.size(); i++) + locks[i].reset(); + locks.clear(); + } + + void resize(int n) { + int current = (int)locks.size(); + if (current <= n) { + locks.resize(n); + for (int i = current; i < n; i++) + locks[i].reset(new std::mutex); + } + else { + for (int i = n; i < current; i++) + locks[i].reset(); + locks.resize(n); + } + } + + std::mutex& operator[](int idx) { + return *locks[idx]; + } + + const std::mutex& operator[](int idx) const { + return *locks[idx]; + } + private: + std::vector> locks; + }; + } +} + +#endif // _SPTAG_COMMON_FINEGRAINEDLOCK_H_ \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common/Heap.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common/Heap.h new file mode 100644 index 0000000000..261aa498a6 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common/Heap.h @@ -0,0 +1,105 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_COMMON_HEAP_H_ +#define _SPTAG_COMMON_HEAP_H_ + +namespace SPTAG +{ + namespace COMMON + { + + // priority queue + template + class Heap { + public: + Heap() : heap(nullptr), length(0), count(0) {} + + Heap(int size) { Resize(size); } + + void Resize(int size) + { + length = size; + heap.reset(new T[length + 1]); // heap uses 1-based indexing + count = 0; + lastlevel = int(pow(2.0, floor(log2(size)))); + } + ~Heap() {} + inline int size() { return count; } + inline bool empty() { return count == 0; } + inline void clear() { count = 0; } + inline T& Top() { if (count == 0) return heap[0]; else return heap[1]; } + + // Insert a new element in the heap. + void insert(T value) + { + /* If heap is full, then return without adding this element. */ + int loc; + if (count == length) { + int maxi = lastlevel; + for (int i = lastlevel + 1; i <= length; i++) + if (heap[maxi] < heap[i]) maxi = i; + if (value > heap[maxi]) return; + loc = maxi; + } + else { + loc = ++(count); /* Remember 1-based indexing. */ + } + /* Keep moving parents down until a place is found for this node. */ + int par = (loc >> 1); /* Location of parent. */ + while (par > 0 && value < heap[par]) { + heap[loc] = heap[par]; /* Move parent down to loc. */ + loc = par; + par >>= 1; + } + /* Insert the element at the determined location. */ + heap[loc] = value; + } + // Returns the node of minimum value from the heap (top of the heap). + bool pop(T& value) + { + if (count == 0) return false; + /* Switch first node with last. */ + value = heap[1]; + std::swap(heap[1], heap[count]); + count--; + heapify(); /* Move new node 1 to right position. */ + return true; /* Return old last node. */ + } + T& pop() + { + if (count == 0) return heap[0]; + /* Switch first node with last. */ + std::swap(heap[1], heap[count]); + count--; + heapify(); /* Move new node 1 to right position. */ + return heap[count + 1]; /* Return old last node. */ + } + private: + // Storage array for the heap. + // Type T must be comparable. + std::unique_ptr heap; + int length; + int count; // Number of element in the heap + int lastlevel; + // Reorganizes the heap (a parent is smaller than its children) starting with a node. + + void heapify() + { + int parent = 1, next = 2; + while (next < count) { + if (heap[next] > heap[next + 1]) next++; + if (heap[next] < heap[parent]) { + std::swap(heap[parent], heap[next]); + parent = next; + next <<= 1; + } + else break; + } + if (next == count && heap[next] < heap[parent]) std::swap(heap[parent], heap[next]); + } + }; + } +} + +#endif // _SPTAG_COMMON_HEAP_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common/KDTree.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common/KDTree.h new file mode 100644 index 0000000000..95d4ae36e4 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common/KDTree.h @@ -0,0 +1,358 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_COMMON_KDTREE_H_ +#define _SPTAG_COMMON_KDTREE_H_ + +#include +#include +#include + +#include "../VectorIndex.h" + +#include "CommonUtils.h" +#include "QueryResultSet.h" +#include "WorkSpace.h" + +#pragma warning(disable:4996) // 'fopen': This function or variable may be unsafe. Consider using fopen_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. + +namespace SPTAG +{ + namespace COMMON + { + // node type for storing KDT + struct KDTNode + { + int left; + int right; + short split_dim; + float split_value; + }; + + class KDTree + { + public: + KDTree() : m_iTreeNumber(2), m_numTopDimensionKDTSplit(5), m_iSamples(1000) {} + + KDTree(KDTree& other) : m_iTreeNumber(other.m_iTreeNumber), + m_numTopDimensionKDTSplit(other.m_numTopDimensionKDTSplit), + m_iSamples(other.m_iSamples) {} + ~KDTree() {} + + inline const KDTNode& operator[](int index) const { return m_pTreeRoots[index]; } + inline KDTNode& operator[](int index) { return m_pTreeRoots[index]; } + + inline int size() const { return (int)m_pTreeRoots.size(); } + + template + void BuildTrees(VectorIndex* p_index, std::vector* indices = nullptr) + { + std::vector localindices; + if (indices == nullptr) { + localindices.resize(p_index->GetNumSamples()); + for (int i = 0; i < p_index->GetNumSamples(); i++) localindices[i] = i; + } + else { + localindices.assign(indices->begin(), indices->end()); + } + + m_pTreeRoots.resize(m_iTreeNumber * localindices.size()); + m_pTreeStart.resize(m_iTreeNumber, 0); +#pragma omp parallel for + for (int i = 0; i < m_iTreeNumber; i++) + { + Sleep(i * 100); std::srand(clock()); + + std::vector pindices(localindices.begin(), localindices.end()); + std::random_shuffle(pindices.begin(), pindices.end()); + + m_pTreeStart[i] = i * (int)pindices.size(); + std::cout << "Start to build KDTree " << i + 1 << std::endl; + int iTreeSize = m_pTreeStart[i]; + DivideTree(p_index, pindices, 0, (int)pindices.size() - 1, m_pTreeStart[i], iTreeSize); + std::cout << i + 1 << " KDTree built, " << iTreeSize - m_pTreeStart[i] << " " << pindices.size() << std::endl; + } + } + + bool SaveTrees(void **pKDTMemFile, int64_t &len) const + { + int treeNodeSize = (int)m_pTreeRoots.size(); + + size_t size = sizeof(int) + + sizeof(int) * m_iTreeNumber + + sizeof(int) + + sizeof(KDTNode) * treeNodeSize; + char *mem = (char*)malloc(size); + if (mem == NULL) return false; + + auto ptr = mem; + *(int*)ptr = m_iTreeNumber; + ptr += sizeof(int); + + memcpy(ptr, m_pTreeStart.data(), sizeof(int) * m_iTreeNumber); + ptr += sizeof(int) * m_iTreeNumber; + + *(int*)ptr = treeNodeSize; + ptr += sizeof(int); + + memcpy(ptr, m_pTreeRoots.data(), sizeof(KDTNode) * treeNodeSize); + *pKDTMemFile = mem; + len = size; + + return true; + } + + bool SaveTrees(std::string sTreeFileName) const + { + std::cout << "Save KDT to " << sTreeFileName << std::endl; + FILE *fp = fopen(sTreeFileName.c_str(), "wb"); + if (fp == NULL) return false; + + fwrite(&m_iTreeNumber, sizeof(int), 1, fp); + fwrite(m_pTreeStart.data(), sizeof(int), m_iTreeNumber, fp); + int treeNodeSize = (int)m_pTreeRoots.size(); + fwrite(&treeNodeSize, sizeof(int), 1, fp); + fwrite(m_pTreeRoots.data(), sizeof(KDTNode), treeNodeSize, fp); + fclose(fp); + std::cout << "Save KDT (" << m_iTreeNumber << "," << treeNodeSize << ") Finish!" << std::endl; + return true; + } + + bool LoadTrees(char* pKDTMemFile) + { + m_iTreeNumber = *((int*)pKDTMemFile); + pKDTMemFile += sizeof(int); + m_pTreeStart.resize(m_iTreeNumber); + memcpy(m_pTreeStart.data(), pKDTMemFile, sizeof(int) * m_iTreeNumber); + pKDTMemFile += sizeof(int)*m_iTreeNumber; + + int treeNodeSize = *((int*)pKDTMemFile); + pKDTMemFile += sizeof(int); + m_pTreeRoots.resize(treeNodeSize); + memcpy(m_pTreeRoots.data(), pKDTMemFile, sizeof(KDTNode) * treeNodeSize); + return true; + } + + bool LoadTrees(std::string sTreeFileName) + { + std::cout << "Load KDT From " << sTreeFileName << std::endl; + FILE *fp = fopen(sTreeFileName.c_str(), "rb"); + if (fp == NULL) return false; + + fread(&m_iTreeNumber, sizeof(int), 1, fp); + m_pTreeStart.resize(m_iTreeNumber); + fread(m_pTreeStart.data(), sizeof(int), m_iTreeNumber, fp); + + int treeNodeSize; + fread(&treeNodeSize, sizeof(int), 1, fp); + m_pTreeRoots.resize(treeNodeSize); + fread(m_pTreeRoots.data(), sizeof(KDTNode), treeNodeSize, fp); + fclose(fp); + std::cout << "Load KDT (" << m_iTreeNumber << "," << treeNodeSize << ") Finish!" << std::endl; + return true; + } + + template + void InitSearchTrees(const VectorIndex* p_index, const COMMON::QueryResultSet &p_query, COMMON::WorkSpace &p_space, const int p_limits) const + { + for (char i = 0; i < m_iTreeNumber; i++) { + KDTSearch(p_index, p_query, p_space, m_pTreeStart[i], true, 0); + } + + while (!p_space.m_SPTQueue.empty() && p_space.m_iNumberOfCheckedLeaves < p_limits) + { + auto& tcell = p_space.m_SPTQueue.pop(); + if (p_query.worstDist() < tcell.distance) break; + KDTSearch(p_index, p_query, p_space, tcell.node, true, tcell.distance); + } + } + + template + void SearchTrees(const VectorIndex* p_index, const COMMON::QueryResultSet &p_query, COMMON::WorkSpace &p_space, const int p_limits) const + { + while (!p_space.m_SPTQueue.empty() && p_space.m_iNumberOfCheckedLeaves < p_limits) + { + auto& tcell = p_space.m_SPTQueue.pop(); + KDTSearch(p_index, p_query, p_space, tcell.node, false, tcell.distance); + } + } + + private: + + template + void KDTSearch(const VectorIndex* p_index, const COMMON::QueryResultSet &p_query, + COMMON::WorkSpace& p_space, const int node, const bool isInit, const float distBound) const { + if (node < 0) + { + int index = -node - 1; + if (index >= p_index->GetNumSamples()) return; +#ifdef PREFETCH + const char* data = (const char *)(p_index->GetSample(index)); + _mm_prefetch(data, _MM_HINT_T0); + _mm_prefetch(data + 64, _MM_HINT_T0); +#endif + if (p_space.CheckAndSet(index)) return; + + ++p_space.m_iNumberOfTreeCheckedLeaves; + ++p_space.m_iNumberOfCheckedLeaves; + p_space.m_NGQueue.insert(COMMON::HeapCell(index, p_index->ComputeDistance((const void*)p_query.GetTarget(), (const void*)data))); + return; + } + + auto& tnode = m_pTreeRoots[node]; + + float diff = (p_query.GetTarget())[tnode.split_dim] - tnode.split_value; + float distanceBound = distBound + diff * diff; + int otherChild, bestChild; + if (diff < 0) + { + bestChild = tnode.left; + otherChild = tnode.right; + } + else + { + otherChild = tnode.left; + bestChild = tnode.right; + } + + if (!isInit || distanceBound < p_query.worstDist()) + { + p_space.m_SPTQueue.insert(COMMON::HeapCell(otherChild, distanceBound)); + } + KDTSearch(p_index, p_query, p_space, bestChild, isInit, distBound); + } + + + template + void DivideTree(VectorIndex* p_index, std::vector& indices, int first, int last, + int index, int &iTreeSize) { + ChooseDivision(p_index, m_pTreeRoots[index], indices, first, last); + int i = Subdivide(p_index, m_pTreeRoots[index], indices, first, last); + if (i - 1 <= first) + { + m_pTreeRoots[index].left = -indices[first] - 1; + } + else + { + iTreeSize++; + m_pTreeRoots[index].left = iTreeSize; + DivideTree(p_index, indices, first, i - 1, iTreeSize, iTreeSize); + } + if (last == i) + { + m_pTreeRoots[index].right = -indices[last] - 1; + } + else + { + iTreeSize++; + m_pTreeRoots[index].right = iTreeSize; + DivideTree(p_index, indices, i, last, iTreeSize, iTreeSize); + } + } + + template + void ChooseDivision(VectorIndex* p_index, KDTNode& node, const std::vector& indices, const int first, const int last) + { + std::vector meanValues(p_index->GetFeatureDim(), 0); + std::vector varianceValues(p_index->GetFeatureDim(), 0); + int end = min(first + m_iSamples, last); + int count = end - first + 1; + // calculate the mean of each dimension + for (int j = first; j <= end; j++) + { + const T* v = (const T*)p_index->GetSample(indices[j]); + for (int k = 0; k < p_index->GetFeatureDim(); k++) + { + meanValues[k] += v[k]; + } + } + for (int k = 0; k < p_index->GetFeatureDim(); k++) + { + meanValues[k] /= count; + } + // calculate the variance of each dimension + for (int j = first; j <= end; j++) + { + const T* v = (const T*)p_index->GetSample(indices[j]); + for (int k = 0; k < p_index->GetFeatureDim(); k++) + { + float dist = v[k] - meanValues[k]; + varianceValues[k] += dist*dist; + } + } + // choose the split dimension as one of the dimension inside TOP_DIM maximum variance + node.split_dim = SelectDivisionDimension(varianceValues); + // determine the threshold + node.split_value = meanValues[node.split_dim]; + } + + int SelectDivisionDimension(const std::vector& varianceValues) const + { + // Record the top maximum variances + std::vector topind(m_numTopDimensionKDTSplit); + int num = 0; + // order the variances + for (int i = 0; i < varianceValues.size(); i++) + { + if (num < m_numTopDimensionKDTSplit || varianceValues[i] > varianceValues[topind[num - 1]]) + { + if (num < m_numTopDimensionKDTSplit) + { + topind[num++] = i; + } + else + { + topind[num - 1] = i; + } + int j = num - 1; + // order the TOP_DIM variances + while (j > 0 && varianceValues[topind[j]] > varianceValues[topind[j - 1]]) + { + std::swap(topind[j], topind[j - 1]); + j--; + } + } + } + // randomly choose a dimension from TOP_DIM + return topind[COMMON::Utils::rand_int(num)]; + } + + template + int Subdivide(VectorIndex* p_index, const KDTNode& node, std::vector& indices, const int first, const int last) const + { + int i = first; + int j = last; + // decide which child one point belongs + while (i <= j) + { + int ind = indices[i]; + const T* v = (const T*)p_index->GetSample(ind); + float val = v[node.split_dim]; + if (val < node.split_value) + { + i++; + } + else + { + std::swap(indices[i], indices[j]); + j--; + } + } + // if all the points in the node are equal,equally split the node into 2 + if ((i == first) || (i == last + 1)) + { + i = (first + last + 1) / 2; + } + return i; + } + + private: + std::vector m_pTreeStart; + std::vector m_pTreeRoots; + + public: + int m_iTreeNumber, m_numTopDimensionKDTSplit, m_iSamples; + }; + } +} +#endif diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common/NeighborhoodGraph.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common/NeighborhoodGraph.h new file mode 100644 index 0000000000..02d2541754 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common/NeighborhoodGraph.h @@ -0,0 +1,436 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_COMMON_NG_H_ +#define _SPTAG_COMMON_NG_H_ + +#include "../VectorIndex.h" + +#include "CommonUtils.h" +#include "Dataset.h" +#include "FineGrainedLock.h" +#include "QueryResultSet.h" + +namespace SPTAG +{ + namespace COMMON + { + class NeighborhoodGraph + { + public: + NeighborhoodGraph(): m_iTPTNumber(32), + m_iTPTLeafSize(2000), + m_iSamples(1000), + m_numTopDimensionTPTSplit(5), + m_iNeighborhoodSize(32), + m_iNeighborhoodScale(2), + m_iCEFScale(2), + m_iRefineIter(0), + m_iCEF(1000), + m_iMaxCheckForRefineGraph(10000) {} + + ~NeighborhoodGraph() {} + + virtual void InsertNeighbors(VectorIndex* index, const int node, int insertNode, float insertDist) = 0; + + virtual void RebuildNeighbors(VectorIndex* index, const int node, int* nodes, const BasicResult* queryResults, const int numResults) = 0; + + virtual float GraphAccuracyEstimation(VectorIndex* index, const int samples, const std::unordered_map* idmap = nullptr) = 0; + + template + void BuildGraph(VectorIndex* index, const std::unordered_map* idmap = nullptr) + { + std::cout << "build RNG graph!" << std::endl; + + m_iGraphSize = index->GetNumSamples(); + m_iNeighborhoodSize = m_iNeighborhoodSize * m_iNeighborhoodScale; + m_pNeighborhoodGraph.Initialize(m_iGraphSize, m_iNeighborhoodSize); + m_dataUpdateLock.resize(m_iGraphSize); + + if (m_iGraphSize < 1000) { + RefineGraph(index, idmap); + std::cout << "Build RNG Graph end!" << std::endl; + return; + } + + { + COMMON::Dataset NeighborhoodDists(m_iGraphSize, m_iNeighborhoodSize); + std::vector> TptreeDataIndices(m_iTPTNumber, std::vector(m_iGraphSize)); + std::vector>> TptreeLeafNodes(m_iTPTNumber, std::vector>()); + + for (int i = 0; i < m_iGraphSize; i++) + for (int j = 0; j < m_iNeighborhoodSize; j++) + (NeighborhoodDists)[i][j] = MaxDist; + + std::cout << "Parallel TpTree Partition begin " << std::endl; +#pragma omp parallel for schedule(dynamic) + for (int i = 0; i < m_iTPTNumber; i++) + { + Sleep(i * 100); std::srand(clock()); + for (int j = 0; j < m_iGraphSize; j++) TptreeDataIndices[i][j] = j; + std::random_shuffle(TptreeDataIndices[i].begin(), TptreeDataIndices[i].end()); + PartitionByTptree(index, TptreeDataIndices[i], 0, m_iGraphSize - 1, TptreeLeafNodes[i]); + std::cout << "Finish Getting Leaves for Tree " << i << std::endl; + } + std::cout << "Parallel TpTree Partition done" << std::endl; + + for (int i = 0; i < m_iTPTNumber; i++) + { +#pragma omp parallel for schedule(dynamic) + for (int j = 0; j < TptreeLeafNodes[i].size(); j++) + { + int start_index = TptreeLeafNodes[i][j].first; + int end_index = TptreeLeafNodes[i][j].second; + if (omp_get_thread_num() == 0) std::cout << "\rProcessing Tree " << i << ' ' << j * 100 / TptreeLeafNodes[i].size() << '%'; + for (int x = start_index; x < end_index; x++) + { + for (int y = x + 1; y <= end_index; y++) + { + int p1 = TptreeDataIndices[i][x]; + int p2 = TptreeDataIndices[i][y]; + float dist = index->ComputeDistance(index->GetSample(p1), index->GetSample(p2)); + if (idmap != nullptr) { + p1 = (idmap->find(p1) == idmap->end()) ? p1 : idmap->at(p1); + p2 = (idmap->find(p2) == idmap->end()) ? p2 : idmap->at(p2); + } + COMMON::Utils::AddNeighbor(p2, dist, (m_pNeighborhoodGraph)[p1], (NeighborhoodDists)[p1], m_iNeighborhoodSize); + COMMON::Utils::AddNeighbor(p1, dist, (m_pNeighborhoodGraph)[p2], (NeighborhoodDists)[p2], m_iNeighborhoodSize); + } + } + } + TptreeDataIndices[i].clear(); + TptreeLeafNodes[i].clear(); + std::cout << std::endl; + } + TptreeDataIndices.clear(); + TptreeLeafNodes.clear(); + } + + if (m_iMaxCheckForRefineGraph > 0) { + RefineGraph(index, idmap); + } + } + + template + void RefineGraph(VectorIndex* index, const std::unordered_map* idmap = nullptr) + { + m_iCEF *= m_iCEFScale; + m_iMaxCheckForRefineGraph *= m_iCEFScale; + +#pragma omp parallel for schedule(dynamic) + for (int i = 0; i < m_iGraphSize; i++) + { + RefineNode(index, i, false); + if (i % 1000 == 0) std::cout << "\rRefine 1 " << (i * 100 / m_iGraphSize) << "%"; + } + std::cout << "Refine RNG, graph acc:" << GraphAccuracyEstimation(index, 100, idmap) << std::endl; + + m_iCEF /= m_iCEFScale; + m_iMaxCheckForRefineGraph /= m_iCEFScale; + m_iNeighborhoodSize /= m_iNeighborhoodScale; + +#pragma omp parallel for schedule(dynamic) + for (int i = 0; i < m_iGraphSize; i++) + { + RefineNode(index, i, false); + if (i % 1000 == 0) std::cout << "\rRefine 2 " << (i * 100 / m_iGraphSize) << "%"; + } + std::cout << "Refine RNG, graph acc:" << GraphAccuracyEstimation(index, 100, idmap) << std::endl; + + if (idmap != nullptr) { + for (auto iter = idmap->begin(); iter != idmap->end(); iter++) + if (iter->first < 0) + { + m_pNeighborhoodGraph[-1 - iter->first][m_iNeighborhoodSize - 1] = -2 - iter->second; + } + } + } + + template + ErrorCode RefineGraph(VectorIndex* index, std::vector& indices, std::vector& reverseIndices, + std::string graphFileName, const std::unordered_map* idmap = nullptr) + { + int R = (int)indices.size(); + +#pragma omp parallel for schedule(dynamic) + for (int i = 0; i < R; i++) + { + RefineNode(index, indices[i], false); + int* nodes = m_pNeighborhoodGraph[indices[i]]; + for (int j = 0; j < m_iNeighborhoodSize; j++) + { + if (nodes[j] < 0) nodes[j] = -1; + else nodes[j] = reverseIndices[nodes[j]]; + } + if (idmap == nullptr || idmap->find(-1 - indices[i]) == idmap->end()) continue; + nodes[m_iNeighborhoodSize - 1] = -2 - idmap->at(-1 - indices[i]); + } + + std::ofstream graphOut(graphFileName, std::ios::binary); + if (!graphOut.is_open()) return ErrorCode::FailedCreateFile; + graphOut.write((char*)&R, sizeof(int)); + graphOut.write((char*)&m_iNeighborhoodSize, sizeof(int)); + for (int i = 0; i < R; i++) { + graphOut.write((char*)m_pNeighborhoodGraph[indices[i]], sizeof(int) * m_iNeighborhoodSize); + } + graphOut.close(); + return ErrorCode::Success; + } + + + template + void RefineNode(VectorIndex* index, const int node, bool updateNeighbors) + { + COMMON::QueryResultSet query((const T*)index->GetSample(node), m_iCEF + 1); + index->SearchIndex(query); + RebuildNeighbors(index, node, m_pNeighborhoodGraph[node], query.GetResults(), m_iCEF + 1); + + if (updateNeighbors) { + // update neighbors + for (int j = 0; j <= m_iCEF; j++) + { + BasicResult* item = query.GetResult(j); + if (item->VID < 0) break; + if (item->VID == node) continue; + + std::lock_guard lock(m_dataUpdateLock[item->VID]); + InsertNeighbors(index, item->VID, node, item->Dist); + } + } + } + + template + void PartitionByTptree(VectorIndex* index, std::vector& indices, const int first, const int last, + std::vector> & leaves) + { + if (last - first <= m_iTPTLeafSize) + { + leaves.push_back(std::make_pair(first, last)); + } + else + { + std::vector Mean(index->GetFeatureDim(), 0); + + int iIteration = 100; + int end = min(first + m_iSamples, last); + int count = end - first + 1; + // calculate the mean of each dimension + for (int j = first; j <= end; j++) + { + const T* v = (const T*)index->GetSample(indices[j]); + for (int k = 0; k < index->GetFeatureDim(); k++) + { + Mean[k] += v[k]; + } + } + for (int k = 0; k < index->GetFeatureDim(); k++) + { + Mean[k] /= count; + } + std::vector Variance; + Variance.reserve(index->GetFeatureDim()); + for (int j = 0; j < index->GetFeatureDim(); j++) + { + Variance.push_back(BasicResult(j, 0)); + } + // calculate the variance of each dimension + for (int j = first; j <= end; j++) + { + const T* v = (const T*)index->GetSample(indices[j]); + for (int k = 0; k < index->GetFeatureDim(); k++) + { + float dist = v[k] - Mean[k]; + Variance[k].Dist += dist*dist; + } + } + std::sort(Variance.begin(), Variance.end(), COMMON::Compare); + std::vector indexs(m_numTopDimensionTPTSplit); + std::vector weight(m_numTopDimensionTPTSplit), bestweight(m_numTopDimensionTPTSplit); + float bestvariance = Variance[index->GetFeatureDim() - 1].Dist; + for (int i = 0; i < m_numTopDimensionTPTSplit; i++) + { + indexs[i] = Variance[index->GetFeatureDim() - 1 - i].VID; + bestweight[i] = 0; + } + bestweight[0] = 1; + float bestmean = Mean[indexs[0]]; + + std::vector Val(count); + for (int i = 0; i < iIteration; i++) + { + float sumweight = 0; + for (int j = 0; j < m_numTopDimensionTPTSplit; j++) + { + weight[j] = float(rand() % 10000) / 5000.0f - 1.0f; + sumweight += weight[j] * weight[j]; + } + sumweight = sqrt(sumweight); + for (int j = 0; j < m_numTopDimensionTPTSplit; j++) + { + weight[j] /= sumweight; + } + float mean = 0; + for (int j = 0; j < count; j++) + { + Val[j] = 0; + const T* v = (const T*)index->GetSample(indices[first + j]); + for (int k = 0; k < m_numTopDimensionTPTSplit; k++) + { + Val[j] += weight[k] * v[indexs[k]]; + } + mean += Val[j]; + } + mean /= count; + float var = 0; + for (int j = 0; j < count; j++) + { + float dist = Val[j] - mean; + var += dist * dist; + } + if (var > bestvariance) + { + bestvariance = var; + bestmean = mean; + for (int j = 0; j < m_numTopDimensionTPTSplit; j++) + { + bestweight[j] = weight[j]; + } + } + } + int i = first; + int j = last; + // decide which child one point belongs + while (i <= j) + { + float val = 0; + const T* v = (const T*)index->GetSample(indices[i]); + for (int k = 0; k < m_numTopDimensionTPTSplit; k++) + { + val += bestweight[k] * v[indexs[k]]; + } + if (val < bestmean) + { + i++; + } + else + { + std::swap(indices[i], indices[j]); + j--; + } + } + // if all the points in the node are equal,equally split the node into 2 + if ((i == first) || (i == last + 1)) + { + i = (first + last + 1) / 2; + } + + Mean.clear(); + Variance.clear(); + Val.clear(); + indexs.clear(); + weight.clear(); + bestweight.clear(); + + PartitionByTptree(index, indices, first, i - 1, leaves); + PartitionByTptree(index, indices, i, last, leaves); + } + } + + bool LoadGraph(std::string sGraphFilename) + { + std::cout << "Load Graph From " << sGraphFilename << std::endl; + FILE * fp = fopen(sGraphFilename.c_str(), "rb"); + if (fp == NULL) return false; + + fread(&m_iGraphSize, sizeof(int), 1, fp); + fread(&m_iNeighborhoodSize, sizeof(int), 1, fp); + m_pNeighborhoodGraph.Initialize(m_iGraphSize, m_iNeighborhoodSize); + m_dataUpdateLock.resize(m_iGraphSize); + + for (int i = 0; i < m_iGraphSize; i++) + { + fread((m_pNeighborhoodGraph)[i], sizeof(int), m_iNeighborhoodSize, fp); + } + fclose(fp); + std::cout << "Load Graph (" << m_iGraphSize << "," << m_iNeighborhoodSize << ") Finish!" << std::endl; + return true; + } + + bool LoadGraphFromMemory(char* pGraphMemFile) + { + m_iGraphSize = *((int*)pGraphMemFile); + pGraphMemFile += sizeof(int); + + m_iNeighborhoodSize = *((int*)pGraphMemFile); + pGraphMemFile += sizeof(int); + + m_pNeighborhoodGraph.Initialize(m_iGraphSize, m_iNeighborhoodSize, (int*)pGraphMemFile); + m_dataUpdateLock.resize(m_iGraphSize); + return true; + } + + bool SaveGraph(std::string sGraphFilename) const + { + std::cout << "Save Graph To " << sGraphFilename << std::endl; + FILE *fp = fopen(sGraphFilename.c_str(), "wb"); + if (fp == NULL) return false; + + fwrite(&m_iGraphSize, sizeof(int), 1, fp); + fwrite(&m_iNeighborhoodSize, sizeof(int), 1, fp); + for (int i = 0; i < m_iGraphSize; i++) + { + fwrite((m_pNeighborhoodGraph)[i], sizeof(int), m_iNeighborhoodSize, fp); + } + fclose(fp); + std::cout << "Save Graph (" << m_iGraphSize << "," << m_iNeighborhoodSize << ") Finish!" << std::endl; + return true; + } + + bool SaveGraphToMemory(void **pGraphMemFile, int64_t &len) { + size_t size = sizeof(int) + sizeof(int) + sizeof(int) * m_iNeighborhoodSize * m_iGraphSize; + char *mem = (char*)malloc(size); + if (mem == NULL) return false; + + auto ptr = mem; + *(int*)ptr = m_iGraphSize; + ptr += sizeof(int); + + *(int*)ptr = m_iNeighborhoodSize; + ptr += sizeof(int); + + for (int i = 0; i < m_iGraphSize; i++) + { + memcpy(ptr, (m_pNeighborhoodGraph)[i], sizeof(int) * m_iNeighborhoodSize); + ptr += sizeof(int) * m_iNeighborhoodSize; + } + *pGraphMemFile = mem; + len = size; + + return true; + } + + inline void AddBatch(int num) { m_pNeighborhoodGraph.AddBatch(num); m_iGraphSize += num; m_dataUpdateLock.resize(m_iGraphSize); } + + inline int* operator[](int index) { return m_pNeighborhoodGraph[index]; } + + inline const int* operator[](int index) const { return m_pNeighborhoodGraph[index]; } + + inline void SetR(int rows) { m_pNeighborhoodGraph.SetR(rows); m_iGraphSize = rows; m_dataUpdateLock.resize(m_iGraphSize); } + + inline int R() const { return m_iGraphSize; } + + static std::shared_ptr CreateInstance(std::string type); + + protected: + // Graph structure + int m_iGraphSize; + COMMON::Dataset m_pNeighborhoodGraph; + COMMON::FineGrainedLock m_dataUpdateLock; // protect one row of the graph + + public: + int m_iTPTNumber, m_iTPTLeafSize, m_iSamples, m_numTopDimensionTPTSplit; + int m_iNeighborhoodSize, m_iNeighborhoodScale, m_iCEFScale, m_iRefineIter, m_iCEF, m_iMaxCheckForRefineGraph; + }; + } +} +#endif diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common/QueryResultSet.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common/QueryResultSet.h new file mode 100644 index 0000000000..1e66287892 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common/QueryResultSet.h @@ -0,0 +1,96 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_COMMON_QUERYRESULTSET_H_ +#define _SPTAG_COMMON_QUERYRESULTSET_H_ + +#include "../SearchQuery.h" + +namespace SPTAG +{ +namespace COMMON +{ + +inline bool operator < (const BasicResult& lhs, const BasicResult& rhs) +{ + return ((lhs.Dist < rhs.Dist) || ((lhs.Dist == rhs.Dist) && (lhs.VID < rhs.VID))); +} + + +inline bool Compare(const BasicResult& lhs, const BasicResult& rhs) +{ + return ((lhs.Dist < rhs.Dist) || ((lhs.Dist == rhs.Dist) && (lhs.VID < rhs.VID))); +} + + +// Space to save temporary answer, similar with TopKCache +template +class QueryResultSet : public QueryResult +{ +public: + QueryResultSet(const T* _target, int _K) : QueryResult(_target, _K, false) + { + } + + QueryResultSet(const QueryResultSet& other) : QueryResult(other) + { + } + + inline void SetTarget(const T *p_target) + { + m_target = p_target; + } + + inline const T* GetTarget() const + { + return reinterpret_cast(m_target); + } + + inline float worstDist() const + { + return m_results[0].Dist; + } + + bool AddPoint(const int index, float dist) + { + if (dist < m_results[0].Dist || (dist == m_results[0].Dist && index < m_results[0].VID)) + { + m_results[0].VID = index; + m_results[0].Dist = dist; + Heapify(m_resultNum); + return true; + } + return false; + } + + inline void SortResult() + { + for (int i = m_resultNum - 1; i >= 0; i--) + { + std::swap(m_results[0], m_results[i]); + Heapify(i); + } + } + +private: + void Heapify(int count) + { + int parent = 0, next = 1, maxidx = count - 1; + while (next < maxidx) + { + if (m_results[next] < m_results[next + 1]) next++; + if (m_results[parent] < m_results[next]) + { + std::swap(m_results[next], m_results[parent]); + parent = next; + next = (parent << 1) + 1; + } + else break; + } + if (next == maxidx && m_results[parent] < m_results[next]) std::swap(m_results[parent], m_results[next]); + } +}; +} +} + +#endif // _SPTAG_COMMON_QUERYRESULTSET_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common/RelativeNeighborhoodGraph.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common/RelativeNeighborhoodGraph.h new file mode 100644 index 0000000000..4992508644 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common/RelativeNeighborhoodGraph.h @@ -0,0 +1,123 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_COMMON_RNG_H_ +#define _SPTAG_COMMON_RNG_H_ + +#include "NeighborhoodGraph.h" + +namespace SPTAG +{ + namespace COMMON + { + class RelativeNeighborhoodGraph: public NeighborhoodGraph + { + public: + void RebuildNeighbors(VectorIndex* index, const int node, int* nodes, const BasicResult* queryResults, const int numResults) { + int count = 0; + for (int j = 0; j < numResults && count < m_iNeighborhoodSize; j++) { + const BasicResult& item = queryResults[j]; + if (item.VID < 0) break; + if (item.VID == node) continue; + + bool good = true; + for (int k = 0; k < count; k++) { + if (index->ComputeDistance(index->GetSample(nodes[k]), index->GetSample(item.VID)) <= item.Dist) { + good = false; + break; + } + } + if (good) nodes[count++] = item.VID; + } + for (int j = count; j < m_iNeighborhoodSize; j++) nodes[j] = -1; + } + + void InsertNeighbors(VectorIndex* index, const int node, int insertNode, float insertDist) + { + int* nodes = m_pNeighborhoodGraph[node]; + for (int k = 0; k < m_iNeighborhoodSize; k++) + { + int tmpNode = nodes[k]; + if (tmpNode < -1) continue; + + if (tmpNode < 0) + { + bool good = true; + for (int t = 0; t < k; t++) { + if (index->ComputeDistance(index->GetSample(insertNode), index->GetSample(nodes[t])) < insertDist) { + good = false; + break; + } + } + if (good) { + nodes[k] = insertNode; + } + break; + } + float tmpDist = index->ComputeDistance(index->GetSample(node), index->GetSample(tmpNode)); + if (insertDist < tmpDist || (insertDist == tmpDist && insertNode < tmpNode)) + { + bool good = true; + for (int t = 0; t < k; t++) { + if (index->ComputeDistance(index->GetSample(insertNode), index->GetSample(nodes[t])) < insertDist) { + good = false; + break; + } + } + if (good) { + nodes[k] = insertNode; + insertNode = tmpNode; + insertDist = tmpDist; + } + else { + break; + } + } + } + } + + float GraphAccuracyEstimation(VectorIndex* index, const int samples, const std::unordered_map* idmap = nullptr) + { + int* correct = new int[samples]; + +#pragma omp parallel for schedule(dynamic) + for (int i = 0; i < samples; i++) + { + int x = COMMON::Utils::rand_int(m_iGraphSize); + //int x = i; + COMMON::QueryResultSet query(nullptr, m_iCEF); + for (int y = 0; y < m_iGraphSize; y++) + { + if ((idmap != nullptr && idmap->find(y) != idmap->end())) continue; + float dist = index->ComputeDistance(index->GetSample(x), index->GetSample(y)); + query.AddPoint(y, dist); + } + query.SortResult(); + int * exact_rng = new int[m_iNeighborhoodSize]; + RebuildNeighbors(index, x, exact_rng, query.GetResults(), m_iCEF); + + correct[i] = 0; + for (int j = 0; j < m_iNeighborhoodSize; j++) { + if (exact_rng[j] == -1) { + correct[i] += m_iNeighborhoodSize - j; + break; + } + for (int k = 0; k < m_iNeighborhoodSize; k++) + if ((m_pNeighborhoodGraph)[x][k] == exact_rng[j]) { + correct[i]++; + break; + } + } + delete[] exact_rng; + } + float acc = 0; + for (int i = 0; i < samples; i++) acc += float(correct[i]); + acc = acc / samples / m_iNeighborhoodSize; + delete[] correct; + return acc; + } + + }; + } +} +#endif \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common/WorkSpace.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common/WorkSpace.h new file mode 100644 index 0000000000..74d0a5039b --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common/WorkSpace.h @@ -0,0 +1,185 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_COMMON_WORKSPACE_H_ +#define _SPTAG_COMMON_WORKSPACE_H_ + +#include "CommonUtils.h" +#include "Heap.h" + +namespace SPTAG +{ + namespace COMMON + { + // node type in the priority queue + struct HeapCell + { + int node; + float distance; + + HeapCell(int _node = -1, float _distance = MaxDist) : node(_node), distance(_distance) {} + + inline bool operator < (const HeapCell& rhs) + { + return distance < rhs.distance; + } + + inline bool operator > (const HeapCell& rhs) + { + return distance > rhs.distance; + } + }; + + class OptHashPosVector + { + protected: + // Max loop number in one hash block. + static const int m_maxLoop = 8; + + // Max pool size. + static const int m_poolSize = 8191; + + // Could we use the second hash block. + bool m_secondHash; + + // Record 2 hash tables. + // [0~m_poolSize + 1) is the first block. + // [m_poolSize + 1, 2*(m_poolSize + 1)) is the second block; + int m_hashTable[(m_poolSize + 1) * 2]; + + + inline unsigned hash_func2(int idx, int loop) + { + return ((unsigned)idx + loop) & m_poolSize; + } + + + inline unsigned hash_func(unsigned idx) + { + return ((unsigned)(idx * 99991) + _rotl(idx, 2) + 101) & m_poolSize; + } + + public: + OptHashPosVector() {} + + ~OptHashPosVector() {} + + + void Init(int size) + { + m_secondHash = true; + clear(); + } + + void clear() + { + if (!m_secondHash) + { + // Clear first block. + memset(&m_hashTable[0], 0, sizeof(int)*(m_poolSize + 1)); + } + else + { + // Clear all blocks. + memset(&m_hashTable[0], 0, 2 * sizeof(int) * (m_poolSize + 1)); + m_secondHash = false; + } + } + + + inline bool CheckAndSet(int idx) + { + // Inner Index is begin from 1 + return _CheckAndSet(&m_hashTable[0], idx + 1) == 0; + } + + + inline int _CheckAndSet(int* hashTable, int idx) + { + unsigned index, loop; + + // Get first hash position. + index = hash_func(idx); + for (loop = 0; loop < m_maxLoop; ++loop) + { + if (!hashTable[index]) + { + // index first match and record it. + hashTable[index] = idx; + return 1; + } + if (hashTable[index] == idx) + { + // Hit this item in hash table. + return 0; + } + // Get next hash position. + index = hash_func2(index, loop); + } + + if (hashTable == &m_hashTable[0]) + { + // Use second hash block. + m_secondHash = true; + return _CheckAndSet(&m_hashTable[m_poolSize + 1], idx); + } + + // Do not include this item. + return -1; + } + }; + + // Variables for each single NN search + struct WorkSpace + { + void Initialize(int maxCheck, int dataSize) + { + nodeCheckStatus.Init(dataSize); + m_SPTQueue.Resize(maxCheck * 10); + m_NGQueue.Resize(maxCheck * 30); + + m_iNumberOfTreeCheckedLeaves = 0; + m_iNumberOfCheckedLeaves = 0; + m_iContinuousLimit = maxCheck / 64; + m_iMaxCheck = maxCheck; + m_iNumOfContinuousNoBetterPropagation = 0; + } + + void Reset(int maxCheck) + { + nodeCheckStatus.clear(); + m_SPTQueue.clear(); + m_NGQueue.clear(); + + m_iNumberOfTreeCheckedLeaves = 0; + m_iNumberOfCheckedLeaves = 0; + m_iContinuousLimit = maxCheck / 64; + m_iMaxCheck = maxCheck; + m_iNumOfContinuousNoBetterPropagation = 0; + } + + inline bool CheckAndSet(int idx) + { + return nodeCheckStatus.CheckAndSet(idx); + } + + OptHashPosVector nodeCheckStatus; + //OptHashPosVector nodeCheckStatus; + + // counter for dynamic pivoting + int m_iNumOfContinuousNoBetterPropagation; + int m_iContinuousLimit; + int m_iNumberOfTreeCheckedLeaves; + int m_iNumberOfCheckedLeaves; + int m_iMaxCheck; + + // Prioriy queue used for neighborhood graph + Heap m_NGQueue; + + // Priority queue Used for BKT-Tree + Heap m_SPTQueue; + }; + } +} + +#endif // _SPTAG_COMMON_WORKSPACE_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common/WorkSpacePool.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common/WorkSpacePool.h new file mode 100644 index 0000000000..9a7154e693 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/Common/WorkSpacePool.h @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_COMMON_WORKSPACEPOOL_H_ +#define _SPTAG_COMMON_WORKSPACEPOOL_H_ + +#include "WorkSpace.h" + +#include +#include + +namespace SPTAG +{ +namespace COMMON +{ + +class WorkSpacePool +{ +public: + WorkSpacePool(int p_maxCheck, int p_vectorCount); + + virtual ~WorkSpacePool(); + + std::shared_ptr Rent(); + + void Return(const std::shared_ptr& p_workSpace); + + void Init(int size); + +private: + std::list> m_workSpacePool; + + std::mutex m_workSpacePoolMutex; + + int m_maxCheck; + + int m_vectorCount; +}; + +} +} + +#endif // _SPTAG_COMMON_WORKSPACEPOOL_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/CommonDataStructure.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/CommonDataStructure.h new file mode 100644 index 0000000000..74d7980f4b --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/CommonDataStructure.h @@ -0,0 +1,56 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_COMMONDATASTRUCTURE_H_ +#define _SPTAG_COMMONDATASTRUCTURE_H_ + +#include "Common.h" + +namespace SPTAG +{ + +class ByteArray +{ +public: + ByteArray(); + + ByteArray(ByteArray&& p_right); + + ByteArray(std::uint8_t* p_array, std::size_t p_length, bool p_transferOnwership); + + ByteArray(std::uint8_t* p_array, std::size_t p_length, std::shared_ptr p_dataHolder); + + ByteArray(const ByteArray& p_right); + + ByteArray& operator= (const ByteArray& p_right); + + ByteArray& operator= (ByteArray&& p_right); + + ~ByteArray(); + + static ByteArray Alloc(std::size_t p_length); + + std::uint8_t* Data() const; + + std::size_t Length() const; + + void SetData(std::uint8_t* p_array, std::size_t p_length); + + std::shared_ptr DataHolder() const; + + void Clear(); + + const static ByteArray c_empty; + +private: + std::uint8_t* m_data; + + std::size_t m_length; + + // Notice this is holding an array. Set correct deleter for this. + std::shared_ptr m_dataHolder; +}; + +} // namespace SPTAG + +#endif // _SPTAG_COMMONDATASTRUCTURE_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/DefinitionList.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/DefinitionList.h new file mode 100644 index 0000000000..f5b66422d7 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/DefinitionList.h @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifdef DefineVectorValueType + +DefineVectorValueType(Int8, std::int8_t) +DefineVectorValueType(UInt8, std::uint8_t) +DefineVectorValueType(Int16, std::int16_t) +DefineVectorValueType(Float, float) + +#endif // DefineVectorValueType + + +#ifdef DefineDistCalcMethod + +DefineDistCalcMethod(L2) +DefineDistCalcMethod(Cosine) + +#endif // DefineDistCalcMethod + + +#ifdef DefineErrorCode + +// 0x0000 ~ 0x0FFF General Status +DefineErrorCode(Success, 0x0000) +DefineErrorCode(Fail, 0x0001) +DefineErrorCode(FailedOpenFile, 0x0002) +DefineErrorCode(FailedCreateFile, 0x0003) +DefineErrorCode(ParamNotFound, 0x0010) +DefineErrorCode(FailedParseValue, 0x0011) + +// 0x1000 ~ 0x1FFF Index Build Status + +// 0x2000 ~ 0x2FFF Index Serve Status + +// 0x3000 ~ 0x3FFF Helper Function Status +DefineErrorCode(ReadIni_FailedParseSection, 0x3000) +DefineErrorCode(ReadIni_FailedParseParam, 0x3001) +DefineErrorCode(ReadIni_DuplicatedSection, 0x3002) +DefineErrorCode(ReadIni_DuplicatedParam, 0x3003) + + +// 0x4000 ~ 0x4FFF Socket Library Status +DefineErrorCode(Socket_FailedResolveEndPoint, 0x4000) +DefineErrorCode(Socket_FailedConnectToEndPoint, 0x4001) + + +#endif // DefineErrorCode + + + +#ifdef DefineIndexAlgo + +DefineIndexAlgo(BKT) +DefineIndexAlgo(KDT) + +#endif // DefineIndexAlgo diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/KDT/Index.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/KDT/Index.h new file mode 100644 index 0000000000..7ab4b8daec --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/KDT/Index.h @@ -0,0 +1,112 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_KDT_INDEX_H_ +#define _SPTAG_KDT_INDEX_H_ + +#include "../Common.h" +#include "../VectorIndex.h" + +#include "../Common/CommonUtils.h" +#include "../Common/DistanceUtils.h" +#include "../Common/QueryResultSet.h" +#include "../Common/Dataset.h" +#include "../Common/WorkSpace.h" +#include "../Common/WorkSpacePool.h" +#include "../Common/RelativeNeighborhoodGraph.h" +#include "../Common/KDTree.h" +#include "inc/Helper/StringConvert.h" +#include "inc/Helper/SimpleIniReader.h" + +#include +#include +#include + +namespace SPTAG +{ + + namespace Helper + { + class IniReader; + } + + namespace KDT + { + template + class Index : public VectorIndex + { + private: + // data points + COMMON::Dataset m_pSamples; + + // KDT structures. + COMMON::KDTree m_pTrees; + + // Graph structure + COMMON::RelativeNeighborhoodGraph m_pGraph; + + std::string m_sKDTFilename; + std::string m_sGraphFilename; + std::string m_sDataPointsFilename; + + std::mutex m_dataLock; // protect data and graph + tbb::concurrent_unordered_set m_deletedID; + std::unique_ptr m_workSpacePool; + + int m_iNumberOfThreads; + DistCalcMethod m_iDistCalcMethod; + float(*m_fComputeDistance)(const T* pX, const T* pY, int length); + + int m_iMaxCheck; + int m_iThresholdOfNumberOfContinuousNoBetterPropagation; + int m_iNumberOfInitialDynamicPivots; + int m_iNumberOfOtherDynamicPivots; + public: + Index() + { +#define DefineKDTParameter(VarName, VarType, DefaultValue, RepresentStr) \ + VarName = DefaultValue; \ + +#include "inc/Core/KDT/ParameterDefinitionList.h" +#undef DefineKDTParameter + + m_fComputeDistance = COMMON::DistanceCalcSelector(m_iDistCalcMethod); + } + + ~Index() {} + + inline int GetNumSamples() const { return m_pSamples.R(); } + inline int GetFeatureDim() const { return m_pSamples.C(); } + + inline int GetCurrMaxCheck() const { return m_iMaxCheck; } + inline int GetNumThreads() const { return m_iNumberOfThreads; } + inline DistCalcMethod GetDistCalcMethod() const { return m_iDistCalcMethod; } + inline IndexAlgoType GetIndexAlgoType() const { return IndexAlgoType::KDT; } + inline VectorValueType GetVectorValueType() const { return GetEnumValueType(); } + + inline float ComputeDistance(const void* pX, const void* pY) const { return m_fComputeDistance((const T*)pX, (const T*)pY, m_pSamples.C()); } + inline const void* GetSample(const int idx) const { return (void*)m_pSamples[idx]; } + + ErrorCode BuildIndex(const void* p_data, int p_vectorNum, int p_dimension); + + ErrorCode SaveIndexToMemory(std::vector& p_indexBlobs, std::vector& p_indexBlobsLen); + ErrorCode LoadIndexFromMemory(const std::vector& p_indexBlobs); + + ErrorCode SaveIndex(const std::string& p_folderPath, std::ofstream& p_configout); + ErrorCode LoadIndex(const std::string& p_folderPath, Helper::IniReader& p_reader); + ErrorCode SearchIndex(QueryResult &p_query) const; + ErrorCode AddIndex(const void* p_vectors, int p_vectorNum, int p_dimension); + ErrorCode DeleteIndex(const void* p_vectors, int p_vectorNum); + + ErrorCode SetParameter(const char* p_param, const char* p_value); + std::string GetParameter(const char* p_param) const; + + private: + ErrorCode RefineIndex(const std::string& p_folderPath); + void SearchIndexWithDeleted(COMMON::QueryResultSet &p_query, COMMON::WorkSpace &p_space, const tbb::concurrent_unordered_set &p_deleted) const; + void SearchIndexWithoutDeleted(COMMON::QueryResultSet &p_query, COMMON::WorkSpace &p_space) const; + }; + } // namespace KDT +} // namespace SPTAG + +#endif // _SPTAG_KDT_INDEX_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/KDT/ParameterDefinitionList.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/KDT/ParameterDefinitionList.h new file mode 100644 index 0000000000..70d70ccbe7 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/KDT/ParameterDefinitionList.h @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifdef DefineKDTParameter + +// DefineKDTParameter(VarName, VarType, DefaultValue, RepresentStr) +DefineKDTParameter(m_sKDTFilename, std::string, std::string("tree.bin"), "TreeFilePath") +DefineKDTParameter(m_sGraphFilename, std::string, std::string("graph.bin"), "GraphFilePath") +DefineKDTParameter(m_sDataPointsFilename, std::string, std::string("vectors.bin"), "VectorFilePath") + +DefineKDTParameter(m_pTrees.m_iTreeNumber, int, 1L, "KDTNumber") +DefineKDTParameter(m_pTrees.m_numTopDimensionKDTSplit, int, 5L, "NumTopDimensionKDTSplit") +DefineKDTParameter(m_pTrees.m_iSamples, int, 100L, "NumSamplesKDTSplitConsideration") + +DefineKDTParameter(m_pGraph.m_iTPTNumber, int, 32L, "TPTNumber") +DefineKDTParameter(m_pGraph.m_iTPTLeafSize, int, 2000L, "TPTLeafSize") +DefineKDTParameter(m_pGraph.m_numTopDimensionTPTSplit, int, 5L, "NumTopDimensionTPTSplit") + +DefineKDTParameter(m_pGraph.m_iNeighborhoodSize, int, 32L, "NeighborhoodSize") +DefineKDTParameter(m_pGraph.m_iNeighborhoodScale, int, 2L, "GraphNeighborhoodScale") +DefineKDTParameter(m_pGraph.m_iCEFScale, int, 2L, "GraphCEFScale") +DefineKDTParameter(m_pGraph.m_iRefineIter, int, 0L, "RefineIterations") +DefineKDTParameter(m_pGraph.m_iCEF, int, 1000L, "CEF") +DefineKDTParameter(m_pGraph.m_iMaxCheckForRefineGraph, int, 10000L, "MaxCheckForRefineGraph") + +DefineKDTParameter(m_iNumberOfThreads, int, 1L, "NumberOfThreads") +DefineKDTParameter(m_iDistCalcMethod, SPTAG::DistCalcMethod, SPTAG::DistCalcMethod::Cosine, "DistCalcMethod") + +DefineKDTParameter(m_iMaxCheck, int, 8192L, "MaxCheck") +DefineKDTParameter(m_iThresholdOfNumberOfContinuousNoBetterPropagation, int, 3L, "ThresholdOfNumberOfContinuousNoBetterPropagation") +DefineKDTParameter(m_iNumberOfInitialDynamicPivots, int, 50L, "NumberOfInitialDynamicPivots") +DefineKDTParameter(m_iNumberOfOtherDynamicPivots, int, 4L, "NumberOfOtherDynamicPivots") + +#endif diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/MetadataSet.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/MetadataSet.h new file mode 100644 index 0000000000..7b7baed50d --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/MetadataSet.h @@ -0,0 +1,114 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_METADATASET_H_ +#define _SPTAG_METADATASET_H_ + +#include "CommonDataStructure.h" + +#include +#include + +namespace SPTAG +{ + +class MetadataSet +{ +public: + MetadataSet(); + + virtual ~MetadataSet(); + + virtual ByteArray GetMetadata(IndexType p_vectorID) const = 0; + + virtual SizeType Count() const = 0; + + virtual bool Available() const = 0; + + virtual void AddBatch(MetadataSet& data) = 0; + + virtual ErrorCode SaveMetadata(const std::string& p_metaFile, const std::string& p_metaindexFile) = 0; + + virtual ErrorCode SaveMetadataToMemory(void **pGraphMemFile, int64_t &len) = 0; + + virtual ErrorCode LoadMetadataFromMemory(void *pGraphMemFile) = 0; + + virtual ErrorCode RefineMetadata(std::vector& indices, const std::string& p_folderPath); + + static ErrorCode MetaCopy(const std::string& p_src, const std::string& p_dst); +}; + + +class FileMetadataSet : public MetadataSet +{ +public: + FileMetadataSet(const std::string& p_metaFile, const std::string& p_metaindexFile); + + ~FileMetadataSet(); + + ByteArray GetMetadata(IndexType p_vectorID) const; + + SizeType Count() const; + + bool Available() const; + + void AddBatch(MetadataSet& data); + + ErrorCode SaveMetadata(const std::string& p_metaFile, const std::string& p_metaindexFile); + + ErrorCode SaveMetadataToMemory(void **pGraphMemFile, int64_t &len); + + ErrorCode LoadMetadataFromMemory(void *pGraphMemFile); +private: + std::ifstream* m_fp = nullptr; + + std::vector m_pOffsets; + + SizeType m_count; + + std::string m_metaFile; + + std::string m_metaindexFile; + + std::vector m_newdata; +}; + + +class MemMetadataSet : public MetadataSet +{ +public: + MemMetadataSet() = default; + + MemMetadataSet(ByteArray p_metadata, ByteArray p_offsets, SizeType p_count); + + ~MemMetadataSet(); + + ByteArray GetMetadata(IndexType p_vectorID) const; + + SizeType Count() const; + + bool Available() const; + + void AddBatch(MetadataSet& data); + + ErrorCode SaveMetadata(const std::string& p_metaFile, const std::string& p_metaindexFile); + + ErrorCode SaveMetadataToMemory(void **pGraphMemFile, int64_t &len); + + ErrorCode LoadMetadataFromMemory(void *pGraphMemFile); +private: + std::vector m_offsets; + + SizeType m_count; + + ByteArray m_metadataHolder; + + ByteArray m_offsetHolder; + + std::vector m_newdata; +}; + + +} // namespace SPTAG + +#endif // _SPTAG_METADATASET_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/SearchQuery.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/SearchQuery.h new file mode 100644 index 0000000000..ede82cc938 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/SearchQuery.h @@ -0,0 +1,239 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_SEARCHQUERY_H_ +#define _SPTAG_SEARCHQUERY_H_ + +#include "CommonDataStructure.h" + +#include + +namespace SPTAG +{ + + struct BasicResult + { + int VID; + float Dist; + + BasicResult() : VID(-1), Dist(MaxDist) {} + + BasicResult(int p_vid, float p_dist) : VID(p_vid), Dist(p_dist) {} + }; + + +// Space to save temporary answer, similar with TopKCache +class QueryResult +{ +public: + typedef BasicResult* iterator; + typedef const BasicResult* const_iterator; + + QueryResult() + : m_target(nullptr), + m_resultNum(0), + m_withMeta(false) + { + } + + + QueryResult(const void* p_target, int p_resultNum, bool p_withMeta) + : m_target(nullptr), + m_resultNum(0), + m_withMeta(false) + { + Init(p_target, p_resultNum, p_withMeta); + } + + + QueryResult(const void* p_target, int p_resultNum, std::vector& p_results) + : m_target(p_target), + m_resultNum(p_resultNum), + m_withMeta(false) + { + p_results.resize(p_resultNum); + m_results.reset(p_results.data()); + } + + + QueryResult(const QueryResult& p_other) + : m_target(p_other.m_target), + m_resultNum(p_other.m_resultNum), + m_withMeta(p_other.m_withMeta) + { + if (m_resultNum > 0) + { + m_results.reset(new BasicResult[m_resultNum]); + std::memcpy(m_results.get(), p_other.m_results.get(), sizeof(BasicResult) * m_resultNum); + + if (m_withMeta) + { + m_metadatas.reset(new ByteArray[m_resultNum]); + std::copy(p_other.m_metadatas.get(), p_other.m_metadatas.get() + m_resultNum, m_metadatas.get()); + } + } + } + + + QueryResult& operator=(const QueryResult& p_other) + { + Init(p_other.m_target, p_other.m_resultNum, p_other.m_withMeta); + + if (m_resultNum > 0) + { + std::memcpy(m_results.get(), p_other.m_results.get(), sizeof(BasicResult) * m_resultNum); + if (m_withMeta) + { + std::copy(p_other.m_metadatas.get(), p_other.m_metadatas.get() + m_resultNum, m_metadatas.get()); + } + } + + return *this; + } + + + ~QueryResult() + { + } + + + inline void Init(const void* p_target, int p_resultNum, bool p_withMeta) + { + m_target = p_target; + if (p_resultNum > m_resultNum) + { + m_results.reset(new BasicResult[p_resultNum]); + } + + if (p_withMeta && (!m_withMeta || p_resultNum > m_resultNum)) + { + m_metadatas.reset(new ByteArray[p_resultNum]); + } + + m_resultNum = p_resultNum; + m_withMeta = p_withMeta; + } + + + inline int GetResultNum() const + { + return m_resultNum; + } + + + inline const void* GetTarget() + { + return m_target; + } + + + inline void SetTarget(const void* p_target) + { + m_target = p_target; + } + + + inline BasicResult* GetResult(int i) const + { + return i < m_resultNum ? m_results.get() + i : nullptr; + } + + + inline void SetResult(int p_index, int p_VID, float p_dist) + { + if (p_index < m_resultNum) + { + m_results[p_index].VID = p_VID; + m_results[p_index].Dist = p_dist; + } + } + + + inline BasicResult* GetResults() const + { + return m_results.get(); + } + + + inline bool WithMeta() const + { + return m_withMeta; + } + + + inline const ByteArray& GetMetadata(int p_index) const + { + if (p_index < m_resultNum && m_withMeta) + { + return m_metadatas[p_index]; + } + + return ByteArray::c_empty; + } + + + inline void SetMetadata(int p_index, ByteArray p_metadata) + { + if (p_index < m_resultNum && m_withMeta) + { + m_metadatas[p_index] = std::move(p_metadata); + } + } + + + inline void Reset() + { + for (int i = 0; i < m_resultNum; i++) + { + m_results[i].VID = -1; + m_results[i].Dist = MaxDist; + } + + if (m_withMeta) + { + for (int i = 0; i < m_resultNum; i++) + { + m_metadatas[i].Clear(); + } + } + } + + + iterator begin() + { + return m_results.get(); + } + + + iterator end() + { + return m_results.get() + m_resultNum; + } + + + const_iterator begin() const + { + return m_results.get(); + } + + + const_iterator end() const + { + return m_results.get() + m_resultNum; + } + + +protected: + const void* m_target; + + int m_resultNum; + + bool m_withMeta; + + std::unique_ptr m_results; + + std::unique_ptr m_metadatas; +}; +} // namespace SPTAG + +#endif // _SPTAG_SEARCHQUERY_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/VectorIndex.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/VectorIndex.h new file mode 100644 index 0000000000..5fc508e3ad --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/VectorIndex.h @@ -0,0 +1,94 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_VECTORINDEX_H_ +#define _SPTAG_VECTORINDEX_H_ + +#include "Common.h" +#include "SearchQuery.h" +#include "VectorSet.h" +#include "MetadataSet.h" +#include "inc/Helper/SimpleIniReader.h" + +namespace SPTAG +{ + +class VectorIndex +{ +public: + VectorIndex(); + + virtual ~VectorIndex(); + + virtual ErrorCode SaveIndex(const std::string& p_folderPath, std::ofstream& p_configout) = 0; + + virtual ErrorCode LoadIndex(const std::string& p_folderPath, Helper::IniReader& p_reader) = 0; + + virtual ErrorCode SaveIndexToMemory(std::vector& p_indexBlobs, std::vector& p_indexBlobsLen) = 0; + + virtual ErrorCode LoadIndexFromMemory(const std::vector& p_indexBlobs) = 0; + + virtual ErrorCode BuildIndex(const void* p_data, int p_vectorNum, int p_dimension) = 0; + + virtual ErrorCode SearchIndex(QueryResult& p_results) const = 0; + + virtual ErrorCode AddIndex(const void* p_vectors, int p_vectorNum, int p_dimension) = 0; + + virtual ErrorCode DeleteIndex(const void* p_vectors, int p_vectorNum) = 0; + + //virtual ErrorCode AddIndexWithID(const void* p_vector, const int& p_id) = 0; + + //virtual ErrorCode DeleteIndexWithID(const void* p_vector, const int& p_id) = 0; + + virtual float ComputeDistance(const void* pX, const void* pY) const = 0; + virtual const void* GetSample(const int idx) const = 0; + virtual int GetFeatureDim() const = 0; + virtual int GetNumSamples() const = 0; + + virtual DistCalcMethod GetDistCalcMethod() const = 0; + virtual IndexAlgoType GetIndexAlgoType() const = 0; + virtual VectorValueType GetVectorValueType() const = 0; + virtual int GetNumThreads() const = 0; + + virtual std::string GetParameter(const char* p_param) const = 0; + virtual ErrorCode SetParameter(const char* p_param, const char* p_value) = 0; + + virtual ErrorCode LoadIndex(const std::string& p_folderPath); + + virtual ErrorCode SaveIndex(const std::string& p_folderPath); + + virtual ErrorCode BuildIndex(std::shared_ptr p_vectorSet, std::shared_ptr p_metadataSet); + + virtual ErrorCode SearchIndex(const void* p_vector, int p_neighborCount, std::vector& p_results) const; + + virtual ErrorCode AddIndex(std::shared_ptr p_vectorSet, std::shared_ptr p_metadataSet); + + virtual std::string GetParameter(const std::string& p_param) const; + virtual ErrorCode SetParameter(const std::string& p_param, const std::string& p_value); + + virtual ByteArray GetMetadata(IndexType p_vectorID) const; + virtual void SetMetadata(const std::string& p_metadataFilePath, const std::string& p_metadataIndexPath); + + virtual std::string GetIndexName() const + { + if (m_sIndexName == "") + return Helper::Convert::ConvertToString(GetIndexAlgoType()); + return m_sIndexName; + } + virtual void SetIndexName(std::string p_name) { m_sIndexName = p_name; } + + static std::shared_ptr CreateInstance(IndexAlgoType p_algo, VectorValueType p_valuetype); + + static ErrorCode MergeIndex(const char* p_indexFilePath1, const char* p_indexFilePath2); + + static ErrorCode LoadIndex(const std::string& p_loaderFilePath, std::shared_ptr& p_vectorIndex); + +protected: + std::string m_sIndexName; + std::shared_ptr m_pMetadata; +}; + + +} // namespace SPTAG + +#endif // _SPTAG_VECTORINDEX_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/VectorSet.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/VectorSet.h new file mode 100644 index 0000000000..4d0727aa81 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Core/VectorSet.h @@ -0,0 +1,73 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_VECTORSET_H_ +#define _SPTAG_VECTORSET_H_ + +#include "CommonDataStructure.h" + +namespace SPTAG +{ + +class VectorSet +{ +public: + VectorSet(); + + virtual ~VectorSet(); + + virtual VectorValueType GetValueType() const = 0; + + virtual void* GetVector(IndexType p_vectorID) const = 0; + + virtual void* GetData() const = 0; + + virtual SizeType Dimension() const = 0; + + virtual SizeType Count() const = 0; + + virtual bool Available() const = 0; + + virtual ErrorCode Save(const std::string& p_vectorFile) const = 0; +}; + + +class BasicVectorSet : public VectorSet +{ +public: + BasicVectorSet(const ByteArray& p_bytesArray, + VectorValueType p_valueType, + SizeType p_dimension, + SizeType p_vectorCount); + + virtual ~BasicVectorSet(); + + virtual VectorValueType GetValueType() const; + + virtual void* GetVector(IndexType p_vectorID) const; + + virtual void* GetData() const; + + virtual SizeType Dimension() const; + + virtual SizeType Count() const; + + virtual bool Available() const; + + virtual ErrorCode Save(const std::string& p_vectorFile) const; + +private: + ByteArray m_data; + + VectorValueType m_valueType; + + SizeType m_dimension; + + SizeType m_vectorCount; + + SizeType m_perVectorDataSize; +}; + +} // namespace SPTAG + +#endif // _SPTAG_VECTORSET_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Helper/ArgumentsParser.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Helper/ArgumentsParser.h new file mode 100644 index 0000000000..0ae19b8e8f --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Helper/ArgumentsParser.h @@ -0,0 +1,253 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_HELPER_ARGUMENTSPARSER_H_ +#define _SPTAG_HELPER_ARGUMENTSPARSER_H_ + +#include "inc/Helper/StringConvert.h" + +#include +#include +#include +#include +#include + +namespace SPTAG +{ +namespace Helper +{ + +class ArgumentsParser +{ +public: + ArgumentsParser(); + + virtual ~ArgumentsParser(); + + virtual bool Parse(int p_argc, char** p_args); + + virtual void PrintHelp(); + +protected: + class IArgument + { + public: + IArgument(); + + virtual ~IArgument(); + + virtual bool ParseValue(int& p_restArgc, char** (&p_args)) = 0; + + virtual void PrintDescription(FILE* p_output) = 0; + + virtual bool IsRequiredButNotSet() const = 0; + }; + + + template + class ArgumentT : public IArgument + { + public: + ArgumentT(DataType& p_target, + const std::string& p_representStringShort, + const std::string& p_representString, + const std::string& p_description, + bool p_followedValue, + const DataType& p_switchAsValue, + bool p_isRequired) + : m_value(p_target), + m_representStringShort(p_representStringShort), + m_representString(p_representString), + m_description(p_description), + m_followedValue(p_followedValue), + c_switchAsValue(p_switchAsValue), + m_isRequired(p_isRequired), + m_isSet(false) + { + } + + virtual ~ArgumentT() + { + } + + + virtual bool ParseValue(int& p_restArgc, char** (&p_args)) + { + if (0 == p_restArgc) + { + return true; + } + + if (0 != strcmp(*p_args, m_representString.c_str()) + && 0 != strcmp(*p_args, m_representStringShort.c_str())) + { + return true; + } + + if (!m_followedValue) + { + m_value = c_switchAsValue; + --p_restArgc; + ++p_args; + m_isSet = true; + return true; + } + + if (p_restArgc < 2) + { + return false; + } + + DataType tmp; + if (!Helper::Convert::ConvertStringTo(p_args[1], tmp)) + { + return false; + } + + m_value = std::move(tmp); + + p_restArgc -= 2; + p_args += 2; + m_isSet = true; + return true; + } + + + virtual void PrintDescription(FILE* p_output) + { + std::size_t padding = 30; + if (!m_representStringShort.empty()) + { + fprintf(p_output, "%s", m_representStringShort.c_str()); + padding -= m_representStringShort.size(); + } + + if (!m_representString.empty()) + { + if (!m_representStringShort.empty()) + { + fprintf(p_output, ", "); + padding -= 2; + } + + fprintf(p_output, "%s", m_representString.c_str()); + padding -= m_representString.size(); + } + + if (m_followedValue) + { + fprintf(p_output, " "); + padding -= 8; + } + + while (padding-- > 0) + { + fputc(' ', p_output); + } + + fprintf(p_output, "%s", m_description.c_str()); + } + + + virtual bool IsRequiredButNotSet() const + { + return m_isRequired && !m_isSet; + } + + private: + DataType & m_value; + + std::string m_representStringShort; + + std::string m_representString; + + std::string m_description; + + bool m_followedValue; + + const DataType c_switchAsValue; + + bool m_isRequired; + + bool m_isSet; + }; + + + template + void AddRequiredOption(DataType& p_target, + const std::string& p_representStringShort, + const std::string& p_representString, + const std::string& p_description) + { + m_arguments.emplace_back(std::shared_ptr( + new ArgumentT(p_target, + p_representStringShort, + p_representString, + p_description, + true, + DataType(), + true))); + } + + + template + void AddOptionalOption(DataType& p_target, + const std::string& p_representStringShort, + const std::string& p_representString, + const std::string& p_description) + { + m_arguments.emplace_back(std::shared_ptr( + new ArgumentT(p_target, + p_representStringShort, + p_representString, + p_description, + true, + DataType(), + false))); + } + + + template + void AddRequiredSwitch(DataType& p_target, + const std::string& p_representStringShort, + const std::string& p_representString, + const std::string& p_description, + const DataType& p_switchAsValue) + { + m_arguments.emplace_back(std::shared_ptr( + new ArgumentT(p_target, + p_representStringShort, + p_representString, + p_description, + false, + p_switchAsValue, + true))); + } + + + template + void AddOptionalSwitch(DataType& p_target, + const std::string& p_representStringShort, + const std::string& p_representString, + const std::string& p_description, + const DataType& p_switchAsValue) + { + m_arguments.emplace_back(std::shared_ptr( + new ArgumentT(p_target, + p_representStringShort, + p_representString, + p_description, + false, + p_switchAsValue, + false))); + } + +private: + std::vector> m_arguments; +}; + + +} // namespace Helper +} // namespace SPTAG + +#endif // _SPTAG_HELPER_ARGUMENTSPARSER_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Helper/Base64Encode.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Helper/Base64Encode.h new file mode 100644 index 0000000000..8e7919345d --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Helper/Base64Encode.h @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_HELPER_BASE64ENCODE_H_ +#define _SPTAG_HELPER_BASE64ENCODE_H_ + +#include +#include +#include + +namespace SPTAG +{ +namespace Helper +{ +namespace Base64 +{ + +bool Encode(const std::uint8_t* p_in, std::size_t p_inLen, char* p_out, std::size_t& p_outLen); + +bool Encode(const std::uint8_t* p_in, std::size_t p_inLen, std::ostream& p_out, std::size_t& p_outLen); + +bool Decode(const char* p_in, std::size_t p_inLen, std::uint8_t* p_out, std::size_t& p_outLen); + +std::size_t CapacityForEncode(std::size_t p_inLen); + +std::size_t CapacityForDecode(std::size_t p_inLen); + + +} // namespace Base64 +} // namespace Helper +} // namespace SPTAG + +#endif // _SPTAG_HELPER_BASE64ENCODE_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Helper/CommonHelper.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Helper/CommonHelper.h new file mode 100644 index 0000000000..7f14784707 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Helper/CommonHelper.h @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_HELPER_COMMONHELPER_H_ +#define _SPTAG_HELPER_COMMONHELPER_H_ + +#include "../Core/Common.h" + +#include +#include +#include +#include +#include +#include + + +namespace SPTAG +{ +namespace Helper +{ +namespace StrUtils +{ + +void ToLowerInPlace(std::string& p_str); + +std::vector SplitString(const std::string& p_str, const std::string& p_separator); + +std::pair FindTrimmedSegment(const char* p_begin, + const char* p_end, + const std::function& p_isSkippedChar); + +bool StartsWith(const char* p_str, const char* p_prefix); + +bool StrEqualIgnoreCase(const char* p_left, const char* p_right); + +} // namespace StrUtils +} // namespace Helper +} // namespace SPTAG + +#endif // _SPTAG_HELPER_COMMONHELPER_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Helper/Concurrent.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Helper/Concurrent.h new file mode 100644 index 0000000000..35c7cc93e4 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Helper/Concurrent.h @@ -0,0 +1,97 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_HELPER_CONCURRENT_H_ +#define _SPTAG_HELPER_CONCURRENT_H_ + + +#include +#include +#include + + +namespace SPTAG +{ +namespace Helper +{ +namespace Concurrent +{ + +class SpinLock +{ +public: + SpinLock() = default; + + void Lock() noexcept + { + while (m_lock.test_and_set(std::memory_order_acquire)) + { + } + } + + void Unlock() noexcept + { + m_lock.clear(std::memory_order_release); + } + + SpinLock(const SpinLock&) = delete; + SpinLock& operator = (const SpinLock&) = delete; + +private: + std::atomic_flag m_lock = ATOMIC_FLAG_INIT; +}; + +template +class LockGuard { +public: + LockGuard(Lock& lock) noexcept + : m_lock(lock) { + lock.Lock(); + } + + LockGuard(Lock& lock, std::adopt_lock_t) noexcept + : m_lock(lock) {} + + ~LockGuard() { + m_lock.Unlock(); + } + + LockGuard(const LockGuard&) = delete; + LockGuard& operator=(const LockGuard&) = delete; + +private: + Lock& m_lock; +}; + + +class WaitSignal +{ +public: + WaitSignal(); + + WaitSignal(std::uint32_t p_unfinished); + + ~WaitSignal(); + + void Reset(std::uint32_t p_unfinished); + + void Wait(); + + void FinishOne(); + +private: + std::atomic m_unfinished; + + std::atomic_bool m_isWaiting; + + std::mutex m_mutex; + + std::condition_variable m_cv; +}; + + +} // namespace Base64 +} // namespace Helper +} // namespace SPTAG + +#endif // _SPTAG_HELPER_CONCURRENT_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Helper/SimpleIniReader.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Helper/SimpleIniReader.h new file mode 100644 index 0000000000..31b797aba9 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Helper/SimpleIniReader.h @@ -0,0 +1,97 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_HELPER_INIREADER_H_ +#define _SPTAG_HELPER_INIREADER_H_ + +#include "../Core/Common.h" +#include "StringConvert.h" + +#include +#include +#include +#include +#include + + +namespace SPTAG +{ +namespace Helper +{ + +// Simple INI Reader with basic functions. Case insensitive. +class IniReader +{ +public: + typedef std::map ParameterValueMap; + + IniReader(); + + ~IniReader(); + + ErrorCode LoadIniFile(const std::string& p_iniFilePath); + + bool DoesSectionExist(const std::string& p_section) const; + + bool DoesParameterExist(const std::string& p_section, const std::string& p_param) const; + + const ParameterValueMap& GetParameters(const std::string& p_section) const; + + template + DataType GetParameter(const std::string& p_section, const std::string& p_param, const DataType& p_defaultVal) const; + + void SetParameter(const std::string& p_section, const std::string& p_param, const std::string& p_val); + +private: + bool GetRawValue(const std::string& p_section, const std::string& p_param, std::string& p_value) const; + + template + static inline DataType ConvertStringTo(std::string&& p_str, const DataType& p_defaultVal); + +private: + const static ParameterValueMap c_emptyParameters; + + std::map> m_parameters; +}; + + +template +DataType +IniReader::GetParameter(const std::string& p_section, const std::string& p_param, const DataType& p_defaultVal) const +{ + std::string value; + if (!GetRawValue(p_section, p_param, value)) + { + return p_defaultVal; + } + + return ConvertStringTo(std::move(value), p_defaultVal); +} + + +template +inline DataType +IniReader::ConvertStringTo(std::string&& p_str, const DataType& p_defaultVal) +{ + DataType value; + if (Convert::ConvertStringTo(p_str.c_str(), value)) + { + return value; + } + + return p_defaultVal; +} + + +template <> +inline std::string +IniReader::ConvertStringTo(std::string&& p_str, const std::string& p_defaultVal) +{ + return std::move(p_str); +} + + +} // namespace Helper +} // namespace SPTAG + +#endif // _SPTAG_HELPER_INIREADER_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Helper/StringConvert.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Helper/StringConvert.h new file mode 100644 index 0000000000..b6e53df785 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Helper/StringConvert.h @@ -0,0 +1,374 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_HELPER_STRINGCONVERTHELPER_H_ +#define _SPTAG_HELPER_STRINGCONVERTHELPER_H_ + +#include "inc/Core/Common.h" +#include "CommonHelper.h" + +#include +#include +#include +#include +#include +#include + +namespace SPTAG +{ +namespace Helper +{ +namespace Convert +{ + +template +inline bool ConvertStringTo(const char* p_str, DataType& p_value) +{ + if (nullptr == p_str) + { + return false; + } + + std::istringstream sstream; + sstream.str(p_str); + if (p_str >> p_value) + { + return true; + } + + return false; +} + + +template +inline std::string ConvertToString(const DataType& p_value) +{ + return std::to_string(p_value); +} + + +// Specialization of ConvertStringTo<>(). + +template +inline bool ConvertStringToSignedInt(const char* p_str, DataType& p_value) +{ + static_assert(std::is_integral::value && std::is_signed::value, "type check"); + + if (nullptr == p_str) + { + return false; + } + + char* end = nullptr; + errno = 0; + auto val = std::strtoll(p_str, &end, 10); + if (errno == ERANGE || end == p_str || *end != '\0') + { + return false; + } + + if (val < (std::numeric_limits::min)() || val >(std::numeric_limits::max)()) + { + return false; + } + + p_value = static_cast(val); + return true; +} + + +template +inline bool ConvertStringToUnsignedInt(const char* p_str, DataType& p_value) +{ + static_assert(std::is_integral::value && std::is_unsigned::value, "type check"); + + if (nullptr == p_str) + { + return false; + } + + char* end = nullptr; + errno = 0; + auto val = std::strtoull(p_str, &end, 10); + if (errno == ERANGE || end == p_str || *end != '\0') + { + return false; + } + + if (val < (std::numeric_limits::min)() || val >(std::numeric_limits::max)()) + { + return false; + } + + p_value = static_cast(val); + return true; +} + + +template <> +inline bool ConvertStringTo(const char* p_str, std::string& p_value) +{ + if (nullptr == p_str) + { + return false; + } + + p_value = p_str; + return true; +} + + +template <> +inline bool ConvertStringTo(const char* p_str, float& p_value) +{ + if (nullptr == p_str) + { + return false; + } + + char* end = nullptr; + errno = 0; + p_value = std::strtof(p_str, &end); + return (errno != ERANGE && end != p_str && *end == '\0'); +} + + +template <> +inline bool ConvertStringTo(const char* p_str, double& p_value) +{ + if (nullptr == p_str) + { + return false; + } + + char* end = nullptr; + errno = 0; + p_value = std::strtod(p_str, &end); + return (errno != ERANGE && end != p_str && *end == '\0'); +} + + +template <> +inline bool ConvertStringTo(const char* p_str, std::int8_t& p_value) +{ + return ConvertStringToSignedInt(p_str, p_value); +} + + +template <> +inline bool ConvertStringTo(const char* p_str, std::int16_t& p_value) +{ + return ConvertStringToSignedInt(p_str, p_value); +} + + +template <> +inline bool ConvertStringTo(const char* p_str, std::int32_t& p_value) +{ + return ConvertStringToSignedInt(p_str, p_value); +} + + +template <> +inline bool ConvertStringTo(const char* p_str, std::int64_t& p_value) +{ + return ConvertStringToSignedInt(p_str, p_value); +} + + +template <> +inline bool ConvertStringTo(const char* p_str, std::uint8_t& p_value) +{ + return ConvertStringToUnsignedInt(p_str, p_value); +} + + +template <> +inline bool ConvertStringTo(const char* p_str, std::uint16_t& p_value) +{ + return ConvertStringToUnsignedInt(p_str, p_value); +} + + +template <> +inline bool ConvertStringTo(const char* p_str, std::uint32_t& p_value) +{ + return ConvertStringToUnsignedInt(p_str, p_value); +} + + +template <> +inline bool ConvertStringTo(const char* p_str, std::uint64_t& p_value) +{ + return ConvertStringToUnsignedInt(p_str, p_value); +} + + +template <> +inline bool ConvertStringTo(const char* p_str, bool& p_value) +{ + if (StrUtils::StrEqualIgnoreCase(p_str, "true")) + { + p_value = true; + + } + else if (StrUtils::StrEqualIgnoreCase(p_str, "false")) + { + p_value = false; + } + else + { + return false; + } + + return true; +} + + +template <> +inline bool ConvertStringTo(const char* p_str, IndexAlgoType& p_value) +{ + if (nullptr == p_str) + { + return false; + } + +#define DefineIndexAlgo(Name) \ + else if (StrUtils::StrEqualIgnoreCase(p_str, #Name)) \ + { \ + p_value = IndexAlgoType::Name; \ + return true; \ + } \ + +#include "inc/Core/DefinitionList.h" +#undef DefineIndexAlgo + + return false; +} + + +template <> +inline bool ConvertStringTo(const char* p_str, DistCalcMethod& p_value) +{ + if (nullptr == p_str) + { + return false; + } + +#define DefineDistCalcMethod(Name) \ + else if (StrUtils::StrEqualIgnoreCase(p_str, #Name)) \ + { \ + p_value = DistCalcMethod::Name; \ + return true; \ + } \ + +#include "inc/Core/DefinitionList.h" +#undef DefineDistCalcMethod + + return false; +} + + +template <> +inline bool ConvertStringTo(const char* p_str, VectorValueType& p_value) +{ + if (nullptr == p_str) + { + return false; + } + +#define DefineVectorValueType(Name, Type) \ + else if (StrUtils::StrEqualIgnoreCase(p_str, #Name)) \ + { \ + p_value = VectorValueType::Name; \ + return true; \ + } \ + +#include "inc/Core/DefinitionList.h" +#undef DefineVectorValueType + + return false; +} + + +// Specialization of ConvertToString<>(). + +template<> +inline std::string ConvertToString(const std::string& p_value) +{ + return p_value; +} + + +template<> +inline std::string ConvertToString(const bool& p_value) +{ + return p_value ? "true" : "false"; +} + + +template <> +inline std::string ConvertToString(const IndexAlgoType& p_value) +{ + switch (p_value) + { +#define DefineIndexAlgo(Name) \ + case IndexAlgoType::Name: \ + return #Name; \ + +#include "inc/Core/DefinitionList.h" +#undef DefineIndexAlgo + + default: + break; + } + + return "Undefined"; +} + + +template <> +inline std::string ConvertToString(const DistCalcMethod& p_value) +{ + switch (p_value) + { +#define DefineDistCalcMethod(Name) \ + case DistCalcMethod::Name: \ + return #Name; \ + +#include "inc/Core/DefinitionList.h" +#undef DefineDistCalcMethod + + default: + break; + } + + return "Undefined"; +} + + +template <> +inline std::string ConvertToString(const VectorValueType& p_value) +{ + switch (p_value) + { +#define DefineVectorValueType(Name, Type) \ + case VectorValueType::Name: \ + return #Name; \ + +#include "inc/Core/DefinitionList.h" +#undef DefineVectorValueType + + default: + break; + } + + return "Undefined"; +} + + +} // namespace Convert +} // namespace Helper +} // namespace SPTAG + +#endif // _SPTAG_HELPER_STRINGCONVERTHELPER_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/IndexBuilder/Options.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/IndexBuilder/Options.h new file mode 100644 index 0000000000..7c939efae5 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/IndexBuilder/Options.h @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_INDEXBUILDER_OPTIONS_H_ +#define _SPTAG_INDEXBUILDER_OPTIONS_H_ + +#include "inc/Core/Common.h" +#include "inc/Helper/ArgumentsParser.h" + +#include +#include +#include + +namespace SPTAG +{ +namespace IndexBuilder +{ + +class BuilderOptions : public Helper::ArgumentsParser +{ +public: + BuilderOptions(); + + ~BuilderOptions(); + + std::uint32_t m_threadNum; + + std::uint32_t m_dimension; + + std::string m_vectorDelimiter; + + SPTAG::VectorValueType m_inputValueType; + + std::string m_inputFiles; + + std::string m_outputFolder; + + SPTAG::IndexAlgoType m_indexAlgoType; + + std::string m_builderConfigFile; +}; + + +} // namespace IndexBuilder +} // namespace SPTAG + +#endif // _SPTAG_INDEXBUILDER_OPTIONS_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/IndexBuilder/ThreadPool.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/IndexBuilder/ThreadPool.h new file mode 100644 index 0000000000..7256f71ae5 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/IndexBuilder/ThreadPool.h @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_INDEXBUILDER_THREADPOOL_H_ +#define _SPTAG_INDEXBUILDER_THREADPOOL_H_ + +#include +#include + +namespace SPTAG +{ +namespace IndexBuilder +{ +namespace ThreadPool +{ + +void Init(std::uint32_t p_threadNum); + +bool Queue(std::function p_workItem); + +std::uint32_t CurrentThreadNum(); + +} +} // namespace IndexBuilder +} // namespace SPTAG + +#endif // _SPTAG_INDEXBUILDER_THREADPOOL_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/IndexBuilder/VectorSetReader.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/IndexBuilder/VectorSetReader.h new file mode 100644 index 0000000000..6bb3026aa0 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/IndexBuilder/VectorSetReader.h @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_INDEXBUILDER_VECTORSETREADER_H_ +#define _SPTAG_INDEXBUILDER_VECTORSETREADER_H_ + +#include "inc/Core/Common.h" +#include "inc/Core/VectorSet.h" +#include "inc/Core/MetadataSet.h" +#include "Options.h" + +#include + +namespace SPTAG +{ +namespace IndexBuilder +{ + +class VectorSetReader +{ +public: + VectorSetReader(std::shared_ptr p_options); + + virtual ~VectorSetReader(); + + virtual ErrorCode LoadFile(const std::string& p_filePath) = 0; + + virtual std::shared_ptr GetVectorSet() const = 0; + + virtual std::shared_ptr GetMetadataSet() const = 0; + + static std::shared_ptr CreateInstance(std::shared_ptr p_options); + +protected: + std::shared_ptr m_options; +}; + + + +} // namespace IndexBuilder +} // namespace SPTAG + +#endif // _SPTAG_INDEXBUILDER_VECTORSETREADER_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/IndexBuilder/VectorSetReaders/DefaultReader.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/IndexBuilder/VectorSetReaders/DefaultReader.h new file mode 100644 index 0000000000..e3e1911a9d --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/IndexBuilder/VectorSetReaders/DefaultReader.h @@ -0,0 +1,108 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_INDEXBUILDER_VECTORSETREADERS_DEFAULTREADER_H_ +#define _SPTAG_INDEXBUILDER_VECTORSETREADERS_DEFAULTREADER_H_ + +#include "../VectorSetReader.h" +#include "inc/Helper/Concurrent.h" + +#include +#include +#include + +namespace SPTAG +{ +namespace IndexBuilder +{ + +class DefaultReader : public VectorSetReader +{ +public: + DefaultReader(std::shared_ptr p_options); + + virtual ~DefaultReader(); + + virtual ErrorCode LoadFile(const std::string& p_filePaths); + + virtual std::shared_ptr GetVectorSet() const; + + virtual std::shared_ptr GetMetadataSet() const; + +private: + typedef std::pair FileInfoPair; + + static std::vector GetFileSizes(const std::string& p_filePaths); + + void LoadFileInternal(const std::string& p_filePath, + std::uint32_t p_subtaskID, + std::uint32_t p_fileBlockID, + std::size_t p_fileBlockSize); + + void MergeData(); + + template + bool TranslateVector(char* p_str, DataType* p_vector) + { + std::uint32_t eleCount = 0; + char* next = p_str; + while ((*next) != '\0') + { + while ((*next) != '\0' && m_options->m_vectorDelimiter.find(*next) == std::string::npos) + { + ++next; + } + + bool reachEnd = ('\0' == (*next)); + *next = '\0'; + if (p_str != next) + { + if (eleCount >= m_options->m_dimension) + { + return false; + } + + if (!Helper::Convert::ConvertStringTo(p_str, p_vector[eleCount++])) + { + return false; + } + } + + if (reachEnd) + { + break; + } + + ++next; + p_str = next; + } + + return eleCount == m_options->m_dimension; + } + +private: + std::uint32_t m_subTaskCount; + + std::size_t m_subTaskBlocksize; + + std::atomic m_totalRecordCount; + + std::atomic m_totalRecordVectorBytes; + + std::vector m_subTaskRecordCount; + + std::string m_vectorOutput; + + std::string m_metadataConentOutput; + + std::string m_metadataIndexOutput; + + Helper::Concurrent::WaitSignal m_waitSignal; +}; + + + +} // namespace IndexBuilder +} // namespace SPTAG + +#endif // _SPTAG_INDEXBUILDER_VECTORSETREADERS_DEFAULT_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Server/QueryParser.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Server/QueryParser.h new file mode 100644 index 0000000000..9444e40862 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Server/QueryParser.h @@ -0,0 +1,56 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_SERVER_QUERYPARSER_H_ +#define _SPTAG_SERVER_QUERYPARSER_H_ + +#include "../Core/Common.h" +#include "../Core/CommonDataStructure.h" + +#include + +namespace SPTAG +{ +namespace Service +{ + + +class QueryParser +{ +public: + typedef std::pair OptionPair; + + QueryParser(); + + ~QueryParser(); + + ErrorCode Parse(const std::string& p_query, const char* p_vectorSeparator); + + const std::vector& GetVectorElements() const; + + const std::vector& GetOptions() const; + + const char* GetVectorBase64() const; + + SizeType GetVectorBase64Length() const; + +private: + std::vector m_options; + + std::vector m_vectorElements; + + const char* m_vectorBase64; + + SizeType m_vectorBase64Length; + + ByteArray m_dataHolder; + + static const char* c_defaultVectorSeparator; +}; + + +} // namespace Server +} // namespace AnnService + + +#endif // _SPTAG_SERVER_QUERYPARSER_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Server/SearchExecutionContext.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Server/SearchExecutionContext.h new file mode 100644 index 0000000000..cba4df4651 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Server/SearchExecutionContext.h @@ -0,0 +1,80 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_SERVER_SEARCHEXECUTIONCONTEXT_H_ +#define _SPTAG_SERVER_SEARCHEXECUTIONCONTEXT_H_ + +#include "inc/Core/VectorIndex.h" +#include "inc/Core/SearchQuery.h" +#include "inc/Socket/RemoteSearchQuery.h" +#include "ServiceSettings.h" +#include "QueryParser.h" + +#include +#include +#include + + +namespace SPTAG +{ +namespace Service +{ + +typedef Socket::IndexSearchResult SearchResult; + +class SearchExecutionContext +{ +public: + SearchExecutionContext(const std::shared_ptr& p_serviceSettings); + + ~SearchExecutionContext(); + + ErrorCode ParseQuery(const std::string& p_query); + + ErrorCode ExtractOption(); + + ErrorCode ExtractVector(VectorValueType p_targetType); + + void AddResults(std::string p_indexName, QueryResult& p_results); + + std::vector& GetResults(); + + const std::vector& GetResults() const; + + const ByteArray& GetVector() const; + + const std::vector& GetSelectedIndexNames() const; + + const SizeType GetVectorDimension() const; + + const std::vector& GetOptions() const; + + const SizeType GetResultNum() const; + + const bool GetExtractMetadata() const; + +private: + const std::shared_ptr c_serviceSettings; + + QueryParser m_queryParser; + + std::vector m_indexNames; + + ByteArray m_vector; + + SizeType m_vectorDimension; + + std::vector m_results; + + VectorValueType m_inputValueType; + + bool m_extractMetadata; + + SizeType m_resultNum; +}; + +} // namespace Server +} // namespace AnnService + + +#endif // _SPTAG_SERVER_SEARCHEXECUTIONCONTEXT_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Server/SearchExecutor.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Server/SearchExecutor.h new file mode 100644 index 0000000000..201832651b --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Server/SearchExecutor.h @@ -0,0 +1,56 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_SERVER_SEARCHEXECUTOR_H_ +#define _SPTAG_SERVER_SEARCHEXECUTOR_H_ + +#include "ServiceContext.h" +#include "ServiceSettings.h" +#include "SearchExecutionContext.h" +#include "QueryParser.h" + +#include +#include +#include + +namespace SPTAG +{ +namespace Service +{ + +class SearchExecutor +{ +public: + typedef std::function)> CallBack; + + SearchExecutor(std::string p_queryString, + std::shared_ptr p_serviceContext, + const CallBack& p_callback); + + ~SearchExecutor(); + + void Execute(); + +private: + void ExecuteInternal(); + + void SelectIndex(); + +private: + CallBack m_callback; + + const std::shared_ptr c_serviceContext; + + std::shared_ptr m_executionContext; + + std::string m_queryString; + + std::vector> m_selectedIndex; +}; + + +} // namespace Server +} // namespace AnnService + + +#endif // _SPTAG_SERVER_SEARCHEXECUTOR_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Server/SearchService.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Server/SearchService.h new file mode 100644 index 0000000000..34d0c6064c --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Server/SearchService.h @@ -0,0 +1,73 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_SERVER_SERVICE_H_ +#define _SPTAG_SERVER_SERVICE_H_ + +#include "ServiceContext.h" +#include "../Socket/Server.h" + +#include + +#include +#include +#include +#include + +namespace SPTAG +{ +namespace Service +{ + +class SearchExecutionContext; + +class SearchService +{ +public: + SearchService(); + + ~SearchService(); + + bool Initialize(int p_argNum, char* p_args[]); + + void Run(); + +private: + void RunSocketMode(); + + void RunInteractiveMode(); + + void SearchHanlder(Socket::ConnectionID p_localConnectionID, Socket::Packet p_packet); + + void SearchHanlderCallback(std::shared_ptr p_exeContext, + Socket::Packet p_srcPacket); + +private: + enum class ServeMode : std::uint8_t + { + Interactive, + + Socket + }; + + std::shared_ptr m_serviceContext; + + std::shared_ptr m_socketServer; + + bool m_initialized; + + ServeMode m_serveMode; + + std::unique_ptr m_threadPool; + + boost::asio::io_context m_ioContext; + + boost::asio::signal_set m_shutdownSignals; +}; + + +} // namespace Server +} // namespace AnnService + + +#endif // _SPTAG_SERVER_SERVICE_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Server/ServiceContext.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Server/ServiceContext.h new file mode 100644 index 0000000000..b1a7b84045 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Server/ServiceContext.h @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_SERVER_SERVICECONTEX_H_ +#define _SPTAG_SERVER_SERVICECONTEX_H_ + +#include "inc/Core/VectorIndex.h" +#include "ServiceSettings.h" + +#include +#include + +namespace SPTAG +{ +namespace Service +{ + +class ServiceContext +{ +public: + ServiceContext(const std::string& p_configFilePath); + + ~ServiceContext(); + + const std::map>& GetIndexMap() const; + + const std::shared_ptr& GetServiceSettings() const; + + bool IsInitialized() const; + +private: + bool m_initialized; + + std::shared_ptr m_settings; + + std::map> m_fullIndexList; +}; + + +} // namespace Server +} // namespace AnnService + +#endif // _SPTAG_SERVER_SERVICECONTEX_H_ + diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Server/ServiceSettings.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Server/ServiceSettings.h new file mode 100644 index 0000000000..9077487355 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Server/ServiceSettings.h @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_SERVER_SERVICESTTINGS_H_ +#define _SPTAG_SERVER_SERVICESTTINGS_H_ + +#include "../Core/Common.h" + +#include + +namespace SPTAG +{ +namespace Service +{ + +struct ServiceSettings +{ + ServiceSettings(); + + std::string m_vectorSeparator; + + std::string m_listenAddr; + + std::string m_listenPort; + + SizeType m_defaultMaxResultNumber; + + SizeType m_threadNum; + + SizeType m_socketThreadNum; +}; + + + + +} // namespace Server +} // namespace AnnService + + +#endif // _SPTAG_SERVER_SERVICESTTINGS_H_ + diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Socket/Client.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Socket/Client.h new file mode 100644 index 0000000000..a57465dfd7 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Socket/Client.h @@ -0,0 +1,68 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_SOCKET_CLIENT_H_ +#define _SPTAG_SOCKET_CLIENT_H_ + +#include "inc/Core/Common.h" +#include "Connection.h" +#include "ConnectionManager.h" +#include "Packet.h" + +#include +#include +#include +#include + +namespace SPTAG +{ +namespace Socket +{ + +class Client +{ +public: + typedef std::function ConnectCallback; + + Client(const PacketHandlerMapPtr& p_handlerMap, + std::size_t p_threadNum, + std::uint32_t p_heartbeatIntervalSeconds); + + ~Client(); + + ConnectionID ConnectToServer(const std::string& p_address, + const std::string& p_port, + SPTAG::ErrorCode& p_ec); + + void AsyncConnectToServer(const std::string& p_address, + const std::string& p_port, + ConnectCallback p_callback); + + void SendPacket(ConnectionID p_connection, Packet p_packet, std::function p_callback); + + void SetEventOnConnectionClose(std::function p_event); + +private: + void KeepIoContext(); + +private: + std::atomic_bool m_stopped; + + std::uint32_t m_heartbeatIntervalSeconds; + + boost::asio::io_context m_ioContext; + + boost::asio::deadline_timer m_deadlineTimer; + + std::shared_ptr m_connectionManager; + + std::vector m_threadPool; + + const PacketHandlerMapPtr c_requestHandlerMap; +}; + + +} // namespace Socket +} // namespace SPTAG + +#endif // _SPTAG_SOCKET_CLIENT_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Socket/Common.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Socket/Common.h new file mode 100644 index 0000000000..dc06af1bb4 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Socket/Common.h @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_SOCKET_COMMON_H_ +#define _SPTAG_SOCKET_COMMON_H_ + +#include + +namespace SPTAG +{ +namespace Socket +{ + +typedef std::uint32_t ConnectionID; + +typedef std::uint32_t ResourceID; + +extern const ConnectionID c_invalidConnectionID; + +extern const ResourceID c_invalidResourceID; + +} // namespace Socket +} // namespace SPTAG + +#endif // _SPTAG_SOCKET_COMMON_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Socket/Connection.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Socket/Connection.h new file mode 100644 index 0000000000..1d75d093b3 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Socket/Connection.h @@ -0,0 +1,100 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_SOCKET_CONNECTION_H_ +#define _SPTAG_SOCKET_CONNECTION_H_ + +#include "Packet.h" + +#include +#include +#include + +#include +#include +#include + +namespace SPTAG +{ +namespace Socket +{ + +class ConnectionManager; + +class Connection : public std::enable_shared_from_this +{ +public: + typedef std::shared_ptr Ptr; + + Connection(ConnectionID p_connectionID, + boost::asio::ip::tcp::socket&& p_socket, + const PacketHandlerMapPtr& p_handlerMap, + std::weak_ptr p_connectionManager); + + void Start(); + + void Stop(); + + void StartHeartbeat(std::size_t p_intervalSeconds); + + void AsyncSend(Packet p_packet, std::function p_callback); + + ConnectionID GetConnectionID() const; + + ConnectionID GetRemoteConnectionID() const; + + Connection(const Connection&) = delete; + Connection& operator=(const Connection&) = delete; + +private: + void AsyncReadHeader(); + + void AsyncReadBody(); + + void HandleReadHeader(boost::system::error_code p_ec, std::size_t p_bytesTransferred); + + void HandleReadBody(boost::system::error_code p_ec, std::size_t p_bytesTransferred); + + void SendHeartbeat(std::size_t p_intervalSeconds); + + void SendRegister(); + + void HandleHeartbeatRequest(); + + void HandleRegisterRequest(); + + void HandleRegisterResponse(); + + void HandleNoHandlerResponse(); + + void OnConnectionFail(const boost::system::error_code& p_ec); + +private: + const ConnectionID c_connectionID; + + ConnectionID m_remoteConnectionID; + + const std::weak_ptr c_connectionManager; + + const PacketHandlerMapPtr c_handlerMap; + + boost::asio::ip::tcp::socket m_socket; + + boost::asio::io_context::strand m_strand; + + boost::asio::deadline_timer m_heartbeatTimer; + + std::uint8_t m_packetHeaderReadBuffer[PacketHeader::c_bufferSize]; + + Packet m_packetRead; + + std::atomic_bool m_stopped; + + std::atomic_bool m_heartbeatStarted; +}; + + +} // namespace Socket +} // namespace SPTAG + +#endif // _SPTAG_SOCKET_CONNECTION_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Socket/ConnectionManager.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Socket/ConnectionManager.h new file mode 100644 index 0000000000..e487c61053 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Socket/ConnectionManager.h @@ -0,0 +1,73 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_SOCKET_CONNECTIONMANAGER_H_ +#define _SPTAG_SOCKET_CONNECTIONMANAGER_H_ + +#include "Connection.h" +#include "inc/Helper/Concurrent.h" + +#include +#include +#include +#include +#include + +#include + +namespace SPTAG +{ +namespace Socket +{ + +class ConnectionManager : public std::enable_shared_from_this +{ +public: + ConnectionManager(); + + ConnectionID AddConnection(boost::asio::ip::tcp::socket&& p_socket, + const PacketHandlerMapPtr& p_handlerMap, + std::uint32_t p_heartbeatIntervalSeconds); + + void RemoveConnection(ConnectionID p_connectionID); + + Connection::Ptr GetConnection(ConnectionID p_connectionID); + + void SetEventOnRemoving(std::function p_event); + + void StopAll(); + +private: + inline static std::uint32_t GetPosition(ConnectionID p_connectionID); + +private: + static constexpr std::uint32_t c_connectionPoolSize = 1 << 8; + + static constexpr std::uint32_t c_connectionPoolMask = c_connectionPoolSize - 1; + + struct ConnectionItem + { + ConnectionItem(); + + std::atomic_bool m_isEmpty; + + Connection::Ptr m_connection; + }; + + // Start from 1. 0 means not assigned. + std::atomic m_nextConnectionID; + + std::atomic m_connectionCount; + + std::array m_connections; + + Helper::Concurrent::SpinLock m_spinLock; + + std::function m_eventOnRemoving; +}; + + +} // namespace Socket +} // namespace SPTAG + +#endif // _SPTAG_SOCKET_CONNECTIONMANAGER_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Socket/Packet.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Socket/Packet.h new file mode 100644 index 0000000000..8c99b09fed --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Socket/Packet.h @@ -0,0 +1,142 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_SOCKET_PACKET_H_ +#define _SPTAG_SOCKET_PACKET_H_ + +#include "Common.h" + +#include +#include +#include +#include +#include + +namespace SPTAG +{ +namespace Socket +{ + +enum class PacketType : std::uint8_t +{ + Undefined = 0x00, + + HeartbeatRequest = 0x01, + + RegisterRequest = 0x02, + + SearchRequest = 0x03, + + ResponseMask = 0x80, + + HeartbeatResponse = ResponseMask | HeartbeatRequest, + + RegisterResponse = ResponseMask | RegisterRequest, + + SearchResponse = ResponseMask | SearchRequest +}; + + +enum class PacketProcessStatus : std::uint8_t +{ + Ok = 0x00, + + Timeout = 0x01, + + Dropped = 0x02, + + Failed = 0x03 +}; + + +struct PacketHeader +{ + static constexpr std::size_t c_bufferSize = 16; + + PacketHeader(); + PacketHeader(PacketHeader&& p_right); + PacketHeader(const PacketHeader& p_right); + + std::size_t WriteBuffer(std::uint8_t* p_buffer); + + void ReadBuffer(const std::uint8_t* p_buffer); + + PacketType m_packetType; + + PacketProcessStatus m_processStatus; + + std::uint32_t m_bodyLength; + + // Meaning of this is different with different PacketType. + // In most request case, it means connection expeced for response. + // In most response case, it means connection which handled request. + ConnectionID m_connectionID; + + ResourceID m_resourceID; +}; + + +static_assert(sizeof(PacketHeader) <= PacketHeader::c_bufferSize, ""); + + +class Packet +{ +public: + Packet(); + Packet(Packet&& p_right); + Packet(const Packet& p_right); + + PacketHeader& Header(); + + std::uint8_t* HeaderBuffer() const; + + std::uint8_t* Body() const; + + std::uint8_t* Buffer() const; + + std::uint32_t BufferLength() const; + + std::uint32_t BufferCapacity() const; + + void AllocateBuffer(std::uint32_t p_bodyCapacity); + +private: + PacketHeader m_header; + + std::shared_ptr m_buffer; + + std::uint32_t m_bufferCapacity; +}; + + +struct PacketTypeHash +{ + std::size_t operator()(const PacketType& p_val) const + { + return static_cast(p_val); + } +}; + + +typedef std::function PacketHandler; + +typedef std::unordered_map PacketHandlerMap; +typedef std::shared_ptr PacketHandlerMapPtr; + + +namespace PacketTypeHelper +{ + +bool IsRequestPacket(PacketType p_type); + +bool IsResponsePacket(PacketType p_type); + +PacketType GetCrosspondingResponseType(PacketType p_type); + +} + + +} // namespace SPTAG +} // namespace Socket + +#endif // _SPTAG_SOCKET_SOCKETSERVER_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Socket/RemoteSearchQuery.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Socket/RemoteSearchQuery.h new file mode 100644 index 0000000000..900aa6cb16 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Socket/RemoteSearchQuery.h @@ -0,0 +1,99 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_SOCKET_REMOTESEARCHQUERY_H_ +#define _SPTAG_SOCKET_REMOTESEARCHQUERY_H_ + +#include "inc/Core/CommonDataStructure.h" +#include "inc/Core/SearchQuery.h" + +#include +#include +#include +#include +#include + +namespace SPTAG +{ +namespace Socket +{ + +// TODO: use Bond replace below structures. + +struct RemoteQuery +{ + static constexpr std::uint16_t MajorVersion() { return 1; } + static constexpr std::uint16_t MirrorVersion() { return 0; } + + enum class QueryType : std::uint8_t + { + String = 0 + }; + + RemoteQuery(); + + std::size_t EstimateBufferSize() const; + + std::uint8_t* Write(std::uint8_t* p_buffer) const; + + const std::uint8_t* Read(const std::uint8_t* p_buffer); + + + QueryType m_type; + + std::string m_queryString; +}; + + +struct IndexSearchResult +{ + std::string m_indexName; + + QueryResult m_results; +}; + + +struct RemoteSearchResult +{ + static constexpr std::uint16_t MajorVersion() { return 1; } + static constexpr std::uint16_t MirrorVersion() { return 0; } + + enum class ResultStatus : std::uint8_t + { + Success = 0, + + Timeout = 1, + + FailedNetwork = 2, + + FailedExecute = 3, + + Dropped = 4 + }; + + RemoteSearchResult(); + + RemoteSearchResult(const RemoteSearchResult& p_right); + + RemoteSearchResult(RemoteSearchResult&& p_right); + + RemoteSearchResult& operator=(RemoteSearchResult&& p_right); + + std::size_t EstimateBufferSize() const; + + std::uint8_t* Write(std::uint8_t* p_buffer) const; + + const std::uint8_t* Read(const std::uint8_t* p_buffer); + + + ResultStatus m_status; + + std::vector m_allIndexResults; +}; + + + +} // namespace SPTAG +} // namespace Socket + +#endif // _SPTAG_SOCKET_REMOTESEARCHQUERY_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Socket/ResourceManager.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Socket/ResourceManager.h new file mode 100644 index 0000000000..404cac830f --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Socket/ResourceManager.h @@ -0,0 +1,190 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_SOCKET_RESOURCEMANAGER_H_ +#define _SPTAG_SOCKET_RESOURCEMANAGER_H_ + +#include "Common.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace std +{ +typedef atomic atomic_uint32_t; +} + +namespace SPTAG +{ +namespace Socket +{ + +template +class ResourceManager : public std::enable_shared_from_this> +{ +public: + typedef std::function)> TimeoutCallback; + + ResourceManager() + : m_nextResourceID(1), + m_isStopped(false), + m_timeoutItemCount(0) + { + m_timeoutChecker = std::thread(&ResourceManager::StartCheckTimeout, this); + } + + + ~ResourceManager() + { + m_isStopped = true; + m_timeoutChecker.join(); + } + + + ResourceID Add(const std::shared_ptr& p_resource, + std::uint32_t p_timeoutMilliseconds, + TimeoutCallback p_timeoutCallback) + { + ResourceID rid = m_nextResourceID.fetch_add(1); + while (c_invalidResourceID == rid) + { + rid = m_nextResourceID.fetch_add(1); + } + + { + std::lock_guard guard(m_resourcesMutex); + m_resources.emplace(rid, p_resource); + } + + if (p_timeoutMilliseconds > 0) + { + std::unique_ptr item(new ResourceItem); + + item->m_resourceID = rid; + item->m_callback = std::move(p_timeoutCallback); + item->m_expireTime = m_clock.now() + std::chrono::milliseconds(p_timeoutMilliseconds); + + { + std::lock_guard guard(m_timeoutListMutex); + m_timeoutList.emplace_back(std::move(item)); + } + + ++m_timeoutItemCount; + } + + return rid; + } + + + std::shared_ptr GetAndRemove(ResourceID p_resourceID) + { + std::shared_ptr ret; + std::lock_guard guard(m_resourcesMutex); + auto iter = m_resources.find(p_resourceID); + if (iter != m_resources.end()) + { + ret = iter->second; + m_resources.erase(iter); + } + + return ret; + } + + + void Remove(ResourceID p_resourceID) + { + std::lock_guard guard(m_resourcesMutex); + auto iter = m_resources.find(p_resourceID); + if (iter != m_resources.end()) + { + m_resources.erase(iter); + } + } + +private: + void StartCheckTimeout() + { + std::vector> timeouted; + timeouted.reserve(1024); + while (!m_isStopped) + { + if (m_timeoutItemCount > 0) + { + std::lock_guard guard(m_timeoutListMutex); + while (!m_timeoutList.empty() + && m_timeoutList.front()->m_expireTime <= m_clock.now()) + { + timeouted.emplace_back(std::move(m_timeoutList.front())); + m_timeoutList.pop_front(); + --m_timeoutItemCount; + } + } + + if (timeouted.empty()) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + else + { + for (auto& item : timeouted) + { + auto resource = GetAndRemove(item->m_resourceID); + if (nullptr != resource) + { + item->m_callback(std::move(resource)); + } + } + + timeouted.clear(); + } + } + } + + +private: + struct ResourceItem + { + ResourceItem() + : m_resourceID(c_invalidResourceID) + { + } + + ResourceID m_resourceID; + + TimeoutCallback m_callback; + + std::chrono::time_point m_expireTime; + }; + + std::deque> m_timeoutList; + + std::atomic m_timeoutItemCount; + + std::mutex m_timeoutListMutex; + + std::unordered_map> m_resources; + + std::atomic m_nextResourceID; + + std::mutex m_resourcesMutex; + + std::chrono::high_resolution_clock m_clock; + + std::thread m_timeoutChecker; + + bool m_isStopped; +}; + + +} // namespace Socket +} // namespace SPTAG + +#endif // _SPTAG_SOCKET_RESOURCEMANAGER_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Socket/Server.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Socket/Server.h new file mode 100644 index 0000000000..aac97bf84b --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Socket/Server.h @@ -0,0 +1,55 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_SOCKET_SERVER_H_ +#define _SPTAG_SOCKET_SERVER_H_ + +#include "Connection.h" +#include "ConnectionManager.h" +#include "Packet.h" + +#include +#include +#include + +namespace SPTAG +{ +namespace Socket +{ + +class Server +{ +public: + Server(const std::string& p_address, + const std::string& p_port, + const PacketHandlerMapPtr& p_handlerMap, + std::size_t p_threadNum); + + ~Server(); + + void StartListen(); + + void SendPacket(ConnectionID p_connection, Packet p_packet, std::function p_callback); + + void SetEventOnConnectionClose(std::function p_event); + +private: + void StartAccept(); + +private: + boost::asio::io_context m_ioContext; + + boost::asio::ip::tcp::acceptor m_acceptor; + + std::shared_ptr m_connectionManager; + + std::vector m_threadPool; + + const PacketHandlerMapPtr m_requestHandlerMap; +}; + + +} // namespace Socket +} // namespace SPTAG + +#endif // _SPTAG_SOCKET_SERVER_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Socket/SimpleSerialization.h b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Socket/SimpleSerialization.h new file mode 100644 index 0000000000..6da925625b --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/inc/Socket/SimpleSerialization.h @@ -0,0 +1,174 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_SOCKET_SIMPLESERIALIZATION_H_ +#define _SPTAG_SOCKET_SIMPLESERIALIZATION_H_ + +#include "inc/Core/CommonDataStructure.h" + +#include +#include +#include +#include + +namespace SPTAG +{ +namespace Socket +{ +namespace SimpleSerialization +{ + + template + inline std::uint8_t* + SimpleWriteBuffer(const T& p_val, std::uint8_t* p_buffer) + { + static_assert(std::is_fundamental::value || std::is_enum::value, + "Only applied for fundanmental type."); + + *(reinterpret_cast(p_buffer)) = p_val; + return p_buffer + sizeof(T); + } + + + template + inline const std::uint8_t* + SimpleReadBuffer(const std::uint8_t* p_buffer, T& p_val) + { + static_assert(std::is_fundamental::value || std::is_enum::value, + "Only applied for fundanmental type."); + + p_val = *(reinterpret_cast(p_buffer)); + return p_buffer + sizeof(T); + } + + + template + inline std::size_t + EstimateBufferSize(const T& p_val) + { + static_assert(std::is_fundamental::value || std::is_enum::value, + "Only applied for fundanmental type."); + + return sizeof(T); + } + + + template<> + inline std::uint8_t* + SimpleWriteBuffer(const std::string& p_val, std::uint8_t* p_buffer) + { + p_buffer = SimpleWriteBuffer(static_cast(p_val.size()), p_buffer); + + std::memcpy(p_buffer, p_val.c_str(), p_val.size()); + return p_buffer + p_val.size(); + } + + + template<> + inline const std::uint8_t* + SimpleReadBuffer(const std::uint8_t* p_buffer, std::string& p_val) + { + p_val.clear(); + std::uint32_t len = 0; + p_buffer = SimpleReadBuffer(p_buffer, len); + + if (len > 0) + { + p_val.reserve(len); + p_val.assign(reinterpret_cast(p_buffer), len); + } + + return p_buffer + len; + } + + + template<> + inline std::size_t + EstimateBufferSize(const std::string& p_val) + { + return sizeof(std::uint32_t) + p_val.size(); + } + + + template<> + inline std::uint8_t* + SimpleWriteBuffer(const ByteArray& p_val, std::uint8_t* p_buffer) + { + p_buffer = SimpleWriteBuffer(static_cast(p_val.Length()), p_buffer); + + std::memcpy(p_buffer, p_val.Data(), p_val.Length()); + return p_buffer + p_val.Length(); + } + + + template<> + inline const std::uint8_t* + SimpleReadBuffer(const std::uint8_t* p_buffer, ByteArray& p_val) + { + p_val.Clear(); + std::uint32_t len = 0; + p_buffer = SimpleReadBuffer(p_buffer, len); + + if (len > 0) + { + p_val = ByteArray::Alloc(len); + std::memcpy(p_val.Data(), p_buffer, len); + } + + return p_buffer + len; + } + + + template<> + inline std::size_t + EstimateBufferSize(const ByteArray& p_val) + { + return sizeof(std::uint32_t) + p_val.Length(); + } + + + template + inline std::uint8_t* + SimpleWriteSharedPtrBuffer(const std::shared_ptr& p_val, std::uint8_t* p_buffer) + { + if (nullptr == p_val) + { + return SimpleWriteBuffer(false, p_buffer); + } + + p_buffer = SimpleWriteBuffer(true, p_buffer); + p_buffer = SimpleWriteBuffer(*p_val, p_buffer); + return p_buffer; + } + + + template + inline const std::uint8_t* + SimpleReadSharedPtrBuffer(const std::uint8_t* p_buffer, std::shared_ptr& p_val) + { + p_val.reset(); + bool isNotNull = false; + p_buffer = SimpleReadBuffer(p_buffer, isNotNull); + + if (isNotNull) + { + p_val.reset(new T); + p_buffer = SimpleReadBuffer(p_buffer, *p_val); + } + + return p_buffer; + } + + + template + inline std::size_t + EstimateSharedPtrBufferSize(const std::shared_ptr& p_val) + { + return sizeof(bool) + (nullptr == p_val ? 0 : EstimateBufferSize(*p_val)); + } + +} // namespace SimpleSerialization +} // namespace SPTAG +} // namespace Socket + +#endif // _SPTAG_SOCKET_SIMPLESERIALIZATION_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/packages.config b/cpp/src/core/thirdparty/SPTAG/AnnService/packages.config new file mode 100644 index 0000000000..424245f6dc --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/packages.config @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/Aggregator/AggregatorContext.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Aggregator/AggregatorContext.cpp new file mode 100644 index 0000000000..a36c2c61e9 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Aggregator/AggregatorContext.cpp @@ -0,0 +1,86 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Aggregator/AggregatorContext.h" +#include "inc/Helper/SimpleIniReader.h" + +using namespace SPTAG; +using namespace SPTAG::Aggregator; + +RemoteMachine::RemoteMachine() + : m_connectionID(Socket::c_invalidConnectionID), + m_status(RemoteMachineStatus::Disconnected) +{ +} + + +AggregatorContext::AggregatorContext(const std::string& p_filePath) + : m_initialized(false) +{ + Helper::IniReader iniReader; + if (ErrorCode::Success != iniReader.LoadIniFile(p_filePath)) + { + return; + } + + m_settings.reset(new AggregatorSettings); + + m_settings->m_listenAddr = iniReader.GetParameter("Service", "ListenAddr", std::string("0.0.0.0")); + m_settings->m_listenPort = iniReader.GetParameter("Service", "ListenPort", std::string("8100")); + m_settings->m_threadNum = iniReader.GetParameter("Service", "ThreadNumber", static_cast(8)); + m_settings->m_socketThreadNum = iniReader.GetParameter("Service", "SocketThreadNumber", static_cast(8)); + + const std::string emptyStr; + + std::uint32_t serverNum = iniReader.GetParameter("Servers", "Number", static_cast(0)); + + for (std::uint32_t i = 0; i < serverNum; ++i) + { + std::string sectionName("Server_"); + sectionName += std::to_string(i); + if (!iniReader.DoesSectionExist(sectionName)) + { + continue; + } + + std::shared_ptr remoteMachine(new RemoteMachine); + + remoteMachine->m_address = iniReader.GetParameter(sectionName, "Address", emptyStr); + remoteMachine->m_port = iniReader.GetParameter(sectionName, "Port", emptyStr); + + if (remoteMachine->m_address.empty() || remoteMachine->m_port.empty()) + { + continue; + } + + m_remoteServers.push_back(std::move(remoteMachine)); + } + + m_initialized = true; +} + + +AggregatorContext::~AggregatorContext() +{ +} + + +bool +AggregatorContext::IsInitialized() const +{ + return m_initialized; +} + + +const std::vector>& +AggregatorContext::GetRemoteServers() const +{ + return m_remoteServers; +} + + +const std::shared_ptr& +AggregatorContext::GetSettings() const +{ + return m_settings; +} diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/Aggregator/AggregatorExecutionContext.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Aggregator/AggregatorExecutionContext.cpp new file mode 100644 index 0000000000..8f7a28375a --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Aggregator/AggregatorExecutionContext.cpp @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Aggregator/AggregatorExecutionContext.h" + +using namespace SPTAG; +using namespace SPTAG::Aggregator; + +AggregatorExecutionContext::AggregatorExecutionContext(std::size_t p_totalServerNumber, + Socket::PacketHeader p_requestHeader) + : m_requestHeader(std::move(p_requestHeader)) +{ + m_results.clear(); + m_results.resize(p_totalServerNumber); + + m_unfinishedCount = static_cast(p_totalServerNumber); +} + + +AggregatorExecutionContext::~AggregatorExecutionContext() +{ +} + + +std::size_t +AggregatorExecutionContext::GetServerNumber() const +{ + return m_results.size(); +} + + +AggregatorResult& +AggregatorExecutionContext::GetResult(std::size_t p_num) +{ + return m_results[p_num]; +} + + +const Socket::PacketHeader& +AggregatorExecutionContext::GetRequestHeader() const +{ + return m_requestHeader; +} + + +bool +AggregatorExecutionContext::IsCompletedAfterFinsh(std::uint32_t p_finishedCount) +{ + auto lastCount = m_unfinishedCount.fetch_sub(p_finishedCount); + return lastCount <= p_finishedCount; +} diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/Aggregator/AggregatorService.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Aggregator/AggregatorService.cpp new file mode 100644 index 0000000000..24c1672cde --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Aggregator/AggregatorService.cpp @@ -0,0 +1,366 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Aggregator/AggregatorService.h" + +using namespace SPTAG; +using namespace SPTAG::Aggregator; + +AggregatorService::AggregatorService() + : m_shutdownSignals(m_ioContext), + m_pendingConnectServersTimer(m_ioContext) +{ +} + + +AggregatorService::~AggregatorService() +{ +} + + +bool +AggregatorService::Initialize() +{ + std::string configFilePath = "Aggregator.ini"; + m_aggregatorContext.reset(new AggregatorContext(configFilePath)); + + m_initalized = m_aggregatorContext->IsInitialized(); + + return m_initalized; +} + + +void +AggregatorService::Run() +{ + auto threadNum = max((SPTAG::SizeType)1, GetContext()->GetSettings()->m_threadNum); + m_threadPool.reset(new boost::asio::thread_pool(threadNum)); + + StartClient(); + StartListen(); + WaitForShutdown(); +} + + +void +AggregatorService::StartClient() +{ + auto context = GetContext(); + Socket::PacketHandlerMapPtr handlerMap(new Socket::PacketHandlerMap); + handlerMap->emplace(Socket::PacketType::SearchResponse, + [this](Socket::ConnectionID p_srcID, Socket::Packet p_packet) + { + boost::asio::post(*m_threadPool, + std::bind(&AggregatorService::SearchResponseHanlder, + this, + p_srcID, + std::move(p_packet))); + }); + + + m_socketClient.reset(new Socket::Client(handlerMap, + context->GetSettings()->m_socketThreadNum, + 30)); + + m_socketClient->SetEventOnConnectionClose([this](Socket::ConnectionID p_cid) + { + auto context = this->GetContext(); + for (const auto& server : context->GetRemoteServers()) + { + if (nullptr != server && p_cid == server->m_connectionID) + { + server->m_status = RemoteMachineStatus::Disconnected; + this->AddToPendingServers(server); + } + } + }); + + { + std::lock_guard guard(m_pendingConnectServersMutex); + m_pendingConnectServers = context->GetRemoteServers(); + } + + ConnectToPendingServers(); +} + + +void +AggregatorService::StartListen() +{ + auto context = GetContext(); + Socket::PacketHandlerMapPtr handlerMap(new Socket::PacketHandlerMap); + handlerMap->emplace(Socket::PacketType::SearchRequest, + [this](Socket::ConnectionID p_srcID, Socket::Packet p_packet) + { + boost::asio::post(*m_threadPool, + std::bind(&AggregatorService::SearchRequestHanlder, + this, + p_srcID, + std::move(p_packet))); + }); + + m_socketServer.reset(new Socket::Server(context->GetSettings()->m_listenAddr, + context->GetSettings()->m_listenPort, + handlerMap, + context->GetSettings()->m_socketThreadNum)); + + fprintf(stderr, + "Start to listen %s:%s ...\n", + context->GetSettings()->m_listenAddr.c_str(), + context->GetSettings()->m_listenPort.c_str()); +} + + +void +AggregatorService::WaitForShutdown() +{ + m_shutdownSignals.add(SIGINT); + m_shutdownSignals.add(SIGTERM); +#ifdef SIGQUIT + m_shutdownSignals.add(SIGQUIT); +#endif + + m_shutdownSignals.async_wait([this](boost::system::error_code p_ec, int p_signal) + { + fprintf(stderr, "Received shutdown signals.\n"); + m_pendingConnectServersTimer.cancel(); + }); + + m_ioContext.run(); + fprintf(stderr, "Start shutdown procedure.\n"); + + m_socketServer.reset(); + m_threadPool->stop(); + m_threadPool->join(); +} + + +void +AggregatorService::ConnectToPendingServers() +{ + auto context = GetContext(); + std::vector> pendingList; + pendingList.reserve(context->GetRemoteServers().size()); + + { + std::lock_guard guard(m_pendingConnectServersMutex); + pendingList.swap(m_pendingConnectServers); + } + + for (auto& pendingServer : pendingList) + { + if (pendingServer->m_status != RemoteMachineStatus::Disconnected) + { + continue; + } + + pendingServer->m_status = RemoteMachineStatus::Connecting; + std::shared_ptr server = pendingServer; + auto runner = [server, this]() + { + ErrorCode errCode; + auto cid = m_socketClient->ConnectToServer(server->m_address, server->m_port, errCode); + if (Socket::c_invalidConnectionID == cid) + { + if (ErrorCode::Socket_FailedResolveEndPoint == errCode) + { + fprintf(stderr, + "[Error] Failed to resolve %s %s.\n", + server->m_address.c_str(), + server->m_port.c_str()); + } + else + { + this->AddToPendingServers(std::move(server)); + } + } + else + { + server->m_connectionID = cid; + server->m_status = RemoteMachineStatus::Connected; + } + }; + boost::asio::post(*m_threadPool, std::move(runner)); + } + + m_pendingConnectServersTimer.expires_from_now(boost::posix_time::seconds(30)); + m_pendingConnectServersTimer.async_wait([this](const boost::system::error_code& p_ec) + { + if (boost::asio::error::operation_aborted != p_ec) + { + ConnectToPendingServers(); + } + }); +} + + +void +AggregatorService::AddToPendingServers(std::shared_ptr p_remoteServer) +{ + std::lock_guard guard(m_pendingConnectServersMutex); + m_pendingConnectServers.emplace_back(std::move(p_remoteServer)); +} + + +void +AggregatorService::SearchRequestHanlder(Socket::ConnectionID p_localConnectionID, Socket::Packet p_packet) +{ + auto context = GetContext(); + std::vector remoteServers; + remoteServers.reserve(context->GetRemoteServers().size()); + + for (const auto& server : context->GetRemoteServers()) + { + if (RemoteMachineStatus::Connected != server->m_status) + { + continue; + } + + remoteServers.push_back(server->m_connectionID); + } + + Socket::PacketHeader requestHeader = p_packet.Header(); + if (Socket::c_invalidConnectionID == requestHeader.m_connectionID) + { + requestHeader.m_connectionID = p_localConnectionID; + } + + std::shared_ptr executionContext( + new AggregatorExecutionContext(remoteServers.size(), requestHeader)); + + for (std::uint32_t i = 0; i < remoteServers.size(); ++i) + { + AggregatorCallback callback = [this, executionContext, i](Socket::RemoteSearchResult p_result) + { + executionContext->GetResult(i).reset(new Socket::RemoteSearchResult(std::move(p_result))); + if (executionContext->IsCompletedAfterFinsh(1)) + { + this->AggregateResults(std::move(executionContext)); + } + }; + + auto timeoutCallback = [](std::shared_ptr p_callback) + { + if (nullptr != p_callback) + { + Socket::RemoteSearchResult result; + result.m_status = Socket::RemoteSearchResult::ResultStatus::Timeout; + + (*p_callback)(std::move(result)); + } + }; + + auto connectCallback = [callback](bool p_connectSucc) + { + if (!p_connectSucc) + { + Socket::RemoteSearchResult result; + result.m_status = Socket::RemoteSearchResult::ResultStatus::FailedNetwork; + + callback(std::move(result)); + } + }; + + Socket::Packet packet; + packet.Header().m_packetType = Socket::PacketType::SearchRequest; + packet.Header().m_processStatus = Socket::PacketProcessStatus::Ok; + packet.Header().m_bodyLength = p_packet.Header().m_bodyLength; + packet.Header().m_connectionID = Socket::c_invalidConnectionID; + packet.Header().m_resourceID = m_aggregatorCallbackManager.Add(std::make_shared(std::move(callback)), + context->GetSettings()->m_searchTimeout, + std::move(timeoutCallback)); + + packet.AllocateBuffer(packet.Header().m_bodyLength); + packet.Header().WriteBuffer(packet.HeaderBuffer()); + memcpy(packet.Body(), p_packet.Body(), packet.Header().m_bodyLength); + + m_socketClient->SendPacket(remoteServers[i], std::move(packet), connectCallback); + } +} + + +void +AggregatorService::SearchResponseHanlder(Socket::ConnectionID p_localConnectionID, Socket::Packet p_packet) +{ + auto callback = m_aggregatorCallbackManager.GetAndRemove(p_packet.Header().m_resourceID); + if (nullptr == callback) + { + return; + } + + if (p_packet.Header().m_processStatus != Socket::PacketProcessStatus::Ok || 0 == p_packet.Header().m_bodyLength) + { + Socket::RemoteSearchResult result; + result.m_status = Socket::RemoteSearchResult::ResultStatus::FailedExecute; + + (*callback)(std::move(result)); + } + else + { + Socket::RemoteSearchResult result; + result.Read(p_packet.Body()); + (*callback)(std::move(result)); + } +} + + +std::shared_ptr +AggregatorService::GetContext() +{ + // Add mutex if necessary. + return m_aggregatorContext; +} + + +void +AggregatorService::AggregateResults(std::shared_ptr p_exectionContext) +{ + if (nullptr == p_exectionContext) + { + return; + } + + Socket::Packet packet; + packet.Header().m_packetType = Socket::PacketType::SearchResponse; + packet.Header().m_processStatus = Socket::PacketProcessStatus::Ok; + packet.Header().m_resourceID = p_exectionContext->GetRequestHeader().m_resourceID; + + Socket::RemoteSearchResult remoteResult; + remoteResult.m_status = Socket::RemoteSearchResult::ResultStatus::Success; + + std::size_t resultNum = 0; + for (std::size_t i = 0; i < p_exectionContext->GetServerNumber(); ++i) + { + const auto& result = p_exectionContext->GetResult(i); + if (nullptr == result) + { + continue; + } + + resultNum += result->m_allIndexResults.size(); + } + + remoteResult.m_allIndexResults.reserve(resultNum); + for (std::size_t i = 0; i < p_exectionContext->GetServerNumber(); ++i) + { + const auto& result = p_exectionContext->GetResult(i); + if (nullptr == result) + { + continue; + } + + for (auto& indexRes : result->m_allIndexResults) + { + remoteResult.m_allIndexResults.emplace_back(std::move(indexRes)); + } + } + + std::uint32_t cap = static_cast(remoteResult.EstimateBufferSize()); + packet.AllocateBuffer(cap); + packet.Header().m_bodyLength = static_cast(remoteResult.Write(packet.Body()) - packet.Body()); + packet.Header().WriteBuffer(packet.HeaderBuffer()); + + m_socketServer->SendPacket(p_exectionContext->GetRequestHeader().m_connectionID, + std::move(packet), + nullptr); +} diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/Aggregator/AggregatorSettings.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Aggregator/AggregatorSettings.cpp new file mode 100644 index 0000000000..a3e2bc6806 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Aggregator/AggregatorSettings.cpp @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Aggregator/AggregatorSettings.h" + +using namespace SPTAG; +using namespace SPTAG::Aggregator; + +AggregatorSettings::AggregatorSettings() + : m_searchTimeout(100), + m_threadNum(8), + m_socketThreadNum(8) +{ +} diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/Aggregator/main.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Aggregator/main.cpp new file mode 100644 index 0000000000..2a06025d5e --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Aggregator/main.cpp @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Aggregator/AggregatorService.h" + +SPTAG::Aggregator::AggregatorService g_service; + +int main(int argc, char* argv[]) +{ + if (!g_service.Initialize()) + { + return 1; + } + + g_service.Run(); + + return 0; +} + diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/Client/ClientWrapper.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Client/ClientWrapper.cpp new file mode 100644 index 0000000000..7e91c63195 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Client/ClientWrapper.cpp @@ -0,0 +1,235 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Client/ClientWrapper.h" + +using namespace SPTAG; +using namespace SPTAG::Socket; +using namespace SPTAG::Client; + +ClientWrapper::ClientWrapper(const ClientOptions& p_options) + : m_options(p_options), + m_unfinishedJobCount(0), + m_isWaitingFinish(false) +{ + m_client.reset(new SPTAG::Socket::Client(GetHandlerMap(), p_options.m_socketThreadNum, 30)); + m_client->SetEventOnConnectionClose(std::bind(&ClientWrapper::HandleDeadConnection, + this, + std::placeholders::_1)); + + m_connections.reserve(m_options.m_threadNum); + for (std::uint32_t i = 0; i < m_options.m_threadNum; ++i) + { + SPTAG::ErrorCode errCode; + ConnectionPair conn(c_invalidConnectionID, c_invalidConnectionID); + conn.first = m_client->ConnectToServer(p_options.m_serverAddr, p_options.m_serverPort, errCode); + if (SPTAG::ErrorCode::Socket_FailedResolveEndPoint == errCode) + { + fprintf(stderr, "Unable to resolve remote address.\n"); + return; + } + + if (c_invalidConnectionID != conn.first) + { + m_connections.emplace_back(std::move(conn)); + } + } +} + + +ClientWrapper::~ClientWrapper() +{ +} + + +void +ClientWrapper::SendQueryAsync(const Socket::RemoteQuery& p_query, + Callback p_callback, + const ClientOptions& p_options) +{ + if (!bool(p_callback)) + { + return; + } + + auto conn = GetConnection(); + + auto timeoutCallback = [this](std::shared_ptr p_callback) + { + DecreaseUnfnishedJobCount(); + if (nullptr != p_callback) + { + Socket::RemoteSearchResult result; + result.m_status = Socket::RemoteSearchResult::ResultStatus::Timeout; + + (*p_callback)(std::move(result)); + } + }; + + + auto connectCallback = [p_callback, this](bool p_connectSucc) + { + if (!p_connectSucc) + { + Socket::RemoteSearchResult result; + result.m_status = Socket::RemoteSearchResult::ResultStatus::FailedNetwork; + + p_callback(std::move(result)); + DecreaseUnfnishedJobCount(); + } + }; + + Socket::Packet packet; + packet.Header().m_connectionID = c_invalidConnectionID; + packet.Header().m_packetType = PacketType::SearchRequest; + packet.Header().m_processStatus = PacketProcessStatus::Ok; + packet.Header().m_resourceID = m_callbackManager.Add(std::make_shared(std::move(p_callback)), + p_options.m_searchTimeout, + std::move(timeoutCallback)); + + packet.Header().m_bodyLength = static_cast(p_query.EstimateBufferSize()); + packet.AllocateBuffer(packet.Header().m_bodyLength); + p_query.Write(packet.Body()); + packet.Header().WriteBuffer(packet.HeaderBuffer()); + + ++m_unfinishedJobCount; + m_client->SendPacket(conn.first, std::move(packet), connectCallback); +} + + +void +ClientWrapper::WaitAllFinished() +{ + if (m_unfinishedJobCount > 0) + { + std::unique_lock lock(m_waitingMutex); + if (m_unfinishedJobCount > 0) + { + m_isWaitingFinish = true; + m_waitingQueue.wait(lock); + } + } +} + + +PacketHandlerMapPtr +ClientWrapper::GetHandlerMap() +{ + PacketHandlerMapPtr handlerMap(new PacketHandlerMap); + handlerMap->emplace(PacketType::RegisterResponse, + [this](ConnectionID p_localConnectionID, Packet p_packet) -> void + { + for (auto& conn : m_connections) + { + if (conn.first == p_localConnectionID) + { + conn.second = p_packet.Header().m_connectionID; + return; + } + } + }); + + handlerMap->emplace(PacketType::SearchResponse, + std::bind(&ClientWrapper::SearchResponseHanlder, + this, + std::placeholders::_1, + std::placeholders::_2)); + + return handlerMap; +} + + +void +ClientWrapper::DecreaseUnfnishedJobCount() +{ + --m_unfinishedJobCount; + if (0 == m_unfinishedJobCount) + { + std::lock_guard guard(m_waitingMutex); + if (0 == m_unfinishedJobCount && m_isWaitingFinish) + { + m_waitingQueue.notify_all(); + m_isWaitingFinish = false; + } + } +} + + +const ClientWrapper::ConnectionPair& +ClientWrapper::GetConnection() +{ + if (m_connections.size() == 1) + { + return m_connections.front(); + } + + std::size_t triedCount = 0; + std::uint32_t pos = m_spinCountOfConnection.fetch_add(1) % m_connections.size(); + while (c_invalidConnectionID == m_connections[pos].first && triedCount < m_connections.size()) + { + pos = m_spinCountOfConnection.fetch_add(1) % m_connections.size(); + ++triedCount; + } + + return m_connections[pos]; +} + + +void +ClientWrapper::SearchResponseHanlder(Socket::ConnectionID p_localConnectionID, Socket::Packet p_packet) +{ + std::shared_ptr callback = m_callbackManager.GetAndRemove(p_packet.Header().m_resourceID); + if (nullptr == callback) + { + return; + } + + if (p_packet.Header().m_processStatus != PacketProcessStatus::Ok || 0 == p_packet.Header().m_bodyLength) + { + Socket::RemoteSearchResult result; + result.m_status = Socket::RemoteSearchResult::ResultStatus::FailedExecute; + + (*callback)(std::move(result)); + } + else + { + Socket::RemoteSearchResult result; + result.Read(p_packet.Body()); + (*callback)(std::move(result)); + } + + DecreaseUnfnishedJobCount(); +} + + +void +ClientWrapper::HandleDeadConnection(Socket::ConnectionID p_cid) +{ + for (auto& conn : m_connections) + { + if (conn.first == p_cid) + { + conn.first = c_invalidConnectionID; + conn.second = c_invalidConnectionID; + + SPTAG::ErrorCode errCode; + while (c_invalidConnectionID == conn.first) + { + conn.first = m_client->ConnectToServer(m_options.m_serverAddr, m_options.m_serverPort, errCode); + if (SPTAG::ErrorCode::Socket_FailedResolveEndPoint == errCode) + { + break; + } + } + + return; + } + } +} + + +bool +ClientWrapper::IsAvailable() const +{ + return !m_connections.empty(); +} diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/Client/Options.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Client/Options.cpp new file mode 100644 index 0000000000..bb067d3d58 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Client/Options.cpp @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Client/Options.h" +#include "inc/Helper/StringConvert.h" + +#include + +using namespace SPTAG; +using namespace SPTAG::Client; + +ClientOptions::ClientOptions() + : m_searchTimeout(9000), + m_threadNum(1), + m_socketThreadNum(2) +{ + AddRequiredOption(m_serverAddr, "-s", "--server", "Server address."); + AddRequiredOption(m_serverPort, "-p", "--port", "Server port."); + AddOptionalOption(m_searchTimeout, "-t", "", "Search timeout."); + AddOptionalOption(m_threadNum, "-cth", "", "Client Thread Number."); + AddOptionalOption(m_socketThreadNum, "-sth", "", "Socket Thread Number."); +} + + +ClientOptions::~ClientOptions() +{ +} diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/Client/main.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Client/main.cpp new file mode 100644 index 0000000000..b15121dc75 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Client/main.cpp @@ -0,0 +1,78 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Client/Options.h" +#include "inc/Client/ClientWrapper.h" + +#include +#include +#include + +std::unique_ptr g_client; + +int main(int argc, char** argv) +{ + SPTAG::Client::ClientOptions options; + if (!options.Parse(argc - 1, argv + 1)) + { + return 1; + } + + g_client.reset(new SPTAG::Client::ClientWrapper(options)); + if (!g_client->IsAvailable()) + { + return 1; + } + + g_client->WaitAllFinished(); + fprintf(stdout, "connection done\n"); + + std::string line; + std::cout << "Query: " << std::flush; + while (std::getline(std::cin, line)) + { + if (line.empty()) + { + break; + } + + SPTAG::Socket::RemoteQuery query; + query.m_type = SPTAG::Socket::RemoteQuery::QueryType::String; + query.m_queryString = std::move(line); + + SPTAG::Socket::RemoteSearchResult result; + auto callback = [&result](SPTAG::Socket::RemoteSearchResult p_result) + { + result = std::move(p_result); + }; + + g_client->SendQueryAsync(query, callback, options); + g_client->WaitAllFinished(); + + std::cout << "Status: " << static_cast(result.m_status) << std::endl; + + for (const auto& indexRes : result.m_allIndexResults) + { + fprintf(stdout, "Index: %s\n", indexRes.m_indexName.c_str()); + + int idx = 0; + for (const auto& res : indexRes.m_results) + { + fprintf(stdout, "------------------\n"); + fprintf(stdout, "DocIndex: %d Distance: %f\n", res.VID, res.Dist); + if (indexRes.m_results.WithMeta()) + { + const auto& metadata = indexRes.m_results.GetMetadata(idx); + fprintf(stdout, " MetaData: %.*s\n", static_cast(metadata.Length()), metadata.Data()); + } + + ++idx; + } + } + + std::cout << "Query: " << std::flush; + } + + return 0; +} + diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/Core/BKT/BKTIndex.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Core/BKT/BKTIndex.cpp new file mode 100644 index 0000000000..db64cd507d --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Core/BKT/BKTIndex.cpp @@ -0,0 +1,364 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Core/BKT/Index.h" + +#pragma warning(disable:4996) // 'fopen': This function or variable may be unsafe. Consider using fopen_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. +#pragma warning(disable:4242) // '=' : conversion from 'int' to 'short', possible loss of data +#pragma warning(disable:4244) // '=' : conversion from 'int' to 'short', possible loss of data +#pragma warning(disable:4127) // conditional expression is constant + +namespace SPTAG +{ + namespace BKT + { + template + ErrorCode Index::LoadIndexFromMemory(const std::vector& p_indexBlobs) + { + if (!m_pSamples.Load((char*)p_indexBlobs[0])) return ErrorCode::FailedParseValue; + if (!m_pTrees.LoadTrees((char*)p_indexBlobs[1])) return ErrorCode::FailedParseValue; + if (!m_pGraph.LoadGraphFromMemory((char*)p_indexBlobs[2])) return ErrorCode::FailedParseValue; + m_pMetadata = std::make_shared(); + if (ErrorCode::Success != m_pMetadata->LoadMetadataFromMemory((char*)p_indexBlobs[3])) + return ErrorCode::FailedParseValue; + + m_workSpacePool.reset(new COMMON::WorkSpacePool(m_iMaxCheck, GetNumSamples())); + m_workSpacePool->Init(m_iNumberOfThreads); + return ErrorCode::Success; + } + + template + ErrorCode Index::LoadIndex(const std::string& p_folderPath, Helper::IniReader& p_reader) + { +#define DefineBKTParameter(VarName, VarType, DefaultValue, RepresentStr) \ + SetParameter(RepresentStr, \ + p_reader.GetParameter("Index", \ + RepresentStr, \ + std::string(#DefaultValue)).c_str()); \ + +#include "inc/Core/BKT/ParameterDefinitionList.h" +#undef DefineBKTParameter + + if (!m_pSamples.Load(p_folderPath + m_sDataPointsFilename)) return ErrorCode::Fail; + if (!m_pTrees.LoadTrees(p_folderPath + m_sBKTFilename)) return ErrorCode::Fail; + if (!m_pGraph.LoadGraph(p_folderPath + m_sGraphFilename)) return ErrorCode::Fail; + + m_workSpacePool.reset(new COMMON::WorkSpacePool(m_iMaxCheck, GetNumSamples())); + m_workSpacePool->Init(m_iNumberOfThreads); + return ErrorCode::Success; + } + +#pragma region K-NN search + +#define Search(CheckDeleted1) \ + m_pTrees.InitSearchTrees(this, p_query, p_space); \ + const int checkPos = m_pGraph.m_iNeighborhoodSize - 1; \ + while (!p_space.m_SPTQueue.empty()) { \ + m_pTrees.SearchTrees(this, p_query, p_space, m_iNumberOfOtherDynamicPivots + p_space.m_iNumberOfCheckedLeaves); \ + while (!p_space.m_NGQueue.empty()) { \ + COMMON::HeapCell gnode = p_space.m_NGQueue.pop(); \ + const int *node = m_pGraph[gnode.node]; \ + _mm_prefetch((const char *)node, _MM_HINT_T0); \ + CheckDeleted1 { \ + if (p_query.AddPoint(gnode.node, gnode.distance)) { \ + p_space.m_iNumOfContinuousNoBetterPropagation = 0; \ + int checkNode = node[checkPos]; \ + if (checkNode < -1) { \ + const COMMON::BKTNode& tnode = m_pTrees[-2 - checkNode]; \ + for (int i = -tnode.childStart; i < tnode.childEnd; i++) { \ + if (!p_query.AddPoint(m_pTrees[i].centerid, gnode.distance)) break; \ + } \ + } \ + } \ + else { \ + p_space.m_iNumOfContinuousNoBetterPropagation++; \ + if (p_space.m_iNumOfContinuousNoBetterPropagation > p_space.m_iContinuousLimit || p_space.m_iNumberOfCheckedLeaves > p_space.m_iMaxCheck) { \ + p_query.SortResult(); return; \ + } \ + } \ + } \ + for (int i = 0; i <= checkPos; i++) { \ + _mm_prefetch((const char *)(m_pSamples)[node[i]], _MM_HINT_T0); \ + } \ + for (int i = 0; i <= checkPos; i++) { \ + int nn_index = node[i]; \ + if (nn_index < 0) break; \ + if (p_space.CheckAndSet(nn_index)) continue; \ + float distance2leaf = m_fComputeDistance(p_query.GetTarget(), (m_pSamples)[nn_index], GetFeatureDim()); \ + p_space.m_iNumberOfCheckedLeaves++; \ + p_space.m_NGQueue.insert(COMMON::HeapCell(nn_index, distance2leaf)); \ + } \ + if (p_space.m_NGQueue.Top().distance > p_space.m_SPTQueue.Top().distance) { \ + break; \ + } \ + } \ + } \ + p_query.SortResult(); \ + + template + void Index::SearchIndexWithDeleted(COMMON::QueryResultSet &p_query, COMMON::WorkSpace &p_space, const tbb::concurrent_unordered_set &p_deleted) const + { + Search(if (p_deleted.find(gnode.node) == p_deleted.end())) + } + + template + void Index::SearchIndexWithoutDeleted(COMMON::QueryResultSet &p_query, COMMON::WorkSpace &p_space) const + { + Search(;) + } + + template + ErrorCode + Index::SearchIndex(QueryResult &p_query) const + { + auto workSpace = m_workSpacePool->Rent(); + workSpace->Reset(m_iMaxCheck); + + if (m_deletedID.size() > 0) + SearchIndexWithDeleted(*((COMMON::QueryResultSet*)&p_query), *workSpace, m_deletedID); + else + SearchIndexWithoutDeleted(*((COMMON::QueryResultSet*)&p_query), *workSpace); + + m_workSpacePool->Return(workSpace); + + if (p_query.WithMeta() && nullptr != m_pMetadata) + { + for (int i = 0; i < p_query.GetResultNum(); ++i) + { + int result = p_query.GetResult(i)->VID; + p_query.SetMetadata(i, (result < 0) ? ByteArray::c_empty : m_pMetadata->GetMetadata(result)); + } + } + return ErrorCode::Success; + } +#pragma endregion + + template + ErrorCode Index::BuildIndex(const void* p_data, int p_vectorNum, int p_dimension) + { + omp_set_num_threads(m_iNumberOfThreads); + + m_pSamples.Initialize(p_vectorNum, p_dimension, (T*)p_data, false); + + if (DistCalcMethod::Cosine == m_iDistCalcMethod) + { + int base = COMMON::Utils::GetBase(); +#pragma omp parallel for + for (int i = 0; i < GetNumSamples(); i++) { + COMMON::Utils::Normalize(m_pSamples[i], GetFeatureDim(), base); + } + } + + m_workSpacePool.reset(new COMMON::WorkSpacePool(m_iMaxCheck, GetNumSamples())); + m_workSpacePool->Init(m_iNumberOfThreads); + + m_pTrees.BuildTrees(this); + m_pGraph.BuildGraph(this, &(m_pTrees.GetSampleMap())); + + return ErrorCode::Success; + } + + template + ErrorCode Index::RefineIndex(const std::string& p_folderPath) + { + std::string folderPath(p_folderPath); + if (!folderPath.empty() && *(folderPath.rbegin()) != FolderSep) + { + folderPath += FolderSep; + } + + if (!direxists(folderPath.c_str())) + { + mkdir(folderPath.c_str()); + } + + std::lock_guard lock(m_dataLock); + int newR = GetNumSamples(); + + std::vector indices; + std::vector reverseIndices(newR); + for (int i = 0; i < newR; i++) { + if (m_deletedID.find(i) == m_deletedID.end()) { + indices.push_back(i); + reverseIndices[i] = i; + } + else { + while (m_deletedID.find(newR - 1) != m_deletedID.end() && newR > i) newR--; + if (newR == i) break; + indices.push_back(newR - 1); + reverseIndices[newR - 1] = i; + newR--; + } + } + + std::cout << "Refine... from " << GetNumSamples() << "->" << newR << std::endl; + + if (false == m_pSamples.Refine(indices, folderPath + m_sDataPointsFilename)) return ErrorCode::FailedCreateFile; + if (nullptr != m_pMetadata && ErrorCode::Success != m_pMetadata->RefineMetadata(indices, folderPath)) return ErrorCode::FailedCreateFile; + + COMMON::BKTree newTrees(m_pTrees); + newTrees.BuildTrees(this, &indices); +#pragma omp parallel for + for (int i = 0; i < newTrees.size(); i++) { + newTrees[i].centerid = reverseIndices[newTrees[i].centerid]; + } + newTrees.SaveTrees(folderPath + m_sBKTFilename); + + m_pGraph.RefineGraph(this, indices, reverseIndices, folderPath + m_sGraphFilename, + &(newTrees.GetSampleMap())); + return ErrorCode::Success; + } + + template + ErrorCode Index::DeleteIndex(const void* p_vectors, int p_vectorNum) { + const T* ptr_v = (const T*)p_vectors; +#pragma omp parallel for schedule(dynamic) + for (int i = 0; i < p_vectorNum; i++) { + COMMON::QueryResultSet query(ptr_v + i * GetFeatureDim(), m_pGraph.m_iCEF); + SearchIndex(query); + + for (int i = 0; i < m_pGraph.m_iCEF; i++) { + if (query.GetResult(i)->Dist < 1e-6) { + std::lock_guard lock(m_dataLock); + m_deletedID.insert(query.GetResult(i)->VID); + } + } + } + return ErrorCode::Success; + } + + template + ErrorCode Index::AddIndex(const void* p_vectors, int p_vectorNum, int p_dimension) + { + int begin, end; + { + std::lock_guard lock(m_dataLock); + + if (GetNumSamples() == 0) + return BuildIndex(p_vectors, p_vectorNum, p_dimension); + + if (p_dimension != GetFeatureDim()) + return ErrorCode::FailedParseValue; + + begin = GetNumSamples(); + end = GetNumSamples() + p_vectorNum; + + m_pSamples.AddBatch((const T*)p_vectors, p_vectorNum); + m_pGraph.AddBatch(p_vectorNum); + + if (m_pSamples.R() != end || m_pGraph.R() != end) { + std::cout << "Memory Error: Cannot alloc space for vectors" << std::endl; + m_pSamples.SetR(begin); + m_pGraph.SetR(begin); + return ErrorCode::Fail; + } + if (DistCalcMethod::Cosine == m_iDistCalcMethod) + { + int base = COMMON::Utils::GetBase(); + for (int i = begin; i < end; i++) { + COMMON::Utils::Normalize((T*)m_pSamples[i], GetFeatureDim(), base); + } + } + } + + for (int node = begin; node < end; node++) + { + m_pGraph.RefineNode(this, node, true); + } + std::cout << "Add " << p_vectorNum << " vectors" << std::endl; + return ErrorCode::Success; + } + + template + ErrorCode + Index::SaveIndexToMemory(std::vector& p_indexBlobs, std::vector &p_indexBlobsLen) + { + p_indexBlobs.resize(4); + p_indexBlobsLen.resize(4); + if (!m_pSamples.Save(&p_indexBlobs[0], p_indexBlobsLen[0])) return ErrorCode::Fail; + if (!m_pTrees.SaveTrees(&p_indexBlobs[1], p_indexBlobsLen[1])) return ErrorCode::Fail; + if (!m_pGraph.SaveGraphToMemory(&p_indexBlobs[2], p_indexBlobsLen[2])) return ErrorCode::Fail; + if (ErrorCode::Success != m_pMetadata->SaveMetadataToMemory(&p_indexBlobs[3], p_indexBlobsLen[3])) + return ErrorCode::Fail; + return ErrorCode::Success; + } + + template + ErrorCode + Index::SaveIndex(const std::string& p_folderPath, std::ofstream& p_configout) + { + m_sDataPointsFilename = "vectors.bin"; + m_sBKTFilename = "tree.bin"; + m_sGraphFilename = "graph.bin"; + +#define DefineBKTParameter(VarName, VarType, DefaultValue, RepresentStr) \ + p_configout << RepresentStr << "=" << GetParameter(RepresentStr) << std::endl; + +#include "inc/Core/BKT/ParameterDefinitionList.h" +#undef DefineBKTParameter + + p_configout << std::endl; + + if (m_deletedID.size() > 0) { + RefineIndex(p_folderPath); + } + else { + if (!m_pSamples.Save(p_folderPath + m_sDataPointsFilename)) return ErrorCode::Fail; + if (!m_pTrees.SaveTrees(p_folderPath + m_sBKTFilename)) return ErrorCode::Fail; + if (!m_pGraph.SaveGraph(p_folderPath + m_sGraphFilename)) return ErrorCode::Fail; + } + return ErrorCode::Success; + } + + template + ErrorCode + Index::SetParameter(const char* p_param, const char* p_value) + { + if (nullptr == p_param || nullptr == p_value) return ErrorCode::Fail; + +#define DefineBKTParameter(VarName, VarType, DefaultValue, RepresentStr) \ + else if (SPTAG::Helper::StrUtils::StrEqualIgnoreCase(p_param, RepresentStr)) \ + { \ + fprintf(stderr, "Setting %s with value %s\n", RepresentStr, p_value); \ + VarType tmp; \ + if (SPTAG::Helper::Convert::ConvertStringTo(p_value, tmp)) \ + { \ + VarName = tmp; \ + } \ + } \ + +#include "inc/Core/BKT/ParameterDefinitionList.h" +#undef DefineBKTParameter + + m_fComputeDistance = COMMON::DistanceCalcSelector(m_iDistCalcMethod); + return ErrorCode::Success; + } + + + template + std::string + Index::GetParameter(const char* p_param) const + { + if (nullptr == p_param) return std::string(); + +#define DefineBKTParameter(VarName, VarType, DefaultValue, RepresentStr) \ + else if (SPTAG::Helper::StrUtils::StrEqualIgnoreCase(p_param, RepresentStr)) \ + { \ + return SPTAG::Helper::Convert::ConvertToString(VarName); \ + } \ + +#include "inc/Core/BKT/ParameterDefinitionList.h" +#undef DefineBKTParameter + + return std::string(); + } + } +} + +#define DefineVectorValueType(Name, Type) \ +template class SPTAG::BKT::Index; \ + +#include "inc/Core/DefinitionList.h" +#undef DefineVectorValueType + + diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/Core/Common/NeighborhoodGraph.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Core/Common/NeighborhoodGraph.cpp new file mode 100644 index 0000000000..94115dd0a3 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Core/Common/NeighborhoodGraph.cpp @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Core/Common/NeighborhoodGraph.h" +#include "inc/Core/Common/RelativeNeighborhoodGraph.h" + +using namespace SPTAG::COMMON; + +std::shared_ptr NeighborhoodGraph::CreateInstance(std::string type) +{ + std::shared_ptr res; + if (type == "RNG") + { + res.reset(new RelativeNeighborhoodGraph); + } + return res; +} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/Core/Common/WorkSpacePool.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Core/Common/WorkSpacePool.cpp new file mode 100644 index 0000000000..036e281ec8 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Core/Common/WorkSpacePool.cpp @@ -0,0 +1,66 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Core/Common/WorkSpacePool.h" + +using namespace SPTAG; +using namespace SPTAG::COMMON; + + +WorkSpacePool::WorkSpacePool(int p_maxCheck, int p_vectorCount) + : m_maxCheck(p_maxCheck), + m_vectorCount(p_vectorCount) +{ +} + + +WorkSpacePool::~WorkSpacePool() +{ + for (auto& workSpace : m_workSpacePool) + workSpace.reset(); + m_workSpacePool.clear(); +} + + +std::shared_ptr +WorkSpacePool::Rent() +{ + std::shared_ptr workSpace; + + { + std::lock_guard lock(m_workSpacePoolMutex); + if (!m_workSpacePool.empty()) + { + workSpace = m_workSpacePool.front(); + m_workSpacePool.pop_front(); + } + else + { + workSpace.reset(new WorkSpace); + workSpace->Initialize(m_maxCheck, m_vectorCount); + } + } + return workSpace; +} + + +void +WorkSpacePool::Return(const std::shared_ptr& p_workSpace) +{ + { + std::lock_guard lock(m_workSpacePoolMutex); + m_workSpacePool.push_back(p_workSpace); + } +} + + +void +WorkSpacePool::Init(int size) +{ + for (int i = 0; i < size; i++) + { + std::shared_ptr workSpace(new WorkSpace); + workSpace->Initialize(m_maxCheck, m_vectorCount); + m_workSpacePool.push_back(std::move(workSpace)); + } +} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/Core/CommonDataStructure.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Core/CommonDataStructure.cpp new file mode 100644 index 0000000000..4a91554dac --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Core/CommonDataStructure.cpp @@ -0,0 +1,132 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Core/CommonDataStructure.h" + +using namespace SPTAG; + +const ByteArray ByteArray::c_empty; + +ByteArray::ByteArray() + : m_data(nullptr), + m_length(0) +{ +} + + +ByteArray::ByteArray(ByteArray&& p_right) + : m_data(p_right.m_data), + m_length(p_right.m_length), + m_dataHolder(std::move(p_right.m_dataHolder)) +{ +} + + +ByteArray::ByteArray(std::uint8_t* p_array, std::size_t p_length, bool p_transferOnwership) + : m_data(p_array), + m_length(p_length) +{ + if (p_transferOnwership) + { + m_dataHolder.reset(m_data, std::default_delete()); + } +} + + +ByteArray::ByteArray(std::uint8_t* p_array, std::size_t p_length, std::shared_ptr p_dataHolder) + : m_data(p_array), + m_length(p_length), + m_dataHolder(std::move(p_dataHolder)) +{ +} + + +ByteArray::ByteArray(const ByteArray& p_right) + : m_data(p_right.m_data), + m_length(p_right.m_length), + m_dataHolder(p_right.m_dataHolder) +{ +} + + +ByteArray& +ByteArray::operator= (const ByteArray& p_right) +{ + m_data = p_right.m_data; + m_length = p_right.m_length; + m_dataHolder = p_right.m_dataHolder; + + return *this; +} + + +ByteArray& +ByteArray::operator= (ByteArray&& p_right) +{ + m_data = p_right.m_data; + m_length = p_right.m_length; + m_dataHolder = std::move(p_right.m_dataHolder); + + return *this; +} + + +ByteArray::~ByteArray() +{ +} + + +ByteArray +ByteArray::Alloc(std::size_t p_length) +{ + ByteArray byteArray; + if (0 == p_length) + { + return byteArray; + } + + byteArray.m_dataHolder.reset(new std::uint8_t[p_length], + std::default_delete()); + + byteArray.m_length = p_length; + byteArray.m_data = byteArray.m_dataHolder.get(); + return byteArray; +} + + +std::uint8_t* +ByteArray::Data() const +{ + return m_data; +} + + +std::size_t +ByteArray::Length() const +{ + return m_length; +} + + +void +ByteArray::SetData(std::uint8_t* p_array, std::size_t p_length) +{ + m_data = p_array; + m_length = p_length; +} + + +std::shared_ptr +ByteArray::DataHolder() const +{ + return m_dataHolder; +} + + +void +ByteArray::Clear() +{ + m_data = nullptr; + m_dataHolder.reset(); + m_length = 0; +} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/Core/KDT/KDTIndex.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Core/KDT/KDTIndex.cpp new file mode 100644 index 0000000000..5fce713a56 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Core/KDT/KDTIndex.cpp @@ -0,0 +1,357 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Core/KDT/Index.h" + +#pragma warning(disable:4996) // 'fopen': This function or variable may be unsafe. Consider using fopen_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. +#pragma warning(disable:4242) // '=' : conversion from 'int' to 'short', possible loss of data +#pragma warning(disable:4244) // '=' : conversion from 'int' to 'short', possible loss of data +#pragma warning(disable:4127) // conditional expression is constant + +namespace SPTAG +{ + namespace KDT + { + template + ErrorCode Index::LoadIndexFromMemory(const std::vector& p_indexBlobs) + { + if (!m_pSamples.Load((char*)p_indexBlobs[0])) return ErrorCode::FailedParseValue; + if (!m_pTrees.LoadTrees((char*)p_indexBlobs[1])) return ErrorCode::FailedParseValue; + if (!m_pGraph.LoadGraphFromMemory((char*)p_indexBlobs[2])) return ErrorCode::FailedParseValue; + m_pMetadata = std::make_shared(); + if (ErrorCode::Success != m_pMetadata->LoadMetadataFromMemory((char*)p_indexBlobs[3])) + return ErrorCode::FailedParseValue; + + m_workSpacePool.reset(new COMMON::WorkSpacePool(m_iMaxCheck, GetNumSamples())); + m_workSpacePool->Init(m_iNumberOfThreads); + return ErrorCode::Success; + } + + template + ErrorCode Index::LoadIndex(const std::string& p_folderPath, Helper::IniReader& p_reader) + { +#define DefineKDTParameter(VarName, VarType, DefaultValue, RepresentStr) \ + SetParameter(RepresentStr, \ + p_reader.GetParameter("Index", \ + RepresentStr, \ + std::string(#DefaultValue)).c_str()); \ + +#include "inc/Core/KDT/ParameterDefinitionList.h" +#undef DefineKDTParameter + + if (!m_pSamples.Load(p_folderPath + m_sDataPointsFilename)) return ErrorCode::Fail; + if (!m_pTrees.LoadTrees(p_folderPath + m_sKDTFilename)) return ErrorCode::Fail; + if (!m_pGraph.LoadGraph(p_folderPath + m_sGraphFilename)) return ErrorCode::Fail; + + m_workSpacePool.reset(new COMMON::WorkSpacePool(m_iMaxCheck, GetNumSamples())); + m_workSpacePool->Init(m_iNumberOfThreads); + return ErrorCode::Success; + } + +#pragma region K-NN search + +#define Search(CheckDeleted1) \ + m_pTrees.InitSearchTrees(this, p_query, p_space, m_iNumberOfInitialDynamicPivots); \ + while (!p_space.m_NGQueue.empty()) { \ + COMMON::HeapCell gnode = p_space.m_NGQueue.pop(); \ + const int *node = m_pGraph[gnode.node]; \ + _mm_prefetch((const char *)node, _MM_HINT_T0); \ + CheckDeleted1 { \ + if (!p_query.AddPoint(gnode.node, gnode.distance) && p_space.m_iNumberOfCheckedLeaves > p_space.m_iMaxCheck) { \ + p_query.SortResult(); return; \ + } \ + } \ + for (int i = 0; i < m_pGraph.m_iNeighborhoodSize; i++) \ + _mm_prefetch((const char *)(m_pSamples)[node[i]], _MM_HINT_T0); \ + float upperBound = max(p_query.worstDist(), gnode.distance); \ + bool bLocalOpt = true; \ + for (int i = 0; i < m_pGraph.m_iNeighborhoodSize; i++) { \ + int nn_index = node[i]; \ + if (nn_index < 0) break; \ + if (p_space.CheckAndSet(nn_index)) continue; \ + float distance2leaf = m_fComputeDistance(p_query.GetTarget(), (m_pSamples)[nn_index], GetFeatureDim()); \ + if (distance2leaf <= upperBound) bLocalOpt = false; \ + p_space.m_iNumberOfCheckedLeaves++; \ + p_space.m_NGQueue.insert(COMMON::HeapCell(nn_index, distance2leaf)); \ + } \ + if (bLocalOpt) p_space.m_iNumOfContinuousNoBetterPropagation++; \ + else p_space.m_iNumOfContinuousNoBetterPropagation = 0; \ + if (p_space.m_iNumOfContinuousNoBetterPropagation > m_iThresholdOfNumberOfContinuousNoBetterPropagation) { \ + if (p_space.m_iNumberOfTreeCheckedLeaves <= p_space.m_iNumberOfCheckedLeaves / 10) { \ + m_pTrees.SearchTrees(this, p_query, p_space, m_iNumberOfOtherDynamicPivots + p_space.m_iNumberOfCheckedLeaves); \ + } else if (gnode.distance > p_query.worstDist()) { \ + break; \ + } \ + } \ + } \ + p_query.SortResult(); \ + + template + void Index::SearchIndexWithDeleted(COMMON::QueryResultSet &p_query, COMMON::WorkSpace &p_space, const tbb::concurrent_unordered_set &p_deleted) const + { + Search(if (p_deleted.find(gnode.node) == p_deleted.end())) + } + + template + void Index::SearchIndexWithoutDeleted(COMMON::QueryResultSet &p_query, COMMON::WorkSpace &p_space) const + { + Search(;) + } + + template + ErrorCode + Index::SearchIndex(QueryResult &p_query) const + { + auto workSpace = m_workSpacePool->Rent(); + workSpace->Reset(m_iMaxCheck); + + if (m_deletedID.size() > 0) + SearchIndexWithDeleted(*((COMMON::QueryResultSet*)&p_query), *workSpace, m_deletedID); + else + SearchIndexWithoutDeleted(*((COMMON::QueryResultSet*)&p_query), *workSpace); + + m_workSpacePool->Return(workSpace); + + if (p_query.WithMeta() && nullptr != m_pMetadata) + { + for (int i = 0; i < p_query.GetResultNum(); ++i) + { + int result = p_query.GetResult(i)->VID; + p_query.SetMetadata(i, (result < 0) ? ByteArray::c_empty : m_pMetadata->GetMetadata(result)); + } + } + return ErrorCode::Success; + } +#pragma endregion + + template + ErrorCode Index::BuildIndex(const void* p_data, int p_vectorNum, int p_dimension) + { + omp_set_num_threads(m_iNumberOfThreads); + + m_pSamples.Initialize(p_vectorNum, p_dimension, (T*)p_data, false); + + if (DistCalcMethod::Cosine == m_iDistCalcMethod) + { + int base = COMMON::Utils::GetBase(); +#pragma omp parallel for + for (int i = 0; i < GetNumSamples(); i++) { + COMMON::Utils::Normalize(m_pSamples[i], GetFeatureDim(), base); + } + } + + m_workSpacePool.reset(new COMMON::WorkSpacePool(m_iMaxCheck, GetNumSamples())); + m_workSpacePool->Init(m_iNumberOfThreads); + + m_pTrees.BuildTrees(this); + m_pGraph.BuildGraph(this); + + return ErrorCode::Success; + } + + template + ErrorCode Index::RefineIndex(const std::string& p_folderPath) + { + std::string folderPath(p_folderPath); + if (!folderPath.empty() && *(folderPath.rbegin()) != FolderSep) + { + folderPath += FolderSep; + } + + if (!direxists(folderPath.c_str())) + { + mkdir(folderPath.c_str()); + } + + std::lock_guard lock(m_dataLock); + int newR = GetNumSamples(); + + std::vector indices; + std::vector reverseIndices(newR); + for (int i = 0; i < newR; i++) { + if (m_deletedID.find(i) == m_deletedID.end()) { + indices.push_back(i); + reverseIndices[i] = i; + } + else { + while (m_deletedID.find(newR - 1) != m_deletedID.end() && newR > i) newR--; + if (newR == i) break; + indices.push_back(newR - 1); + reverseIndices[newR - 1] = i; + newR--; + } + } + + std::cout << "Refine... from " << GetNumSamples() << "->" << newR << std::endl; + + if (false == m_pSamples.Refine(indices, folderPath + m_sDataPointsFilename)) return ErrorCode::FailedCreateFile; + if (nullptr != m_pMetadata && ErrorCode::Success != m_pMetadata->RefineMetadata(indices, folderPath)) return ErrorCode::FailedCreateFile; + + m_pGraph.RefineGraph(this, indices, reverseIndices, folderPath + m_sGraphFilename); + + COMMON::KDTree newTrees(m_pTrees); + newTrees.BuildTrees(this, &indices); +#pragma omp parallel for + for (int i = 0; i < newTrees.size(); i++) { + if (newTrees[i].left < 0) + newTrees[i].left = -reverseIndices[-newTrees[i].left - 1] - 1; + if (newTrees[i].right < 0) + newTrees[i].right = -reverseIndices[-newTrees[i].right - 1] - 1; + } + newTrees.SaveTrees(folderPath + m_sKDTFilename); + return ErrorCode::Success; + } + + template + ErrorCode Index::DeleteIndex(const void* p_vectors, int p_vectorNum) { + const T* ptr_v = (const T*)p_vectors; +#pragma omp parallel for schedule(dynamic) + for (int i = 0; i < p_vectorNum; i++) { + COMMON::QueryResultSet query(ptr_v + i * GetFeatureDim(), m_pGraph.m_iCEF); + SearchIndex(query); + + for (int i = 0; i < m_pGraph.m_iCEF; i++) { + if (query.GetResult(i)->Dist < 1e-6) { + std::lock_guard lock(m_dataLock); + m_deletedID.insert(query.GetResult(i)->VID); + } + } + } + return ErrorCode::Success; + } + + template + ErrorCode Index::AddIndex(const void* p_vectors, int p_vectorNum, int p_dimension) + { + int begin, end; + { + std::lock_guard lock(m_dataLock); + + if (GetNumSamples() == 0) + return BuildIndex(p_vectors, p_vectorNum, p_dimension); + + if (p_dimension != GetFeatureDim()) + return ErrorCode::FailedParseValue; + + begin = GetNumSamples(); + end = GetNumSamples() + p_vectorNum; + + m_pSamples.AddBatch((const T*)p_vectors, p_vectorNum); + m_pGraph.AddBatch(p_vectorNum); + + if (m_pSamples.R() != end || m_pGraph.R() != end) { + std::cout << "Memory Error: Cannot alloc space for vectors" << std::endl; + m_pSamples.SetR(begin); + m_pGraph.SetR(begin); + return ErrorCode::Fail; + } + if (DistCalcMethod::Cosine == m_iDistCalcMethod) + { + int base = COMMON::Utils::GetBase(); + for (int i = begin; i < end; i++) { + COMMON::Utils::Normalize((T*)m_pSamples[i], GetFeatureDim(), base); + } + } + } + + for (int node = begin; node < end; node++) + { + m_pGraph.RefineNode(this, node, true); + } + std::cout << "Add " << p_vectorNum << " vectors" << std::endl; + return ErrorCode::Success; + } + + template + ErrorCode + Index::SaveIndexToMemory(std::vector& p_indexBlobs, std::vector &p_indexBlobsLen) + { + p_indexBlobs.resize(4); + p_indexBlobsLen.resize(4); + if (!m_pSamples.Save(&p_indexBlobs[0], p_indexBlobsLen[0])) return ErrorCode::Fail; + if (!m_pTrees.SaveTrees(&p_indexBlobs[1], p_indexBlobsLen[1])) return ErrorCode::Fail; + if (!m_pGraph.SaveGraphToMemory(&p_indexBlobs[2], p_indexBlobsLen[2])) return ErrorCode::Fail; + if (ErrorCode::Success != m_pMetadata->SaveMetadataToMemory(&p_indexBlobs[3], p_indexBlobsLen[3])) + return ErrorCode::Fail; + return ErrorCode::Success; + } + + template + ErrorCode + Index::SaveIndex(const std::string& p_folderPath, std::ofstream& p_configout) + { + m_sDataPointsFilename = "vectors.bin"; + m_sKDTFilename = "tree.bin"; + m_sGraphFilename = "graph.bin"; + +#define DefineKDTParameter(VarName, VarType, DefaultValue, RepresentStr) \ + p_configout << RepresentStr << "=" << GetParameter(RepresentStr) << std::endl; + +#include "inc/Core/KDT/ParameterDefinitionList.h" +#undef DefineKDTParameter + + p_configout << std::endl; + + if (m_deletedID.size() > 0) { + RefineIndex(p_folderPath); + } + else { + if (!m_pSamples.Save(p_folderPath + m_sDataPointsFilename)) return ErrorCode::Fail; + if (!m_pTrees.SaveTrees(p_folderPath + m_sKDTFilename)) return ErrorCode::Fail; + if (!m_pGraph.SaveGraph(p_folderPath + m_sGraphFilename)) return ErrorCode::Fail; + } + return ErrorCode::Success; + } + + template + ErrorCode + Index::SetParameter(const char* p_param, const char* p_value) + { + if (nullptr == p_param || nullptr == p_value) return ErrorCode::Fail; + +#define DefineKDTParameter(VarName, VarType, DefaultValue, RepresentStr) \ + else if (SPTAG::Helper::StrUtils::StrEqualIgnoreCase(p_param, RepresentStr)) \ + { \ + fprintf(stderr, "Setting %s with value %s\n", RepresentStr, p_value); \ + VarType tmp; \ + if (SPTAG::Helper::Convert::ConvertStringTo(p_value, tmp)) \ + { \ + VarName = tmp; \ + } \ + } \ + +#include "inc/Core/KDT/ParameterDefinitionList.h" +#undef DefineKDTParameter + + m_fComputeDistance = COMMON::DistanceCalcSelector(m_iDistCalcMethod); + return ErrorCode::Success; + } + + + template + std::string + Index::GetParameter(const char* p_param) const + { + if (nullptr == p_param) return std::string(); + +#define DefineKDTParameter(VarName, VarType, DefaultValue, RepresentStr) \ + else if (SPTAG::Helper::StrUtils::StrEqualIgnoreCase(p_param, RepresentStr)) \ + { \ + return SPTAG::Helper::Convert::ConvertToString(VarName); \ + } \ + +#include "inc/Core/KDT/ParameterDefinitionList.h" +#undef DefineKDTParameter + + return std::string(); + } + } +} + +#define DefineVectorValueType(Name, Type) \ +template class SPTAG::KDT::Index; \ + +#include "inc/Core/DefinitionList.h" +#undef DefineVectorValueType + + diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/Core/MetadataSet.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Core/MetadataSet.cpp new file mode 100644 index 0000000000..2eefcea68f --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Core/MetadataSet.cpp @@ -0,0 +1,329 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Core/MetadataSet.h" + +#include +#include +#include + +using namespace SPTAG; + +ErrorCode +MetadataSet::RefineMetadata(std::vector& indices, const std::string& p_folderPath) +{ + std::ofstream metaOut(p_folderPath + "metadata.bin_tmp", std::ios::binary); + std::ofstream metaIndexOut(p_folderPath + "metadataIndex.bin", std::ios::binary); + if (!metaOut.is_open() || !metaIndexOut.is_open()) return ErrorCode::FailedCreateFile; + + int R = (int)indices.size(); + metaIndexOut.write((char*)&R, sizeof(int)); + std::uint64_t offset = 0; + for (int i = 0; i < R; i++) { + metaIndexOut.write((char*)&offset, sizeof(std::uint64_t)); + ByteArray meta = GetMetadata(indices[i]); + metaOut.write((char*)meta.Data(), sizeof(uint8_t)*meta.Length()); + offset += meta.Length(); + } + metaOut.close(); + metaIndexOut.write((char*)&offset, sizeof(std::uint64_t)); + metaIndexOut.close(); + + SPTAG::MetadataSet::MetaCopy(p_folderPath + "metadata.bin_tmp", p_folderPath + "metadata.bin"); + return ErrorCode::Success; +} + + +ErrorCode +MetadataSet::MetaCopy(const std::string& p_src, const std::string& p_dst) +{ + if (p_src == p_dst) return ErrorCode::Success; + + std::ifstream src(p_src, std::ios::binary); + if (!src.is_open()) + { + std::cerr << "ERROR: Can't open " << p_src << std::endl; + return ErrorCode::FailedOpenFile; + } + + std::ofstream dst(p_dst, std::ios::binary); + if (!dst.is_open()) + { + std::cerr << "ERROR: Can't create " << p_dst << std::endl; + src.close(); + return ErrorCode::FailedCreateFile; + } + + int bufsize = 1000000; + char* buf = new char[bufsize]; + while (!src.eof()) { + src.read(buf, bufsize); + dst.write(buf, src.gcount()); + } + delete[] buf; + src.close(); + dst.close(); + + return ErrorCode::Success; +} + +MetadataSet::MetadataSet() +{ +} + + +MetadataSet:: ~MetadataSet() +{ +} + + +FileMetadataSet::FileMetadataSet(const std::string& p_metafile, const std::string& p_metaindexfile) + : m_metaFile(p_metafile), + m_metaindexFile(p_metaindexfile) +{ + m_fp = new std::ifstream(p_metafile, std::ifstream::binary); + std::ifstream fpidx(p_metaindexfile, std::ifstream::binary); + if (!m_fp->is_open() || !fpidx.is_open()) + { + std::cerr << "ERROR: Cannot open meta files " << p_metafile << " and " << p_metaindexfile << "!" << std::endl; + return; + } + + fpidx.read((char *)&m_count, sizeof(m_count)); + m_pOffsets.resize(m_count + 1); + fpidx.read((char *)m_pOffsets.data(), sizeof(std::uint64_t) * (m_count + 1)); + fpidx.close(); +} + + +FileMetadataSet::~FileMetadataSet() +{ + if (m_fp) + { + m_fp->close(); + delete m_fp; + } +} + + +ByteArray +FileMetadataSet::GetMetadata(IndexType p_vectorID) const +{ + std::uint64_t startoff = m_pOffsets[p_vectorID]; + std::uint64_t bytes = m_pOffsets[p_vectorID + 1] - startoff; + if (p_vectorID < (IndexType)m_count) { + m_fp->seekg(startoff, std::ios_base::beg); + ByteArray b = ByteArray::Alloc((SizeType)bytes); + m_fp->read((char*)b.Data(), bytes); + return b; + } + else { + startoff -= m_pOffsets[m_count]; + return ByteArray((std::uint8_t*)m_newdata.data() + startoff, static_cast(bytes), false); + } +} + + +SizeType +FileMetadataSet::Count() const +{ + return static_cast(m_pOffsets.size() - 1); +} + + +bool +FileMetadataSet::Available() const +{ + return m_fp && m_fp->is_open() && m_pOffsets.size() > 1; +} + + +void +FileMetadataSet::AddBatch(MetadataSet& data) +{ + for (int i = 0; i < static_cast(data.Count()); i++) + { + ByteArray newdata = data.GetMetadata(i); + m_newdata.insert(m_newdata.end(), newdata.Data(), newdata.Data() + newdata.Length()); + m_pOffsets.push_back(m_pOffsets[m_pOffsets.size() - 1] + newdata.Length()); + } +} + + +ErrorCode +FileMetadataSet::SaveMetadata(const std::string& p_metaFile, const std::string& p_metaindexFile) +{ + ErrorCode ret = ErrorCode::Success; + m_fp->close(); + ret = MetaCopy(m_metaFile, p_metaFile); + if (ErrorCode::Success != ret) + { + return ret; + } + if (m_newdata.size() > 0) { + std::ofstream tmpout(p_metaFile, std::ofstream::app|std::ios::binary); + if (!tmpout.is_open()) return ErrorCode::FailedOpenFile; + tmpout.write((char*)m_newdata.data(), m_newdata.size()); + tmpout.close(); + } + m_fp->open(p_metaFile, std::ifstream::binary); + + std::ofstream dst(p_metaindexFile, std::ios::binary); + m_count = static_cast(m_pOffsets.size()) - 1; + m_newdata.clear(); + dst.write((char*)&m_count, sizeof(m_count)); + dst.write((char*)m_pOffsets.data(), sizeof(std::uint64_t) * m_pOffsets.size()); + return ret; +} + + +ErrorCode +FileMetadataSet::SaveMetadataToMemory(void **pGraphMemFile, int64_t &len) { + // TODO: serialize file to mem? + return ErrorCode::Fail; +} + +ErrorCode +FileMetadataSet::LoadMetadataFromMemory(void *pGraphMemFile) { + // TODO: not support yet + return ErrorCode::Fail; +} + +MemMetadataSet::MemMetadataSet(ByteArray p_metadata, ByteArray p_offsets, SizeType p_count) + : m_metadataHolder(std::move(p_metadata)), + m_offsetHolder(std::move(p_offsets)), + m_count(p_count) +{ + const std::uint64_t* newdata = reinterpret_cast(m_offsetHolder.Data()); + m_offsets.insert(m_offsets.end(), newdata, newdata + p_count + 1); +} + + +MemMetadataSet::~MemMetadataSet() +{ +} + + +ByteArray +MemMetadataSet::GetMetadata(IndexType p_vectorID) const +{ + if (static_cast(p_vectorID) < m_count) + { + return ByteArray(m_metadataHolder.Data() + m_offsets[p_vectorID], + static_cast(m_offsets[p_vectorID + 1] - m_offsets[p_vectorID]), + m_metadataHolder.DataHolder()); + } + else if (p_vectorID < m_offsets.size() - 1) { + return ByteArray((std::uint8_t*)m_newdata.data() + m_offsets[p_vectorID] - m_offsets[m_count], + static_cast(m_offsets[p_vectorID + 1] - m_offsets[p_vectorID]), + false); + } + + return ByteArray::c_empty; +} + + +SizeType +MemMetadataSet::Count() const +{ + return m_count; +} + + +bool +MemMetadataSet::Available() const +{ + return m_metadataHolder.Length() > 0 && m_offsetHolder.Length() > 0; +} + +void +MemMetadataSet::AddBatch(MetadataSet& data) +{ + for (int i = 0; i < static_cast(data.Count()); i++) + { + ByteArray newdata = data.GetMetadata(i); + m_newdata.insert(m_newdata.end(), newdata.Data(), newdata.Data() + newdata.Length()); + m_offsets.push_back(m_offsets[m_offsets.size() - 1] + newdata.Length()); + } +} + +ErrorCode +MemMetadataSet::SaveMetadata(const std::string& p_metaFile, const std::string& p_metaindexFile) +{ + std::ofstream outputStream; + outputStream.open(p_metaFile, std::ios::binary); + if (!outputStream.is_open()) + { + std::cerr << "Error: Failed to create file " << p_metaFile << "." << std::endl; + return ErrorCode::FailedCreateFile; + } + + outputStream.write(reinterpret_cast(m_metadataHolder.Data()), m_metadataHolder.Length()); + outputStream.write((const char*)m_newdata.data(), sizeof(std::uint8_t)*m_newdata.size()); + outputStream.close(); + + outputStream.open(p_metaindexFile, std::ios::binary); + if (!outputStream.is_open()) + { + std::cerr << "Error: Failed to create file " << p_metaindexFile << "." << std::endl; + return ErrorCode::FailedCreateFile; + } + + m_count = static_cast(m_offsets.size()) - 1; + outputStream.write(reinterpret_cast(&m_count), sizeof(m_count)); + outputStream.write(reinterpret_cast(m_offsets.data()), sizeof(std::uint64_t)*m_offsets.size()); + outputStream.close(); + + return ErrorCode::Success; +} + +ErrorCode +MemMetadataSet::SaveMetadataToMemory(void **pGraphMemFile, int64_t &len) { + auto size = sizeof(int64_t) + sizeof(int64_t) + m_metadataHolder.Length() + sizeof(std::uint64_t) * m_offsets.size(); + char* mem = (char*)malloc(size); + if (mem == NULL) return ErrorCode::Fail; + + auto ptr = mem; + *(int64_t*)ptr = m_metadataHolder.Length(); + ptr += sizeof(int64_t); + + m_count = static_cast(m_offsets.size()) - 1; + *(int64_t*)ptr = m_count; + ptr += sizeof(int64_t); + + memcpy(ptr, m_metadataHolder.Data(), m_metadataHolder.Length()); + ptr += m_metadataHolder.Length(); + + memcpy(ptr, m_offsets.data(), sizeof(std::uint64_t)*m_offsets.size()); + + *pGraphMemFile = mem; + len = size; + + return ErrorCode::Success; +} + +ErrorCode +MemMetadataSet::LoadMetadataFromMemory(void *pGraphMemFile) { + m_metadataHolder.Clear(); + m_offsetHolder.Clear(); + m_offsets.clear(); + + char* ptr = (char *)pGraphMemFile; + auto metadataHolderLength = *(int64_t *)ptr; + ptr += sizeof(int64_t); + + m_count = *(int64_t *)ptr; + ptr += sizeof(int64_t); + + m_metadataHolder = ByteArray::Alloc(metadataHolderLength); + memcpy(m_metadataHolder.Data(), ptr, metadataHolderLength); + ptr += metadataHolderLength; + + m_offsetHolder = ByteArray::Alloc(sizeof(std::uint64_t ) * (m_count + 1)); + memcpy(m_offsetHolder.Data(), ptr, sizeof(std::uint64_t ) * (m_count + 1)); + + const std::uint64_t* newdata = reinterpret_cast(m_offsetHolder.Data()); + m_offsets.insert(m_offsets.end(), newdata, newdata + m_count + 1); + + return ErrorCode::Success; +} diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/Core/VectorIndex.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Core/VectorIndex.cpp new file mode 100644 index 0000000000..657978b749 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Core/VectorIndex.cpp @@ -0,0 +1,322 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Core/VectorIndex.h" +#include "inc/Core/Common/DataUtils.h" +#include "inc/Helper/CommonHelper.h" +#include "inc/Helper/StringConvert.h" +#include "inc/Helper/SimpleIniReader.h" + +#include "inc/Core/BKT/Index.h" +#include "inc/Core/KDT/Index.h" +#include + + +using namespace SPTAG; + + +VectorIndex::VectorIndex() +{ +} + + +VectorIndex::~VectorIndex() +{ +} + + +std::string +VectorIndex::GetParameter(const std::string& p_param) const +{ + return GetParameter(p_param.c_str()); +} + + +ErrorCode +VectorIndex::SetParameter(const std::string& p_param, const std::string& p_value) +{ + return SetParameter(p_param.c_str(), p_value.c_str()); +} + + +void +VectorIndex::SetMetadata(const std::string& p_metadataFilePath, const std::string& p_metadataIndexPath) { + m_pMetadata.reset(new FileMetadataSet(p_metadataFilePath, p_metadataIndexPath)); +} + + +ByteArray +VectorIndex::GetMetadata(IndexType p_vectorID) const { + if (nullptr != m_pMetadata) + { + return m_pMetadata->GetMetadata(p_vectorID); + } + return ByteArray::c_empty; +} + + +ErrorCode +VectorIndex::LoadIndex(const std::string& p_folderPath) +{ + std::string folderPath(p_folderPath); + if (!folderPath.empty() && *(folderPath.rbegin()) != FolderSep) + { + folderPath += FolderSep; + } + + Helper::IniReader p_configReader; + if (ErrorCode::Success != p_configReader.LoadIniFile(folderPath + "/indexloader.ini")) + { + return ErrorCode::FailedOpenFile; + } + + std::string metadataSection("MetaData"); + if (p_configReader.DoesSectionExist(metadataSection)) + { + std::string metadataFilePath = p_configReader.GetParameter(metadataSection, + "MetaDataFilePath", + std::string()); + std::string metadataIndexFilePath = p_configReader.GetParameter(metadataSection, + "MetaDataIndexPath", + std::string()); + + m_pMetadata.reset(new FileMetadataSet(folderPath + metadataFilePath, folderPath + metadataIndexFilePath)); + + if (!m_pMetadata->Available()) + { + std::cerr << "Error: Failed to load metadata." << std::endl; + return ErrorCode::Fail; + } + } + if (DistCalcMethod::Undefined == p_configReader.GetParameter("Index", "DistCalcMethod", DistCalcMethod::Undefined)) + { + std::cerr << "Error: Failed to load parameter DistCalcMethod." << std::endl; + return ErrorCode::Fail; + } + + return LoadIndex(folderPath, p_configReader); +} + + +ErrorCode VectorIndex::SaveIndex(const std::string& p_folderPath) +{ + std::string folderPath(p_folderPath); + if (!folderPath.empty() && *(folderPath.rbegin()) != FolderSep) + { + folderPath += FolderSep; + } + + if (!direxists(folderPath.c_str())) + { + mkdir(folderPath.c_str()); + } + + std::string loaderFilePath = folderPath + "indexloader.ini"; + + std::ofstream loaderFile(loaderFilePath); + if (!loaderFile.is_open()) + { + return ErrorCode::FailedCreateFile; + } + + if (nullptr != m_pMetadata) + { + std::string metadataFile = "metadata.bin"; + std::string metadataIndexFile = "metadataIndex.bin"; + loaderFile << "[MetaData]" << std::endl; + loaderFile << "MetaDataFilePath=" << metadataFile << std::endl; + loaderFile << "MetaDataIndexPath=" << metadataIndexFile << std::endl; + loaderFile << std::endl; + + m_pMetadata->SaveMetadata(folderPath + metadataFile, folderPath + metadataIndexFile); + } + + loaderFile << "[Index]" << std::endl; + loaderFile << "IndexAlgoType=" << Helper::Convert::ConvertToString(GetIndexAlgoType()) << std::endl; + loaderFile << "ValueType=" << Helper::Convert::ConvertToString(GetVectorValueType()) << std::endl; + loaderFile << std::endl; + + ErrorCode ret = SaveIndex(folderPath, loaderFile); + loaderFile.close(); + return ret; +} + +ErrorCode +VectorIndex::BuildIndex(std::shared_ptr p_vectorSet, + std::shared_ptr p_metadataSet) +{ + if (nullptr == p_vectorSet || p_vectorSet->Count() == 0 || p_vectorSet->Dimension() == 0 || p_vectorSet->GetValueType() != GetVectorValueType()) + { + return ErrorCode::Fail; + } + + BuildIndex(p_vectorSet->GetData(), p_vectorSet->Count(), p_vectorSet->Dimension()); + m_pMetadata = std::move(p_metadataSet); + return ErrorCode::Success; +} + + +ErrorCode +VectorIndex::SearchIndex(const void* p_vector, int p_neighborCount, std::vector& p_results) const { + QueryResult res(p_vector, p_neighborCount, p_results); + SearchIndex(res); + return ErrorCode::Success; +} + + +ErrorCode +VectorIndex::AddIndex(std::shared_ptr p_vectorSet, std::shared_ptr p_metadataSet) { + if (nullptr == p_vectorSet || p_vectorSet->Count() == 0 || p_vectorSet->Dimension() == 0 || p_vectorSet->GetValueType() != GetVectorValueType()) + { + return ErrorCode::Fail; + } + AddIndex(p_vectorSet->GetData(), p_vectorSet->Count(), p_vectorSet->Dimension()); + if (m_pMetadata == nullptr) { + m_pMetadata = std::move(p_metadataSet); + } + else { + m_pMetadata->AddBatch(*p_metadataSet); + } + return ErrorCode::Success; +} + + +std::shared_ptr +VectorIndex::CreateInstance(IndexAlgoType p_algo, VectorValueType p_valuetype) +{ + if (IndexAlgoType::Undefined == p_algo || VectorValueType::Undefined == p_valuetype) + { + return nullptr; + } + + if (p_algo == IndexAlgoType::BKT) { + switch (p_valuetype) + { +#define DefineVectorValueType(Name, Type) \ + case VectorValueType::Name: \ + return std::shared_ptr(new BKT::Index); \ + +#include "inc/Core/DefinitionList.h" +#undef DefineVectorValueType + + default: break; + } + } + else if (p_algo == IndexAlgoType::KDT) { + switch (p_valuetype) + { +#define DefineVectorValueType(Name, Type) \ + case VectorValueType::Name: \ + return std::shared_ptr(new KDT::Index); \ + +#include "inc/Core/DefinitionList.h" +#undef DefineVectorValueType + + default: break; + } + } + return nullptr; +} + + +ErrorCode +VectorIndex::LoadIndex(const std::string& p_loaderFilePath, std::shared_ptr& p_vectorIndex) +{ + Helper::IniReader iniReader; + + if (ErrorCode::Success != iniReader.LoadIniFile(p_loaderFilePath + "/indexloader.ini")) + { + return ErrorCode::FailedOpenFile; + } + + IndexAlgoType algoType = iniReader.GetParameter("Index", "IndexAlgoType", IndexAlgoType::Undefined); + VectorValueType valueType = iniReader.GetParameter("Index", "ValueType", VectorValueType::Undefined); + if (IndexAlgoType::Undefined == algoType || VectorValueType::Undefined == valueType) + { + return ErrorCode::Fail; + } + + if (algoType == IndexAlgoType::BKT) { + switch (valueType) + { +#define DefineVectorValueType(Name, Type) \ + case VectorValueType::Name: \ + p_vectorIndex.reset(new BKT::Index); \ + p_vectorIndex->LoadIndex(p_loaderFilePath); \ + break; \ + +#include "inc/Core/DefinitionList.h" +#undef DefineVectorValueType + + default: break; + } + } + else if (algoType == IndexAlgoType::KDT) { + switch (valueType) + { +#define DefineVectorValueType(Name, Type) \ + case VectorValueType::Name: \ + p_vectorIndex.reset(new KDT::Index); \ + p_vectorIndex->LoadIndex(p_loaderFilePath); \ + break; \ + +#include "inc/Core/DefinitionList.h" +#undef DefineVectorValueType + + default: break; + } + } + return ErrorCode::Success; +} + + +ErrorCode VectorIndex::MergeIndex(const char* p_indexFilePath1, const char* p_indexFilePath2) +{ + std::string folderPath1(p_indexFilePath1), folderPath2(p_indexFilePath2); + if (!folderPath1.empty() && *(folderPath1.rbegin()) != FolderSep) folderPath1 += FolderSep; + if (!folderPath2.empty() && *(folderPath2.rbegin()) != FolderSep) folderPath2 += FolderSep; + + Helper::IniReader p_configReader1, p_configReader2; + if (ErrorCode::Success != p_configReader1.LoadIniFile(folderPath1 + "/indexloader.ini")) + return ErrorCode::FailedOpenFile; + + if (ErrorCode::Success != p_configReader2.LoadIniFile(folderPath2 + "/indexloader.ini")) + return ErrorCode::FailedOpenFile; + + std::shared_ptr index = CreateInstance( + p_configReader1.GetParameter("Index", "IndexAlgoType", IndexAlgoType::Undefined), + p_configReader1.GetParameter("Index", "ValueType", VectorValueType::Undefined)); + if (index == nullptr) return ErrorCode::FailedParseValue; + + std::string empty(""); + if (!COMMON::DataUtils::MergeIndex(folderPath1 + p_configReader1.GetParameter("Index", "VectorFilePath", empty), + folderPath1 + p_configReader1.GetParameter("MetaData", "MetaDataFilePath", empty), + folderPath1 + p_configReader1.GetParameter("MetaData", "MetaDataIndexPath", empty), + folderPath2 + p_configReader1.GetParameter("Index", "VectorFilePath", empty), + folderPath2 + p_configReader1.GetParameter("MetaData", "MetaDataFilePath", empty), + folderPath2 + p_configReader1.GetParameter("MetaData", "MetaDataIndexPath", empty))) + return ErrorCode::Fail; + + for (const auto& iter : p_configReader1.GetParameters("Index")) + index->SetParameter(iter.first.c_str(), iter.second.c_str()); + + if (p_configReader1.DoesSectionExist("MetaData")) + { + for (const auto& iter : p_configReader1.GetParameters("MetaData")) + index->SetParameter(iter.first.c_str(), iter.second.c_str()); + index->SetMetadata(folderPath1 + p_configReader1.GetParameter("MetaData", "MetaDataFilePath", empty), + folderPath1 + p_configReader1.GetParameter("MetaData", "MetaDataIndexPath", empty)); + } + + std::ifstream vecIn(folderPath1 + p_configReader1.GetParameter("Index", "VectorFilePath", empty), std::ios::binary); + int R, C; + vecIn.read((char*)&R, sizeof(int)); + vecIn.read((char*)&C, sizeof(int)); + size_t size = R * C * GetValueTypeSize(index->GetVectorValueType()); + char* data = new char[size]; + vecIn.read(data, size); + vecIn.close(); + index->BuildIndex((void*)data, R, C); + index->SaveIndex(folderPath1); + return ErrorCode::Success; +} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/Core/VectorSet.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Core/VectorSet.cpp new file mode 100644 index 0000000000..36178d62cb --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Core/VectorSet.cpp @@ -0,0 +1,97 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Core/VectorSet.h" + +using namespace SPTAG; + +#pragma warning(disable:4996) // 'fopen': This function or variable may be unsafe. Consider using fopen_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. + +VectorSet::VectorSet() +{ +} + + +VectorSet::~VectorSet() +{ +} + + +BasicVectorSet::BasicVectorSet(const ByteArray& p_bytesArray, + VectorValueType p_valueType, + SizeType p_dimension, + SizeType p_vectorCount) + : m_data(p_bytesArray), + m_valueType(p_valueType), + m_dimension(p_dimension), + m_vectorCount(p_vectorCount), + m_perVectorDataSize(static_cast(p_dimension * GetValueTypeSize(p_valueType))) +{ +} + + +BasicVectorSet::~BasicVectorSet() +{ +} + + +VectorValueType +BasicVectorSet::GetValueType() const +{ + return m_valueType; +} + + +void* +BasicVectorSet::GetVector(IndexType p_vectorID) const +{ + if (p_vectorID < 0 || static_cast(p_vectorID) >= m_vectorCount) + { + return nullptr; + } + + SizeType offset = static_cast(p_vectorID) * m_perVectorDataSize; + return reinterpret_cast(m_data.Data() + offset); +} + + +void* +BasicVectorSet::GetData() const +{ + return reinterpret_cast(m_data.Data()); +} + +SizeType +BasicVectorSet::Dimension() const +{ + return m_dimension; +} + + +SizeType +BasicVectorSet::Count() const +{ + return m_vectorCount; +} + + +bool +BasicVectorSet::Available() const +{ + return m_data.Data() != nullptr; +} + + +ErrorCode +BasicVectorSet::Save(const std::string& p_vectorFile) const +{ + FILE * fp = fopen(p_vectorFile.c_str(), "wb"); + if (fp == NULL) return ErrorCode::FailedOpenFile; + + fwrite(&m_vectorCount, sizeof(int), 1, fp); + fwrite(&m_dimension, sizeof(int), 1, fp); + + fwrite((const void*)(m_data.Data()), m_data.Length(), 1, fp); + fclose(fp); + return ErrorCode::Success; +} diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/Helper/ArgumentsParser.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Helper/ArgumentsParser.cpp new file mode 100644 index 0000000000..4f630ec01c --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Helper/ArgumentsParser.cpp @@ -0,0 +1,86 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Helper/ArgumentsParser.h" + +using namespace SPTAG::Helper; + + +ArgumentsParser::IArgument::IArgument() +{ +} + + +ArgumentsParser::IArgument::~IArgument() +{ +} + + +ArgumentsParser::ArgumentsParser() +{ +} + + +ArgumentsParser::~ArgumentsParser() +{ +} + + +bool +ArgumentsParser::Parse(int p_argc, char** p_args) +{ + while (p_argc > 0) + { + int last = p_argc; + for (auto& option : m_arguments) + { + if (!option->ParseValue(p_argc, p_args)) + { + fprintf(stderr, "Failed to parse args around \"%s\"\n", *p_args); + PrintHelp(); + return false; + } + } + + if (last == p_argc) + { + p_argc -= 1; + p_args += 1; + } + } + + bool isValid = true; + for (auto& option : m_arguments) + { + if (option->IsRequiredButNotSet()) + { + fprintf(stderr, "Required option not set:\n "); + option->PrintDescription(stderr); + fprintf(stderr, "\n"); + isValid = false; + } + } + + if (!isValid) + { + fprintf(stderr, "\n"); + PrintHelp(); + return false; + } + + return true; +} + + +void +ArgumentsParser::PrintHelp() +{ + fprintf(stderr, "Usage: "); + for (auto& option : m_arguments) + { + fprintf(stderr, "\n "); + option->PrintDescription(stderr); + } + + fprintf(stderr, "\n\n"); +} diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/Helper/Base64Encode.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Helper/Base64Encode.cpp new file mode 100644 index 0000000000..5992fa5a31 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Helper/Base64Encode.cpp @@ -0,0 +1,240 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Helper/Base64Encode.h" + +using namespace SPTAG; +using namespace SPTAG::Helper; + +namespace +{ +namespace Local +{ +const char c_encTable[] = +{ + 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z', + 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z', + '0','1','2','3','4','5','6','7','8','9','+','/' +}; + + +const std::uint8_t c_decTable[] = +{ + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, // 0x00 - 0x0f + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, // 0x10 - 0x1f + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, // 0x20 - 0x2f + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, // 0x30 - 0x3f + 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 0x40 - 0x4f + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64, // 0x50 - 0x5f + 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 0x60 - 0x6f + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64, // 0x70 - 0x7f + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, // 0x80 - 0x8f + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, // 0x90 - 0x9f + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, // 0xa0 - 0xaf + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, // 0xb0 - 0xbf + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, // 0xc0 - 0xcf + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, // 0xd0 - 0xdf + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, // 0xe0 - 0xef + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, // 0xf0 - 0xff +}; + + +const char c_paddingChar = '='; +} +} + + +bool +Base64::Encode(const std::uint8_t* p_in, std::size_t p_inLen, char* p_out, std::size_t& p_outLen) +{ + using namespace Local; + + p_outLen = 0; + while (p_inLen >= 3) + { + p_out[0] = c_encTable[p_in[0] >> 2]; + p_out[1] = c_encTable[((p_in[0] & 0x03) << 4) | ((p_in[1] & 0xf0) >> 4)]; + p_out[2] = c_encTable[((p_in[1] & 0x0f) << 2) | ((p_in[2] & 0xc0) >> 6)]; + p_out[3] = c_encTable[p_in[2] & 0x3f]; + + p_in += 3; + p_inLen -= 3; + p_out += 4; + p_outLen += 4; + } + + switch (p_inLen) + { + case 1: + p_out[0] = c_encTable[p_in[0] >> 2]; + p_out[1] = c_encTable[(p_in[0] & 0x03) << 4]; + p_out[2] = c_paddingChar; + p_out[3] = c_paddingChar; + + p_outLen += 4; + break; + + case 2: + p_out[0] = c_encTable[p_in[0] >> 2]; + p_out[1] = c_encTable[((p_in[0] & 0x03) << 4) | ((p_in[1] & 0xf0) >> 4)]; + p_out[2] = c_encTable[(p_in[1] & 0x0f) << 2]; + p_out[3] = c_paddingChar; + + p_outLen += 4; + break; + } + + return true; +} + + +bool +Base64::Encode(const std::uint8_t* p_in, std::size_t p_inLen, std::ostream& p_out, std::size_t& p_outLen) +{ + using namespace Local; + + p_outLen = 0; + while (p_inLen >= 3) + { + p_out << c_encTable[p_in[0] >> 2]; + p_out << c_encTable[((p_in[0] & 0x03) << 4) | ((p_in[1] & 0xf0) >> 4)]; + p_out << c_encTable[((p_in[1] & 0x0f) << 2) | ((p_in[2] & 0xc0) >> 6)]; + p_out << c_encTable[p_in[2] & 0x3f]; + + p_in += 3; + p_inLen -= 3; + p_outLen += 4; + } + + switch (p_inLen) + { + case 1: + p_out << c_encTable[p_in[0] >> 2]; + p_out << c_encTable[(p_in[0] & 0x03) << 4]; + p_out << c_paddingChar; + p_out << c_paddingChar; + + p_outLen += 4; + break; + + case 2: + p_out << c_encTable[p_in[0] >> 2]; + p_out << c_encTable[((p_in[0] & 0x03) << 4) | ((p_in[1] & 0xf0) >> 4)]; + p_out << c_encTable[(p_in[1] & 0x0f) << 2]; + p_out << c_paddingChar; + + p_outLen += 4; + break; + + default: + break; + } + + return true; +} + + +bool +Base64::Decode(const char* p_in, std::size_t p_inLen, std::uint8_t* p_out, std::size_t& p_outLen) +{ + using namespace Local; + + // Should always be padding. + if ((p_inLen & 0x03) != 0) + { + return false; + } + + std::uint8_t u0 = 0; + std::uint8_t u1 = 0; + std::uint8_t u2 = 0; + std::uint8_t u3 = 0; + + p_outLen = 0; + while (p_inLen > 4) + { + u0 = c_decTable[static_cast(p_in[0])]; + u1 = c_decTable[static_cast(p_in[1])]; + u2 = c_decTable[static_cast(p_in[2])]; + u3 = c_decTable[static_cast(p_in[3])]; + + if (u0 > 63 || u1 > 63 || u2 > 63 || u3 > 63) + { + return false; + } + + p_out[0] = (u0 << 2) | (u1 >> 4); + p_out[1] = (u1 << 4) | (u2 >> 2); + p_out[2] = (u2 << 6) | u3; + + p_inLen -= 4; + p_in += 4; + p_out += 3; + p_outLen += 3; + } + + u0 = c_decTable[static_cast(p_in[0])]; + u1 = c_decTable[static_cast(p_in[1])]; + u2 = c_decTable[static_cast(p_in[2])]; + u3 = c_decTable[static_cast(p_in[3])]; + + if (u0 > 63 || u1 > 63 || (c_paddingChar == p_in[2] && c_paddingChar != p_in[3])) + { + return false; + } + + if (u2 > 63 && c_paddingChar != p_in[2]) + { + return false; + } + + if (u3 > 63 && c_paddingChar != p_in[3]) + { + return false; + } + + + p_out[0] = (u0 << 2) | (u1 >> 4); + ++p_outLen; + if (c_paddingChar == p_in[2]) + { + if ((u1 & 0x0F) != 0) + { + return false; + } + } + else + { + p_out[1] = (u1 << 4) | (u2 >> 2); + ++p_outLen; + if (c_paddingChar == p_in[3]) + { + if ((u3 & 0x03) != 0) + { + return false; + } + } + else + { + p_out[2] = (u2 << 6) | u3; + ++p_outLen; + } + } + + return true; +} + + +std::size_t +Base64::CapacityForEncode(std::size_t p_inLen) +{ + return ((p_inLen + 2) / 3) * 4; +} + + +std::size_t +Base64::CapacityForDecode(std::size_t p_inLen) +{ + return (p_inLen / 4) * 3 + ((p_inLen % 4) * 2) / 3; +} + diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/Helper/CommonHelper.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Helper/CommonHelper.cpp new file mode 100644 index 0000000000..2d4dc0de5c --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Helper/CommonHelper.cpp @@ -0,0 +1,144 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Helper/CommonHelper.h" + +#include +#include +#include +#include + +using namespace SPTAG; +using namespace SPTAG::Helper; + +void +StrUtils::ToLowerInPlace(std::string& p_str) +{ + for (char& ch : p_str) + { + if (std::isupper(ch)) + { + ch = ch | 0x20; + } + } +} + + +std::vector +StrUtils::SplitString(const std::string& p_str, const std::string& p_separator) +{ + std::vector ret; + + std::size_t begin = p_str.find_first_not_of(p_separator); + while (std::string::npos != begin) + { + std::size_t end = p_str.find_first_of(p_separator, begin); + if (std::string::npos == end) + { + ret.emplace_back(p_str.substr(begin, p_str.size() - begin)); + break; + } + else + { + ret.emplace_back(p_str.substr(begin, end - begin)); + } + + begin = p_str.find_first_not_of(p_separator, end); + } + + return ret; +} + + +std::pair +StrUtils::FindTrimmedSegment(const char* p_begin, + const char* p_end, + const std::function& p_isSkippedChar) +{ + while (p_begin < p_end) + { + if (!p_isSkippedChar(*p_begin)) + { + break; + } + + ++p_begin; + } + + while (p_end > p_begin) + { + if (!p_isSkippedChar(*(p_end - 1))) + { + break; + } + + --p_end; + } + + return std::make_pair(p_begin, p_end); +} + + +bool +StrUtils::StartsWith(const char* p_str, const char* p_prefix) +{ + if (nullptr == p_prefix) + { + return true; + } + + if (nullptr == p_str) + { + return false; + } + + while ('\0' != (*p_prefix) && '\0' != (*p_str)) + { + if (*p_prefix != *p_str) + { + return false; + } + ++p_prefix; + ++p_str; + } + + return '\0' == *p_prefix; +} + + +bool +StrUtils::StrEqualIgnoreCase(const char* p_left, const char* p_right) +{ + if (p_left == p_right) + { + return true; + } + + if (p_left == nullptr || p_right == nullptr) + { + return false; + } + + auto tryConv = [](char p_ch) -> char + { + if ('a' <= p_ch && p_ch <= 'z') + { + return p_ch - 32; + } + + return p_ch; + }; + + while (*p_left != '\0' && *p_right != '\0') + { + if (tryConv(*p_left) != tryConv(*p_right)) + { + return false; + } + + ++p_left; + ++p_right; + } + + return *p_left == *p_right; +} diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/Helper/Concurrent.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Helper/Concurrent.cpp new file mode 100644 index 0000000000..cbb1bdb643 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Helper/Concurrent.cpp @@ -0,0 +1,71 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Helper/Concurrent.h" + +using namespace SPTAG; +using namespace SPTAG::Helper::Concurrent; + +WaitSignal::WaitSignal() + : m_isWaiting(false), + m_unfinished(0) +{ +} + + +WaitSignal::WaitSignal(std::uint32_t p_unfinished) + : m_isWaiting(false), + m_unfinished(p_unfinished) +{ +} + + +WaitSignal::~WaitSignal() +{ + std::lock_guard guard(m_mutex); + if (m_isWaiting) + { + m_cv.notify_all(); + } +} + + +void +WaitSignal::Reset(std::uint32_t p_unfinished) +{ + std::lock_guard guard(m_mutex); + if (m_isWaiting) + { + m_cv.notify_all(); + } + + m_isWaiting = false; + m_unfinished = p_unfinished; +} + + +void +WaitSignal::Wait() +{ + std::unique_lock lock(m_mutex); + if (m_unfinished > 0) + { + m_isWaiting = true; + m_cv.wait(lock); + } +} + + +void +WaitSignal::FinishOne() +{ + if (1 == m_unfinished.fetch_sub(1)) + { + std::lock_guard guard(m_mutex); + if (m_isWaiting) + { + m_isWaiting = false; + m_cv.notify_all(); + } + } +} diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/Helper/SimpleIniReader.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Helper/SimpleIniReader.cpp new file mode 100644 index 0000000000..7456ad9df3 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Helper/SimpleIniReader.cpp @@ -0,0 +1,239 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Helper/SimpleIniReader.h" +#include "inc/Helper/CommonHelper.h" + +#include +#include +#include +#include + +using namespace SPTAG; +using namespace SPTAG::Helper; + +const IniReader::ParameterValueMap IniReader::c_emptyParameters; + + +IniReader::IniReader() +{ +} + + +IniReader::~IniReader() +{ +} + + +ErrorCode +IniReader::LoadIniFile(const std::string& p_iniFilePath) +{ + std::ifstream input(p_iniFilePath); + if (!input.is_open()) + { + return ErrorCode::FailedOpenFile; + } + + const std::size_t c_bufferSize = 1 << 16; + + std::unique_ptr line(new char[c_bufferSize]); + + std::string currSection; + std::shared_ptr currParamMap(new ParameterValueMap); + + if (m_parameters.count(currSection) == 0) + { + m_parameters.emplace(currSection, currParamMap); + } + + auto isSpace = [](char p_ch) -> bool + { + return std::isspace(p_ch) != 0; + }; + + while (!input.eof()) + { + if (!input.getline(line.get(), c_bufferSize)) + { + break; + } + + std::size_t len = 0; + while (len < c_bufferSize && line[len] != '\0') + { + ++len; + } + + auto nonSpaceSeg = StrUtils::FindTrimmedSegment(line.get(), line.get() + len, isSpace); + + if (nonSpaceSeg.second <= nonSpaceSeg.first) + { + // Blank line. + continue; + } + + if (';' == *nonSpaceSeg.first) + { + // Comments. + continue; + } + else if ('[' == *nonSpaceSeg.first) + { + // Parse Section + if (']' != *(nonSpaceSeg.second - 1)) + { + return ErrorCode::ReadIni_FailedParseSection; + } + + auto sectionSeg = StrUtils::FindTrimmedSegment(nonSpaceSeg.first + 1, nonSpaceSeg.second - 1, isSpace); + + if (sectionSeg.second <= sectionSeg.first) + { + // Empty section name. + return ErrorCode::ReadIni_FailedParseSection; + } + + currSection.assign(sectionSeg.first, sectionSeg.second); + StrUtils::ToLowerInPlace(currSection); + + if (m_parameters.count(currSection) == 0) + { + currParamMap.reset(new ParameterValueMap); + m_parameters.emplace(currSection, currParamMap); + } + else + { + return ErrorCode::ReadIni_DuplicatedSection; + } + } + else + { + // Parameter Value Pair. + const char* equalSignLoc = nonSpaceSeg.first; + while (equalSignLoc < nonSpaceSeg.second && '=' != *equalSignLoc) + { + ++equalSignLoc; + } + + if (equalSignLoc >= nonSpaceSeg.second) + { + return ErrorCode::ReadIni_FailedParseParam; + } + + auto paramSeg = StrUtils::FindTrimmedSegment(nonSpaceSeg.first, equalSignLoc, isSpace); + + if (paramSeg.second <= paramSeg.first) + { + // Empty parameter name. + return ErrorCode::ReadIni_FailedParseParam; + } + + std::string paramName(paramSeg.first, paramSeg.second); + StrUtils::ToLowerInPlace(paramName); + + if (currParamMap->count(paramName) == 0) + { + currParamMap->emplace(std::move(paramName), std::string(equalSignLoc + 1, nonSpaceSeg.second)); + } + else + { + return ErrorCode::ReadIni_DuplicatedParam; + } + } + } + + return ErrorCode::Success; +} + + +bool +IniReader::DoesSectionExist(const std::string& p_section) const +{ + std::string section(p_section); + StrUtils::ToLowerInPlace(section); + return m_parameters.count(section) != 0; +} + + +bool +IniReader::DoesParameterExist(const std::string& p_section, const std::string& p_param) const +{ + std::string name(p_section); + StrUtils::ToLowerInPlace(name); + auto iter = m_parameters.find(name); + if (iter == m_parameters.cend()) + { + return false; + } + + const auto& paramMap = iter->second; + if (paramMap == nullptr) + { + return false; + } + + name = p_param; + StrUtils::ToLowerInPlace(name); + return paramMap->count(name) != 0; +} + + +bool +IniReader::GetRawValue(const std::string& p_section, const std::string& p_param, std::string& p_value) const +{ + std::string name(p_section); + StrUtils::ToLowerInPlace(name); + auto sectionIter = m_parameters.find(name); + if (sectionIter == m_parameters.cend()) + { + return false; + } + + const auto& paramMap = sectionIter->second; + if (paramMap == nullptr) + { + return false; + } + + name = p_param; + StrUtils::ToLowerInPlace(name); + auto paramIter = paramMap->find(name); + if (paramIter == paramMap->cend()) + { + return false; + } + + p_value = paramIter->second; + return true; +} + + +const IniReader::ParameterValueMap& +IniReader::GetParameters(const std::string& p_section) const +{ + std::string name(p_section); + StrUtils::ToLowerInPlace(name); + auto sectionIter = m_parameters.find(name); + if (sectionIter == m_parameters.cend() || nullptr == sectionIter->second) + { + return c_emptyParameters; + } + + return *(sectionIter->second); +} + +void +IniReader::SetParameter(const std::string& p_section, const std::string& p_param, const std::string& p_val) +{ + std::string name(p_section); + StrUtils::ToLowerInPlace(name); + auto sectionIter = m_parameters.find(name); + if (sectionIter == m_parameters.cend() || sectionIter->second == nullptr) + { + m_parameters[name] = std::shared_ptr(new ParameterValueMap); + } + + std::string param(p_param); + StrUtils::ToLowerInPlace(param); + (*m_parameters[name])[param] = p_val; +} diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/IndexBuilder/Options.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/IndexBuilder/Options.cpp new file mode 100644 index 0000000000..d0fcd0fd8e --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/IndexBuilder/Options.cpp @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/IndexBuilder/Options.h" +#include "inc/Helper/StringConvert.h" + +#include + +using namespace SPTAG; +using namespace SPTAG::IndexBuilder; + + +BuilderOptions::BuilderOptions() + : m_threadNum(32), + m_inputValueType(VectorValueType::Float), + m_vectorDelimiter("|") +{ + AddOptionalOption(m_threadNum, "-t", "--thread", "Thread Number."); + AddOptionalOption(m_vectorDelimiter, "", "--delimiter", "Vector delimiter."); + AddRequiredOption(m_dimension, "-d", "--dimension", "Dimension of vector."); + AddRequiredOption(m_inputValueType, "-v", "--vectortype", "Input vector data type. Default is float."); + AddRequiredOption(m_inputFiles, "-i", "--input", "Input raw data."); + AddRequiredOption(m_outputFolder, "-o", "--outputfolder", "Output folder."); + AddRequiredOption(m_indexAlgoType, "-a", "--algo", "Index Algorithm type."); + AddOptionalOption(m_builderConfigFile, "-c", "--config", "Config file for builder."); +} + + +BuilderOptions::~BuilderOptions() +{ +} diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/IndexBuilder/ThreadPool.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/IndexBuilder/ThreadPool.cpp new file mode 100644 index 0000000000..0ecddc1279 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/IndexBuilder/ThreadPool.cpp @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/IndexBuilder/ThreadPool.h" + +#include + +#include +#include + +using namespace SPTAG::IndexBuilder; + +namespace Local +{ +std::unique_ptr g_threadPool; + +std::atomic_bool g_initialized(false); + +std::uint32_t g_threadNum = 1; +} + + +void +ThreadPool::Init(std::uint32_t p_threadNum) +{ + if (Local::g_initialized.exchange(true)) + { + return; + } + + Local::g_threadNum = std::max((std::uint32_t)1, p_threadNum); + + Local::g_threadPool.reset(new boost::asio::thread_pool(Local::g_threadNum)); +} + + +bool +ThreadPool::Queue(std::function p_workItem) +{ + if (nullptr == Local::g_threadPool) + { + return false; + } + + boost::asio::post(*Local::g_threadPool, std::move(p_workItem)); + return true; +} + + +std::uint32_t +ThreadPool::CurrentThreadNum() +{ + return Local::g_threadNum; +} diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/IndexBuilder/VectorSetReader.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/IndexBuilder/VectorSetReader.cpp new file mode 100644 index 0000000000..e50f6f5eb0 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/IndexBuilder/VectorSetReader.cpp @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/IndexBuilder/VectorSetReader.h" +#include "inc/IndexBuilder/VectorSetReaders/DefaultReader.h" + + +using namespace SPTAG; +using namespace SPTAG::IndexBuilder; + +VectorSetReader::VectorSetReader(std::shared_ptr p_options) + : m_options(p_options) +{ +} + + +VectorSetReader:: ~VectorSetReader() +{ +} + + +std::shared_ptr +VectorSetReader::CreateInstance(std::shared_ptr p_options) +{ + return std::shared_ptr(new DefaultReader(std::move(p_options))); +} + diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/IndexBuilder/VectorSetReaders/DefaultReader.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/IndexBuilder/VectorSetReaders/DefaultReader.cpp new file mode 100644 index 0000000000..7f7c4187b0 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/IndexBuilder/VectorSetReaders/DefaultReader.cpp @@ -0,0 +1,510 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/IndexBuilder/VectorSetReaders/DefaultReader.h" +#include "inc/Helper/StringConvert.h" +#include "inc/Helper/CommonHelper.h" +#include "inc/IndexBuilder/ThreadPool.h" + +#include +#include +#include + +using namespace SPTAG; +using namespace SPTAG::IndexBuilder; + +namespace +{ +namespace Local +{ + +class BinaryLineReader +{ +public: + BinaryLineReader(std::istream& p_inStream) + : m_inStream(p_inStream) + { + m_buffer.reset(new char[c_bufferSize]); + } + + + bool Eof() + { + return m_inStream.eof() && (m_curOffset == m_curTotal); + } + + + std::size_t GetLine(std::unique_ptr& p_buffer, std::size_t& p_bufferSize, std::size_t& p_length) + { + std::size_t consumedCount = 0; + p_length = 0; + while (true) + { + while (m_curOffset < m_curTotal) + { + if (p_bufferSize > p_length) + { + ++consumedCount; + if (!IsDelimiter(m_buffer[m_curOffset])) + { + p_buffer[p_length++] = m_buffer[m_curOffset++]; + } + else + { + ++m_curOffset; + p_buffer[p_length] = '\0'; + return consumedCount + MoveToNextValid(); + } + } + else + { + p_bufferSize *= 2; + std::unique_ptr newBuffer(new char[p_bufferSize]); + memcpy(newBuffer.get(), p_buffer.get(), p_length); + p_buffer.swap(newBuffer); + } + } + + if (m_inStream.eof()) + { + break; + } + + m_inStream.read(m_buffer.get(), c_bufferSize); + m_curTotal = m_inStream.gcount(); + m_curOffset = 0; + } + + if (p_bufferSize <= p_length) + { + p_bufferSize *= 2; + std::unique_ptr newBuffer(new char[p_bufferSize]); + memcpy(newBuffer.get(), p_buffer.get(), p_length); + p_buffer.swap(newBuffer); + } + + p_buffer[p_length] = '\0'; + return consumedCount; + } + + +private: + std::size_t MoveToNextValid() + { + std::size_t skipped = 0; + while (true) + { + while (m_curOffset < m_curTotal) + { + if (IsDelimiter(m_buffer[m_curOffset])) + { + ++skipped; + ++m_curOffset; + } + else + { + return skipped; + } + } + + if (m_inStream.eof()) + { + break; + } + + m_inStream.read(m_buffer.get(), c_bufferSize); + m_curTotal = m_inStream.gcount(); + m_curOffset = 0; + } + + return skipped; + } + + bool IsDelimiter(char p_ch) + { + return p_ch == '\r' || p_ch == '\n'; + } + + static const std::size_t c_bufferSize = 1 << 10; + + std::unique_ptr m_buffer; + + std::istream& m_inStream; + + std::size_t m_curOffset; + + std::size_t m_curTotal; +}; + +} // namespace Local +} // namespace + +DefaultReader::DefaultReader(std::shared_ptr p_options) + : VectorSetReader(std::move(p_options)), + m_subTaskBlocksize(0) +{ + std::string tempFolder("tempfolder"); + if (!direxists(tempFolder.c_str())) + { + mkdir(tempFolder.c_str()); + } + + tempFolder += FolderSep; + m_vectorOutput = tempFolder + "vectorset.bin"; + m_metadataConentOutput = tempFolder + "metadata.bin"; + m_metadataIndexOutput = tempFolder + "metadataindex.bin"; +} + + +DefaultReader::~DefaultReader() +{ + if (fileexists(m_vectorOutput.c_str())) + { + remove(m_vectorOutput.c_str()); + } + + if (fileexists(m_metadataIndexOutput.c_str())) + { + remove(m_metadataIndexOutput.c_str()); + } + + if (fileexists(m_metadataConentOutput.c_str())) + { + remove(m_metadataConentOutput.c_str()); + } +} + + +ErrorCode +DefaultReader::LoadFile(const std::string& p_filePaths) +{ + const auto& files = GetFileSizes(p_filePaths); + std::vector> subWorks; + subWorks.reserve(files.size() * ThreadPool::CurrentThreadNum()); + + m_subTaskCount = 0; + for (const auto& fileInfo : files) + { + if (fileInfo.second == (std::numeric_limits::max)()) + { + std::stringstream msg; + msg << "File " << fileInfo.first << " not exists or can't access."; + std::cerr << msg.str() << std::endl; + exit(1); + } + + std::uint32_t fileTaskCount = 0; + std::size_t blockSize = m_subTaskBlocksize; + if (0 == blockSize) + { + fileTaskCount = ThreadPool::CurrentThreadNum(); + blockSize = (fileInfo.second + fileTaskCount - 1) / fileTaskCount; + } + else + { + fileTaskCount = static_cast((fileInfo.second + blockSize - 1) / blockSize); + } + + for (std::uint32_t i = 0; i < fileTaskCount; ++i) + { + subWorks.emplace_back(std::bind(&DefaultReader::LoadFileInternal, + this, + fileInfo.first, + m_subTaskCount++, + i, + blockSize)); + } + } + + m_totalRecordCount = 0; + m_totalRecordVectorBytes = 0; + m_subTaskRecordCount.clear(); + m_subTaskRecordCount.resize(m_subTaskCount, 0); + + m_waitSignal.Reset(m_subTaskCount); + + for (auto& workItem : subWorks) + { + ThreadPool::Queue(std::move(workItem)); + } + + m_waitSignal.Wait(); + + MergeData(); + + return ErrorCode::Success; +} + + +std::shared_ptr +DefaultReader::GetVectorSet() const +{ + ByteArray vectorSet = ByteArray::Alloc(m_totalRecordVectorBytes); + char* vecBuf = reinterpret_cast(vectorSet.Data()); + + std::ifstream inputStream; + inputStream.open(m_vectorOutput, std::ifstream::binary); + inputStream.seekg(sizeof(uint32_t) + sizeof(uint32_t), std::ifstream::beg); + inputStream.read(vecBuf, m_totalRecordVectorBytes); + inputStream.close(); + + return std::shared_ptr(new BasicVectorSet(vectorSet, + m_options->m_inputValueType, + m_options->m_dimension, + m_totalRecordCount)); +} + + +std::shared_ptr +DefaultReader::GetMetadataSet() const +{ + return std::shared_ptr(new FileMetadataSet(m_metadataConentOutput, m_metadataIndexOutput)); +} + + +void +DefaultReader::LoadFileInternal(const std::string& p_filePath, + std::uint32_t p_subTaskID, + std::uint32_t p_fileBlockID, + std::size_t p_fileBlockSize) +{ + std::size_t lineBufferSize = 1 << 16; + std::unique_ptr currentLine(new char[lineBufferSize]); + + std::ifstream inputStream; + std::ofstream outputStream; + std::ofstream metaStreamContent; + std::ofstream metaStreamIndex; + + std::uint32_t recordCount = 0; + std::uint64_t metaOffset = 0; + std::size_t totalRead = 0; + std::streamoff startpos = p_fileBlockID * p_fileBlockSize; + + inputStream.open(p_filePath, std::ios_base::in | std::ios_base::binary); + if (inputStream.is_open() == false) + { + std::stringstream msg; + msg << "Unable to open file: " << p_filePath << std::endl; + const auto& msgStr = msg.str(); + std::cerr << msgStr; + throw MyException(msgStr); + exit(1); + } + + { + std::stringstream msg; + msg << "Begin Subtask: " << p_subTaskID << ", start offset position:" << startpos << std::endl; + std::cout << msg.str(); + } + + std::string subFileSuffix("_"); + subFileSuffix += std::to_string(p_subTaskID); + subFileSuffix += ".tmp"; + + outputStream.open(m_vectorOutput + subFileSuffix, std::ofstream::binary); + metaStreamContent.open(m_metadataConentOutput + subFileSuffix, std::ofstream::binary); + metaStreamIndex.open(m_metadataIndexOutput + subFileSuffix, std::ofstream::binary); + + inputStream.seekg(startpos, std::ifstream::beg); + + Local::BinaryLineReader lineReader(inputStream); + + std::size_t lineLength; + if (p_fileBlockID != 0) + { + totalRead += lineReader.GetLine(currentLine, lineBufferSize, lineLength); + } + + std::size_t vectorByteSize = GetValueTypeSize(m_options->m_inputValueType) * m_options->m_dimension; + std::unique_ptr vector; + vector.reset(new std::uint8_t[vectorByteSize]); + + while (!lineReader.Eof() && totalRead <= p_fileBlockSize) + { + totalRead += lineReader.GetLine(currentLine, lineBufferSize, lineLength); + if (0 == lineLength) + { + continue; + } + + std::size_t tabIndex = lineLength - 1; + while (tabIndex > 0 && currentLine[tabIndex] != '\t') + { + --tabIndex; + } + + if (0 == tabIndex && currentLine[tabIndex] != '\t') + { + std::stringstream msg; + msg << "Subtask: " << p_subTaskID << " cannot parsing line:" << currentLine.get() << std::endl; + std::cout << msg.str(); + exit(1); + } + + bool parseSuccess = false; + switch (m_options->m_inputValueType) + { +#define DefineVectorValueType(Name, Type) \ + case VectorValueType::Name: \ + parseSuccess = TranslateVector(currentLine.get() + tabIndex + 1, reinterpret_cast(vector.get())); \ + break; \ + +#include "inc/Core/DefinitionList.h" +#undef DefineVectorValueType + + default: + parseSuccess = false; + break; + } + + if (!parseSuccess) + { + std::stringstream msg; + msg << "Subtask: " << p_subTaskID << " cannot parsing vector:" << (currentLine.get() + tabIndex + 1) << std::endl; + std::cout << msg.str(); + exit(1); + } + + ++recordCount; + outputStream.write(reinterpret_cast(vector.get()), vectorByteSize); + metaStreamContent.write(currentLine.get(), tabIndex); + metaStreamIndex.write(reinterpret_cast(&metaOffset), sizeof(metaOffset)); + + metaOffset += tabIndex; + } + + metaStreamIndex.write(reinterpret_cast(&metaOffset), sizeof(metaOffset)); + + inputStream.close(); + outputStream.close(); + metaStreamContent.close(); + metaStreamIndex.close(); + + m_totalRecordCount += recordCount; + m_subTaskRecordCount[p_subTaskID] = recordCount; + m_totalRecordVectorBytes += recordCount * vectorByteSize; + + m_waitSignal.FinishOne(); +} + + +void +DefaultReader::MergeData() +{ + const std::size_t bufferSize = 1 << 30; + const std::size_t bufferSizeTrim64 = (bufferSize / sizeof(std::uint64_t)) * sizeof(std::uint64_t); + std::ifstream inputStream; + std::ofstream outputStream; + + std::unique_ptr bufferHolder(new char[bufferSize]); + char* buf = bufferHolder.get(); + + std::uint32_t uint32Var = m_totalRecordCount; + + outputStream.open(m_vectorOutput, std::ofstream::binary); + + outputStream.write(reinterpret_cast(&uint32Var), sizeof(uint32Var)); + outputStream.write(reinterpret_cast(&(m_options->m_dimension)), sizeof(m_options->m_dimension)); + + for (std::uint32_t i = 0; i < m_subTaskCount; ++i) + { + std::string file = m_vectorOutput; + file += "_"; + file += std::to_string(i); + file += ".tmp"; + + inputStream.open(file, std::ifstream::binary); + outputStream << inputStream.rdbuf(); + + inputStream.close(); + remove(file.c_str()); + } + + outputStream.close(); + + outputStream.open(m_metadataConentOutput, std::ofstream::binary); + for (std::uint32_t i = 0; i < m_subTaskCount; ++i) + { + std::string file = m_metadataConentOutput; + file += "_"; + file += std::to_string(i); + file += ".tmp"; + + inputStream.open(file, std::ifstream::binary); + outputStream << inputStream.rdbuf(); + + inputStream.close(); + remove(file.c_str()); + } + + outputStream.close(); + + outputStream.open(m_metadataIndexOutput, std::ofstream::binary); + + outputStream.write(reinterpret_cast(&uint32Var), sizeof(uint32Var)); + + std::uint64_t totalOffset = 0; + for (std::uint32_t i = 0; i < m_subTaskCount; ++i) + { + std::string file = m_metadataIndexOutput; + file += "_"; + file += std::to_string(i); + file += ".tmp"; + + inputStream.open(file, std::ifstream::binary); + for (std::uint32_t remains = m_subTaskRecordCount[i]; remains > 0;) + { + std::size_t readBytesCount = min(remains * sizeof(std::uint64_t), bufferSizeTrim64); + inputStream.read(buf, readBytesCount); + std::uint64_t* offset = reinterpret_cast(buf); + for (std::uint32_t i = 0; i < readBytesCount / sizeof(std::uint64_t); ++i) + { + offset[i] += totalOffset; + } + + outputStream.write(buf, readBytesCount); + remains -= static_cast(readBytesCount / sizeof(std::uint64_t)); + } + + inputStream.read(buf, sizeof(std::uint64_t)); + totalOffset += *(reinterpret_cast(buf)); + + inputStream.close(); + remove(file.c_str()); + } + + outputStream.write(reinterpret_cast(&totalOffset), sizeof(totalOffset)); + outputStream.close(); +} + + +std::vector +DefaultReader::GetFileSizes(const std::string& p_filePaths) +{ + const auto& files = Helper::StrUtils::SplitString(p_filePaths, ","); + std::vector res; + res.reserve(files.size()); + + for (const auto& filePath : files) + { + if (!fileexists(filePath.c_str())) + { + res.emplace_back(filePath, (std::numeric_limits::max)()); + continue; + } +#ifndef _MSC_VER + struct stat stat_buf; + stat(filePath.c_str(), &stat_buf); +#else + struct _stat64 stat_buf; + _stat64(filePath.c_str(), &stat_buf); +#endif + std::size_t fileSize = stat_buf.st_size; + res.emplace_back(filePath, static_cast(fileSize)); + } + + return res; +} + + diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/IndexBuilder/main.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/IndexBuilder/main.cpp new file mode 100644 index 0000000000..ba4de46128 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/IndexBuilder/main.cpp @@ -0,0 +1,100 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/IndexBuilder/ThreadPool.h" +#include "inc/IndexBuilder/Options.h" +#include "inc/IndexBuilder/VectorSetReader.h" +#include "inc/Core/VectorIndex.h" +#include "inc/Core/Common.h" +#include "inc/Helper/SimpleIniReader.h" + +#include +#include + +using namespace SPTAG; + +int main(int argc, char* argv[]) +{ + std::shared_ptr options(new IndexBuilder::BuilderOptions); + if (!options->Parse(argc - 1, argv + 1)) + { + exit(1); + } + IndexBuilder::ThreadPool::Init(options->m_threadNum); + auto indexBuilder = VectorIndex::CreateInstance(options->m_indexAlgoType, options->m_inputValueType); + + Helper::IniReader iniReader; + if (!options->m_builderConfigFile.empty()) + { + iniReader.LoadIniFile(options->m_builderConfigFile); + } + + for (int i = 1; i < argc; i++) + { + std::string param(argv[i]); + int idx = (int)param.find("="); + if (idx < 0) continue; + + std::string paramName = param.substr(0, idx); + std::string paramVal = param.substr(idx + 1); + std::string sectionName; + idx = (int)paramName.find("."); + if (idx >= 0) { + sectionName = paramName.substr(0, idx); + paramName = paramName.substr(idx + 1); + } + iniReader.SetParameter(sectionName, paramName, paramVal); + std::cout << "Set [" << sectionName << "]" << paramName << " = " << paramVal << std::endl; + } + + if (!iniReader.DoesParameterExist("Index", "NumberOfThreads")) { + iniReader.SetParameter("Index", "NumberOfThreads", std::to_string(options->m_threadNum)); + } + for (const auto& iter : iniReader.GetParameters("Index")) + { + indexBuilder->SetParameter(iter.first.c_str(), iter.second.c_str()); + } + + ErrorCode code; + if (options->m_inputFiles.find("BIN:") == 0) { + std::vector files = SPTAG::Helper::StrUtils::SplitString(options->m_inputFiles.substr(4), ","); + std::ifstream inputStream(files[0], std::ifstream::binary); + if (!inputStream.is_open()) { + fprintf(stderr, "Failed to read input file.\n"); + exit(1); + } + int row, col; + inputStream.read((char*)&row, sizeof(int)); + inputStream.read((char*)&col, sizeof(int)); + std::uint64_t totalRecordVectorBytes = ((std::uint64_t)GetValueTypeSize(options->m_inputValueType)) * row * col; + ByteArray vectorSet = ByteArray::Alloc(totalRecordVectorBytes); + char* vecBuf = reinterpret_cast(vectorSet.Data()); + inputStream.read(vecBuf, totalRecordVectorBytes); + inputStream.close(); + std::shared_ptr p_vectorSet(new BasicVectorSet(vectorSet, options->m_inputValueType, col, row)); + + std::shared_ptr p_metaSet = nullptr; + if (files.size() >= 3) { + p_metaSet.reset(new FileMetadataSet(files[1], files[2])); + } + code = indexBuilder->BuildIndex(p_vectorSet, p_metaSet); + indexBuilder->SaveIndex(options->m_outputFolder); + } + else { + auto vectorReader = IndexBuilder::VectorSetReader::CreateInstance(options); + if (ErrorCode::Success != vectorReader->LoadFile(options->m_inputFiles)) + { + fprintf(stderr, "Failed to read input file.\n"); + exit(1); + } + code = indexBuilder->BuildIndex(vectorReader->GetVectorSet(), vectorReader->GetMetadataSet()); + indexBuilder->SaveIndex(options->m_outputFolder); + } + + if (ErrorCode::Success != code) + { + fprintf(stderr, "Failed to build index.\n"); + exit(1); + } + return 0; +} diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/IndexSearcher/main.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/IndexSearcher/main.cpp new file mode 100644 index 0000000000..316516d92e --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/IndexSearcher/main.cpp @@ -0,0 +1,288 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Helper/SimpleIniReader.h" +#include "inc/Helper/CommonHelper.h" +#include "inc/Core/Common.h" +#include "inc/Core/MetadataSet.h" +#include "inc/Core/VectorIndex.h" +#include "inc/Core/SearchQuery.h" +#include "inc/Core/Common/WorkSpace.h" +#include "inc/Core/Common/DataUtils.h" +#include +#include + +using namespace SPTAG; + +template +float CalcRecall(std::vector &results, const std::vector> &truth, int NumQuerys, int K, std::ofstream& log) +{ + float meanrecall = 0, minrecall = MaxDist, maxrecall = 0, stdrecall = 0; + std::vector thisrecall(NumQuerys, 0); + for (int i = 0; i < NumQuerys; i++) + { + for (int id : truth[i]) + { + for (int j = 0; j < K; j++) + { + if (results[i].GetResult(j)->VID == id) + { + thisrecall[i] += 1; + break; + } + } + } + thisrecall[i] /= K; + meanrecall += thisrecall[i]; + if (thisrecall[i] < minrecall) minrecall = thisrecall[i]; + if (thisrecall[i] > maxrecall) maxrecall = thisrecall[i]; + } + meanrecall /= NumQuerys; + for (int i = 0; i < NumQuerys; i++) + { + stdrecall += (thisrecall[i] - meanrecall) * (thisrecall[i] - meanrecall); + } + stdrecall = std::sqrt(stdrecall / NumQuerys); + log << meanrecall << " " << stdrecall << " " << minrecall << " " << maxrecall << std::endl; + return meanrecall; +} + +void LoadTruth(std::ifstream& fp, std::vector>& truth, int NumQuerys, int K) +{ + int get; + std::string line; + for (int i = 0; i < NumQuerys; ++i) + { + truth[i].clear(); + for (int j = 0; j < K; ++j) + { + fp >> get; + truth[i].insert(get); + } + std::getline(fp, line); + } +} + +template +int Process(Helper::IniReader& reader, VectorIndex& index) +{ + std::string queryFile = reader.GetParameter("Index", "QueryFile", std::string("querys.bin")); + std::string truthFile = reader.GetParameter("Index", "TruthFile", std::string("truth.txt")); + std::string outputFile = reader.GetParameter("Index", "ResultFile", std::string("")); + + int numBatchQuerys = reader.GetParameter("Index", "NumBatchQuerys", 10000); + int numDebugQuerys = reader.GetParameter("Index", "NumDebugQuerys", -1); + int K = reader.GetParameter("Index", "K", 32); + + std::vector maxCheck = Helper::StrUtils::SplitString(reader.GetParameter("Index", "MaxCheck", std::string("2048")), "#"); + + std::ifstream inStream(queryFile); + std::ifstream ftruth(truthFile); + std::ofstream fp; + if (!inStream.is_open()) + { + std::cout << "ERROR: Cannot Load Query file " << queryFile << "!" << std::endl; + return -1; + } + if (outputFile != "") + { + fp.open(outputFile); + if (!fp.is_open()) + { + std::cout << "ERROR: Cannot open " << outputFile << " for write!" << std::endl; + } + } + + std::ofstream log(index.GetIndexName() + "_" + std::to_string(K) + ".txt"); + if (!log.is_open()) + { + std::cout << "ERROR: Cannot open logging file!" << std::endl; + return -1; + } + + int numQuerys = (numDebugQuerys >= 0) ? numDebugQuerys : numBatchQuerys; + + std::vector> Query(numQuerys, std::vector(index.GetFeatureDim(), 0)); + std::vector> truth(numQuerys); + std::vector results(numQuerys, QueryResult(NULL, K, 0)); + + int * latencies = new int[numQuerys + 1]; + + int base = 1; + if (index.GetDistCalcMethod() == DistCalcMethod::Cosine) { + base = COMMON::Utils::GetBase(); + } + int basesquare = base * base; + + int dims = index.GetFeatureDim(); + std::vector QStrings; + while (!inStream.eof()) + { + QStrings.clear(); + COMMON::Utils::PrepareQuerys(inStream, QStrings, Query, numQuerys, dims, index.GetDistCalcMethod(), base); + if (numQuerys == 0) break; + + for (int i = 0; i < numQuerys; i++) results[i].SetTarget(Query[i].data()); + if (ftruth.is_open()) LoadTruth(ftruth, truth, numQuerys, K); + + std::cout << " \t[avg] \t[99%] \t[95%] \t[recall] \t[mem]" << std::endl; + + int subSize = (numQuerys - 1) / index.GetNumThreads() + 1; + for (std::string& mc : maxCheck) + { + index.SetParameter("MaxCheck", mc.c_str()); + for (int i = 0; i < numQuerys; i++) results[i].Reset(); + + if (index.GetNumThreads() == 1) + { + for (int i = 0; i < numQuerys; i++) + { + latencies[i] = clock(); + index.SearchIndex(results[i]); + } + } + else + { +#pragma omp parallel for + for (int tid = 0; tid < index.GetNumThreads(); tid++) + { + int start = tid * subSize; + int end = min((tid + 1) * subSize, numQuerys); + for (int i = start; i < end; i++) + { + latencies[i] = clock(); + index.SearchIndex(results[i]); + } + } + } + latencies[numQuerys] = clock(); + + float timeMean = 0, timeMin = MaxDist, timeMax = 0, timeStd = 0; + for (int i = 0; i < numQuerys; i++) + { + if (latencies[i + 1] >= latencies[i]) + latencies[i] = latencies[i + 1] - latencies[i]; + else + latencies[i] = latencies[numQuerys] - latencies[i]; + timeMean += latencies[i]; + if (latencies[i] > timeMax) timeMax = (float)latencies[i]; + if (latencies[i] < timeMin) timeMin = (float)latencies[i]; + } + timeMean /= numQuerys; + for (int i = 0; i < numQuerys; i++) timeStd += ((float)latencies[i] - timeMean) * ((float)latencies[i] - timeMean); + timeStd = std::sqrt(timeStd / numQuerys); + log << timeMean << " " << timeStd << " " << timeMin << " " << timeMax << " "; + + std::sort(latencies, latencies + numQuerys, [](int x, int y) + { + return x < y; + }); + float l99 = float(latencies[int(numQuerys * 0.99)]) / CLOCKS_PER_SEC; + float l95 = float(latencies[int(numQuerys * 0.95)]) / CLOCKS_PER_SEC; + + float recall = 0; + if (ftruth.is_open()) + { + recall = CalcRecall(results, truth, numQuerys, K, log); + } + +#ifndef _MSC_VER + struct rusage rusage; + getrusage(RUSAGE_SELF, &rusage); + unsigned long long peakWSS = rusage.ru_maxrss * 1024 / 1000000000; +#else + PROCESS_MEMORY_COUNTERS pmc; + GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)); + unsigned long long peakWSS = pmc.PeakWorkingSetSize / 1000000000; +#endif + std::cout << mc << "\t" << std::fixed << std::setprecision(6) << (timeMean / CLOCKS_PER_SEC) << "\t" << std::setprecision(4) << l99 << "\t" << l95 << "\t" << recall << "\t\t" << peakWSS << "GB" << std::endl; + + } + + if (fp.is_open()) + { + fp << std::setprecision(3) << std::fixed; + for (int i = 0; i < numQuerys; i++) + { + fp << QStrings[i] << ":"; + for (int j = 0; j < K; j++) + { + if (results[i].GetResult(j)->VID < 0) { + fp << results[i].GetResult(j)->Dist << "@" << results[i].GetResult(j)->VID << std::endl; + } + else { + ByteArray vm = index.GetMetadata(results[i].GetResult(j)->VID); + fp << (results[i].GetResult(j)->Dist / basesquare) << "@"; + fp.write((const char*)vm.Data(), vm.Length()); + } + fp << "|"; + } + fp << std::endl; + } + } + + if (numQuerys < numBatchQuerys || numDebugQuerys >= 0) break; + } + std::cout << "Output results finish!" << std::endl; + + inStream.close(); + fp.close(); + log.close(); + ftruth.close(); + delete[] latencies; + + QStrings.clear(); + results.clear(); + + return 0; +} + +int main(int argc, char** argv) +{ + if (argc < 2) + { + std::cerr << "IndexSearcher.exe folder" << std::endl; + return -1; + } + + std::shared_ptr vecIndex; + auto ret = SPTAG::VectorIndex::LoadIndex(argv[1], vecIndex); + if (SPTAG::ErrorCode::Success != ret || nullptr == vecIndex) + { + std::cerr << "Cannot open configure file!" << std::endl; + return -1; + } + + Helper::IniReader iniReader; + for (int i = 1; i < argc; i++) + { + std::string param(argv[i]); + size_t idx = param.find("="); + if (idx < 0) continue; + + std::string paramName = param.substr(0, idx); + std::string paramVal = param.substr(idx + 1); + std::string sectionName; + idx = paramName.find("."); + if (idx >= 0) { + sectionName = paramName.substr(0, idx); + paramName = paramName.substr(idx + 1); + } + iniReader.SetParameter(sectionName, paramName, paramVal); + std::cout << "Set [" << sectionName << "]" << paramName << " = " << paramVal << std::endl; + } + + switch (vecIndex->GetVectorValueType()) + { +#define DefineVectorValueType(Name, Type) \ + case VectorValueType::Name: \ + Process(iniReader, *(vecIndex.get())); \ + break; \ + +#include "inc/Core/DefinitionList.h" +#undef DefineVectorValueType + + default: break; + } + return 0; +} diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/Server/QueryParser.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Server/QueryParser.cpp new file mode 100644 index 0000000000..0fb47e9390 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Server/QueryParser.cpp @@ -0,0 +1,209 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Server/QueryParser.h" + +#include +#include + +using namespace SPTAG; +using namespace SPTAG::Service; + + +const char* QueryParser::c_defaultVectorSeparator = "|"; + + +QueryParser::QueryParser() + : m_vectorBase64(nullptr), + m_vectorBase64Length(0) +{ +} + + +QueryParser::~QueryParser() +{ +} + + +ErrorCode +QueryParser::Parse(const std::string& p_query, const char* p_vectorSeparator) +{ + if (p_vectorSeparator == nullptr) + { + p_vectorSeparator = c_defaultVectorSeparator; + } + + m_vectorElements.clear(); + m_options.clear(); + + m_dataHolder = ByteArray::Alloc(p_query.size() + 1); + memcpy(m_dataHolder.Data(), p_query.c_str(), p_query.size() + 1); + + enum class State : uint8_t + { + OptionNameBegin, + OptionName, + OptionValueBegin, + OptionValue, + Vector, + VectorBase64, + None + }; + + State currState = State::None; + + char* optionName = nullptr; + char* vectorStrBegin = nullptr; + char* vectorStrEnd = nullptr; + SizeType estDimension = 0; + + char* iter = nullptr; + + for (iter = reinterpret_cast(m_dataHolder.Data()); *iter != '\0'; ++iter) + { + if (std::isspace(*iter)) + { + *iter = '\0'; + if (State::Vector == currState) + { + ++estDimension; + vectorStrEnd = iter; + } + else if (State::VectorBase64 == currState) + { + m_vectorBase64Length = iter - m_vectorBase64; + } + + currState = State::None; + continue; + } + + switch (currState) + { + case State::None: + if ('$' == *iter) + { + currState = State::OptionNameBegin; + } + else if ('#' == *iter) + { + currState = State::VectorBase64; + m_vectorBase64 = iter + 1; + } + else + { + currState = State::Vector; + vectorStrBegin = iter; + } + + break; + + case State::OptionNameBegin: + optionName = iter; + currState = State::OptionName; + break; + + case State::OptionName: + if (':' == *iter || '=' == *iter) + { + *iter = '\0'; + currState = State::OptionValueBegin; + } + else if (std::isupper(*iter)) + { + // Convert OptionName to lowercase. + *iter = (*iter) | 0x20; + } + + break; + + case State::OptionValueBegin: + currState = State::OptionValue; + m_options.emplace_back(optionName, iter); + break; + + case State::Vector: + if (std::strchr(p_vectorSeparator, *iter) != nullptr) + { + ++estDimension; + *iter = '\0'; + } + + break; + + default: + break; + } + } + + if (State::Vector == currState) + { + ++estDimension; + vectorStrEnd = iter; + } + else if (State::VectorBase64 == currState) + { + m_vectorBase64Length = iter - m_vectorBase64; + } + + if (vectorStrBegin == nullptr || 0 == estDimension) + { + return ErrorCode::Fail; + } + + m_vectorElements.reserve(estDimension); + while (vectorStrBegin < vectorStrEnd) + { + while (vectorStrBegin < vectorStrEnd && '\0' == *vectorStrBegin) + { + ++vectorStrBegin; + } + + if (vectorStrBegin >= vectorStrEnd) + { + break; + } + + m_vectorElements.push_back(vectorStrBegin); + + while (vectorStrBegin < vectorStrEnd && '\0' != *vectorStrBegin) + { + ++vectorStrBegin; + } + } + + if (m_vectorElements.empty()) + { + return ErrorCode::Fail; + } + + return ErrorCode::Success; +} + + +const std::vector& +QueryParser::GetVectorElements() const +{ + return m_vectorElements; +} + + +const std::vector& +QueryParser::GetOptions() const +{ + return m_options; +} + + +const char* +QueryParser::GetVectorBase64() const +{ + return m_vectorBase64; +} + + +SizeType +QueryParser::GetVectorBase64Length() const +{ + return m_vectorBase64Length; +} diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/Server/SearchExecutionContext.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Server/SearchExecutionContext.cpp new file mode 100644 index 0000000000..36ff082404 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Server/SearchExecutionContext.cpp @@ -0,0 +1,220 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Server/SearchExecutionContext.h" +#include "inc/Helper/StringConvert.h" +#include "inc/Helper/CommonHelper.h" +#include "inc/Helper/Base64Encode.h" + +using namespace SPTAG; +using namespace SPTAG::Service; + +namespace +{ +namespace Local +{ + +template +ErrorCode +ConvertVectorFromString(const std::vector& p_source, ByteArray& p_dest, SizeType& p_dimension) +{ + p_dimension = 0; + p_dest = ByteArray::Alloc(p_source.size() * sizeof(ValueType)); + ValueType* arr = reinterpret_cast(p_dest.Data()); + for (std::size_t i = 0; i < p_source.size(); ++i) + { + if (!Helper::Convert::ConvertStringTo(p_source[i], arr[i])) + { + p_dest.Clear(); + p_dimension = 0; + return ErrorCode::Fail; + } + + ++p_dimension; + } + + return ErrorCode::Success; +} + +} +} + + +SearchExecutionContext::SearchExecutionContext(const std::shared_ptr& p_serviceSettings) + : c_serviceSettings(p_serviceSettings), + m_vectorDimension(0), + m_inputValueType(VectorValueType::Undefined), + m_extractMetadata(false), + m_resultNum(p_serviceSettings->m_defaultMaxResultNumber) +{ +} + + +SearchExecutionContext::~SearchExecutionContext() +{ + m_results.clear(); +} + + +ErrorCode +SearchExecutionContext::ParseQuery(const std::string& p_query) +{ + return m_queryParser.Parse(p_query, c_serviceSettings->m_vectorSeparator.c_str()); +} + + +ErrorCode +SearchExecutionContext::ExtractOption() +{ + for (const auto& optionPair : m_queryParser.GetOptions()) + { + if (Helper::StrUtils::StrEqualIgnoreCase(optionPair.first, "indexname")) + { + const char* begin = optionPair.second; + const char* end = optionPair.second; + while (*end != '\0') + { + while (*end != '\0' && *end != ',') + { + ++end; + } + + if (end != begin) + { + m_indexNames.emplace_back(begin, end - begin); + } + + if (*end != '\0') + { + ++end; + begin = end; + } + } + } + else if (Helper::StrUtils::StrEqualIgnoreCase(optionPair.first, "datatype")) + { + Helper::Convert::ConvertStringTo(optionPair.second, m_inputValueType); + } + else if (Helper::StrUtils::StrEqualIgnoreCase(optionPair.first, "extractmetadata")) + { + Helper::Convert::ConvertStringTo(optionPair.second, m_extractMetadata); + } + else if (Helper::StrUtils::StrEqualIgnoreCase(optionPair.first, "resultnum")) + { + Helper::Convert::ConvertStringTo(optionPair.second, m_resultNum); + } + } + + return ErrorCode::Success; +} + + +ErrorCode +SearchExecutionContext::ExtractVector(VectorValueType p_targetType) +{ + if (!m_queryParser.GetVectorElements().empty()) + { + switch (p_targetType) + { +#define DefineVectorValueType(Name, Type) \ + case VectorValueType::Name: \ + return Local::ConvertVectorFromString( \ + m_queryParser.GetVectorElements(), m_vector, m_vectorDimension); \ + break; \ + +#include "inc/Core/DefinitionList.h" +#undef DefineVectorValueType + + default: + break; + } + } + else if (m_queryParser.GetVectorBase64() != nullptr + && m_queryParser.GetVectorBase64Length() != 0) + { + SizeType estLen = m_queryParser.GetVectorBase64Length(); + auto temp = ByteArray::Alloc(Helper::Base64::CapacityForDecode(estLen)); + std::size_t outLen = 0; + if (!Helper::Base64::Decode(m_queryParser.GetVectorBase64(), estLen, temp.Data(), outLen)) + { + return ErrorCode::Fail; + } + + if (outLen % GetValueTypeSize(p_targetType) != 0) + { + return ErrorCode::Fail; + } + + m_vectorDimension = outLen / GetValueTypeSize(p_targetType); + m_vector = ByteArray(temp.Data(), outLen, temp.DataHolder()); + + return ErrorCode::Success; + } + + return ErrorCode::Fail; +} + + +const std::vector& +SearchExecutionContext::GetSelectedIndexNames() const +{ + return m_indexNames; +} + + +void +SearchExecutionContext::AddResults(std::string p_indexName, QueryResult& p_results) +{ + m_results.emplace_back(); + m_results.back().m_indexName.swap(p_indexName); + m_results.back().m_results = p_results; +} + + +std::vector& +SearchExecutionContext::GetResults() +{ + return m_results; +} + + +const std::vector& +SearchExecutionContext::GetResults() const +{ + return m_results; +} + + +const ByteArray& +SearchExecutionContext::GetVector() const +{ + return m_vector; +} + + +const SizeType +SearchExecutionContext::GetVectorDimension() const +{ + return m_vectorDimension; +} + + +const std::vector& +SearchExecutionContext::GetOptions() const +{ + return m_queryParser.GetOptions(); +} + + +const SizeType +SearchExecutionContext::GetResultNum() const +{ + return m_resultNum; +} + + +const bool +SearchExecutionContext::GetExtractMetadata() const +{ + return m_extractMetadata; +} diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/Server/SearchExecutor.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Server/SearchExecutor.cpp new file mode 100644 index 0000000000..2bc3832d88 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Server/SearchExecutor.cpp @@ -0,0 +1,113 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Server/SearchExecutor.h" + +using namespace SPTAG; +using namespace SPTAG::Service; + + +SearchExecutor::SearchExecutor(std::string p_queryString, + std::shared_ptr p_serviceContext, + const CallBack& p_callback) + : m_callback(p_callback), + c_serviceContext(std::move(p_serviceContext)), + m_queryString(std::move(p_queryString)) +{ +} + + +SearchExecutor::~SearchExecutor() +{ +} + + +void +SearchExecutor::Execute() +{ + ExecuteInternal(); + if (bool(m_callback)) + { + m_callback(std::move(m_executionContext)); + } +} + + +void +SearchExecutor::ExecuteInternal() +{ + m_executionContext.reset(new SearchExecutionContext(c_serviceContext->GetServiceSettings())); + + m_executionContext->ParseQuery(m_queryString); + m_executionContext->ExtractOption(); + + SelectIndex(); + + if (m_selectedIndex.empty()) + { + return; + } + + const auto& firstIndex = m_selectedIndex.front(); + + if (ErrorCode::Success != m_executionContext->ExtractVector(firstIndex->GetVectorValueType())) + { + return; + } + + if (m_executionContext->GetVectorDimension() != firstIndex->GetFeatureDim()) + { + return; + } + + QueryResult query(m_executionContext->GetVector().Data(), + m_executionContext->GetResultNum(), + m_executionContext->GetExtractMetadata()); + + for (const auto& vectorIndex : m_selectedIndex) + { + if (vectorIndex->GetVectorValueType() != firstIndex->GetVectorValueType() + || vectorIndex->GetFeatureDim() != firstIndex->GetFeatureDim()) + { + continue; + } + + query.Reset(); + if (ErrorCode::Success == vectorIndex->SearchIndex(query)) + { + m_executionContext->AddResults(vectorIndex->GetIndexName(), query); + } + } +} + + +void +SearchExecutor::SelectIndex() +{ + const auto& indexNames = m_executionContext->GetSelectedIndexNames(); + const auto& indexMap = c_serviceContext->GetIndexMap(); + if (indexMap.empty()) + { + return; + } + + if (indexNames.empty()) + { + if (indexMap.size() == 1) + { + m_selectedIndex.push_back(indexMap.begin()->second); + } + } + else + { + for (const auto& indexName : indexNames) + { + auto iter = indexMap.find(indexName); + if (iter != indexMap.cend()) + { + m_selectedIndex.push_back(iter->second); + } + } + } +} + diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/Server/SearchService.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Server/SearchService.cpp new file mode 100644 index 0000000000..a85fdcdb39 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Server/SearchService.cpp @@ -0,0 +1,263 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Server/SearchService.h" +#include "inc/Server/SearchExecutor.h" +#include "inc/Socket/RemoteSearchQuery.h" +#include "inc/Helper/CommonHelper.h" +#include "inc/Helper/ArgumentsParser.h" + +#include + +using namespace SPTAG; +using namespace SPTAG::Service; + + +namespace +{ +namespace Local +{ + +class SerivceCmdOptions : public Helper::ArgumentsParser +{ +public: + SerivceCmdOptions() + : m_serveMode("interactive"), + m_configFile("AnnService.ini") + { + AddOptionalOption(m_serveMode, "-m", "--mode", "Service mode, interactive or socket."); + AddOptionalOption(m_configFile, "-c", "--config", "Service config file path."); + } + + virtual ~SerivceCmdOptions() + { + } + + std::string m_serveMode; + + std::string m_configFile; +}; + +} + +} // namespace + + +SearchService::SearchService() + : m_initialized(false), + m_shutdownSignals(m_ioContext), + m_serveMode(ServeMode::Interactive) +{ +} + + +SearchService::~SearchService() +{ +} + + +bool +SearchService::Initialize(int p_argNum, char* p_args[]) +{ + Local::SerivceCmdOptions cmdOptions; + if (!cmdOptions.Parse(p_argNum - 1, p_args + 1)) + { + return false; + } + + if (Helper::StrUtils::StrEqualIgnoreCase(cmdOptions.m_serveMode.c_str(), "interactive")) + { + m_serveMode = ServeMode::Interactive; + } + else if (Helper::StrUtils::StrEqualIgnoreCase(cmdOptions.m_serveMode.c_str(), "socket")) + { + m_serveMode = ServeMode::Socket; + } + else + { + fprintf(stderr, "Failed parse Serve Mode!\n"); + return false; + } + + m_serviceContext.reset(new ServiceContext(cmdOptions.m_configFile)); + + m_initialized = m_serviceContext->IsInitialized(); + + return m_initialized; +} + + +void +SearchService::Run() +{ + if (!m_initialized) + { + return; + } + + switch (m_serveMode) + { + case ServeMode::Interactive: + RunInteractiveMode(); + break; + + case ServeMode::Socket: + RunSocketMode(); + break; + + default: + break; + } +} + + +void +SearchService::RunSocketMode() +{ + auto threadNum = max((unsigned int)1, m_serviceContext->GetServiceSettings()->m_threadNum); + m_threadPool.reset(new boost::asio::thread_pool(threadNum)); + + Socket::PacketHandlerMapPtr handlerMap(new Socket::PacketHandlerMap); + handlerMap->emplace(Socket::PacketType::SearchRequest, + [this](Socket::ConnectionID p_srcID, Socket::Packet p_packet) + { + boost::asio::post(*m_threadPool, std::bind(&SearchService::SearchHanlder, this, p_srcID, std::move(p_packet))); + }); + + m_socketServer.reset(new Socket::Server(m_serviceContext->GetServiceSettings()->m_listenAddr, + m_serviceContext->GetServiceSettings()->m_listenPort, + handlerMap, + m_serviceContext->GetServiceSettings()->m_socketThreadNum)); + + fprintf(stderr, + "Start to listen %s:%s ...\n", + m_serviceContext->GetServiceSettings()->m_listenAddr.c_str(), + m_serviceContext->GetServiceSettings()->m_listenPort.c_str()); + + m_shutdownSignals.add(SIGINT); + m_shutdownSignals.add(SIGTERM); +#ifdef SIGQUIT + m_shutdownSignals.add(SIGQUIT); +#endif + + m_shutdownSignals.async_wait([this](boost::system::error_code p_ec, int p_signal) + { + fprintf(stderr, "Received shutdown signals.\n"); + }); + + m_ioContext.run(); + fprintf(stderr, "Start shutdown procedure.\n"); + + m_socketServer.reset(); + m_threadPool->stop(); + m_threadPool->join(); +} + + +void +SearchService::RunInteractiveMode() +{ + const std::size_t bufferSize = 1 << 16; + std::unique_ptr inputBuffer(new char[bufferSize]); + while (true) + { + fprintf(stdout, "Query: "); + if (!fgets(inputBuffer.get(), bufferSize, stdin)) + { + break; + } + + auto callback = [](std::shared_ptr p_exeContext) + { + fprintf(stdout, "Result:\n"); + if (nullptr == p_exeContext) + { + fprintf(stdout, "Not Executed.\n"); + return; + } + + const auto& results = p_exeContext->GetResults(); + for (const auto& result : results) + { + fprintf(stdout, "Index: %s\n", result.m_indexName.c_str()); + int idx = 0; + for (const auto& res : result.m_results) + { + fprintf(stdout, "------------------\n"); + fprintf(stdout, "DocIndex: %d Distance: %f", res.VID, res.Dist); + if (result.m_results.WithMeta()) + { + const auto& metadata = result.m_results.GetMetadata(idx); + fprintf(stdout, " MetaData: %.*s", static_cast(metadata.Length()), metadata.Data()); + } + + fprintf(stdout, "\n"); + ++idx; + } + } + }; + + SearchExecutor executor(inputBuffer.get(), m_serviceContext, callback); + executor.Execute(); + } +} + + +void +SearchService::SearchHanlder(Socket::ConnectionID p_localConnectionID, Socket::Packet p_packet) +{ + if (p_packet.Header().m_bodyLength == 0) + { + return; + } + + if (Socket::c_invalidConnectionID == p_packet.Header().m_connectionID) + { + p_packet.Header().m_connectionID = p_localConnectionID; + } + + Socket::RemoteQuery remoteQuery; + remoteQuery.Read(p_packet.Body()); + + auto callback = std::bind(&SearchService::SearchHanlderCallback, + this, + std::placeholders::_1, + std::move(p_packet)); + + SearchExecutor executor(std::move(remoteQuery.m_queryString), + m_serviceContext, + callback); + executor.Execute(); +} + + +void +SearchService::SearchHanlderCallback(std::shared_ptr p_exeContext, + Socket::Packet p_srcPacket) +{ + Socket::Packet ret; + ret.Header().m_packetType = Socket::PacketType::SearchResponse; + ret.Header().m_processStatus = Socket::PacketProcessStatus::Ok; + ret.Header().m_connectionID = p_srcPacket.Header().m_connectionID; + ret.Header().m_resourceID = p_srcPacket.Header().m_resourceID; + + if (nullptr == p_exeContext) + { + ret.Header().m_processStatus = Socket::PacketProcessStatus::Failed; + ret.AllocateBuffer(0); + ret.Header().WriteBuffer(ret.HeaderBuffer()); + } + else + { + Socket::RemoteSearchResult remoteResult; + remoteResult.m_status = Socket::RemoteSearchResult::ResultStatus::Success; + remoteResult.m_allIndexResults.swap(p_exeContext->GetResults()); + ret.AllocateBuffer(static_cast(remoteResult.EstimateBufferSize())); + auto bodyEnd = remoteResult.Write(ret.Body()); + + ret.Header().m_bodyLength = static_cast(bodyEnd - ret.Body()); + ret.Header().WriteBuffer(ret.HeaderBuffer()); + } + + m_socketServer->SendPacket(p_srcPacket.Header().m_connectionID, std::move(ret), nullptr); +} diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/Server/ServiceContext.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Server/ServiceContext.cpp new file mode 100644 index 0000000000..8d62b2c7af --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Server/ServiceContext.cpp @@ -0,0 +1,88 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Server/ServiceContext.h" +#include "inc/Helper/SimpleIniReader.h" +#include "inc/Helper/CommonHelper.h" +#include "inc/Helper/StringConvert.h" + +using namespace SPTAG; +using namespace SPTAG::Service; + + +ServiceContext::ServiceContext(const std::string& p_configFilePath) + : m_initialized(false) +{ + Helper::IniReader iniReader; + if (ErrorCode::Success != iniReader.LoadIniFile(p_configFilePath)) + { + return; + } + + m_settings.reset(new ServiceSettings); + + m_settings->m_listenAddr = iniReader.GetParameter("Service", "ListenAddr", std::string("0.0.0.0")); + m_settings->m_listenPort = iniReader.GetParameter("Service", "ListenPort", std::string("8000")); + m_settings->m_threadNum = iniReader.GetParameter("Service", "ThreadNumber", static_cast(8)); + m_settings->m_socketThreadNum = iniReader.GetParameter("Service", "SocketThreadNumber", static_cast(8)); + + m_settings->m_defaultMaxResultNumber = iniReader.GetParameter("QueryConfig", "DefaultMaxResultNumber", static_cast(10)); + m_settings->m_vectorSeparator = iniReader.GetParameter("QueryConfig", "DefaultSeparator", std::string("|")); + + const std::string emptyStr; + + std::string indexListStr = iniReader.GetParameter("Index", "List", emptyStr); + const auto& indexList = Helper::StrUtils::SplitString(indexListStr, ","); + + for (const auto& indexName : indexList) + { + std::string sectionName("Index_"); + sectionName += indexName.c_str(); + if (!iniReader.DoesParameterExist(sectionName, "IndexFolder")) + { + continue; + } + + std::string indexFolder = iniReader.GetParameter(sectionName, "IndexFolder", emptyStr); + + std::shared_ptr vectorIndex; + if (ErrorCode::Success == VectorIndex::LoadIndex(indexFolder, vectorIndex)) + { + vectorIndex->SetIndexName(indexName); + m_fullIndexList.emplace(indexName, vectorIndex); + } + else + { + fprintf(stderr, "Failed loading index: %s\n", indexName.c_str()); + } + } + + m_initialized = true; +} + + +ServiceContext::~ServiceContext() +{ + +} + + +const std::map>& +ServiceContext::GetIndexMap() const +{ + return m_fullIndexList; +} + + +const std::shared_ptr& +ServiceContext::GetServiceSettings() const +{ + return m_settings; +} + + +bool +ServiceContext::IsInitialized() const +{ + return m_initialized; +} diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/Server/ServiceSettings.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Server/ServiceSettings.cpp new file mode 100644 index 0000000000..d51153195b --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Server/ServiceSettings.cpp @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Server/ServiceSettings.h" + +using namespace SPTAG; +using namespace SPTAG::Service; + + +ServiceSettings::ServiceSettings() + : m_defaultMaxResultNumber(10), + m_threadNum(12) +{ +} diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/Server/main.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Server/main.cpp new file mode 100644 index 0000000000..5aa5dc1e59 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Server/main.cpp @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Server/SearchService.h" + +SPTAG::Service::SearchService g_service; + +int main(int argc, char* argv[]) +{ + if (!g_service.Initialize(argc, argv)) + { + return 1; + } + + g_service.Run(); + + return 0; +} + diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/Socket/Client.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Socket/Client.cpp new file mode 100644 index 0000000000..9c4101e4f4 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Socket/Client.cpp @@ -0,0 +1,141 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Socket/Client.h" + +#include + +using namespace SPTAG::Socket; + + +Client::Client(const PacketHandlerMapPtr& p_handlerMap, + std::size_t p_threadNum, + std::uint32_t p_heartbeatIntervalSeconds) + : c_requestHandlerMap(p_handlerMap), + m_connectionManager(new ConnectionManager), + m_deadlineTimer(m_ioContext), + m_heartbeatIntervalSeconds(p_heartbeatIntervalSeconds), + m_stopped(false) +{ + KeepIoContext(); + m_threadPool.reserve(p_threadNum); + for (std::size_t i = 0; i < p_threadNum; ++i) + { + m_threadPool.emplace_back(std::move(std::thread([this]() { m_ioContext.run(); }))); + } +} + + +Client::~Client() +{ + m_stopped = true; + + m_deadlineTimer.cancel(); + m_connectionManager->StopAll(); + while (!m_ioContext.stopped()) + { + m_ioContext.stop(); + } + + for (auto& t : m_threadPool) + { + t.join(); + } +} + + +ConnectionID +Client::ConnectToServer(const std::string& p_address, + const std::string& p_port, + SPTAG::ErrorCode& p_ec) +{ + boost::asio::ip::tcp::resolver resolver(m_ioContext); + + boost::system::error_code errCode; + auto endPoints = resolver.resolve(p_address, p_port, errCode); + if (errCode || endPoints.empty()) + { + p_ec = ErrorCode::Socket_FailedResolveEndPoint; + return c_invalidConnectionID; + } + + boost::asio::ip::tcp::socket socket(m_ioContext); + for (const auto ep : endPoints) + { + errCode.clear(); + socket.connect(ep, errCode); + if (!errCode) + { + break; + } + + socket.close(errCode); + } + + if (socket.is_open()) + { + p_ec = ErrorCode::Success; + return m_connectionManager->AddConnection(std::move(socket), + c_requestHandlerMap, + m_heartbeatIntervalSeconds); + } + + p_ec = ErrorCode::Socket_FailedConnectToEndPoint; + return c_invalidConnectionID; +} + + +void +Client::AsyncConnectToServer(const std::string& p_address, + const std::string& p_port, + ConnectCallback p_callback) +{ + boost::asio::post(m_ioContext, + [this, p_address, p_port, p_callback]() + { + SPTAG::ErrorCode errCode; + auto connID = ConnectToServer(p_address, p_port, errCode); + if (bool(p_callback)) + { + p_callback(connID, errCode); + } + }); +} + + +void +Client::SendPacket(ConnectionID p_connection, Packet p_packet, std::function p_callback) +{ + auto connection = m_connectionManager->GetConnection(p_connection); + if (nullptr != connection) + { + connection->AsyncSend(std::move(p_packet), std::move(p_callback)); + } + else if (bool(p_callback)) + { + p_callback(false); + } +} + + +void +Client::SetEventOnConnectionClose(std::function p_event) +{ + m_connectionManager->SetEventOnRemoving(std::move(p_event)); +} + + +void +Client::KeepIoContext() +{ + if (m_stopped) + { + return; + } + + m_deadlineTimer.expires_from_now(boost::posix_time::hours(24)); + m_deadlineTimer.async_wait([this](boost::system::error_code p_ec) + { + this->KeepIoContext(); + }); +} diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/Socket/Common.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Socket/Common.cpp new file mode 100644 index 0000000000..2cfc1178ed --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Socket/Common.cpp @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Socket/Common.h" + + +using namespace SPTAG::Socket; + +const ConnectionID SPTAG::Socket::c_invalidConnectionID = 0; + +const ResourceID SPTAG::Socket::c_invalidResourceID = 0; diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/Socket/Connection.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Socket/Connection.cpp new file mode 100644 index 0000000000..6e536cbfcf --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Socket/Connection.cpp @@ -0,0 +1,403 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Socket/Connection.h" +#include "inc/Socket/ConnectionManager.h" + +#include +#include +#include +#include +#include + +#include + +using namespace SPTAG::Socket; + +Connection::Connection(ConnectionID p_connectionID, + boost::asio::ip::tcp::socket&& p_socket, + const PacketHandlerMapPtr& p_handlerMap, + std::weak_ptr p_connectionManager) + : c_connectionID(p_connectionID), + c_handlerMap(p_handlerMap), + c_connectionManager(std::move(p_connectionManager)), + m_socket(std::move(p_socket)), + m_strand(p_socket.get_executor().context()), + m_heartbeatTimer(p_socket.get_executor().context()), + m_remoteConnectionID(c_invalidConnectionID), + m_stopped(true), + m_heartbeatStarted(false) +{ +} + + +void +Connection::Start() +{ +#ifdef _DEBUG + fprintf(stderr, "Connection Start, local: %u, remote: %s:%u\n", + static_cast(m_socket.local_endpoint().port()), + m_socket.remote_endpoint().address().to_string().c_str(), + static_cast(m_socket.remote_endpoint().port())); +#endif + + if (!m_stopped.exchange(false)) + { + return; + } + + SendRegister(); + AsyncReadHeader(); +} + + +void +Connection::Stop() +{ +#ifdef _DEBUG + fprintf(stderr, "Connection Stop, local: %u, remote: %s:%u\n", + static_cast(m_socket.local_endpoint().port()), + m_socket.remote_endpoint().address().to_string().c_str(), + static_cast(m_socket.remote_endpoint().port())); +#endif + + if (m_stopped.exchange(true)) + { + return; + } + + boost::system::error_code errCode; + if (m_heartbeatStarted.exchange(false)) + { + m_heartbeatTimer.cancel(errCode); + } + + m_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, errCode); + m_socket.close(errCode); +} + + +void +Connection::StartHeartbeat(std::size_t p_intervalSeconds) +{ + if (m_stopped || m_heartbeatStarted.exchange(true)) + { + return; + } + + SendHeartbeat(p_intervalSeconds); +} + + +ConnectionID +Connection::GetConnectionID() const +{ + return c_connectionID; +} + + +ConnectionID +Connection::GetRemoteConnectionID() const +{ + return m_remoteConnectionID; +} + + +void +Connection::AsyncSend(Packet p_packet, std::function p_callback) +{ + if (m_stopped) + { + if (bool(p_callback)) + { + p_callback(false); + } + + return; + } + + auto sharedThis = shared_from_this(); + boost::asio::post(m_strand, + [sharedThis, p_packet, p_callback]() + { + auto handler = [p_callback, p_packet, sharedThis](boost::system::error_code p_ec, + std::size_t p_bytesTransferred) + { + if (p_ec && boost::asio::error::operation_aborted != p_ec) + { + sharedThis->OnConnectionFail(p_ec); + } + + if (bool(p_callback)) + { + p_callback(!p_ec); + } + }; + + boost::asio::async_write(sharedThis->m_socket, + boost::asio::buffer(p_packet.Buffer(), + p_packet.BufferLength()), + std::move(handler)); + }); +} + + +void +Connection::AsyncReadHeader() +{ + if (m_stopped) + { + return; + } + + auto sharedThis = shared_from_this(); + boost::asio::post(m_strand, + [sharedThis]() + { + auto handler = boost::bind(&Connection::HandleReadHeader, + sharedThis, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred); + + boost::asio::async_read(sharedThis->m_socket, + boost::asio::buffer(sharedThis->m_packetHeaderReadBuffer), + std::move(handler)); + }); +} + + +void +Connection::AsyncReadBody() +{ + if (m_stopped) + { + return; + } + + auto sharedThis = shared_from_this(); + boost::asio::post(m_strand, + [sharedThis]() + { + auto handler = boost::bind(&Connection::HandleReadBody, + sharedThis, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred); + + boost::asio::async_read(sharedThis->m_socket, + boost::asio::buffer(sharedThis->m_packetRead.Body(), + sharedThis->m_packetRead.Header().m_bodyLength), + std::move(handler)); + }); +} + + +void +Connection::HandleReadHeader(boost::system::error_code p_ec, std::size_t p_bytesTransferred) +{ + if (!p_ec) + { + m_packetRead.Header().ReadBuffer(m_packetHeaderReadBuffer); + if (m_packetRead.Header().m_bodyLength > 0) + { + m_packetRead.AllocateBuffer(m_packetRead.Header().m_bodyLength); + AsyncReadBody(); + } + else + { + HandleReadBody(p_ec, p_bytesTransferred); + } + + return; + } + else if (boost::asio::error::operation_aborted != p_ec) + { + OnConnectionFail(p_ec); + return; + } + + AsyncReadHeader(); +} + + +void +Connection::HandleReadBody(boost::system::error_code p_ec, std::size_t p_bytesTransferred) +{ + if (!p_ec) + { + bool foundHanlder = true; + switch (m_packetRead.Header().m_packetType) + { + case PacketType::HeartbeatRequest: + HandleHeartbeatRequest(); + break; + + case PacketType::HeartbeatResponse: + break; + + case PacketType::RegisterRequest: + HandleRegisterRequest(); + break; + + case PacketType::RegisterResponse: + HandleRegisterResponse(); + break; + + default: + foundHanlder = false; + break; + } + + if (nullptr != c_handlerMap) + { + auto iter = c_handlerMap->find(m_packetRead.Header().m_packetType); + if (c_handlerMap->cend() != iter && bool(iter->second)) + { + (iter->second)(c_connectionID, std::move(m_packetRead)); + foundHanlder = true; + } + } + + if (!foundHanlder) + { + HandleNoHandlerResponse(); + } + } + else if (boost::asio::error::operation_aborted != p_ec) + { + OnConnectionFail(p_ec); + return; + } + + AsyncReadHeader(); +} + + +void +Connection::SendHeartbeat(std::size_t p_intervalSeconds) +{ + if (m_stopped) + { + return; + } + + Packet msg; + msg.Header().m_packetType = PacketType::HeartbeatRequest; + msg.Header().m_processStatus = PacketProcessStatus::Ok; + msg.Header().m_connectionID = 0; + + msg.AllocateBuffer(0); + msg.Header().WriteBuffer(msg.HeaderBuffer()); + + AsyncSend(std::move(msg), nullptr); + + m_heartbeatTimer.expires_from_now(boost::posix_time::seconds(p_intervalSeconds)); + m_heartbeatTimer.async_wait(boost::bind(&Connection::SendHeartbeat, + shared_from_this(), + p_intervalSeconds)); +} + + +void +Connection::SendRegister() +{ + Packet msg; + msg.Header().m_packetType = PacketType::RegisterRequest; + msg.Header().m_processStatus = PacketProcessStatus::Ok; + msg.Header().m_connectionID = 0; + + msg.AllocateBuffer(0); + msg.Header().WriteBuffer(msg.HeaderBuffer()); + + AsyncSend(std::move(msg), nullptr); +} + + +void +Connection::HandleHeartbeatRequest() +{ + Packet msg; + msg.Header().m_packetType = PacketType::HeartbeatResponse; + msg.Header().m_processStatus = PacketProcessStatus::Ok; + + msg.AllocateBuffer(0); + + if (0 == m_packetRead.Header().m_connectionID + || c_connectionID == m_packetRead.Header().m_connectionID) + { + m_packetRead.Header().m_connectionID; + msg.Header().WriteBuffer(msg.HeaderBuffer()); + + AsyncSend(std::move(msg), nullptr); + } + else + { + msg.Header().m_connectionID = m_packetRead.Header().m_connectionID; + msg.Header().WriteBuffer(msg.HeaderBuffer()); + + auto mgr = c_connectionManager.lock(); + if (nullptr != mgr) + { + auto con = mgr->GetConnection(m_packetRead.Header().m_connectionID); + if (nullptr != con) + { + con->AsyncSend(std::move(msg), nullptr); + } + } + } +} + + +void +Connection::HandleRegisterRequest() +{ + Packet msg; + msg.Header().m_packetType = PacketType::RegisterResponse; + msg.Header().m_processStatus = PacketProcessStatus::Ok; + msg.Header().m_connectionID = c_connectionID; + msg.Header().m_resourceID = m_packetRead.Header().m_resourceID; + + msg.AllocateBuffer(0); + msg.Header().WriteBuffer(msg.HeaderBuffer()); + + AsyncSend(std::move(msg), nullptr); +} + + +void +Connection::HandleRegisterResponse() +{ + m_remoteConnectionID = m_packetRead.Header().m_connectionID; +} + + +void +Connection::HandleNoHandlerResponse() +{ + auto packetType = m_packetRead.Header().m_packetType; + if (!PacketTypeHelper::IsRequestPacket(packetType)) + { + return; + } + + Packet msg; + msg.Header().m_packetType = PacketTypeHelper::GetCrosspondingResponseType(packetType); + msg.Header().m_processStatus = PacketProcessStatus::Dropped; + msg.Header().m_connectionID = c_connectionID; + msg.Header().m_resourceID = m_packetRead.Header().m_resourceID; + + msg.AllocateBuffer(0); + msg.Header().WriteBuffer(msg.HeaderBuffer()); + + AsyncSend(std::move(msg), nullptr); +} + + +void +Connection::OnConnectionFail(const boost::system::error_code& p_ec) +{ + auto mgr = c_connectionManager.lock(); + if (nullptr != mgr) + { + mgr->RemoveConnection(c_connectionID); + } +} diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/Socket/ConnectionManager.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Socket/ConnectionManager.cpp new file mode 100644 index 0000000000..9d52dbc8b1 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Socket/ConnectionManager.cpp @@ -0,0 +1,133 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Socket/ConnectionManager.h" + +using namespace SPTAG::Socket; + + +ConnectionManager::ConnectionItem::ConnectionItem() + : m_isEmpty(true) +{ +} + + +ConnectionManager::ConnectionManager() + : m_nextConnectionID(1), + m_connectionCount(0) +{ +} + + +ConnectionID +ConnectionManager::AddConnection(boost::asio::ip::tcp::socket&& p_socket, + const PacketHandlerMapPtr& p_handler, + std::uint32_t p_heartbeatIntervalSeconds) +{ + ConnectionID currID = m_nextConnectionID.fetch_add(1); + while (c_invalidConnectionID == currID || !m_connections[GetPosition(currID)].m_isEmpty.exchange(false)) + { + if (m_connectionCount >= c_connectionPoolSize) + { + return c_invalidConnectionID; + } + + currID = m_nextConnectionID.fetch_add(1); + } + + ++m_connectionCount; + + auto connection = std::make_shared(currID, + std::move(p_socket), + p_handler, + std::weak_ptr(shared_from_this())); + + { + Helper::Concurrent::LockGuard guard(m_spinLock); + m_connections[GetPosition(currID)].m_connection = connection; + } + + connection->Start(); + if (p_heartbeatIntervalSeconds > 0) + { + connection->StartHeartbeat(p_heartbeatIntervalSeconds); + } + + return currID; +} + + +void +ConnectionManager::RemoveConnection(ConnectionID p_connectionID) +{ + auto position = GetPosition(p_connectionID); + if (m_connections[position].m_isEmpty.exchange(true)) + { + return; + } + + Connection::Ptr conn; + + { + Helper::Concurrent::LockGuard guard(m_spinLock); + conn = std::move(m_connections[position].m_connection); + } + + --m_connectionCount; + + conn->Stop(); + conn.reset(); + + if (bool(m_eventOnRemoving)) + { + m_eventOnRemoving(p_connectionID); + } +} + + +Connection::Ptr +ConnectionManager::GetConnection(ConnectionID p_connectionID) +{ + auto position = GetPosition(p_connectionID); + Connection::Ptr ret; + + { + Helper::Concurrent::LockGuard guard(m_spinLock); + ret = m_connections[position].m_connection; + } + + if (nullptr == ret || ret->GetConnectionID() != p_connectionID) + { + return nullptr; + } + + return ret; +} + + +void +ConnectionManager::SetEventOnRemoving(std::function p_event) +{ + m_eventOnRemoving = std::move(p_event); +} + + +void +ConnectionManager::StopAll() +{ + Helper::Concurrent::LockGuard guard(m_spinLock); + for (auto& connection : m_connections) + { + if (nullptr != connection.m_connection) + { + connection.m_connection->Stop(); + } + } +} + + +std::uint32_t +ConnectionManager::GetPosition(ConnectionID p_connectionID) +{ + return static_cast(p_connectionID) & c_connectionPoolMask; +} diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/Socket/Packet.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Socket/Packet.cpp new file mode 100644 index 0000000000..335400bbd8 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Socket/Packet.cpp @@ -0,0 +1,177 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Socket/Packet.h" +#include "inc/Socket/SimpleSerialization.h" + +#include + +using namespace SPTAG::Socket; + +PacketHeader::PacketHeader() + : m_packetType(PacketType::Undefined), + m_processStatus(PacketProcessStatus::Ok), + m_bodyLength(0), + m_connectionID(c_invalidConnectionID), + m_resourceID(c_invalidResourceID) +{ +} + + +PacketHeader::PacketHeader(PacketHeader&& p_right) + : m_packetType(std::move(p_right.m_packetType)), + m_processStatus(std::move(p_right.m_processStatus)), + m_bodyLength(std::move(p_right.m_bodyLength)), + m_connectionID(std::move(p_right.m_connectionID)), + m_resourceID(std::move(p_right.m_resourceID)) +{ +} + + +PacketHeader::PacketHeader(const PacketHeader& p_right) + : m_packetType(p_right.m_packetType), + m_processStatus(p_right.m_processStatus), + m_bodyLength(p_right.m_bodyLength), + m_connectionID(p_right.m_connectionID), + m_resourceID(p_right.m_resourceID) +{ +} + + +std::size_t +PacketHeader::WriteBuffer(std::uint8_t* p_buffer) +{ + std::uint8_t* buff = p_buffer; + buff = SimpleSerialization::SimpleWriteBuffer(m_packetType, buff); + buff = SimpleSerialization::SimpleWriteBuffer(m_processStatus, buff); + buff = SimpleSerialization::SimpleWriteBuffer(m_bodyLength, buff); + buff = SimpleSerialization::SimpleWriteBuffer(m_connectionID, buff); + buff = SimpleSerialization::SimpleWriteBuffer(m_resourceID, buff); + + return p_buffer - buff; +} + + +void +PacketHeader::ReadBuffer(const std::uint8_t* p_buffer) +{ + const std::uint8_t* buff = p_buffer; + buff = SimpleSerialization::SimpleReadBuffer(buff, m_packetType); + buff = SimpleSerialization::SimpleReadBuffer(buff, m_processStatus); + buff = SimpleSerialization::SimpleReadBuffer(buff, m_bodyLength); + buff = SimpleSerialization::SimpleReadBuffer(buff, m_connectionID); + buff = SimpleSerialization::SimpleReadBuffer(buff, m_resourceID); +} + + +Packet::Packet() +{ +} + + +Packet::Packet(Packet&& p_right) + : m_header(std::move(p_right.m_header)), + m_buffer(std::move(p_right.m_buffer)), + m_bufferCapacity(std::move(p_right.m_bufferCapacity)) +{ +} + + +Packet::Packet(const Packet& p_right) + : m_header(p_right.m_header), + m_buffer(p_right.m_buffer), + m_bufferCapacity(p_right.m_bufferCapacity) +{ +} + + +PacketHeader& +Packet::Header() +{ + return m_header; +} + + +std::uint8_t* +Packet::HeaderBuffer() const +{ + return m_buffer.get(); +} + + +std::uint8_t* +Packet::Body() const +{ + if (nullptr != m_buffer && PacketHeader::c_bufferSize < m_bufferCapacity) + { + return m_buffer.get() + PacketHeader::c_bufferSize; + } + + return nullptr; +} + + +std::uint8_t* +Packet::Buffer() const +{ + return m_buffer.get(); +} + + +std::uint32_t +Packet::BufferLength() const +{ + return PacketHeader::c_bufferSize + m_header.m_bodyLength; +} + + +std::uint32_t +Packet::BufferCapacity() const +{ + return m_bufferCapacity; +} + + +void +Packet::AllocateBuffer(std::uint32_t p_bodyCapacity) +{ + m_bufferCapacity = PacketHeader::c_bufferSize + p_bodyCapacity; + m_buffer.reset(new std::uint8_t[m_bufferCapacity], std::default_delete()); +} + + +bool +PacketTypeHelper::IsRequestPacket(PacketType p_type) +{ + if (PacketType::Undefined == p_type || PacketType::ResponseMask == p_type) + { + return false; + } + + return (static_cast(p_type) & static_cast(PacketType::ResponseMask)) == 0; +} + + +bool +PacketTypeHelper::IsResponsePacket(PacketType p_type) +{ + if (PacketType::Undefined == p_type || PacketType::ResponseMask == p_type) + { + return false; + } + + return (static_cast(p_type) & static_cast(PacketType::ResponseMask)) != 0; +} + + +PacketType +PacketTypeHelper::GetCrosspondingResponseType(PacketType p_type) +{ + if (PacketType::Undefined == p_type || PacketType::ResponseMask == p_type) + { + return PacketType::Undefined; + } + + auto ret = static_cast(p_type) | static_cast(PacketType::ResponseMask); + return static_cast(ret); +} diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/Socket/RemoteSearchQuery.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Socket/RemoteSearchQuery.cpp new file mode 100644 index 0000000000..2cb450328e --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Socket/RemoteSearchQuery.cpp @@ -0,0 +1,210 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Socket/RemoteSearchQuery.h" +#include "inc/Socket/SimpleSerialization.h" + +using namespace SPTAG; +using namespace SPTAG::Socket; + + +RemoteQuery::RemoteQuery() + : m_type(QueryType::String) +{ +} + + +std::size_t +RemoteQuery::EstimateBufferSize() const +{ + std::size_t sum = 0; + sum += SimpleSerialization::EstimateBufferSize(MajorVersion()); + sum += SimpleSerialization::EstimateBufferSize(MirrorVersion()); + sum += SimpleSerialization::EstimateBufferSize(m_type); + sum += SimpleSerialization::EstimateBufferSize(m_queryString); + + return sum; +} + + +std::uint8_t* +RemoteQuery::Write(std::uint8_t* p_buffer) const +{ + p_buffer = SimpleSerialization::SimpleWriteBuffer(MajorVersion(), p_buffer); + p_buffer = SimpleSerialization::SimpleWriteBuffer(MirrorVersion(), p_buffer); + + p_buffer = SimpleSerialization::SimpleWriteBuffer(m_type, p_buffer); + p_buffer = SimpleSerialization::SimpleWriteBuffer(m_queryString, p_buffer); + + return p_buffer; +} + + +const std::uint8_t* +RemoteQuery::Read(const std::uint8_t* p_buffer) +{ + decltype(MajorVersion()) majorVer = 0; + decltype(MirrorVersion()) mirrorVer = 0; + + p_buffer = SimpleSerialization::SimpleReadBuffer(p_buffer, majorVer); + p_buffer = SimpleSerialization::SimpleReadBuffer(p_buffer, mirrorVer); + if (majorVer != MajorVersion()) + { + return nullptr; + } + + p_buffer = SimpleSerialization::SimpleReadBuffer(p_buffer, m_type); + p_buffer = SimpleSerialization::SimpleReadBuffer(p_buffer, m_queryString); + + return p_buffer; +} + + +RemoteSearchResult::RemoteSearchResult() + : m_status(ResultStatus::Timeout) +{ +} + + +RemoteSearchResult::RemoteSearchResult(const RemoteSearchResult& p_right) + : m_status(p_right.m_status), + m_allIndexResults(p_right.m_allIndexResults) +{ +} + + +RemoteSearchResult::RemoteSearchResult(RemoteSearchResult&& p_right) + : m_status(std::move(p_right.m_status)), + m_allIndexResults(std::move(p_right.m_allIndexResults)) +{ +} + + +RemoteSearchResult& +RemoteSearchResult::operator=(RemoteSearchResult&& p_right) +{ + m_status = p_right.m_status; + m_allIndexResults = std::move(p_right.m_allIndexResults); + + return *this; +} + + +std::size_t +RemoteSearchResult::EstimateBufferSize() const +{ + std::size_t sum = 0; + sum += SimpleSerialization::EstimateBufferSize(MajorVersion()); + sum += SimpleSerialization::EstimateBufferSize(MirrorVersion()); + + sum += SimpleSerialization::EstimateBufferSize(m_status); + + sum += sizeof(std::uint32_t); + for (const auto& indexRes : m_allIndexResults) + { + sum += SimpleSerialization::EstimateBufferSize(indexRes.m_indexName); + sum += sizeof(std::uint32_t); + sum += sizeof(bool); + + for (const auto& res : indexRes.m_results) + { + sum += SimpleSerialization::EstimateBufferSize(res.VID); + sum += SimpleSerialization::EstimateBufferSize(res.Dist); + } + + if (indexRes.m_results.WithMeta()) + { + for (int i = 0; i < indexRes.m_results.GetResultNum(); ++i) + { + sum += SimpleSerialization::EstimateBufferSize(indexRes.m_results.GetMetadata(i)); + } + } + } + + return sum; +} + + +std::uint8_t* +RemoteSearchResult::Write(std::uint8_t* p_buffer) const +{ + p_buffer = SimpleSerialization::SimpleWriteBuffer(MajorVersion(), p_buffer); + p_buffer = SimpleSerialization::SimpleWriteBuffer(MirrorVersion(), p_buffer); + + p_buffer = SimpleSerialization::SimpleWriteBuffer(m_status, p_buffer); + p_buffer = SimpleSerialization::SimpleWriteBuffer(static_cast(m_allIndexResults.size()), p_buffer); + for (const auto& indexRes : m_allIndexResults) + { + p_buffer = SimpleSerialization::SimpleWriteBuffer(indexRes.m_indexName, p_buffer); + + p_buffer = SimpleSerialization::SimpleWriteBuffer(static_cast(indexRes.m_results.GetResultNum()), p_buffer); + p_buffer = SimpleSerialization::SimpleWriteBuffer(indexRes.m_results.WithMeta(), p_buffer); + + for (const auto& res : indexRes.m_results) + { + p_buffer = SimpleSerialization::SimpleWriteBuffer(res.VID, p_buffer); + p_buffer = SimpleSerialization::SimpleWriteBuffer(res.Dist, p_buffer); + } + + if (indexRes.m_results.WithMeta()) + { + for (int i = 0; i < indexRes.m_results.GetResultNum(); ++i) + { + p_buffer = SimpleSerialization::SimpleWriteBuffer(indexRes.m_results.GetMetadata(i), p_buffer); + } + } + } + + return p_buffer; +} + + +const std::uint8_t* +RemoteSearchResult::Read(const std::uint8_t* p_buffer) +{ + decltype(MajorVersion()) majorVer = 0; + decltype(MirrorVersion()) mirrorVer = 0; + + p_buffer = SimpleSerialization::SimpleReadBuffer(p_buffer, majorVer); + p_buffer = SimpleSerialization::SimpleReadBuffer(p_buffer, mirrorVer); + if (majorVer != MajorVersion()) + { + return nullptr; + } + + p_buffer = SimpleSerialization::SimpleReadBuffer(p_buffer, m_status); + + std::uint32_t len = 0; + p_buffer = SimpleSerialization::SimpleReadBuffer(p_buffer, len); + m_allIndexResults.resize(len); + + for (auto& indexRes : m_allIndexResults) + { + p_buffer = SimpleSerialization::SimpleReadBuffer(p_buffer, indexRes.m_indexName); + + std::uint32_t resNum = 0; + p_buffer = SimpleSerialization::SimpleReadBuffer(p_buffer, resNum); + + bool withMeta = false; + p_buffer = SimpleSerialization::SimpleReadBuffer(p_buffer, withMeta); + + indexRes.m_results.Init(nullptr, resNum, withMeta); + for (auto& res : indexRes.m_results) + { + p_buffer = SimpleSerialization::SimpleReadBuffer(p_buffer, res.VID); + p_buffer = SimpleSerialization::SimpleReadBuffer(p_buffer, res.Dist); + } + + if (withMeta) + { + for (int i = 0; i < indexRes.m_results.GetResultNum(); ++i) + { + ByteArray meta; + p_buffer = SimpleSerialization::SimpleReadBuffer(p_buffer, meta); + indexRes.m_results.SetMetadata(i, std::move(meta)); + } + } + } + + return p_buffer; +} diff --git a/cpp/src/core/thirdparty/SPTAG/AnnService/src/Socket/Server.cpp b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Socket/Server.cpp new file mode 100644 index 0000000000..86d60040bf --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/AnnService/src/Socket/Server.cpp @@ -0,0 +1,136 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Socket/Server.h" + +#include + +using namespace SPTAG::Socket; + +Server::Server(const std::string& p_address, + const std::string& p_port, + const PacketHandlerMapPtr& p_handlerMap, + std::size_t p_threadNum) + : m_requestHandlerMap(p_handlerMap), + m_connectionManager(new ConnectionManager), + m_acceptor(m_ioContext) +{ + boost::asio::ip::tcp::resolver resolver(m_ioContext); + + boost::system::error_code errCode; + auto endPoints = resolver.resolve(p_address, p_port, errCode); + if (errCode) + { + fprintf(stderr, + "Failed to resolve %s %s, error: %s", + p_address.c_str(), + p_port.c_str(), + errCode.message().c_str()); + + throw std::runtime_error("Failed to resolve address."); + } + + boost::asio::ip::tcp::endpoint endpoint = *(endPoints.begin()); + m_acceptor.open(endpoint.protocol()); + m_acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(false)); + + m_acceptor.bind(endpoint, errCode); + if (errCode) + { + fprintf(stderr, + "Failed to bind %s %s, error: %s", + p_address.c_str(), + p_port.c_str(), + errCode.message().c_str()); + + throw std::runtime_error("Failed to bind port."); + } + + m_acceptor.listen(boost::asio::socket_base::max_listen_connections, errCode); + if (errCode) + { + fprintf(stderr, + "Failed to listen %s %s, error: %s", + p_address.c_str(), + p_port.c_str(), + errCode.message().c_str()); + + throw std::runtime_error("Failed to listen port."); + } + + StartAccept(); + + m_threadPool.reserve(p_threadNum); + for (std::size_t i = 0; i < p_threadNum; ++i) + { + m_threadPool.emplace_back(std::move(std::thread([this]() { StartListen(); }))); + } +} + + +Server::~Server() +{ + m_acceptor.close(); + m_connectionManager->StopAll(); + while (!m_ioContext.stopped()) + { + m_ioContext.stop(); + } + + for (auto& t : m_threadPool) + { + t.join(); + } +} + + +void +Server::SetEventOnConnectionClose(std::function p_event) +{ + m_connectionManager->SetEventOnRemoving(std::move(p_event)); +} + + +void +Server::StartAccept() +{ + m_acceptor.async_accept([this](boost::system::error_code p_ec, + boost::asio::ip::tcp::socket p_socket) + { + if (!m_acceptor.is_open()) + { + return; + } + + if (!p_ec) + { + m_connectionManager->AddConnection(std::move(p_socket), + m_requestHandlerMap, + 0); + } + + StartAccept(); + }); +} + + +void +Server::StartListen() +{ + m_ioContext.run(); +} + + +void +Server::SendPacket(ConnectionID p_connection, Packet p_packet, std::function p_callback) +{ + auto connection = m_connectionManager->GetConnection(p_connection); + if (nullptr != connection) + { + connection->AsyncSend(std::move(p_packet), std::move(p_callback)); + } + else if (bool(p_callback)) + { + p_callback(false); + } +} diff --git a/cpp/src/core/thirdparty/SPTAG/CMakeLists.txt b/cpp/src/core/thirdparty/SPTAG/CMakeLists.txt new file mode 100644 index 0000000000..01ff74e5d2 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/CMakeLists.txt @@ -0,0 +1,127 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +cmake_minimum_required (VERSION 3.12) + +project (SPTAGLib) + +function(CXX_COMPILER_DUMPVERSION _OUTPUT_VERSION) + exec_program(${CMAKE_CXX_COMPILER} + ARGS ${CMAKE_CXX_COMPILER_ARG1} -dumpversion + OUTPUT_VARIABLE COMPILER_VERSION + ) + + set(${_OUTPUT_VERSION} ${COMPILER_VERSION} PARENT_SCOPE) +endfunction() + +if(NOT WIN32) + CXX_COMPILER_DUMPVERSION(CXX_COMPILER_VERSION) +endif() + +if(${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") + # require at least gcc 4.7 + if (CXX_COMPILER_VERSION VERSION_LESS 4.7) + message(FATAL_ERROR "GCC version must be at least 4.7!") + endif() + set (CMAKE_CXX_FLAGS_RELEASE "-Wall -Wunreachable-code -Wno-reorder -Wno-sign-compare -Wno-unknown-pragmas -Wcast-align -lm -lrt -DNDEBUG -std=c++11 -fopenmp -march=native") + set (CMAKE_CXX_FLAGS_DEBUG "-Wall -Wunreachable-code -Wno-reorder -Wno-sign-compare -Wno-unknown-pragmas -Wcast-align -ggdb -lm -lrt -DNDEBUG -std=c++11 -fopenmp -march=native") +elseif(WIN32) + if(NOT MSVC14) + message(FATAL_ERROR "On Windows, only MSVC version 14 are supported!") + endif() +else () + message(FATAL_ERROR "Unrecognized compiler (use GCC or MSVC)!") +endif() + +if (NOT CMAKE_BUILD_TYPE) + set (CMAKE_BUILD_TYPE Release CACHE STRING "Build types: Release Debug" FORCE) +endif() +message (STATUS "Build type: ${CMAKE_BUILD_TYPE}") + +if (${CMAKE_SIZEOF_VOID_P} EQUAL "8") + set (PROJECTNAME_ARCHITECTURE "x64") +else () + set (PROJECTNAME_ARCHITECTURE "x86") +endif () +message (STATUS "Platform type: ${PROJECTNAME_ARCHITECTURE}") + +set(Boost_USE_MULTITHREADED ON) + +if (WIN32) + set(Boost_USE_STATIC_LIBS ON) + + set(CMAKE_CONFIGURATION_TYPES ${CMAKE_BUILD_TYPE}) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) + + set (LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}) + set (EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}) +else() + set (LIBRARY_OUTPUT_PATH "${PROJECT_SOURCE_DIR}/${CMAKE_BUILD_TYPE}/") + set (EXECUTABLE_OUTPUT_PATH "${PROJECT_SOURCE_DIR}/${CMAKE_BUILD_TYPE}/") +endif() + +set (CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}) + +find_package(OpenMP) +if (OpenMP_FOUND) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}") + message (STATUS "Found openmp.") +else() + message (FATAL_ERROR "Could no find openmp!") +endif() + +#find_package(Boost 1.67 COMPONENTS system thread serialization wserialization regex) +#if (Boost_FOUND) +# include_directories (${Boost_INCLUDE_DIR}) +# link_directories (${Boost_LIBRARY_DIR} "/usr/lib") +# message (STATUS "Found Boost.") +# message (STATUS "Include Path: ${Boost_INCLUDE_DIRS}") +# message (STATUS "Library Path: ${Boost_LIBRARY_DIRS}") +# message (STATUS "Library: ${Boost_LIBRARIES}") +#else() +# message (FATAL_ERROR "Could not find Boost 1.67!") +#endif() + +#set(Boost_LIBRARIES +# boost_system_static +# boost_filesystem_static +# boost_serialization_static +# boost_wserialization_static +# boost_regex_static +# boost_thread_static) +set(TBB_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../tbb) + +if (WIN32) + if (${CMAKE_SIZEOF_VOID_P} EQUAL "8") + set (TBB_LIBRARY_SUFFIX "lib/intel64/vc14") + else() + set (TBB_LIBRARY_SUFFIX "lib/ia32/vc14") + endif() + + find_path(TBB_INCLUDE_DIRS tbb/tbb.h HINTS ${TBB_DIR} "C:/Program Files/Intel/TBB" PATH_SUFFIXES include) + find_library(TBB_LIBRARIES tbb${CMAKE_STATIC_LIBRARY_SUFFIX} HINTS ${TBB_DIR} "C:/Program Files/Intel/TBB" PATH_SUFFIXES ${TBB_LIBRARY_SUFFIX}) +else() + find_path(TBB_INCLUDE_DIRS tbb/tbb.h HINTS ${TBB_DIR} "/usr/" PATH_SUFFIXES include) + find_library(TBB_LIBRARIES libtbb${CMAKE_SHARED_LIBRARY_SUFFIX} HINTS ${TBB_DIR} "/usr/") +endif() + +set(TBB_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../tbb) +find_path(TBB_INCLUDE_DIRS tbb/tbb.h HINTS ${TBB_DIR} "/usr/" PATH_SUFFIXES include) +find_library(TBB_LIBRARIES libtbb${CMAKE_SHARED_LIBRARY_SUFFIX} HINTS ${TBB_DIR} "/usr/") + +if (TBB_INCLUDE_DIRS AND TBB_LIBRARIES) + include_directories (${TBB_INCLUDE_DIRS}) + message (STATUS "Found TBB.") + message (STATUS "Include Path:" ${TBB_INCLUDE_DIRS}) + message (STATUS "Library:" ${TBB_LIBRARIES}) +else() + message (FATAL_ERROR "Could not find TBB!") +endif() + +add_subdirectory (AnnService) +#add_subdirectory (Wrappers) +#add_subdirectory (Test) diff --git a/cpp/src/core/thirdparty/SPTAG/Dockerfile b/cpp/src/core/thirdparty/SPTAG/Dockerfile new file mode 100644 index 0000000000..e7cedb33a9 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/Dockerfile @@ -0,0 +1,31 @@ +FROM ubuntu:18.04 + +WORKDIR /app +COPY CMakeLists.txt ./ +COPY AnnService ./AnnService/ +COPY Test ./Test/ +COPY Wrappers ./Wrappers/ + +RUN apt-get update && apt-get -y install wget build-essential libtbb-dev \ + # remove the following if you don't want to build the wrappers + openjdk-8-jdk python3-pip swig + +# cmake >= 3.12 is required +RUN wget "https://github.com/Kitware/CMake/releases/download/v3.14.4/cmake-3.14.4-Linux-x86_64.tar.gz" -q -O - \ + | tar -xz --strip-components=1 -C /usr/local + +# specific version of boost +RUN wget "https://dl.bintray.com/boostorg/release/1.67.0/source/boost_1_67_0.tar.gz" -q -O - \ + | tar -xz && \ + cd boost_1_67_0 && \ + ./bootstrap.sh && \ + ./b2 install && \ + # update ld cache so it finds boost in /usr/local/lib + ldconfig && \ + cd .. && rm -rf boost_1_67_0 + +# build +RUN mkdir build && cd build && cmake .. && make && cd .. + +# so python can find the SPTAG module +ENV PYTHONPATH=/app/Release \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/LICENSE b/cpp/src/core/thirdparty/SPTAG/LICENSE new file mode 100644 index 0000000000..d1ca00f20a --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/LICENSE @@ -0,0 +1,21 @@ + MIT License + + Copyright (c) Microsoft Corporation. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/README.md b/cpp/src/core/thirdparty/SPTAG/README.md new file mode 100644 index 0000000000..20f2a5458c --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/README.md @@ -0,0 +1,144 @@ +# SPTAG: A library for fast approximate nearest neighbor search + +[![MIT licensed](https://img.shields.io/badge/license-MIT-yellow.svg)](https://github.com/Microsoft/SPTAG/blob/master/LICENSE) +[![Build status](https://sysdnn.visualstudio.com/SPTAG/_apis/build/status/SPTAG-GITHUB)](https://sysdnn.visualstudio.com/SPTAG/_build/latest?definitionId=2) + +## **SPTAG** + SPTAG (Space Partition Tree And Graph) is a library for large scale vector approximate nearest neighbor search scenario released by [Microsoft Research (MSR)](https://www.msra.cn/) and [Microsoft Bing](http://bing.com). + +

+ architecture +

+ + + +## **Introduction** + +This library assumes that the samples are represented as vectors and that the vectors can be compared by L2 distances or cosine distances. +Vectors returned for a query vector are the vectors that have smallest L2 distance or cosine distances with the query vector. + +SPTAG provides two methods: kd-tree and relative neighborhood graph (SPTAG-KDT) +and balanced k-means tree and relative neighborhood graph (SPTAG-BKT). +SPTAG-KDT is advantageous in index building cost, and SPTAG-BKT is advantageous in search accuracy in very high-dimensional data. + + + +## **How it works** + +SPTAG is inspired by the NGS approach [[WangL12](#References)]. It contains two basic modules: index builder and searcher. +The RNG is built on the k-nearest neighborhood graph [[WangWZTG12](#References), [WangWJLZZH14](#References)] +for boosting the connectivity. Balanced k-means trees are used to replace kd-trees to avoid the inaccurate distance bound estimation in kd-trees for very high-dimensional vectors. +The search begins with the search in the space partition trees for +finding several seeds to start the search in the RNG. +The searches in the trees and the graph are iteratively conducted. + + ## **Highlights** + * Fresh update: Support online vector deletion and insertion + * Distributed serving: Search over multiple machines + + ## **Build** + +### **Requirements** + +* swig >= 3.0 +* cmake >= 3.12.0 +* boost >= 1.67.0 +* tbb >= 4.2 + +### **Install** + +> For Linux: +```bash +mkdir build +cd build && cmake .. && make +``` +It will generate a Release folder in the code directory which contains all the build targets. + +> For Windows: +```bash +mkdir build +cd build && cmake -A x64 .. +``` +It will generate a SPTAGLib.sln in the build directory. +Compiling the ALL_BUILD project in the Visual Studio (at least 2015) will generate a Release directory which contains all the build targets. + +> Using Docker: +```bash +docker build -t sptag . +``` +Will build a docker container with binaries in `/app/Release/` + +### **Verify** + +Run the test (or Test.exe) in the Release folder to verify all the tests have passed. + +### **Usage** + +The detailed usage can be found in [Get started](docs/GettingStart.md). + +## **References** +Please cite SPTAG in your publications if it helps your research: +``` +@manual{ChenW18, + author = {Qi Chen and + Haidong Wang and + Mingqin Li and + Gang Ren and + Scarlett Li and + Jeffery Zhu and + Jason Li and + Chuanjie Liu and + Lintao Zhang and + Jingdong Wang}, + title = {SPTAG: A library for fast approximate nearest neighbor search}, + url = {https://github.com/Microsoft/SPTAG}, + year = {2018} +} + +@inproceedings{WangL12, + author = {Jingdong Wang and + Shipeng Li}, + title = {Query-driven iterated neighborhood graph search for large scale indexing}, + booktitle = {ACM Multimedia 2012}, + pages = {179--188}, + year = {2012} +} + +@inproceedings{WangWZTGL12, + author = {Jing Wang and + Jingdong Wang and + Gang Zeng and + Zhuowen Tu and + Rui Gan and + Shipeng Li}, + title = {Scalable k-NN graph construction for visual descriptors}, + booktitle = {CVPR 2012}, + pages = {1106--1113}, + year = {2012} +} + +@article{WangWJLZZH14, + author = {Jingdong Wang and + Naiyan Wang and + You Jia and + Jian Li and + Gang Zeng and + Hongbin Zha and + Xian{-}Sheng Hua}, + title = {Trinary-Projection Trees for Approximate Nearest Neighbor Search}, + journal = {{IEEE} Trans. Pattern Anal. Mach. Intell.}, + volume = {36}, + number = {2}, + pages = {388--403}, + year = {2014 +} +``` + +## **Contribute** + +This project welcomes contributions and suggestions from all the users. + +We use [GitHub issues](https://github.com/Microsoft/SPTAG/issues) for tracking suggestions and bugs. + +## **License** +The entire codebase is under [MIT license](https://github.com/Microsoft/SPTAG/blob/master/LICENSE) diff --git a/cpp/src/core/thirdparty/SPTAG/SPTAG.sdf b/cpp/src/core/thirdparty/SPTAG/SPTAG.sdf new file mode 100644 index 0000000000..254a44ece6 Binary files /dev/null and b/cpp/src/core/thirdparty/SPTAG/SPTAG.sdf differ diff --git a/cpp/src/core/thirdparty/SPTAG/SPTAG.sln b/cpp/src/core/thirdparty/SPTAG/SPTAG.sln new file mode 100644 index 0000000000..77adfe2bb7 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/SPTAG.sln @@ -0,0 +1,172 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CoreLibrary", "AnnService\CoreLibrary.vcxproj", "{C2BC5FDE-C853-4F3D-B7E4-2C9B5524DDF9}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Server", "AnnService\Server.vcxproj", "{E28B1222-8BEA-4A92-8FE0-088EBDAA7FE0}" + ProjectSection(ProjectDependencies) = postProject + {F9A72303-6381-4C80-86FF-606A2F6F7B96} = {F9A72303-6381-4C80-86FF-606A2F6F7B96} + {C2BC5FDE-C853-4F3D-B7E4-2C9B5524DDF9} = {C2BC5FDE-C853-4F3D-B7E4-2C9B5524DDF9} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PythonCore", "Wrappers\PythonCore.vcxproj", "{AF31947C-0495-42FE-A1AD-8F0DA2A679C7}" + ProjectSection(ProjectDependencies) = postProject + {C2BC5FDE-C853-4F3D-B7E4-2C9B5524DDF9} = {C2BC5FDE-C853-4F3D-B7E4-2C9B5524DDF9} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SocketLib", "AnnService\SocketLib.vcxproj", "{F9A72303-6381-4C80-86FF-606A2F6F7B96}" + ProjectSection(ProjectDependencies) = postProject + {C2BC5FDE-C853-4F3D-B7E4-2C9B5524DDF9} = {C2BC5FDE-C853-4F3D-B7E4-2C9B5524DDF9} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Client", "AnnService\Client.vcxproj", "{A89D70C3-C53B-42DE-A5CE-9A472540F5CB}" + ProjectSection(ProjectDependencies) = postProject + {F9A72303-6381-4C80-86FF-606A2F6F7B96} = {F9A72303-6381-4C80-86FF-606A2F6F7B96} + {C2BC5FDE-C853-4F3D-B7E4-2C9B5524DDF9} = {C2BC5FDE-C853-4F3D-B7E4-2C9B5524DDF9} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Aggregator", "AnnService\Aggregator.vcxproj", "{D7F09A63-BDCA-4F6C-A864-8551D1FE447A}" + ProjectSection(ProjectDependencies) = postProject + {F9A72303-6381-4C80-86FF-606A2F6F7B96} = {F9A72303-6381-4C80-86FF-606A2F6F7B96} + {C2BC5FDE-C853-4F3D-B7E4-2C9B5524DDF9} = {C2BC5FDE-C853-4F3D-B7E4-2C9B5524DDF9} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PythonClient", "Wrappers\PythonClient.vcxproj", "{9B014CF6-E3FB-4BD4-B3B1-D26297BB31AA}" + ProjectSection(ProjectDependencies) = postProject + {F9A72303-6381-4C80-86FF-606A2F6F7B96} = {F9A72303-6381-4C80-86FF-606A2F6F7B96} + {C2BC5FDE-C853-4F3D-B7E4-2C9B5524DDF9} = {C2BC5FDE-C853-4F3D-B7E4-2C9B5524DDF9} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IndexBuilder", "AnnService\IndexBuilder.vcxproj", "{F492F794-E78B-4B1F-A556-5E045B9163D5}" + ProjectSection(ProjectDependencies) = postProject + {C2BC5FDE-C853-4F3D-B7E4-2C9B5524DDF9} = {C2BC5FDE-C853-4F3D-B7E4-2C9B5524DDF9} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IndexSearcher", "AnnService\IndexSearcher.vcxproj", "{97615D3B-9FA0-469E-B229-95A91A5087E0}" + ProjectSection(ProjectDependencies) = postProject + {C2BC5FDE-C853-4F3D-B7E4-2C9B5524DDF9} = {C2BC5FDE-C853-4F3D-B7E4-2C9B5524DDF9} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Test", "Test\Test.vcxproj", "{29A25655-CCF2-47F8-8BC8-DFE1B5CF993C}" + ProjectSection(ProjectDependencies) = postProject + {F9A72303-6381-4C80-86FF-606A2F6F7B96} = {F9A72303-6381-4C80-86FF-606A2F6F7B96} + {C2BC5FDE-C853-4F3D-B7E4-2C9B5524DDF9} = {C2BC5FDE-C853-4F3D-B7E4-2C9B5524DDF9} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JavaCore", "Wrappers\JavaCore.vcxproj", "{93FEB26B-965E-4157-8BE5-052F5CA112BB}" + ProjectSection(ProjectDependencies) = postProject + {C2BC5FDE-C853-4F3D-B7E4-2C9B5524DDF9} = {C2BC5FDE-C853-4F3D-B7E4-2C9B5524DDF9} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JavaClient", "Wrappers\JavaClient.vcxproj", "{8866BF98-AA2E-450F-9F33-083E007CCA74}" + ProjectSection(ProjectDependencies) = postProject + {F9A72303-6381-4C80-86FF-606A2F6F7B96} = {F9A72303-6381-4C80-86FF-606A2F6F7B96} + {C2BC5FDE-C853-4F3D-B7E4-2C9B5524DDF9} = {C2BC5FDE-C853-4F3D-B7E4-2C9B5524DDF9} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C2BC5FDE-C853-4F3D-B7E4-2C9B5524DDF9}.Debug|x64.ActiveCfg = Debug|x64 + {C2BC5FDE-C853-4F3D-B7E4-2C9B5524DDF9}.Debug|x64.Build.0 = Debug|x64 + {C2BC5FDE-C853-4F3D-B7E4-2C9B5524DDF9}.Debug|x86.ActiveCfg = Debug|x64 + {C2BC5FDE-C853-4F3D-B7E4-2C9B5524DDF9}.Debug|x86.Build.0 = Debug|x64 + {C2BC5FDE-C853-4F3D-B7E4-2C9B5524DDF9}.Release|x64.ActiveCfg = Release|x64 + {C2BC5FDE-C853-4F3D-B7E4-2C9B5524DDF9}.Release|x64.Build.0 = Release|x64 + {C2BC5FDE-C853-4F3D-B7E4-2C9B5524DDF9}.Release|x86.ActiveCfg = Debug|x64 + {C2BC5FDE-C853-4F3D-B7E4-2C9B5524DDF9}.Release|x86.Build.0 = Debug|x64 + {E28B1222-8BEA-4A92-8FE0-088EBDAA7FE0}.Debug|x64.ActiveCfg = Debug|x64 + {E28B1222-8BEA-4A92-8FE0-088EBDAA7FE0}.Debug|x64.Build.0 = Debug|x64 + {E28B1222-8BEA-4A92-8FE0-088EBDAA7FE0}.Debug|x86.ActiveCfg = Debug|x64 + {E28B1222-8BEA-4A92-8FE0-088EBDAA7FE0}.Debug|x86.Build.0 = Debug|x64 + {E28B1222-8BEA-4A92-8FE0-088EBDAA7FE0}.Release|x64.ActiveCfg = Release|x64 + {E28B1222-8BEA-4A92-8FE0-088EBDAA7FE0}.Release|x64.Build.0 = Release|x64 + {E28B1222-8BEA-4A92-8FE0-088EBDAA7FE0}.Release|x86.ActiveCfg = Debug|x64 + {E28B1222-8BEA-4A92-8FE0-088EBDAA7FE0}.Release|x86.Build.0 = Debug|x64 + {AF31947C-0495-42FE-A1AD-8F0DA2A679C7}.Debug|x64.ActiveCfg = Debug|x64 + {AF31947C-0495-42FE-A1AD-8F0DA2A679C7}.Debug|x64.Build.0 = Debug|x64 + {AF31947C-0495-42FE-A1AD-8F0DA2A679C7}.Debug|x86.ActiveCfg = Debug|x64 + {AF31947C-0495-42FE-A1AD-8F0DA2A679C7}.Debug|x86.Build.0 = Debug|x64 + {AF31947C-0495-42FE-A1AD-8F0DA2A679C7}.Release|x64.ActiveCfg = Release|x64 + {AF31947C-0495-42FE-A1AD-8F0DA2A679C7}.Release|x64.Build.0 = Release|x64 + {AF31947C-0495-42FE-A1AD-8F0DA2A679C7}.Release|x86.ActiveCfg = Debug|x64 + {AF31947C-0495-42FE-A1AD-8F0DA2A679C7}.Release|x86.Build.0 = Debug|x64 + {F9A72303-6381-4C80-86FF-606A2F6F7B96}.Debug|x64.ActiveCfg = Debug|x64 + {F9A72303-6381-4C80-86FF-606A2F6F7B96}.Debug|x64.Build.0 = Debug|x64 + {F9A72303-6381-4C80-86FF-606A2F6F7B96}.Debug|x86.ActiveCfg = Debug|x64 + {F9A72303-6381-4C80-86FF-606A2F6F7B96}.Debug|x86.Build.0 = Debug|x64 + {F9A72303-6381-4C80-86FF-606A2F6F7B96}.Release|x64.ActiveCfg = Release|x64 + {F9A72303-6381-4C80-86FF-606A2F6F7B96}.Release|x64.Build.0 = Release|x64 + {F9A72303-6381-4C80-86FF-606A2F6F7B96}.Release|x86.ActiveCfg = Debug|x64 + {F9A72303-6381-4C80-86FF-606A2F6F7B96}.Release|x86.Build.0 = Debug|x64 + {A89D70C3-C53B-42DE-A5CE-9A472540F5CB}.Debug|x64.ActiveCfg = Debug|x64 + {A89D70C3-C53B-42DE-A5CE-9A472540F5CB}.Debug|x64.Build.0 = Debug|x64 + {A89D70C3-C53B-42DE-A5CE-9A472540F5CB}.Debug|x86.ActiveCfg = Debug|x64 + {A89D70C3-C53B-42DE-A5CE-9A472540F5CB}.Debug|x86.Build.0 = Debug|x64 + {A89D70C3-C53B-42DE-A5CE-9A472540F5CB}.Release|x64.ActiveCfg = Release|x64 + {A89D70C3-C53B-42DE-A5CE-9A472540F5CB}.Release|x64.Build.0 = Release|x64 + {A89D70C3-C53B-42DE-A5CE-9A472540F5CB}.Release|x86.ActiveCfg = Debug|x64 + {A89D70C3-C53B-42DE-A5CE-9A472540F5CB}.Release|x86.Build.0 = Debug|x64 + {D7F09A63-BDCA-4F6C-A864-8551D1FE447A}.Debug|x64.ActiveCfg = Debug|x64 + {D7F09A63-BDCA-4F6C-A864-8551D1FE447A}.Debug|x64.Build.0 = Debug|x64 + {D7F09A63-BDCA-4F6C-A864-8551D1FE447A}.Debug|x86.ActiveCfg = Debug|x64 + {D7F09A63-BDCA-4F6C-A864-8551D1FE447A}.Debug|x86.Build.0 = Debug|x64 + {D7F09A63-BDCA-4F6C-A864-8551D1FE447A}.Release|x64.ActiveCfg = Release|x64 + {D7F09A63-BDCA-4F6C-A864-8551D1FE447A}.Release|x64.Build.0 = Release|x64 + {D7F09A63-BDCA-4F6C-A864-8551D1FE447A}.Release|x86.ActiveCfg = Debug|x64 + {D7F09A63-BDCA-4F6C-A864-8551D1FE447A}.Release|x86.Build.0 = Debug|x64 + {9B014CF6-E3FB-4BD4-B3B1-D26297BB31AA}.Debug|x64.ActiveCfg = Debug|x64 + {9B014CF6-E3FB-4BD4-B3B1-D26297BB31AA}.Debug|x64.Build.0 = Debug|x64 + {9B014CF6-E3FB-4BD4-B3B1-D26297BB31AA}.Debug|x86.ActiveCfg = Debug|Win32 + {9B014CF6-E3FB-4BD4-B3B1-D26297BB31AA}.Debug|x86.Build.0 = Debug|Win32 + {9B014CF6-E3FB-4BD4-B3B1-D26297BB31AA}.Release|x64.ActiveCfg = Release|x64 + {9B014CF6-E3FB-4BD4-B3B1-D26297BB31AA}.Release|x64.Build.0 = Release|x64 + {9B014CF6-E3FB-4BD4-B3B1-D26297BB31AA}.Release|x86.ActiveCfg = Release|Win32 + {9B014CF6-E3FB-4BD4-B3B1-D26297BB31AA}.Release|x86.Build.0 = Release|Win32 + {F492F794-E78B-4B1F-A556-5E045B9163D5}.Debug|x64.ActiveCfg = Debug|x64 + {F492F794-E78B-4B1F-A556-5E045B9163D5}.Debug|x64.Build.0 = Debug|x64 + {F492F794-E78B-4B1F-A556-5E045B9163D5}.Debug|x86.ActiveCfg = Debug|Win32 + {F492F794-E78B-4B1F-A556-5E045B9163D5}.Debug|x86.Build.0 = Debug|Win32 + {F492F794-E78B-4B1F-A556-5E045B9163D5}.Release|x64.ActiveCfg = Release|x64 + {F492F794-E78B-4B1F-A556-5E045B9163D5}.Release|x64.Build.0 = Release|x64 + {F492F794-E78B-4B1F-A556-5E045B9163D5}.Release|x86.ActiveCfg = Release|Win32 + {F492F794-E78B-4B1F-A556-5E045B9163D5}.Release|x86.Build.0 = Release|Win32 + {97615D3B-9FA0-469E-B229-95A91A5087E0}.Debug|x64.ActiveCfg = Debug|x64 + {97615D3B-9FA0-469E-B229-95A91A5087E0}.Debug|x64.Build.0 = Debug|x64 + {97615D3B-9FA0-469E-B229-95A91A5087E0}.Debug|x86.ActiveCfg = Debug|Win32 + {97615D3B-9FA0-469E-B229-95A91A5087E0}.Debug|x86.Build.0 = Debug|Win32 + {97615D3B-9FA0-469E-B229-95A91A5087E0}.Release|x64.ActiveCfg = Release|x64 + {97615D3B-9FA0-469E-B229-95A91A5087E0}.Release|x64.Build.0 = Release|x64 + {97615D3B-9FA0-469E-B229-95A91A5087E0}.Release|x86.ActiveCfg = Release|Win32 + {97615D3B-9FA0-469E-B229-95A91A5087E0}.Release|x86.Build.0 = Release|Win32 + {29A25655-CCF2-47F8-8BC8-DFE1B5CF993C}.Debug|x64.ActiveCfg = Debug|x64 + {29A25655-CCF2-47F8-8BC8-DFE1B5CF993C}.Debug|x64.Build.0 = Debug|x64 + {29A25655-CCF2-47F8-8BC8-DFE1B5CF993C}.Debug|x86.ActiveCfg = Debug|Win32 + {29A25655-CCF2-47F8-8BC8-DFE1B5CF993C}.Debug|x86.Build.0 = Debug|Win32 + {29A25655-CCF2-47F8-8BC8-DFE1B5CF993C}.Release|x64.ActiveCfg = Release|x64 + {29A25655-CCF2-47F8-8BC8-DFE1B5CF993C}.Release|x64.Build.0 = Release|x64 + {29A25655-CCF2-47F8-8BC8-DFE1B5CF993C}.Release|x86.ActiveCfg = Release|Win32 + {29A25655-CCF2-47F8-8BC8-DFE1B5CF993C}.Release|x86.Build.0 = Release|Win32 + {93FEB26B-965E-4157-8BE5-052F5CA112BB}.Debug|x64.ActiveCfg = Debug|x64 + {93FEB26B-965E-4157-8BE5-052F5CA112BB}.Debug|x86.ActiveCfg = Debug|Win32 + {93FEB26B-965E-4157-8BE5-052F5CA112BB}.Release|x64.ActiveCfg = Release|x64 + {93FEB26B-965E-4157-8BE5-052F5CA112BB}.Release|x86.ActiveCfg = Release|Win32 + {8866BF98-AA2E-450F-9F33-083E007CCA74}.Debug|x64.ActiveCfg = Debug|x64 + {8866BF98-AA2E-450F-9F33-083E007CCA74}.Debug|x86.ActiveCfg = Debug|Win32 + {8866BF98-AA2E-450F-9F33-083E007CCA74}.Release|x64.ActiveCfg = Release|x64 + {8866BF98-AA2E-450F-9F33-083E007CCA74}.Release|x86.ActiveCfg = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {38BDFF12-6FEC-4B67-A7BD-436D9E2544FD} + EndGlobalSection +EndGlobal diff --git a/cpp/src/core/thirdparty/SPTAG/Test/CMakeLists.txt b/cpp/src/core/thirdparty/SPTAG/Test/CMakeLists.txt new file mode 100644 index 0000000000..e1179631a0 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/Test/CMakeLists.txt @@ -0,0 +1,32 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +if(NOT WIN32) + ADD_DEFINITIONS(-DBOOST_TEST_DYN_LINK) + message (STATUS "BOOST_TEST_DYN_LINK") +endif() + +find_package(Boost 1.67 COMPONENTS system thread serialization wserialization regex filesystem unit_test_framework) +if (Boost_FOUND) + include_directories (${Boost_INCLUDE_DIR}) + link_directories (${Boost_LIBRARY_DIR}) + message (STATUS "Found Boost.") + message (STATUS "Include Path: ${Boost_INCLUDE_DIRS}") + message (STATUS "Library Path: ${Boost_LIBRARY_DIRS}") + message (STATUS "Library: ${Boost_LIBRARIES}") +else() + message (FATAL_ERROR "Could not find Boost 1.67!") +endif() + +include_directories(${PYTHON_INCLUDE_PATH} ${PROJECT_SOURCE_DIR}/AnnService ${PROJECT_SOURCE_DIR}/PythonWrapper ${PROJECT_SOURCE_DIR}/Test) + +file(GLOB TEST_HDR_FILES ${PROJECT_SOURCE_DIR}/Test/inc/Test.h) +file(GLOB TEST_SRC_FILES ${PROJECT_SOURCE_DIR}/Test/src/*.cpp) +add_executable (test ${TEST_SRC_FILES} ${TEST_HDR_FILES}) +target_link_libraries(test SPTAGLib ${Boost_LIBRARIES} ${TBB_LIBRARIES}) + +install(TARGETS test + RUNTIME DESTINATION bin + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib) + diff --git a/cpp/src/core/thirdparty/SPTAG/Test/Test.vcxproj b/cpp/src/core/thirdparty/SPTAG/Test/Test.vcxproj new file mode 100644 index 0000000000..da9f227498 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/Test/Test.vcxproj @@ -0,0 +1,187 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {29A25655-CCF2-47F8-8BC8-DFE1B5CF993C} + Test + 8.1 + + + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + $(SolutionDir)obj\$(Platform)_$(Configuration)\$(ProjectName)\ + $(ProjectDir);$(SolutionDir)AnnService\;$(IncludePath) + $(OutAppDir) + $(OutLibDir);$(LibraryPath) + + + false + + + + CoreLibrary.lib;%(AdditionalDependencies) + + + + + Level3 + MaxSpeed + true + true + true + true + _MBCS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + true + true + + + Console + + + + + Level3 + Disabled + true + true + + + + + Level3 + Disabled + true + true + _MBCS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + Guard + ProgramDatabase + + + Console + /guard:cf %(AdditionalOptions) + + + + + Level3 + MaxSpeed + true + true + true + true + + + true + true + + + + + + + + + + + + + + + + + Designer + + + + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + + + + \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/Test/Test.vcxproj.filters b/cpp/src/core/thirdparty/SPTAG/Test/Test.vcxproj.filters new file mode 100644 index 0000000000..a814c3ec3f --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/Test/Test.vcxproj.filters @@ -0,0 +1,48 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + + + + \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/Test/Test.vcxproj.user b/cpp/src/core/thirdparty/SPTAG/Test/Test.vcxproj.user new file mode 100644 index 0000000000..10f0fcf2d9 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/Test/Test.vcxproj.user @@ -0,0 +1,7 @@ + + + + $(OutLibDir) + WindowsLocalDebugger + + \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/Test/inc/Test.h b/cpp/src/core/thirdparty/SPTAG/Test/inc/Test.h new file mode 100644 index 0000000000..da6c096ba2 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/Test/inc/Test.h @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include +#include diff --git a/cpp/src/core/thirdparty/SPTAG/Test/packages.config b/cpp/src/core/thirdparty/SPTAG/Test/packages.config new file mode 100644 index 0000000000..ddc362dffb --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/Test/packages.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/Test/src/AlgoTest.cpp b/cpp/src/core/thirdparty/SPTAG/Test/src/AlgoTest.cpp new file mode 100644 index 0000000000..5a4d24c260 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/Test/src/AlgoTest.cpp @@ -0,0 +1,134 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Test.h" +#include "inc/Helper/SimpleIniReader.h" +#include "inc/Core/VectorIndex.h" + +template +void Build(SPTAG::IndexAlgoType algo, std::string distCalcMethod, T* vec, int n, int m) +{ + std::vector meta; + std::vector metaoffset; + for (int i = 0; i < n; i++) { + metaoffset.push_back(meta.size()); + std::string a = std::to_string(i); + for (int j = 0; j < a.length(); j++) + meta.push_back(a[j]); + } + metaoffset.push_back(meta.size()); + + std::shared_ptr vecset(new SPTAG::BasicVectorSet( + SPTAG::ByteArray((std::uint8_t*)vec, n * m * sizeof(T), false), + SPTAG::GetEnumValueType(), m, n)); + + std::shared_ptr metaset(new SPTAG::MemMetadataSet( + SPTAG::ByteArray((std::uint8_t*)meta.data(), meta.size() * sizeof(char), false), + SPTAG::ByteArray((std::uint8_t*)metaoffset.data(), metaoffset.size() * sizeof(long long), false), + n)); + std::shared_ptr vecIndex = SPTAG::VectorIndex::CreateInstance(algo, SPTAG::GetEnumValueType()); + vecIndex->SetParameter("DistCalcMethod", distCalcMethod); + BOOST_CHECK(nullptr != vecIndex); + BOOST_CHECK(SPTAG::ErrorCode::Success == vecIndex->BuildIndex(vecset, metaset)); + BOOST_CHECK(SPTAG::ErrorCode::Success == vecIndex->SaveIndex("origindices")); +} + +template +void Search(std::string folder, T* vec, int k) +{ + std::shared_ptr vecIndex; + BOOST_CHECK(SPTAG::ErrorCode::Success == SPTAG::VectorIndex::LoadIndex(folder, vecIndex)); + BOOST_CHECK(nullptr != vecIndex); + + SPTAG::QueryResult res(vec, k, true); + vecIndex->SearchIndex(res); + for (int i = 0; i < k; i++) { + std::cout << res.GetResult(i)->Dist << "@(" << res.GetResult(i)->VID << "," << std::string((char*)res.GetMetadata(i).Data(), res.GetMetadata(i).Length()) << ") "; + } + std::cout << std::endl; + vecIndex.reset(); +} + +template +void Add(T* vec, int n) +{ + std::shared_ptr vecIndex; + BOOST_CHECK(SPTAG::ErrorCode::Success == SPTAG::VectorIndex::LoadIndex("origindices", vecIndex)); + BOOST_CHECK(nullptr != vecIndex); + + std::vector meta; + std::vector metaoffset; + for (int i = 0; i < n; i++) { + metaoffset.push_back(meta.size()); + std::string a = std::to_string(vecIndex->GetNumSamples() + i); + for (int j = 0; j < a.length(); j++) + meta.push_back(a[j]); + } + metaoffset.push_back(meta.size()); + + int m = vecIndex->GetFeatureDim(); + std::shared_ptr vecset(new SPTAG::BasicVectorSet( + SPTAG::ByteArray((std::uint8_t*)vec, n * m * sizeof(T), false), + SPTAG::GetEnumValueType(), m, n)); + + std::shared_ptr metaset(new SPTAG::MemMetadataSet( + SPTAG::ByteArray((std::uint8_t*)meta.data(), meta.size() * sizeof(char), false), + SPTAG::ByteArray((std::uint8_t*)metaoffset.data(), metaoffset.size() * sizeof(long long), false), + n)); + + BOOST_CHECK(SPTAG::ErrorCode::Success == vecIndex->AddIndex(vecset, metaset)); + BOOST_CHECK(SPTAG::ErrorCode::Success == vecIndex->SaveIndex("addindices")); + vecIndex.reset(); +} + +template +void Delete(T* vec, int n) +{ + std::shared_ptr vecIndex; + BOOST_CHECK(SPTAG::ErrorCode::Success == SPTAG::VectorIndex::LoadIndex("addindices", vecIndex)); + BOOST_CHECK(nullptr != vecIndex); + + BOOST_CHECK(SPTAG::ErrorCode::Success == vecIndex->DeleteIndex((const void*)vec, n)); + BOOST_CHECK(SPTAG::ErrorCode::Success == vecIndex->SaveIndex("delindices")); + vecIndex.reset(); +} + +template +void Test(SPTAG::IndexAlgoType algo, std::string distCalcMethod) +{ + int n = 100, q = 3, m = 10, k = 3; + std::vector vec; + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) { + vec.push_back((T)i); + } + } + + std::vector query; + for (int i = 0; i < q; i++) { + for (int j = 0; j < m; j++) { + query.push_back((T)i*2); + } + } + + Build(algo, distCalcMethod, vec.data(), n, m); + Search("origindices", query.data(), k); + Add(query.data(), q); + Search("addindices", query.data(), k); + Delete(query.data(), q); + Search("delindices", query.data(), k); +} + +BOOST_AUTO_TEST_SUITE (AlgoTest) + +BOOST_AUTO_TEST_CASE(KDTTest) +{ + Test(SPTAG::IndexAlgoType::KDT, "L2"); +} + +BOOST_AUTO_TEST_CASE(BKTTest) +{ + Test(SPTAG::IndexAlgoType::BKT, "L2"); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/cpp/src/core/thirdparty/SPTAG/Test/src/Base64HelperTest.cpp b/cpp/src/core/thirdparty/SPTAG/Test/src/Base64HelperTest.cpp new file mode 100644 index 0000000000..2ead4753e5 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/Test/src/Base64HelperTest.cpp @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Test.h" +#include "inc/Helper/Base64Encode.h" + +#include + +BOOST_AUTO_TEST_SUITE(Base64Test) + +BOOST_AUTO_TEST_CASE(Base64EncDec) +{ + using namespace SPTAG::Helper::Base64; + + const size_t bufferSize = 1 << 10; + std::unique_ptr rawBuffer(new uint8_t[bufferSize]); + std::unique_ptr encBuffer(new char[bufferSize]); + std::unique_ptr rawBuffer2(new uint8_t[bufferSize]); + + for (size_t inputSize = 1; inputSize < 128; ++inputSize) + { + for (size_t i = 0; i < inputSize; ++i) + { + rawBuffer[i] = static_cast(i); + } + + size_t encBufLen = CapacityForEncode(inputSize); + BOOST_CHECK(encBufLen < bufferSize); + + size_t encOutLen = 0; + BOOST_CHECK(Encode(rawBuffer.get(), inputSize, encBuffer.get(), encOutLen)); + BOOST_CHECK(encBufLen >= encOutLen); + + size_t decBufLen = CapacityForDecode(encOutLen); + BOOST_CHECK(decBufLen < bufferSize); + + size_t decOutLen = 0; + BOOST_CHECK(Decode(encBuffer.get(), encOutLen, rawBuffer.get(), decOutLen)); + BOOST_CHECK(decBufLen >= decOutLen); + } +} + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/Test/src/CommonHelperTest.cpp b/cpp/src/core/thirdparty/SPTAG/Test/src/CommonHelperTest.cpp new file mode 100644 index 0000000000..17015642cc --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/Test/src/CommonHelperTest.cpp @@ -0,0 +1,93 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Test.h" +#include "inc/Helper/CommonHelper.h" + +#include + +BOOST_AUTO_TEST_SUITE(CommonHelperTest) + + +BOOST_AUTO_TEST_CASE(ToLowerInPlaceTest) +{ + auto runTestCase = [](std::string p_input, const std::string& p_expected) + { + SPTAG::Helper::StrUtils::ToLowerInPlace(p_input); + BOOST_CHECK(p_input == p_expected); + }; + + runTestCase("abc", "abc"); + runTestCase("ABC", "abc"); + runTestCase("abC", "abc"); + runTestCase("Upper-Case", "upper-case"); + runTestCase("123!-=aBc", "123!-=abc"); +} + + +BOOST_AUTO_TEST_CASE(SplitStringTest) +{ + std::string input("seg1 seg2 seg3 seg4"); + + const auto& segs = SPTAG::Helper::StrUtils::SplitString(input, " "); + BOOST_CHECK(segs.size() == 4); + BOOST_CHECK(segs[0] == "seg1"); + BOOST_CHECK(segs[1] == "seg2"); + BOOST_CHECK(segs[2] == "seg3"); + BOOST_CHECK(segs[3] == "seg4"); +} + + +BOOST_AUTO_TEST_CASE(FindTrimmedSegmentTest) +{ + using namespace SPTAG::Helper::StrUtils; + std::string input("\t Space End \r\n\t"); + + const auto& pos = FindTrimmedSegment(input.c_str(), + input.c_str() + input.size(), + [](char p_val)->bool + { + return std::isspace(p_val) > 0; + }); + + BOOST_CHECK(pos.first == input.c_str() + 2); + BOOST_CHECK(pos.second == input.c_str() + 13); +} + + +BOOST_AUTO_TEST_CASE(StartsWithTest) +{ + using namespace SPTAG::Helper::StrUtils; + + BOOST_CHECK(StartsWith("Abcd", "A")); + BOOST_CHECK(StartsWith("Abcd", "Ab")); + BOOST_CHECK(StartsWith("Abcd", "Abc")); + BOOST_CHECK(StartsWith("Abcd", "Abcd")); + + BOOST_CHECK(!StartsWith("Abcd", "a")); + BOOST_CHECK(!StartsWith("Abcd", "F")); + BOOST_CHECK(!StartsWith("Abcd", "AF")); + BOOST_CHECK(!StartsWith("Abcd", "AbF")); + BOOST_CHECK(!StartsWith("Abcd", "AbcF")); + BOOST_CHECK(!StartsWith("Abcd", "Abcde")); +} + + +BOOST_AUTO_TEST_CASE(StrEqualIgnoreCaseTest) +{ + using namespace SPTAG::Helper::StrUtils; + + BOOST_CHECK(StrEqualIgnoreCase("Abcd", "Abcd")); + BOOST_CHECK(StrEqualIgnoreCase("Abcd", "abcd")); + BOOST_CHECK(StrEqualIgnoreCase("Abcd", "abCD")); + BOOST_CHECK(StrEqualIgnoreCase("Abcd-123", "abcd-123")); + BOOST_CHECK(StrEqualIgnoreCase(" ZZZ", " zzz")); + + BOOST_CHECK(!StrEqualIgnoreCase("abcd", "abcd1")); + BOOST_CHECK(!StrEqualIgnoreCase("Abcd", " abcd")); + BOOST_CHECK(!StrEqualIgnoreCase("000", "OOO")); +} + + + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/Test/src/DistanceTest.cpp b/cpp/src/core/thirdparty/SPTAG/Test/src/DistanceTest.cpp new file mode 100644 index 0000000000..26c5cee3db --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/Test/src/DistanceTest.cpp @@ -0,0 +1,58 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include +#include "inc/Test.h" +#include "inc/Core/Common/DistanceUtils.h" + +template +static float ComputeCosineDistance(const T *pX, const T *pY, int length) { + float diff = 0; + const T* pEnd1 = pX + length; + while (pX < pEnd1) diff += (*pX++) * (*pY++); + return diff; +} + +template +static float ComputeL2Distance(const T *pX, const T *pY, int length) +{ + float diff = 0; + const T* pEnd1 = pX + length; + while (pX < pEnd1) { + float c1 = ((float)(*pX++) - (float)(*pY++)); diff += c1 * c1; + } + return diff; +} + +template +T random(int high = RAND_MAX, int low = 0) // Generates a random value. +{ + return (T)(low + float(high - low)*(std::rand()/static_cast(RAND_MAX + 1.0))); +} + +template +void test(int high) { + int dimension = random(256, 2); + T *X = new T[dimension], *Y = new T[dimension]; + BOOST_ASSERT(X != nullptr && Y != nullptr); + for (int i = 0; i < dimension; i++) { + X[i] = random(high, -high); + Y[i] = random(high, -high); + } + BOOST_CHECK_CLOSE_FRACTION(ComputeL2Distance(X, Y, dimension), SPTAG::COMMON::DistanceUtils::ComputeL2Distance(X, Y, dimension), 1e-5); + BOOST_CHECK_CLOSE_FRACTION(high*high - ComputeCosineDistance(X, Y, dimension), SPTAG::COMMON::DistanceUtils::ComputeCosineDistance(X, Y, dimension), 1e-5); + + delete[] X; + delete[] Y; +} + +BOOST_AUTO_TEST_SUITE(DistanceTest) + +BOOST_AUTO_TEST_CASE(TestDistanceComputation) +{ + test(1); + test(127); + test(32767); +} + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/Test/src/IniReaderTest.cpp b/cpp/src/core/thirdparty/SPTAG/Test/src/IniReaderTest.cpp new file mode 100644 index 0000000000..c5dd0baaf5 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/Test/src/IniReaderTest.cpp @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Test.h" +#include "inc/Helper/SimpleIniReader.h" + +#include + +BOOST_AUTO_TEST_SUITE(IniReaderTest) + +BOOST_AUTO_TEST_CASE(IniReaderLoadTest) +{ + std::ofstream tmpIni("temp.ini"); + tmpIni << "[Common]" << std::endl; + tmpIni << "; Comment " << std::endl; + tmpIni << "Param1=1" << std::endl; + tmpIni << "Param2=Exp=2" << std::endl; + + tmpIni.close(); + + SPTAG::Helper::IniReader reader; + BOOST_CHECK(SPTAG::ErrorCode::Success == reader.LoadIniFile("temp.ini")); + + BOOST_CHECK(reader.DoesSectionExist("Common")); + BOOST_CHECK(reader.DoesParameterExist("Common", "Param1")); + BOOST_CHECK(reader.DoesParameterExist("Common", "Param2")); + + BOOST_CHECK(!reader.DoesSectionExist("NotExist")); + BOOST_CHECK(!reader.DoesParameterExist("NotExist", "Param1")); + BOOST_CHECK(!reader.DoesParameterExist("Common", "ParamNotExist")); + + BOOST_CHECK(1 == reader.GetParameter("Common", "Param1", 0)); + BOOST_CHECK(0 == reader.GetParameter("Common", "ParamNotExist", 0)); + + BOOST_CHECK(std::string("Exp=2") == reader.GetParameter("Common", "Param2", std::string())); + BOOST_CHECK(std::string("1") == reader.GetParameter("Common", "Param1", std::string())); + BOOST_CHECK(std::string() == reader.GetParameter("Common", "ParamNotExist", std::string())); +} + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/Test/src/Serialize.cpp b/cpp/src/core/thirdparty/SPTAG/Test/src/Serialize.cpp new file mode 100644 index 0000000000..6f1ed29a77 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/Test/src/Serialize.cpp @@ -0,0 +1,79 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Test.h" +#include "inc/Helper/SimpleIniReader.h" +#include "inc/Core/VectorIndex.h" + + +template +void Test(SPTAG::IndexAlgoType algo, std::string distCalcMethod) { + int n = 100, q = 3, m = 10, k = 3; + std::vector vec; + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) { + vec.push_back((T) i); + } + } + + std::vector query; + for (int i = 0; i < q; i++) { + for (int j = 0; j < m; j++) { + query.push_back((T) i * 2); + } + } + + std::shared_ptr vecset(new SPTAG::BasicVectorSet( + SPTAG::ByteArray((std::uint8_t *) vec.data(), n * m * sizeof(T), false), + SPTAG::GetEnumValueType(), m, n)); + + std::vector blobs; + std::vector len; + { + std::shared_ptr vecIndex = + SPTAG::VectorIndex::CreateInstance(algo, SPTAG::GetEnumValueType()); + vecIndex->SetParameter("DistCalcMethod", distCalcMethod); + BOOST_CHECK(SPTAG::ErrorCode::Success == vecIndex->BuildIndex(vecset, nullptr)); + BOOST_CHECK(SPTAG::ErrorCode::Success == vecIndex->SaveIndexToMemory(blobs, len)); + } + + std::vector clone_blobs; + std::vector clone_len; + for (auto i = 0; i < blobs.size(); ++i) { + auto mem = malloc(len[i]); + BOOST_CHECK(NULL != mem); + memcpy(mem, blobs[i], len[i]); + clone_blobs.push_back(mem); + clone_len.push_back(len[i]); + } + + std::shared_ptr clone_index = + SPTAG::VectorIndex::CreateInstance(algo, SPTAG::GetEnumValueType()); + clone_index->SetParameter("DistCalcMethod", distCalcMethod); + BOOST_CHECK(SPTAG::ErrorCode::Success == clone_index->LoadIndexFromMemory(clone_blobs)); + + SPTAG::QueryResult res(vec.data(), k, true); + clone_index->SearchIndex(res); + for (int i = 0; i < k; i++) { + std::cout << res.GetResult(i)->Dist << "@(" << res.GetResult(i)->VID << "," + << std::string((char *) res.GetMetadata(i).Data(), res.GetMetadata(i).Length()) << ") "; + } + std::cout << std::endl; + + for (auto &blob : blobs) + free(blob); + for (auto &blob : clone_blobs) + free(blob); +} + +BOOST_AUTO_TEST_SUITE (SerializeTest) + +BOOST_AUTO_TEST_CASE(KDTree) { + Test(SPTAG::IndexAlgoType::KDT, "L2"); +} + +BOOST_AUTO_TEST_CASE(BKTree) { + Test(SPTAG::IndexAlgoType::BKT, "L2"); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/cpp/src/core/thirdparty/SPTAG/Test/src/StringConvertTest.cpp b/cpp/src/core/thirdparty/SPTAG/Test/src/StringConvertTest.cpp new file mode 100644 index 0000000000..fa457debe2 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/Test/src/StringConvertTest.cpp @@ -0,0 +1,128 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/Test.h" +#include "inc/Helper/StringConvert.h" + +namespace +{ + namespace Local + { + + template + void TestConvertSuccCase(ValueType p_val, const char* p_valStr) + { + using namespace SPTAG::Helper::Convert; + + std::string str = ConvertToString(p_val); + if (nullptr != p_valStr) + { + BOOST_CHECK(str == p_valStr); + } + + ValueType val; + BOOST_CHECK(ConvertStringTo(str.c_str(), val)); + BOOST_CHECK(val == p_val); + } + + } +} + +BOOST_AUTO_TEST_SUITE(StringConvertTest) + +BOOST_AUTO_TEST_CASE(ConvertInt8) +{ + Local::TestConvertSuccCase(static_cast(-1), "-1"); + Local::TestConvertSuccCase(static_cast(0), "0"); + Local::TestConvertSuccCase(static_cast(3), "3"); + Local::TestConvertSuccCase(static_cast(100), "100"); +} + +BOOST_AUTO_TEST_CASE(ConvertInt16) +{ + Local::TestConvertSuccCase(static_cast(-1), "-1"); + Local::TestConvertSuccCase(static_cast(0), "0"); + Local::TestConvertSuccCase(static_cast(3), "3"); + Local::TestConvertSuccCase(static_cast(100), "100"); +} + +BOOST_AUTO_TEST_CASE(ConvertInt32) +{ + Local::TestConvertSuccCase(static_cast(-1), "-1"); + Local::TestConvertSuccCase(static_cast(0), "0"); + Local::TestConvertSuccCase(static_cast(3), "3"); + Local::TestConvertSuccCase(static_cast(100), "100"); +} + +BOOST_AUTO_TEST_CASE(ConvertInt64) +{ + Local::TestConvertSuccCase(static_cast(-1), "-1"); + Local::TestConvertSuccCase(static_cast(0), "0"); + Local::TestConvertSuccCase(static_cast(3), "3"); + Local::TestConvertSuccCase(static_cast(100), "100"); +} + +BOOST_AUTO_TEST_CASE(ConvertUInt8) +{ + Local::TestConvertSuccCase(static_cast(0), "0"); + Local::TestConvertSuccCase(static_cast(3), "3"); + Local::TestConvertSuccCase(static_cast(100), "100"); +} + +BOOST_AUTO_TEST_CASE(ConvertUInt16) +{ + Local::TestConvertSuccCase(static_cast(0), "0"); + Local::TestConvertSuccCase(static_cast(3), "3"); + Local::TestConvertSuccCase(static_cast(100), "100"); +} + +BOOST_AUTO_TEST_CASE(ConvertUInt32) +{ + Local::TestConvertSuccCase(static_cast(0), "0"); + Local::TestConvertSuccCase(static_cast(3), "3"); + Local::TestConvertSuccCase(static_cast(100), "100"); +} + +BOOST_AUTO_TEST_CASE(ConvertUInt64) +{ + Local::TestConvertSuccCase(static_cast(0), "0"); + Local::TestConvertSuccCase(static_cast(3), "3"); + Local::TestConvertSuccCase(static_cast(100), "100"); +} + +BOOST_AUTO_TEST_CASE(ConvertFloat) +{ + Local::TestConvertSuccCase(static_cast(-1), nullptr); + Local::TestConvertSuccCase(static_cast(0), nullptr); + Local::TestConvertSuccCase(static_cast(3), nullptr); + Local::TestConvertSuccCase(static_cast(100), nullptr); +} + +BOOST_AUTO_TEST_CASE(ConvertDouble) +{ + Local::TestConvertSuccCase(static_cast(-1), nullptr); + Local::TestConvertSuccCase(static_cast(0), nullptr); + Local::TestConvertSuccCase(static_cast(3), nullptr); + Local::TestConvertSuccCase(static_cast(100), nullptr); +} + +BOOST_AUTO_TEST_CASE(ConvertIndexAlgoType) +{ + Local::TestConvertSuccCase(SPTAG::IndexAlgoType::BKT, "BKT"); + Local::TestConvertSuccCase(SPTAG::IndexAlgoType::KDT, "KDT"); +} + +BOOST_AUTO_TEST_CASE(ConvertVectorValueType) +{ + Local::TestConvertSuccCase(SPTAG::VectorValueType::Float, "Float"); + Local::TestConvertSuccCase(SPTAG::VectorValueType::Int8, "Int8"); + Local::TestConvertSuccCase(SPTAG::VectorValueType::Int16, "Int16"); +} + +BOOST_AUTO_TEST_CASE(ConvertDistCalcMethod) +{ + Local::TestConvertSuccCase(SPTAG::DistCalcMethod::Cosine, "Cosine"); + Local::TestConvertSuccCase(SPTAG::DistCalcMethod::L2, "L2"); +} + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/Test/src/main.cpp b/cpp/src/core/thirdparty/SPTAG/Test/src/main.cpp new file mode 100644 index 0000000000..7bf61ea119 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/Test/src/main.cpp @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#define BOOST_TEST_MAIN +#define BOOST_TEST_MODULE Main +#include "inc/Test.h" + +#include +#include + +using namespace boost::unit_test; + +class SPTAGVisitor : public test_tree_visitor +{ +public: + void visit(test_case const& test) + { + std::string prefix(2, '\t'); + std::cout << prefix << "Case: " << test.p_name << std::endl; + } + + bool test_suite_start(test_suite const& suite) + { + std::string prefix(1, '\t'); + std::cout << prefix << "Suite: " << suite.p_name << std::endl; + return true; + } +}; + +struct GlobalFixture +{ + GlobalFixture() + { + SPTAGVisitor visitor; + traverse_test_tree(framework::master_test_suite(), visitor, false); + } + +}; + +BOOST_TEST_GLOBAL_FIXTURE(GlobalFixture); + diff --git a/cpp/src/core/thirdparty/SPTAG/Wrappers/CMakeLists.txt b/cpp/src/core/thirdparty/SPTAG/Wrappers/CMakeLists.txt new file mode 100644 index 0000000000..cab77a9674 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/Wrappers/CMakeLists.txt @@ -0,0 +1,105 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +find_package(Python2 COMPONENTS Development) +if (Python2_FOUND) + include_directories (${Python2_INCLUDE_DIRS}) + link_directories (${Python2_LIBRARY_DIRS}) + set (Python_INCLUDE_DIRS ${Python2_INCLUDE_DIRS}) + set (Python_LIBRARIES ${Python2_LIBRARIES}) + set (Python_FOUND true) +else() + find_package(Python3 COMPONENTS Development) + if (Python3_FOUND) + include_directories (${Python3_INCLUDE_DIRS}) + link_directories (${Python3_LIBRARY_DIRS}) + set (Python_INCLUDE_DIRS ${Python3_INCLUDE_DIRS}) + set (Python_LIBRARIES ${Python3_LIBRARIES}) + set (Python_FOUND true) + endif() +endif() + +if (Python_FOUND) + message (STATUS "Found Python.") + message (STATUS "Include Path: ${Python_INCLUDE_DIRS}") + message (STATUS "Library Path: ${Python_LIBRARIES}") + + if (WIN32) + set(PY_SUFFIX .pyd) + else() + set(PY_SUFFIX .so) + endif() + + execute_process(COMMAND swig -python -c++ -I${PROJECT_SOURCE_DIR}/Wrappers/inc -o ${PROJECT_SOURCE_DIR}/Wrappers/inc/CoreInterface_pwrap.cpp ${PROJECT_SOURCE_DIR}/Wrappers/inc/PythonCore.i) + execute_process(COMMAND swig -python -c++ -I${PROJECT_SOURCE_DIR}/Wrappers/inc -o ${PROJECT_SOURCE_DIR}/Wrappers/inc/ClientInterface_pwrap.cpp ${PROJECT_SOURCE_DIR}/Wrappers/inc/PythonClient.i) + + include_directories(${PYTHON_INCLUDE_PATH} ${PROJECT_SOURCE_DIR}/AnnService ${PROJECT_SOURCE_DIR}/Wrappers) + + file(GLOB CORE_HDR_FILES ${PROJECT_SOURCE_DIR}/Wrappers/inc/CoreInterface.h) + file(GLOB CORE_SRC_FILES ${PROJECT_SOURCE_DIR}/Wrappers/src/CoreInterface.cpp ${PROJECT_SOURCE_DIR}/Wrappers/inc/CoreInterface_pwrap.cpp) + add_library (_SPTAG SHARED ${CORE_SRC_FILES} ${CORE_HDR_FILES}) + set_target_properties(_SPTAG PROPERTIES PREFIX "" SUFFIX ${PY_SUFFIX}) + target_link_libraries(_SPTAG SPTAGLib ${Python_LIBRARIES} ${TBB_LIBRARIES}) + add_custom_command(TARGET _SPTAG POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/Wrappers/inc/SPTAG.py ${EXECUTABLE_OUTPUT_PATH}) + + file(GLOB CLIENT_HDR_FILES ${PROJECT_SOURCE_DIR}/Wrappers/inc/ClientInterface.h ${PROJECT_SOURCE_DIR}/AnnService/inc/Socket/*.h ${PROJECT_SOURCE_DIR}/AnnService/inc/Client/*.h) + file(GLOB CLIENT_SRC_FILES ${PROJECT_SOURCE_DIR}/Wrappers/src/ClientInterface.cpp ${PROJECT_SOURCE_DIR}/AnnService/src/Socket/*.cpp ${PROJECT_SOURCE_DIR}/AnnService/src/Client/*.cpp ${PROJECT_SOURCE_DIR}/Wrappers/inc/ClientInterface_pwrap.cpp) + add_library (_SPTAGClient SHARED ${CLIENT_SRC_FILES} ${CLIENT_HDR_FILES}) + set_target_properties(_SPTAGClient PROPERTIES PREFIX "" SUFFIX ${PY_SUFFIX}) + target_link_libraries(_SPTAGClient SPTAGLib ${Python_LIBRARIES} ${Boost_LIBRARIES} ${TBB_LIBRARIES}) + add_custom_command(TARGET _SPTAGClient POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/Wrappers/inc/SPTAGClient.py ${EXECUTABLE_OUTPUT_PATH}) + + install(TARGETS _SPTAG _SPTAGClient + RUNTIME DESTINATION bin + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib) + install(FILES ${PROJECT_SOURCE_DIR}/Wrappers/inc/SPTAG.py ${PROJECT_SOURCE_DIR}/Wrappers/inc/SPTAGClient.py DESTINATION bin) +else() + message (STATUS "Could not find Python.") +endif() + +find_package(JNI) +if (!JNI_FOUND) + include_directories (${JNI_INCLUDE_DIRS}) + link_directories (${JNI_LIBRARY_DIRS}) + message (STATUS "Found JNI.") + message (STATUS "Include Path: ${JNI_INCLUDE_DIRS}") + message (STATUS "Library Path: ${JNI_LIBRARIES}") + + if (WIN32) + set (JAVA_SUFFIX .dll) + else() + set (JAVA_SUFFIX .so) + endif() + + execute_process(COMMAND swig -java -c++ -I${PROJECT_SOURCE_DIR}/Wrappers/inc -o ${PROJECT_SOURCE_DIR}/Wrappers/inc/CoreInterface_jwrap.cpp ${PROJECT_SOURCE_DIR}/Wrappers/inc/JavaCore.i) + execute_process(COMMAND swig -java -c++ -I${PROJECT_SOURCE_DIR}/Wrappers/inc -o ${PROJECT_SOURCE_DIR}/Wrappers/inc/ClientInterface_jwrap.cpp ${PROJECT_SOURCE_DIR}/Wrappers/inc/JavaClient.i) + + include_directories(${JNI_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/AnnService ${PROJECT_SOURCE_DIR}/Wrappers) + + file(GLOB CORE_HDR_FILES ${PROJECT_SOURCE_DIR}/Wrappers/inc/CoreInterface.h) + file(GLOB CORE_SRC_FILES ${PROJECT_SOURCE_DIR}/Wrappers/src/CoreInterface.cpp ${PROJECT_SOURCE_DIR}/Wrappers/inc/CoreInterface_jwrap.cpp) + add_library (SPTAG SHARED ${CORE_SRC_FILES} ${CORE_HDR_FILES}) + set_target_properties(SPTAG PROPERTIES SUFFIX ${JAVA_SUFFIX}) + target_link_libraries(SPTAG SPTAGLib ${JNI_LIBRARIES} ${TBB_LIBRARIES}) + + file(GLOB CLIENT_HDR_FILES ${PROJECT_SOURCE_DIR}/Wrappers/inc/ClientInterface.h ${PROJECT_SOURCE_DIR}/AnnService/inc/Socket/*.h ${PROJECT_SOURCE_DIR}/AnnService/inc/Client/*.h) + file(GLOB CLIENT_SRC_FILES ${PROJECT_SOURCE_DIR}/Wrappers/src/ClientInterface.cpp ${PROJECT_SOURCE_DIR}/AnnService/src/Socket/*.cpp ${PROJECT_SOURCE_DIR}/AnnService/src/Client/*.cpp ${PROJECT_SOURCE_DIR}/Wrappers/inc/ClientInterface_jwrap.cpp) + add_library (SPTAGClient SHARED ${CLIENT_SRC_FILES} ${CLIENT_HDR_FILES}) + set_target_properties(SPTAGClient PROPERTIES SUFFIX ${JAVA_SUFFIX}) + target_link_libraries(SPTAGClient SPTAGLib ${JNI_LIBRARIES} ${Boost_LIBRARIES} ${TBB_LIBRARIES}) + + file(GLOB JAVA_FILES ${PROJECT_SOURCE_DIR}/Wrappers/inc/*.java) + foreach(JAVA_FILE ${JAVA_FILES}) + message (STATUS "Add copy post-command for file " ${JAVA_FILE}) + add_custom_command(TARGET SPTAGClient POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${JAVA_FILE} ${EXECUTABLE_OUTPUT_PATH}) + endforeach(JAVA_FILE) + + install(TARGETS SPTAG SPTAGClient + RUNTIME DESTINATION bin + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib) + install(FILES ${PROJECT_SOURCE_DIR}/Wrappers/inc/*.java DESTINATION bin) +else() + message (STATUS "Could not find JNI.") +endif() \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/Wrappers/JavaClient.vcxproj b/cpp/src/core/thirdparty/SPTAG/Wrappers/JavaClient.vcxproj new file mode 100644 index 0000000000..bc917561d4 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/Wrappers/JavaClient.vcxproj @@ -0,0 +1,190 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {8866BF98-AA2E-450F-9F33-083E007CCA74} + JavaClient + 8.1 + + + + + DynamicLibrary + true + v140 + MultiByte + + + DynamicLibrary + false + v140 + true + MultiByte + + + DynamicLibrary + true + v140 + MultiByte + + + DynamicLibrary + false + v140 + true + MultiByte + + + + + + + + + + + + + + + + + + + + SPTAGClient + .dll + $(SolutionDir)obj\$(Platform)_$(Configuration)\$(ProjectName)\ + $(ProjectDir);$(SolutionDir)AnnService\;$(IncludePath) + $(OutLibDir);$(LibraryPath) + $(OutAppDir) + + + false + + + + $(JavaLib);CoreLibrary.lib;SocketLib.lib;%(AdditionalDependencies) + + + + + $(JavaIncDir);%(AdditionalIncludeDirectories) + + + + + Level3 + MaxSpeed + true + true + true + true + _WINDLL;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + true + true + + + + + Level3 + Disabled + true + true + + + + + Level3 + Disabled + true + true + _WINDLL;_SCL_SECURE_NO_WARNINGS;SWIG_JAVA_INTERPRETER_NO_DEBUG;%(PreprocessorDefinitions) + Guard + ProgramDatabase + + + /guard:cf %(AdditionalOptions) + + + + + Level3 + MaxSpeed + true + true + true + true + + + true + true + + + + + + + + + + + + + false + false + false + false + + + + + + + + + + + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/Wrappers/JavaClient.vcxproj.filters b/cpp/src/core/thirdparty/SPTAG/Wrappers/JavaClient.vcxproj.filters new file mode 100644 index 0000000000..e5e9baf576 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/Wrappers/JavaClient.vcxproj.filters @@ -0,0 +1,38 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/Wrappers/JavaCore.vcxproj b/cpp/src/core/thirdparty/SPTAG/Wrappers/JavaCore.vcxproj new file mode 100644 index 0000000000..bf11ef9eb6 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/Wrappers/JavaCore.vcxproj @@ -0,0 +1,137 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {93FEB26B-965E-4157-8BE5-052F5CA112BB} + JavaCore + 8.1 + + + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + DynamicLibrary + true + v140 + MultiByte + + + DynamicLibrary + false + v140 + true + MultiByte + + + + + + + + + + + + + + + + + + + + SPTAG + .dll + $(SolutionDir)obj\$(Platform)_$(Configuration)\$(ProjectName)\ + $(ProjectDir);$(SolutionDir)AnnService\;$(IncludePath) + $(OutLibDir);$(LibraryPath) + $(OutAppDir) + + + false + + + + $(JavaLib);CoreLibrary.lib;%(AdditionalDependencies) + + + + + _WINDLL;SWIG_JAVA_INTERPRETER_NO_DEBUG;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + $(JavaIncDir);%(AdditionalIncludeDirectories) + Guard + ProgramDatabase + _WINDLL;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + /guard:cf %(AdditionalOptions) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/Wrappers/JavaCore.vcxproj.filters b/cpp/src/core/thirdparty/SPTAG/Wrappers/JavaCore.vcxproj.filters new file mode 100644 index 0000000000..ae22a6a6ce --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/Wrappers/JavaCore.vcxproj.filters @@ -0,0 +1,38 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {ba4289c4-f872-4dbc-a57f-7b415614afb3} + + + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + + + + Resources + + + \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/Wrappers/PythonClient.vcxproj b/cpp/src/core/thirdparty/SPTAG/Wrappers/PythonClient.vcxproj new file mode 100644 index 0000000000..a9cad34019 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/Wrappers/PythonClient.vcxproj @@ -0,0 +1,188 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {9B014CF6-E3FB-4BD4-B3B1-D26297BB31AA} + PythonClient + 8.1 + + + + + DynamicLibrary + true + v140 + MultiByte + + + DynamicLibrary + false + v140 + true + MultiByte + + + DynamicLibrary + true + v140 + MultiByte + + + DynamicLibrary + false + v140 + true + MultiByte + + + + + + + + + + + + + + + + + + + + _SPTAGClient + .pyd + $(SolutionDir)obj\$(Platform)_$(Configuration)\$(ProjectName)\ + $(ProjectDir);$(SolutionDir)AnnService\;$(IncludePath) + $(OutLibDir);$(LibraryPath) + $(OutAppDir) + + + false + + + + CoreLibrary.lib;SocketLib.lib;$(SolutionDir)packages\python2.2.7.15\tools\libs\python27.lib;%(AdditionalDependencies) + + + + + $(SolutionDir)packages\python2.2.7.15\tools\include\;%(AdditionalIncludeDirectories) + + + + + Level3 + MaxSpeed + true + true + true + true + _WINDLL;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + true + true + + + + + Level3 + Disabled + true + true + + + + + Level3 + Disabled + true + true + _WINDLL;_SCL_SECURE_NO_WARNINGS;SWIG_PYTHON_INTERPRETER_NO_DEBUG;%(PreprocessorDefinitions) + Guard + ProgramDatabase + + + /guard:cf %(AdditionalOptions) + + + + + Level3 + MaxSpeed + true + true + true + true + + + true + true + + + + + + + + + + + + + false + false + false + false + + + + + + + + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/Wrappers/PythonClient.vcxproj.filters b/cpp/src/core/thirdparty/SPTAG/Wrappers/PythonClient.vcxproj.filters new file mode 100644 index 0000000000..928aef15bc --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/Wrappers/PythonClient.vcxproj.filters @@ -0,0 +1,38 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/Wrappers/PythonCore.vcxproj b/cpp/src/core/thirdparty/SPTAG/Wrappers/PythonCore.vcxproj new file mode 100644 index 0000000000..2ec11c0a45 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/Wrappers/PythonCore.vcxproj @@ -0,0 +1,135 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {AF31947C-0495-42FE-A1AD-8F0DA2A679C7} + PythonCore + 8.1 + + + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + DynamicLibrary + true + v140 + MultiByte + + + DynamicLibrary + false + v140 + true + MultiByte + + + + + + + + + + + + + + + + + + + + _SPTAG + .pyd + $(SolutionDir)obj\$(Platform)_$(Configuration)\$(ProjectName)\ + $(ProjectDir);$(SolutionDir)AnnService\;$(IncludePath) + $(OutLibDir);$(LibraryPath) + $(OutAppDir) + + + false + + + + CoreLibrary.lib;$(SolutionDir)packages\python2.2.7.15\tools\libs\python27.lib;%(AdditionalDependencies) + + + + + _WINDLL;SWIG_PYTHON_INTERPRETER_NO_DEBUG;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + $(SolutionDir)packages\python2.2.7.15\tools\include\;%(AdditionalIncludeDirectories) + Guard + ProgramDatabase + _WINDLL;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + /guard:cf %(AdditionalOptions) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/Wrappers/PythonCore.vcxproj.filters b/cpp/src/core/thirdparty/SPTAG/Wrappers/PythonCore.vcxproj.filters new file mode 100644 index 0000000000..46fb928dd8 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/Wrappers/PythonCore.vcxproj.filters @@ -0,0 +1,38 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {ba4289c4-f872-4dbc-a57f-7b415614afb3} + + + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + + + + Resources + + + \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/Wrappers/PythonCore.vcxproj.user b/cpp/src/core/thirdparty/SPTAG/Wrappers/PythonCore.vcxproj.user new file mode 100644 index 0000000000..abe8dd8961 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/Wrappers/PythonCore.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/Wrappers/inc/ClientInterface.h b/cpp/src/core/thirdparty/SPTAG/Wrappers/inc/ClientInterface.h new file mode 100644 index 0000000000..94d46bcad3 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/Wrappers/inc/ClientInterface.h @@ -0,0 +1,63 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_PW_CLIENTINTERFACE_H_ +#define _SPTAG_PW_CLIENTINTERFACE_H_ + +#include "TransferDataType.h" +#include "inc/Socket/Client.h" +#include "inc/Socket/ResourceManager.h" + +#include +#include +#include + +class AnnClient +{ +public: + AnnClient(const char* p_serverAddr, const char* p_serverPort); + + ~AnnClient(); + + void SetTimeoutMilliseconds(int p_timeout); + + void SetSearchParam(const char* p_name, const char* p_value); + + void ClearSearchParam(); + + std::shared_ptr Search(ByteArray p_data, int p_resultNum, const char* p_valueType, bool p_withMetaData); + + bool IsConnected() const; + +private: + std::string CreateSearchQuery(const ByteArray& p_data, + int p_resultNum, + bool p_extractMetadata, + SPTAG::VectorValueType p_valueType); + + SPTAG::Socket::PacketHandlerMapPtr GetHandlerMap(); + + void SearchResponseHanlder(SPTAG::Socket::ConnectionID p_localConnectionID, + SPTAG::Socket::Packet p_packet); + +private: + typedef std::function Callback; + + std::uint32_t m_timeoutInMilliseconds; + + std::string m_server; + + std::string m_port; + + std::unique_ptr m_socketClient; + + std::atomic m_connectionID; + + SPTAG::Socket::ResourceManager m_callbackManager; + + std::unordered_map m_params; + + std::mutex m_paramMutex; +}; + +#endif // _SPTAG_PW_CLIENTINTERFACE_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/Wrappers/inc/CoreInterface.h b/cpp/src/core/thirdparty/SPTAG/Wrappers/inc/CoreInterface.h new file mode 100644 index 0000000000..e433b67801 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/Wrappers/inc/CoreInterface.h @@ -0,0 +1,58 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_PW_COREINTERFACE_H_ +#define _SPTAG_PW_COREINTERFACE_H_ + +#include "TransferDataType.h" +#include "inc/Core/Common.h" +#include "inc/Core/VectorIndex.h" + +class AnnIndex +{ +public: + AnnIndex(int p_dimension); + + AnnIndex(const char* p_algoType, const char* p_valueType, int p_dimension); + + ~AnnIndex(); + + void SetBuildParam(const char* p_name, const char* p_value); + + void SetSearchParam(const char* p_name, const char* p_value); + + bool Build(ByteArray p_data, int p_num); + + bool BuildWithMetaData(ByteArray p_data, ByteArray p_meta, int p_num); + + std::shared_ptr Search(ByteArray p_data, int p_resultNum); + + std::shared_ptr SearchWithMetaData(ByteArray p_data, int p_resultNum); + + bool ReadyToServe() const; + + bool Save(const char* p_saveFile) const; + + bool Add(ByteArray p_data, int p_num); + + bool AddWithMetaData(ByteArray p_data, ByteArray p_meta, int p_num); + + bool Delete(ByteArray p_data, int p_num); + + static AnnIndex Load(const char* p_loaderFile); + +private: + AnnIndex(const std::shared_ptr& p_index); + + std::shared_ptr m_index; + + size_t m_inputVectorSize; + + int m_dimension; + + SPTAG::IndexAlgoType m_algoType; + + SPTAG::VectorValueType m_inputValueType; +}; + +#endif // _SPTAG_PW_COREINTERFACE_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/Wrappers/inc/JavaClient.i b/cpp/src/core/thirdparty/SPTAG/Wrappers/inc/JavaClient.i new file mode 100644 index 0000000000..ba8d93fcc0 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/Wrappers/inc/JavaClient.i @@ -0,0 +1,16 @@ +%module SPTAGClient + +%{ +#include "inc/ClientInterface.h" +%} + +%include +%shared_ptr(AnnClient) +%shared_ptr(RemoteSearchResult) +%include "JavaCommon.i" + +%{ +#define SWIG_FILE_WITH_INIT +%} + +%include "ClientInterface.h" diff --git a/cpp/src/core/thirdparty/SPTAG/Wrappers/inc/JavaCommon.i b/cpp/src/core/thirdparty/SPTAG/Wrappers/inc/JavaCommon.i new file mode 100644 index 0000000000..8d36675dee --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/Wrappers/inc/JavaCommon.i @@ -0,0 +1,60 @@ +#ifdef SWIGJAVA + +%typemap(jni) ByteArray "jbyteArray" +%typemap(jtype) ByteArray "byte[]" +%typemap(jstype) ByteArray "byte[]" +%typemap(in) ByteArray { + $1.SetData((std::uint8_t*)JCALL2(GetByteArrayElements, jenv, $input, 0), + JCALL1(GetArrayLength, jenv, $input)); +} +%typemap(out) ByteArray { + $result = JCALL1(NewByteArray, jenv, $1.Length()); + JCALL4(SetByteArrayRegion, jenv, $result, 0, $1.Length(), (jbyte *)$1.Data()); +} +%typemap(javain) ByteArray "$javainput" +%typemap(javaout) ByteArray { return $jnicall; } + +%typemap(jni) std::shared_ptr "jobjectArray" +%typemap(jtype) std::shared_ptr "Result[]" +%typemap(jstype) std::shared_ptr "Result[]" +%typemap(out) std::shared_ptr { + jclass retClass = jenv->FindClass("Result"); + int len = $1->GetResultNum(); + $result = jenv->NewObjectArray(len, retClass, NULL); + for (int i = 0; i < len; i++) { + auto& meta = $1->GetMetadata(i); + jbyteArray bptr = jenv->NewByteArray(meta.Length()); + jenv->SetByteArrayRegion(bptr, 0, meta.Length(), (jbyte *)meta.Data()); + jenv->SetObjectArrayElement(jresult, i, jenv->NewObject(retClass, jenv->GetMethodID(retClass, "", "(IF[B)V"), (jint)($1->GetResult(i)->VID), (jfloat)($1->GetResult(i)->Dist), bptr)); + } +} +%typemap(javaout) std::shared_ptr { return $jnicall; } + +%typemap(jni) std::shared_ptr "jobjectArray" +%typemap(jtype) std::shared_ptr "Result[]" +%typemap(jstype) std::shared_ptr "Result[]" +%typemap(out) std::shared_ptr { + int combinelen = 0; + int nodelen = (int)(($1->m_allIndexResults).size()); + for (int i = 0; i < nodelen; i++) { + combinelen += $1->m_allIndexResults[i].m_results.GetResultNum(); + } + jclass retClass = jenv->FindClass("Result"); + $result = jenv->NewObjectArray(combinelen, retClass, NULL); + int id = 0; + for (int i = 0; i < nodelen; i++) { + for (int j = 0; j < $1->m_allIndexResults[i].m_results.GetResultNum(); j++) { + auto& ptr = $1->m_allIndexResults[i].m_results; + auto& meta = ptr.GetMetadata(j); + jbyteArray bptr = jenv->NewByteArray(meta.Length()); + jenv->SetByteArrayRegion(bptr, 0, meta.Length(), (jbyte *)meta.Data()); + jenv->SetObjectArrayElement(jresult, id, jenv->NewObject(retClass, jenv->GetMethodID(retClass, "", "(IF[B)V"), (jint)(ptr.GetResult(j)->VID), (jfloat)(ptr.GetResult(j)->Dist), bptr)); + id++; + } + } +} +%typemap(javaout) std::shared_ptr { + return $jnicall; +} + +#endif diff --git a/cpp/src/core/thirdparty/SPTAG/Wrappers/inc/JavaCore.i b/cpp/src/core/thirdparty/SPTAG/Wrappers/inc/JavaCore.i new file mode 100644 index 0000000000..125ce7e56f --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/Wrappers/inc/JavaCore.i @@ -0,0 +1,17 @@ +%module SPTAG + +%{ +#include "inc/CoreInterface.h" +%} + +%include +%shared_ptr(AnnIndex) +%shared_ptr(QueryResult) +%include "JavaCommon.i" + +%{ +#define SWIG_FILE_WITH_INIT +%} + +%include "CoreInterface.h" +%include "TransferDataType.h" diff --git a/cpp/src/core/thirdparty/SPTAG/Wrappers/inc/PythonClient.i b/cpp/src/core/thirdparty/SPTAG/Wrappers/inc/PythonClient.i new file mode 100644 index 0000000000..a70e2fdeb7 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/Wrappers/inc/PythonClient.i @@ -0,0 +1,16 @@ +%module SPTAGClient + +%{ +#include "inc/ClientInterface.h" +%} + +%include +%shared_ptr(AnnClient) +%shared_ptr(RemoteSearchResult) +%include "PythonCommon.i" + +%{ +#define SWIG_FILE_WITH_INIT +%} + +%include "ClientInterface.h" \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/Wrappers/inc/PythonCommon.i b/cpp/src/core/thirdparty/SPTAG/Wrappers/inc/PythonCommon.i new file mode 100644 index 0000000000..7b10d50b99 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/Wrappers/inc/PythonCommon.i @@ -0,0 +1,117 @@ +#ifdef SWIGPYTHON + +%typemap(out) std::shared_ptr +%{ + { + $result = PyTuple_New(3); + int resNum = $1->GetResultNum(); + auto dstVecIDs = PyList_New(resNum); + auto dstVecDists = PyList_New(resNum); + auto dstMetadata = PyList_New(resNum); + int i = 0; + for (const auto& res : *($1)) + { + PyList_SetItem(dstVecIDs, i, PyInt_FromLong(res.VID)); + PyList_SetItem(dstVecDists, i, PyFloat_FromDouble(res.Dist)); + i++; + } + + if ($1->WithMeta()) + { + for (i = 0; i < resNum; ++i) + { + const auto& metadata = $1->GetMetadata(i); + PyList_SetItem(dstMetadata, i, PyBytes_FromStringAndSize(reinterpret_cast(metadata.Data()), + metadata.Length())); + } + } + + PyTuple_SetItem($result, 0, dstVecIDs); + PyTuple_SetItem($result, 1, dstVecDists); + PyTuple_SetItem($result, 2, dstMetadata); + } +%} + +%typemap(out) std::shared_ptr +%{ + { + $result = PyTuple_New(3); + auto dstVecIDs = PyList_New(0); + auto dstVecDists = PyList_New(0); + auto dstMetadata = PyList_New(0); + for (const auto& indexRes : $1->m_allIndexResults) + { + for (const auto& res : indexRes.m_results) + { + PyList_Append(dstVecIDs, PyInt_FromLong(res.VID)); + PyList_Append(dstVecDists, PyFloat_FromDouble(res.Dist)); + } + + if (indexRes.m_results.WithMeta()) + { + for (int i = 0; i < indexRes.m_results.GetResultNum(); ++i) + { + const auto& metadata = indexRes.m_results.GetMetadata(i); + PyList_Append(dstMetadata, PyBytes_FromStringAndSize(reinterpret_cast(metadata.Data()), + metadata.Length())); + } + } + } + PyTuple_SetItem($result, 0, dstVecIDs); + PyTuple_SetItem($result, 1, dstVecDists); + PyTuple_SetItem($result, 2, dstMetadata); + } +%} + + +%{ +struct PyBufferHolder +{ + PyBufferHolder() : shouldRelease(false) { } + + ~PyBufferHolder() + { + if (shouldRelease) + { + PyBuffer_Release(&buff); + } + } + + Py_buffer buff; + + bool shouldRelease; +}; +%} + +%typemap(in) ByteArray (PyBufferHolder bufferHolder) +%{ + if (PyBytes_Check($input)) + { + $1 = SPTAG::ByteArray((std::uint8_t*)PyBytes_AsString($input), PyBytes_Size($input), false); + } + else if (PyObject_CheckBuffer($input)) + { + if (PyObject_GetBuffer($input, &bufferHolder.buff, PyBUF_SIMPLE | PyBUF_C_CONTIGUOUS) == -1) + { + PyErr_SetString(PyExc_ValueError, "Failed get buffer."); + return NULL; + } + + bufferHolder.shouldRelease = true; + $1 = SPTAG::ByteArray((std::uint8_t*)bufferHolder.buff.buf, bufferHolder.buff.len, false); + } +#if (PY_VERSION_HEX >= 0x03030000) + else if (PyUnicode_Check($input)) + { + $1 = SPTAG::ByteArray((std::uint8_t*)PyUnicode_DATA($input), PyUnicode_GET_LENGTH($input), false); + } +#endif + + if (nullptr == $1.Data()) + { + PyErr_SetString(PyExc_ValueError, "Expected Bytes, Data Structure with Buffer Protocol, or Unicode String after Python 3.3 ."); + return NULL; + } +%} + +#endif diff --git a/cpp/src/core/thirdparty/SPTAG/Wrappers/inc/PythonCore.i b/cpp/src/core/thirdparty/SPTAG/Wrappers/inc/PythonCore.i new file mode 100644 index 0000000000..d2f38ca856 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/Wrappers/inc/PythonCore.i @@ -0,0 +1,16 @@ +%module SPTAG + +%{ +#include "inc/CoreInterface.h" +%} + +%include +%shared_ptr(AnnIndex) +%shared_ptr(QueryResult) +%include "PythonCommon.i" + +%{ +#define SWIG_FILE_WITH_INIT +%} + +%include "CoreInterface.h" \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/Wrappers/inc/TransferDataType.h b/cpp/src/core/thirdparty/SPTAG/Wrappers/inc/TransferDataType.h new file mode 100644 index 0000000000..e9eb64def0 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/Wrappers/inc/TransferDataType.h @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef _SPTAG_PW_TRANSFERDATATYPE_H_ +#define _SPTAG_PW_TRANSFERDATATYPE_H_ + +#include "inc/Core/CommonDataStructure.h" +#include "inc/Core/SearchQuery.h" +#include "inc/Socket/RemoteSearchQuery.h" + +typedef SPTAG::ByteArray ByteArray; + +typedef SPTAG::QueryResult QueryResult; + +typedef SPTAG::Socket::RemoteSearchResult RemoteSearchResult; + +class Result { +public: + int VID; + float Dist; + ByteArray Meta; + + Result(int _VID, float _Dist, ByteArray _Meta): VID(_VID), Dist(_Dist), Meta(_Meta) {} +}; + +#endif // _SPTAG_PW_TRANSFERDATATYPE_H_ diff --git a/cpp/src/core/thirdparty/SPTAG/Wrappers/packages.config b/cpp/src/core/thirdparty/SPTAG/Wrappers/packages.config new file mode 100644 index 0000000000..667ef75b66 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/Wrappers/packages.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/Wrappers/src/ClientInterface.cpp b/cpp/src/core/thirdparty/SPTAG/Wrappers/src/ClientInterface.cpp new file mode 100644 index 0000000000..65a1d4cf17 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/Wrappers/src/ClientInterface.cpp @@ -0,0 +1,250 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/ClientInterface.h" +#include "inc/Helper/CommonHelper.h" +#include "inc/Helper/Concurrent.h" +#include "inc/Helper/Base64Encode.h" +#include "inc/Helper/StringConvert.h" + +#include + + +AnnClient::AnnClient(const char* p_serverAddr, const char* p_serverPort) + : m_connectionID(SPTAG::Socket::c_invalidConnectionID), + m_timeoutInMilliseconds(9000) +{ + using namespace SPTAG; + + m_socketClient.reset(new Socket::Client(GetHandlerMap(), 2, 30)); + + if (nullptr == p_serverAddr || nullptr == p_serverPort) + { + return; + } + + m_server = p_serverAddr; + m_port = p_serverPort; + + auto connectCallback = [this](Socket::ConnectionID p_cid, ErrorCode p_ec) + { + m_connectionID = p_cid; + + if (ErrorCode::Socket_FailedResolveEndPoint == p_ec) + { + return; + } + + while (Socket::c_invalidConnectionID == m_connectionID) + { + ErrorCode errCode; + std::this_thread::sleep_for(std::chrono::seconds(10)); + m_connectionID = m_socketClient->ConnectToServer(m_server, m_port, errCode); + } + }; + + m_socketClient->AsyncConnectToServer(m_server, m_port, connectCallback); + + m_socketClient->SetEventOnConnectionClose([this](Socket::ConnectionID p_cid) + { + ErrorCode errCode; + m_connectionID = Socket::c_invalidConnectionID; + while (Socket::c_invalidConnectionID == m_connectionID) + { + std::this_thread::sleep_for(std::chrono::seconds(10)); + m_connectionID = m_socketClient->ConnectToServer(m_server, m_port, errCode); + } + }); +} + + +AnnClient::~AnnClient() +{ +} + + +void +AnnClient::SetTimeoutMilliseconds(int p_timeout) +{ + m_timeoutInMilliseconds = p_timeout; +} + + +void +AnnClient::SetSearchParam(const char* p_name, const char* p_value) +{ + std::lock_guard guard(m_paramMutex); + + if (nullptr == p_name || '\0' == *p_name) + { + return; + } + + std::string name(p_name); + SPTAG::Helper::StrUtils::ToLowerInPlace(name); + + if (nullptr == p_value || '\0' == *p_value) + { + m_params.erase(name); + return; + } + + m_params[name] = p_value; +} + + +void +AnnClient::ClearSearchParam() +{ + std::lock_guard guard(m_paramMutex); + m_params.clear(); +} + + +std::shared_ptr +AnnClient::Search(ByteArray p_data, int p_resultNum, const char* p_valueType, bool p_withMetaData) +{ + using namespace SPTAG; + + SPTAG::Socket::RemoteSearchResult ret; + if (Socket::c_invalidConnectionID != m_connectionID) + { + + auto signal = std::make_shared(1); + + auto callback = [&ret, signal](RemoteSearchResult p_result) + { + if (RemoteSearchResult::ResultStatus::Success == p_result.m_status) + { + ret = std::move(p_result); + } + + signal->FinishOne(); + }; + + auto timeoutCallback = [this](std::shared_ptr p_callback) + { + if (nullptr != p_callback) + { + RemoteSearchResult result; + result.m_status = RemoteSearchResult::ResultStatus::Timeout; + + (*p_callback)(std::move(result)); + } + }; + + auto connectCallback = [callback, this](bool p_connectSucc) + { + if (!p_connectSucc) + { + RemoteSearchResult result; + result.m_status = RemoteSearchResult::ResultStatus::FailedNetwork; + + callback(std::move(result)); + } + }; + + Socket::Packet packet; + packet.Header().m_connectionID = Socket::c_invalidConnectionID; + packet.Header().m_packetType = Socket::PacketType::SearchRequest; + packet.Header().m_processStatus = Socket::PacketProcessStatus::Ok; + packet.Header().m_resourceID = m_callbackManager.Add(std::make_shared(std::move(callback)), + m_timeoutInMilliseconds, + std::move(timeoutCallback)); + + Socket::RemoteQuery query; + SPTAG::VectorValueType valueType; + SPTAG::Helper::Convert::ConvertStringTo(p_valueType, valueType); + query.m_queryString = CreateSearchQuery(p_data, p_resultNum, p_withMetaData, valueType); + + packet.Header().m_bodyLength = static_cast(query.EstimateBufferSize()); + packet.AllocateBuffer(packet.Header().m_bodyLength); + query.Write(packet.Body()); + packet.Header().WriteBuffer(packet.HeaderBuffer()); + + m_socketClient->SendPacket(m_connectionID, std::move(packet), connectCallback); + + signal->Wait(); + } + return std::make_shared(ret); +} + + +bool +AnnClient::IsConnected() const +{ + return m_connectionID != SPTAG::Socket::c_invalidConnectionID; +} + + +SPTAG::Socket::PacketHandlerMapPtr +AnnClient::GetHandlerMap() +{ + using namespace SPTAG; + + Socket::PacketHandlerMapPtr handlerMap(new Socket::PacketHandlerMap); + handlerMap->emplace(Socket::PacketType::SearchResponse, + std::bind(&AnnClient::SearchResponseHanlder, + this, + std::placeholders::_1, + std::placeholders::_2)); + + return handlerMap; +} + + +void +AnnClient::SearchResponseHanlder(SPTAG::Socket::ConnectionID p_localConnectionID, + SPTAG::Socket::Packet p_packet) +{ + using namespace SPTAG; + + std::shared_ptr callback = m_callbackManager.GetAndRemove(p_packet.Header().m_resourceID); + if (nullptr == callback) + { + return; + } + + if (p_packet.Header().m_processStatus != Socket::PacketProcessStatus::Ok || 0 == p_packet.Header().m_bodyLength) + { + Socket::RemoteSearchResult result; + result.m_status = Socket::RemoteSearchResult::ResultStatus::FailedExecute; + + (*callback)(std::move(result)); + } + else + { + Socket::RemoteSearchResult result; + result.Read(p_packet.Body()); + (*callback)(std::move(result)); + } +} + + +std::string +AnnClient::CreateSearchQuery(const ByteArray& p_data, + int p_resultNum, + bool p_extractMetadata, + SPTAG::VectorValueType p_valueType) +{ + std::stringstream out; + + out << "#"; + std::size_t encLen; + SPTAG::Helper::Base64::Encode(p_data.Data(), p_data.Length(), out, encLen); + + out << " $datatype:" << SPTAG::Helper::Convert::ConvertToString(p_valueType); + out << " $resultnum:" << std::to_string(p_resultNum); + out << " $extractmetadata:" << (p_extractMetadata ? "true" : "false"); + + { + std::lock_guard guard(m_paramMutex); + for (const auto& param : m_params) + { + out << " $" << param.first << ":" << param.second; + } + } + + return out.str(); +} + diff --git a/cpp/src/core/thirdparty/SPTAG/Wrappers/src/CoreInterface.cpp b/cpp/src/core/thirdparty/SPTAG/Wrappers/src/CoreInterface.cpp new file mode 100644 index 0000000000..99d545bc0e --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/Wrappers/src/CoreInterface.cpp @@ -0,0 +1,213 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "inc/CoreInterface.h" +#include "inc/Helper/StringConvert.h" + + +AnnIndex::AnnIndex(int p_dimension) + : m_algoType(SPTAG::IndexAlgoType::BKT), + m_inputValueType(SPTAG::VectorValueType::Float), + m_dimension(p_dimension) +{ + m_inputVectorSize = SPTAG::GetValueTypeSize(m_inputValueType) * m_dimension; +} + + +AnnIndex::AnnIndex(const char* p_algoType, const char* p_valueType, int p_dimension) + : m_algoType(SPTAG::IndexAlgoType::Undefined), + m_inputValueType(SPTAG::VectorValueType::Undefined), + m_dimension(p_dimension) +{ + SPTAG::Helper::Convert::ConvertStringTo(p_algoType, m_algoType); + SPTAG::Helper::Convert::ConvertStringTo(p_valueType, m_inputValueType); + m_inputVectorSize = SPTAG::GetValueTypeSize(m_inputValueType) * m_dimension; +} + + +AnnIndex::AnnIndex(const std::shared_ptr& p_index) + : m_algoType(p_index->GetIndexAlgoType()), + m_inputValueType(p_index->GetVectorValueType()), + m_dimension(p_index->GetFeatureDim()), + m_index(p_index) +{ + m_inputVectorSize = SPTAG::GetValueTypeSize(m_inputValueType) * m_dimension; +} + + +AnnIndex::~AnnIndex() +{ +} + + +bool +AnnIndex::Build(ByteArray p_data, int p_num) +{ + if (nullptr == m_index) + { + m_index = SPTAG::VectorIndex::CreateInstance(m_algoType, m_inputValueType); + } + if (nullptr == m_index || p_num == 0 || m_dimension == 0 || p_data.Length() != p_num * m_inputVectorSize) + { + return false; + } + return (SPTAG::ErrorCode::Success == m_index->BuildIndex(p_data.Data(), p_num, m_dimension)); +} + + +bool +AnnIndex::BuildWithMetaData(ByteArray p_data, ByteArray p_meta, int p_num) +{ + if (nullptr == m_index) + { + m_index = SPTAG::VectorIndex::CreateInstance(m_algoType, m_inputValueType); + } + if (nullptr == m_index || p_num == 0 || m_dimension == 0 || p_data.Length() != p_num * m_inputVectorSize) + { + return false; + } + + std::shared_ptr vectors(new SPTAG::BasicVectorSet(p_data, + m_inputValueType, + static_cast(m_dimension), + static_cast(p_num))); + + std::uint64_t* offsets = new std::uint64_t[p_num + 1]{ 0 }; + int current = 1; + for (size_t i = 0; i < p_meta.Length(); i++) { + if (((char)p_meta.Data()[i]) == '\n') + offsets[current++] = (std::uint64_t)(i + 1); + } + std::shared_ptr meta(new SPTAG::MemMetadataSet(p_meta, ByteArray((std::uint8_t*)offsets, (p_num + 1) * sizeof(std::uint64_t), true), p_num)); + return (SPTAG::ErrorCode::Success == m_index->BuildIndex(vectors, meta)); +} + + +void +AnnIndex::SetBuildParam(const char* p_name, const char* p_value) +{ + if (nullptr == m_index) + { + if (SPTAG::IndexAlgoType::Undefined == m_algoType || + SPTAG::VectorValueType::Undefined == m_inputValueType) + { + return; + } + m_index = SPTAG::VectorIndex::CreateInstance(m_algoType, m_inputValueType); + + } + m_index->SetParameter(p_name, p_value); +} + + +void +AnnIndex::SetSearchParam(const char* p_name, const char* p_value) +{ + if (nullptr != m_index) m_index->SetParameter(p_name, p_value); +} + + +std::shared_ptr +AnnIndex::Search(ByteArray p_data, int p_resultNum) +{ + std::shared_ptr results = std::make_shared(p_data.Data(), p_resultNum, false); + + if (nullptr != m_index && p_data.Length() == m_inputVectorSize) + { + m_index->SearchIndex(*results); + } + return std::move(results); +} + +std::shared_ptr +AnnIndex::SearchWithMetaData(ByteArray p_data, int p_resultNum) +{ + std::shared_ptr results = std::make_shared(p_data.Data(), p_resultNum, true); + + if (nullptr != m_index && p_data.Length() == m_inputVectorSize) + { + m_index->SearchIndex(*results); + } + return std::move(results); +} + +bool +AnnIndex::ReadyToServe() const +{ + return m_index != nullptr; +} + + +bool +AnnIndex::Save(const char* p_savefile) const +{ + return SPTAG::ErrorCode::Success == m_index->SaveIndex(p_savefile); +} + + +AnnIndex +AnnIndex::Load(const char* p_loaderFile) +{ + std::shared_ptr vecIndex; + auto ret = SPTAG::VectorIndex::LoadIndex(p_loaderFile, vecIndex); + if (SPTAG::ErrorCode::Success != ret || nullptr == vecIndex) + { + return AnnIndex(0); + } + + return AnnIndex(vecIndex); +} + + +bool +AnnIndex::Add(ByteArray p_data, int p_num) +{ + if (nullptr == m_index) + { + m_index = SPTAG::VectorIndex::CreateInstance(m_algoType, m_inputValueType); + } + if (nullptr == m_index || p_num == 0 || m_dimension == 0 || p_data.Length() != p_num * m_inputVectorSize) + { + return false; + } + return (SPTAG::ErrorCode::Success == m_index->AddIndex(p_data.Data(), p_num, m_dimension)); +} + + +bool +AnnIndex::AddWithMetaData(ByteArray p_data, ByteArray p_meta, int p_num) +{ + if (nullptr == m_index) + { + m_index = SPTAG::VectorIndex::CreateInstance(m_algoType, m_inputValueType); + } + if (nullptr == m_index || p_num == 0 || m_dimension == 0 || p_data.Length() != p_num * m_inputVectorSize) + { + return false; + } + + std::shared_ptr vectors(new SPTAG::BasicVectorSet(p_data, + m_inputValueType, + static_cast(m_dimension), + static_cast(p_num))); + + std::uint64_t* offsets = new std::uint64_t[p_num + 1]{ 0 }; + int current = 1; + for (size_t i = 0; i < p_meta.Length(); i++) { + if (((char)p_meta.Data()[i]) == '\n') + offsets[current++] = (std::uint64_t)(i + 1); + } + std::shared_ptr meta(new SPTAG::MemMetadataSet(p_meta, ByteArray((std::uint8_t*)offsets, (p_num + 1) * sizeof(std::uint64_t), true), p_num)); + return (SPTAG::ErrorCode::Success == m_index->AddIndex(vectors, meta)); +} + + +bool +AnnIndex::Delete(ByteArray p_data, int p_num) +{ + if (nullptr != m_index && p_num > 0) + { + return (SPTAG::ErrorCode::Success == m_index->DeleteIndex(p_data.Data(), p_num)); + } + return false; +} diff --git a/cpp/src/core/thirdparty/SPTAG/azure-pipelines.yml b/cpp/src/core/thirdparty/SPTAG/azure-pipelines.yml new file mode 100644 index 0000000000..22f697bdd4 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/azure-pipelines.yml @@ -0,0 +1,230 @@ +resources: + +- repo: self + +phases: + +- phase: Phase_1 + + displayName: Agent job + + + + condition: succeeded() + + queue: + + name: SPTAGBuild + + steps: + + - script: | + mkdir build + cd build + cmake .. + make + cd ../Release + ./test + + displayName: 'Command Line Script' + + + + + +- phase: Phase_2 + + displayName: Agent job + + + + condition: succeeded() + + queue: + + name: Hosted + + demands: + + - msbuild + + - visualstudio + + + + steps: + + - task: NuGetToolInstaller@0 + + displayName: 'Use NuGet 4.3.0' + + + + + + - task: NuGetCommand@2 + + displayName: 'NuGet restore' + + inputs: + + restoreSolution: SPTAG.sln + + + + vstsFeed: 'bae5097f-8d64-4f8f-913e-24a4eb8302c3' + + + + + + - task: VSBuild@1 + + displayName: 'Build solution SPTAG.sln' + + inputs: + + solution: SPTAG.sln + + + + vsVersion: 14.0 + + + + platform: x64 + + + + configuration: debug + + + + msbuildArchitecture: x64 + + + + createLogFile: true + + + + + + - script: '.\x64\Debug\Test.exe' + + displayName: 'Command Line Script' + + + + - task: CopyFiles@2 + + displayName: 'Copy Files to: $(Build.ArtifactStagingDirectory)' + + inputs: + + SourceFolder: x64/Debug/ + + + + Contents: '*' + + + + TargetFolder: '$(Build.ArtifactStagingDirectory)' + + + + + + - task: PublishBuildArtifacts@1 + + displayName: 'Publish Artifact: drop' + + + + + + - task: securedevelopmentteam.vss-secure-development-tools.build-task-binskim.BinSkim@3 + + displayName: 'Run BinSkim ' + + inputs: + + InputType: Basic + + + + + + - task: securedevelopmentteam.vss-secure-development-tools.build-task-credscan.CredScan@2 + + displayName: 'Run CredScan' + + inputs: + + scanFolder: AnnService + + + + suppressAsError: true + + + + verboseOutput: true + + + + debugMode: false + + + + + + - task: securedevelopmentteam.vss-secure-development-tools.build-task-autoapplicability.AutoApplicability@1 + + displayName: 'Run AutoApplicability' + + inputs: + + IsSoftware: true + + + + + + - task: securedevelopmentteam.vss-secure-development-tools.build-task-publishsecurityanalysislogs.PublishSecurityAnalysisLogs@2 + + displayName: 'Publish Security Analysis Logs' + + + + + + - task: securedevelopmentteam.vss-secure-development-tools.build-task-report.SdtReport@1 + + displayName: 'Create Security Analysis Report' + + inputs: + + AllTools: true + + + + + + - task: securedevelopmentteam.vss-secure-development-tools.build-task-postanalysis.PostAnalysis@1 + + displayName: 'Post Analysis' + + inputs: + + AllTools: true + + + + + + - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 + + displayName: 'Component Detection' + diff --git a/cpp/src/core/thirdparty/SPTAG/build.sh b/cpp/src/core/thirdparty/SPTAG/build.sh new file mode 100755 index 0000000000..9b83643df2 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/build.sh @@ -0,0 +1,22 @@ +#!/bin/bash -x + +if [[ -d cmake_build ]]; then + rm cmake_build -rf +fi + +mkdir cmake_build +cd cmake_build + +INSTALL_PREFIX=$(pwd)/../../build + +BOOST_PATH="/home/zilliz/opt/app/boost" +TBB_PATH="/home/zilliz/opt/app/tbb/tbb" +OPTION="-DBOOST_ROOT=$BOOST_PATH -DTBB_DIR=${TBB_PATH}" + +# CMAKE_CMD="cmake -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} ${OPTION} ../" + +CMAKE_CMD="cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} ../" + +${CMAKE_CMD} + +make -j8 && make install diff --git a/cpp/src/core/thirdparty/SPTAG/docs/GettingStart.md b/cpp/src/core/thirdparty/SPTAG/docs/GettingStart.md new file mode 100644 index 0000000000..756aa70ed7 --- /dev/null +++ b/cpp/src/core/thirdparty/SPTAG/docs/GettingStart.md @@ -0,0 +1,236 @@ +## **Quick start** + +### **Index Build** + ```bash + Usage: + ./IndexBuiler [options] + Options: + -d, --dimension Dimension of vector, required. + -v, --vectortype Input vector data type (e.g. Float, Int8, Int16), required. + -i, --input Input raw data, required. + -o, --outputfolder Output folder, required. + -a, --algo Index Algorithm type (e.g. BKT, KDT), required. + + -t, --thread Thread Number, default is 32. + --delimiter Vector delimiter, default is |. + Index.= Set the algorithm parameter ArgName with value ArgValue. + ``` + + ### **Index Search** + ```bash + Usage: + ./IndexSearcher [options] + Options + Index.QueryFile=XXX Input Query file + Index.ResultFile=XXX Output result file + Index.TruthFile=XXX Truth file that can help to calculate the recall + Index.K=XXX How many nearest neighbors return + Index.MaxCheck=XXX The maxcheck of the search + ``` + +### ** Input File format ** +> Input raw data for index build and input query file for index search (suppose vector dimension is 3): +``` +\t||| +\t||| +... +``` +where each line represents a vector with its metadata and its value separated by a tab space. Each dimension of a vector is separated by | or use --delimiter to define the separator. + +> Truth file to calculate recall (suppose K is 2): +``` + + +... +``` +where each line represents the K nearest neighbors of a query separated by a blank space. Each neighbor is given by its vector id. + +### **Server** +```bash +Usage: +./Server [options] +Options: + -m, --mode Service mode, interactive or socket. + -c, --config Configure file of the index + +Write a server configuration file service.ini as follows: + +[Service] +ListenAddr=0.0.0.0 +ListenPort=8000 +ThreadNumber=8 +SocketThreadNumber=8 + +[QueryConfig] +DefaultMaxResultNumber=6 +DefaultSeparator=| + +[Index] +List=BKT + +[Index_BKT] +IndexFolder=BKT_gist +``` + +### **Client** +```bash +Usage: +./Client [options] +Options: +-s, --server Server address +-p, --port Server port +-t, Search timeout +-cth, Client Thread Number +-sth Socket Thread Number +``` + +### **Aggregator** +```bash +Usage: +./Aggregator + +Write Aggregator.ini as follows: + +[Service] +ListenAddr=0.0.0.0 +ListenPort=8100 +ThreadNumber=8 +SocketThreadNumber=8 + +[Servers] +Number=2 + +[Server_0] +Address=127.0.0.1 +Port=8000 + +[Server_1] +Address=127.0.0.1 +Port=8010 +``` + +### **Python Support** +> Singlebox PythonWrapper + ```python + +import SPTAG +import numpy as np + +n = 100 +k = 3 +r = 3 + +def testBuild(algo, distmethod, x, out): + i = SPTAG.AnnIndex(algo, 'Float', x.shape[1]) + i.SetBuildParam("NumberOfThreads", '4') + i.SetBuildParam("DistCalcMethod", distmethod) + ret = i.Build(x, x.shape[0]) + i.Save(out) + +def testBuildWithMetaData(algo, distmethod, x, s, out): + i = SPTAG.AnnIndex(algo, 'Float', x.shape[1]) + i.SetBuildParam("NumberOfThreads", '4') + i.SetBuildParam("DistCalcMethod", distmethod) + if i.BuildWithMetaData(x, s, x.shape[0]): + i.Save(out) + +def testSearch(index, q, k): + j = SPTAG.AnnIndex.Load(index) + for t in range(q.shape[0]): + result = j.Search(q[t], k) + print (result[0]) # ids + print (result[1]) # distances + +def testSearchWithMetaData(index, q, k): + j = SPTAG.AnnIndex.Load(index) + j.SetSearchParam("MaxCheck", '1024') + for t in range(q.shape[0]): + result = j.SearchWithMetaData(q[t], k) + print (result[0]) # ids + print (result[1]) # distances + print (result[2]) # metadata + +def testAdd(index, x, out, algo, distmethod): + if index != None: + i = SPTAG.AnnIndex.Load(index) + else: + i = SPTAG.AnnIndex(algo, 'Float', x.shape[1]) + i.SetBuildParam("NumberOfThreads", '4') + i.SetBuildParam("DistCalcMethod", distmethod) + if i.Add(x, x.shape[0]): + i.Save(out) + +def testAddWithMetaData(index, x, s, out, algo, distmethod): + if index != None: + i = SPTAG.AnnIndex.Load(index) + else: + i = SPTAG.AnnIndex(algo, 'Float', x.shape[1]) + i = SPTAG.AnnIndex(algo, 'Float', x.shape[1]) + i.SetBuildParam("NumberOfThreads", '4') + i.SetBuildParam("DistCalcMethod", distmethod) + if i.AddWithMetaData(x, s, x.shape[0]): + i.Save(out) + +def testDelete(index, x, out): + i = SPTAG.AnnIndex.Load(index) + ret = i.Delete(x, x.shape[0]) + print (ret) + i.Save(out) + +def Test(algo, distmethod): + x = np.ones((n, 10), dtype=np.float32) * np.reshape(np.arange(n, dtype=np.float32), (n, 1)) + q = np.ones((r, 10), dtype=np.float32) * np.reshape(np.arange(r, dtype=np.float32), (r, 1)) * 2 + m = '' + for i in range(n): + m += str(i) + '\n' + + m = m.encode() + + print ("Build.............................") + testBuild(algo, distmethod, x, 'testindices') + testSearch('testindices', q, k) + print ("Add.............................") + testAdd('testindices', x, 'testindices', algo, distmethod) + testSearch('testindices', q, k) + print ("Delete.............................") + testDelete('testindices', q, 'testindices') + testSearch('testindices', q, k) + + print ("AddWithMetaData.............................") + testAddWithMetaData(None, x, m, 'testindices', algo, distmethod) + print ("Delete.............................") + testSearchWithMetaData('testindices', q, k) + testDelete('testindices', q, 'testindices') + testSearchWithMetaData('testindices', q, k) + +if __name__ == '__main__': + Test('BKT', 'L2') + Test('KDT', 'L2') + + ``` + + > Python Client Wrapper, Suppose there is a sever run at 127.0.0.1:8000 serving ten-dimensional vector datasets: + ```python +import SPTAGClient +import numpy as np +import time + +def testSPTAGClient(): + index = SPTAGClient.AnnClient('127.0.0.1', '8100') + while not index.IsConnected(): + time.sleep(1) + index.SetTimeoutMilliseconds(18000) + + q = np.ones((10, 10), dtype=np.float32) + for t in range(q.shape[0]): + result = index.Search(q[t], 6, 'Float', False) + print (result[0]) + print (result[1]) + +if __name__ == '__main__': + testSPTAGClient() + + ``` + + + \ No newline at end of file diff --git a/cpp/src/core/thirdparty/SPTAG/docs/img/sptag.png b/cpp/src/core/thirdparty/SPTAG/docs/img/sptag.png new file mode 100644 index 0000000000..dc21bdf3dc Binary files /dev/null and b/cpp/src/core/thirdparty/SPTAG/docs/img/sptag.png differ diff --git a/cpp/src/core/thirdparty/build.sh b/cpp/src/core/thirdparty/build.sh new file mode 100755 index 0000000000..a0af3349d5 --- /dev/null +++ b/cpp/src/core/thirdparty/build.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +BUILD_TYPE="Release" + +while getopts "p:t:d:h" arg +do + case $arg in + t) + BUILD_TYPE=$OPTARG # BUILD_TYPE + ;; + h) # help + echo " + +parameter: +-p: postgresql install path. +-t: build type + +usage: +./build.sh -t \${BUILD_TYPE} + " + exit 0 + ;; + ?) + echo "unknown argument" + exit 1 + ;; + esac +done + +if [[ -d build ]]; then + rm ./build -r +fi + +while IFS='' read -r line || [[ -n "$line" ]]; do + cd $line + ./build.sh -t ${BUILD_TYPE} + if [ $? -ne 0 ];then + exit 1 + fi + cd ../ +done < project.conf + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/.doozer.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/.doozer.json new file mode 100644 index 0000000000..13edcea3b0 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/.doozer.json @@ -0,0 +1,43 @@ +{ + "targets": { + "centos7-x86_64": { + "buildenv": "centos7-x86_64", + "builddeps": ["gcc-c++", "make", "wget"], + "environment": { + "CXXFLAGS": "-std=c++11 -Wall -g3" + }, + "buildcmd": [ + "uname -a", + "rpm -q centos-release", + "g++ --version", + "cd", + "wget https://github.com/Kitware/CMake/releases/download/v3.14.0/cmake-3.14.0.tar.gz", + "tar xfz cmake-3.14.0.tar.gz", + "cd cmake-3.14.0", + "./bootstrap", + "make -j8", + "cd", + "cmake-3.14.0/bin/cmake . -DBUILD_TESTS=ON", + "cmake-3.14.0/bin/cmake --build . --target test_jsoncons", + "cd tests", + "./test_jsoncons;" + ] + }, + "fedora24-x86_64": { + "buildenv": "fedora24-x86_64", + "builddeps": ["cmake", "make", "gcc gcc-c++"], + "environment": { + "CXXFLAGS": "-std=c++11 -Wall -g3" + }, + "buildcmd": [ + "uname -a", + "cat /etc/fedora-release", + "g++ --version", + "cmake . -DBUILD_TESTS=ON", + "cmake --build . --target test_jsoncons", + "cd tests", + "./test_jsoncons;" + ] + } + } +} diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/.gitignore b/cpp/src/core/thirdparty/jsoncons-0.126.0/.gitignore new file mode 100644 index 0000000000..97651319ef --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/.gitignore @@ -0,0 +1,30 @@ +*.suo +*.sdf +*.VC.opendb +*.VC.db +*.vcxproj.user +*.vcxproj.filters +**/x64/Debug/ +**/x64/Release/ +**/*.vcxproj +**/vs2017 +**/vs2015 +**/vs2013 +**/temp +**/build + +examples/build/cmake/build_llvm.sh +examples/build/cmake/build_llvm + +src/jsoncons/json_structures.hpp.orig + +examples/build/vs2013/ + +src/jsoncons/json_serializer2.hpp + +examples/booklist.json +examples/booklist2.json + +examples/build/vs2017/.vs/vs2017/v15/ipch/AutoPCH/2f913b3e9413499/BASICS_EXAMPLES.ipch +examples/build/vs2017/.vs/vs2017/v15/ipch/AutoPCH/8571a45cc244269f/EXAMPLES.ipch +examples/build/vs2017/vs2017.sln diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/.travis.yml b/cpp/src/core/thirdparty/jsoncons-0.126.0/.travis.yml new file mode 100644 index 0000000000..45773607c2 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/.travis.yml @@ -0,0 +1,240 @@ +language: cpp +dist: trusty +sudo: required + +matrix: + include: + - os: linux + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-4.8 + - libgmp-dev + env: COMPILER=gcc VERSION=4.8 CXXFLAGS="-std=c++11" + + - os: linux + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-4.9 + - libgmp-dev + env: COMPILER=gcc VERSION=4.9 JSONCONS_SANITIZE=1 CXXFLAGS="-std=c++11" + + - os: linux + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-5 + env: COMPILER=gcc VERSION=5 CXXFLAGS="-std=gnu++11" + + - os: linux + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-6 + env: COMPILER=gcc VERSION=6 JSONCONS_SANITIZE=1 + + - os: linux + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-7 + env: COMPILER=gcc VERSION=7 JSONCONS_SANITIZE=1 + + - os: linux + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-8 + env: COMPILER=gcc VERSION=8 JSONCONS_SANITIZE=1 CXXFLAGS="-std=c++17 -Werror -Wall -Wextra -Wimplicit-fallthrough -pedantic -Wcast-align -Wcast-qual" + + - os: linux + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-8 + env: COMPILER=gcc VERSION=8 JSONCONS_SANITIZE=1 CXXFLAGS="-std=c++17 -DJSONCONS_HAS_STRING_VIEW" + + - os: linux + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-8 + env: COMPILER=gcc VERSION=8 JSONCONS_SANITIZE=1 CXXFLAGS="-std=gnu++17 -Wall -Wextra -Wimplicit-fallthrough" + + - os: linux + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - clang-3.9 + - g++-4.8-aarch64-linux-gnu + - gcc-4.8-aarch64-linux-gnu + - g++-4.8-multilib + - gcc-4.8-multilib + - qemu + - qemu-system-arm + env: COMPILER=clang VERSION=3.9 CROSS_COMPILE=1 ARM_ARCH_DIR=aarch64-linux-gnu GCC_VER=4.8.4 ARM_SETTINGS="armv8-a -target aarch64-linux-gnueabi" CXXFLAGS="-std=c++11" + + - os: linux + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-trusty-4.0 + packages: + - clang-4.0 + - g++-7 + env: COMPILER=clang VERSION=4.0 CXXFLAGS="-std=c++11" + + - os: linux + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-trusty-5.0 + packages: + - clang-5.0 + - g++-7 + env: COMPILER=clang VERSION=5.0 CXXFLAGS="-std=gnu++11" + + - os: linux + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-trusty-6.0 + packages: + - clang-6.0 + - g++-7 + env: COMPILER=clang VERSION=6.0 JSONCONS_SANITIZE=1 CXXFLAGS="-std=c++11 -Wall -Wextra -Wimplicit-fallthrough" + + - os: linux + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-trusty-6.0 + packages: + - clang-6.0 + - g++-7 + env: COMPILER=clang VERSION=6.0 CXXFLAGS="-DJSONCONS_NO_DEPRECATED" + + - os: osx + osx_image: xcode7.3 + compiler: clang + env: CXXFLAGS="-std=c++11" + + - os: osx + osx_image: xcode8 + compiler: clang + env: CXXFLAGS="-std=c++11" + + - os: osx + osx_image: xcode8.1 + compiler: clang + env: CXXFLAGS="-std=c++11" + + - os: osx + osx_image: xcode8.2 + compiler: clang + env: CXXFLAGS="-std=c++11" + + - os: osx + osx_image: xcode8.3 + compiler: clang + env: CXXFLAGS="-std=c++11" + + - os: osx + osx_image: xcode9 + compiler: clang + env: CXXFLAGS="-std=c++11" + + - os: osx + osx_image: xcode9.1 + compiler: clang + env: CXXFLAGS="-std=c++11" + + - os: osx + osx_image: xcode9.2 + compiler: clang + env: CXXFLAGS="-std=c++11" + + - os: osx + osx_image: xcode9.3 + compiler: clang + env: CXXFLAGS="-std=c++11" + + - os: osx + osx_image: xcode9.4 + compiler: clang + env: CXXFLAGS="-std=c++11" + +before_install: + - | + # Configure build variables + if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then + if [[ "$COMPILER" == "gcc" ]]; then + export CXX=g++-$VERSION CC=gcc-$VERSION; + fi + if [[ "$COMPILER" == "clang" ]]; then + export CXX=clang++-$VERSION CC=clang-$VERSION; + fi + elif [[ "$TRAVIS_OS_NAME" == "osx" ]]; then + export CXX=clang++ CC=clang; + fi +install: + # get CMake (only for systems with brew - macOS) + - | + if [[ (-x $(which brew)) ]]; then + brew update + brew install cmake + brew upgrade cmake + cmake --version + fi + + - if [[ "$CROSS_COMPILE" == 1 ]] ; then + if [[ "$ARM_ARCH_DIR" == "aarch64-linux-gnu" ]] ; then + mkdir $HOME/linker_bin ; + ln -s /usr/bin/aarch64-linux-gnu-ld $HOME/linker_bin/ld ; + echo "SETTING GNU LINKER DIR" ; + ls -al $HOME/linker_bin/ld ; + cmake . -DBUILD_TESTS=ON -DCROSS_COMPILE_ARM=ON -DDOWNLOAD_GTEST=ON -DARM_ARCH_DIRECTORY="$ARM_ARCH_DIR" -DARM_GCC_VER="$GCC_VER" -DTARGET_ARCH="$ARM_SETTINGS --prefix=$HOME/linker_bin/" ${CMAKE_OPTIONS}; + else + cmake . -DBUILD_TESTS=ON -DCROSS_COMPILE_ARM=ON -DDOWNLOAD_GTEST=ON -DARM_ARCH_DIRECTORY="$ARM_ARCH_DIR" -DARM_GCC_VER="$GCC_VER" -DTARGET_ARCH="$ARM_SETTINGS" ${CMAKE_OPTIONS}; + fi + else + cmake . -DBUILD_TESTS=ON ${CMAKE_OPTIONS}; + fi + - make -j2 test_jsoncons + - cd tests +script: + - if [[ "$JSONCONS_VALGRIND" == 1 ]]; then + ctest -T memcheck; + fi + - if [[ "$CROSS_COMPILE" == 1 ]]; then + if [[ "$ARM_ARCH_DIR" == "aarch64-linux-gnu" ]]; then + qemu-aarch64 -L /usr/aarch64-linux-gnu/ ./test_jsoncons ; + else + qemu-arm -L /usr/arm-linux-gnueabi/ ./test_jsoncons ; + fi + else + ./test_jsoncons; + fi diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/CMakeLists.txt b/cpp/src/core/thirdparty/jsoncons-0.126.0/CMakeLists.txt new file mode 100644 index 0000000000..1c067413a7 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/CMakeLists.txt @@ -0,0 +1,73 @@ +cmake_minimum_required(VERSION 3.1) + +project(jsoncons) + +set(JSONCONS_PROJECT_DIR ${PROJECT_SOURCE_DIR}) +set(JSONCONS_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include) + +# Versioning +# ========== + +file(STRINGS "${JSONCONS_INCLUDE_DIR}/jsoncons/config/version.hpp" jsoncons_version_defines + REGEX "#define JSONCONS_VERSION_(MAJOR|MINOR|PATCH)") +foreach(ver ${jsoncons_version_defines}) + if(ver MATCHES "#define JSONCONS_VERSION_(MAJOR|MINOR|PATCH) +([^ ]+)$") + set(JSONCONS_VERSION_${CMAKE_MATCH_1} "${CMAKE_MATCH_2}" CACHE INTERNAL "") + endif() +endforeach() +set(${PROJECT_NAME}_VERSION + ${JSONCONS_VERSION_MAJOR}.${JSONCONS_VERSION_MINOR}.${JSONCONS_VERSION_PATCH}) +message(STATUS "jsoncons v${${PROJECT_NAME}_VERSION}") + +# Build +# ===== + + +file(GLOB_RECURSE JSONCONS_HEADERS ${JSONCONS_INCLUDE_DIR}/*.hpp) + +add_library(jsoncons INTERFACE) +target_include_directories(jsoncons INTERFACE $ + $) + +OPTION(BUILD_TESTS "jsoncons test suite" ON) + +if(BUILD_TESTS) + add_subdirectory(tests) +endif() + +# Installation +# ============ + +include(GNUInstallDirs) +include(CMakePackageConfigHelpers) + +install(TARGETS jsoncons + EXPORT ${PROJECT_NAME}-targets) + +# Makes the project importable from the build directory +export(EXPORT ${PROJECT_NAME}-targets + FILE "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake") + +install(DIRECTORY ${JSONCONS_INCLUDE_DIR}/jsoncons + ${JSONCONS_INCLUDE_DIR}/jsoncons_ext + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + +# GNUInstallDirs "DATADIR" wrong here; CMake search path wants "share". +set(JSONCONS_CMAKECONFIG_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" CACHE STRING "install path for jsonconsConfig.cmake") + +configure_package_config_file(build_files/cmake/config.cmake.in + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" + INSTALL_DESTINATION ${JSONCONS_CMAKECONFIG_INSTALL_DIR}) + +# jsoncons is header-only and does not depend on the architecture. + +write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake + VERSION ${${PROJECT_NAME}_VERSION} + COMPATIBILITY AnyNewerVersion) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake + ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake + DESTINATION ${JSONCONS_CMAKECONFIG_INSTALL_DIR}) +install(EXPORT ${PROJECT_NAME}-targets + FILE ${PROJECT_NAME}Targets.cmake + DESTINATION ${JSONCONS_CMAKECONFIG_INSTALL_DIR}) + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/ChangeLog.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/ChangeLog.md new file mode 100644 index 0000000000..2f9175c98b --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/ChangeLog.md @@ -0,0 +1,2129 @@ +master +------ + +Enhancements + +- The `json_reader` and `csv_reader` constructors have been generalized to take either a value +from which a `jsoncons::string_view` is constructible (e.g. std::string), or a value from which +a `source_type` is constructible (e.g. std::istream). + +- With this enhancement, the convenience typedefs `json_string_reader` and `csv_string_reader` are no +longer needed, and have been deprecated. + +Name change + +- The name `json_pull_reader` has been deprecated (still works) and renamed to `json_cursor` + +Changes to bigfloat mapping + +In previous versions, jsoncons arrays that contained + +- an int64_t or a uint64_t (defines base-2 exponent) +- an int64_t or a uint64_t or a string tagged with `semantic_tag::bigint` (defines the mantissa) + +and that were tagged with `semantic_tag::bigfloat`, were encoded into CBOR bigfloats. +This behaviour has been deprecated. + +CBOR bigfloats are now decoded into a jsoncons string that consists of the following parts + +- (optional) minus sign +- 0x +- nonempty sequence of hexadecimal digits (defines mantissa) +- p followed with optional minus or plus sign and nonempty sequence of hexadecimal digits (defines base-2 exponent) + +and tagged with `semantic_tag::bigfloat` (before they were decoded into a jsoncons array and tagged with `semantic_tag::bigfloat`) + +jsoncons strings that consist of the following parts + +- (optional) plus or minus sign +- 0x or 0X +- nonempty sequence of hexadecimal digits optionally containing a decimal-point character +- (optional) p or P followed with optional minus or plus sign and nonempty sequence of decimal digits, + +and tagged with `semantic_tag::bigfloat` are now encoded into CBOR bignums. + +v0.125.0 +-------- + +CMake build fix + +- The CMAKE_BUILD_TYPE variable is now left alone if already set + +Non-breaking changes to lighten `semantic_tag` names + +- The `semantic_tag` enum values `big_integer`, `big_decimal`, `big_float` and `date_time` + have been deprecated (still work) and renamed to `bigint`, `bigdec`, `bigfloat` and `datetime`. + +- The `json_content_handler` functions `big_integer_value`, `big_decimal_value`, `date_time_value` + and `timestamp_value` have been deprecated (still work.) Calls to these functions should be replaced + by calls to `string_value` with `semantic_tag::bigint`, `semantic_tag::bigdec`, and `semantic_tag::datetime`, + and by calls to `int64_vaue` with `semantic_tag::timestamp`. + +- The enum type `big_integer_chars_format` has been deprecated (still works) and renamed to + `bigint_chars_format`. + +- The `json_options` modifier `big_integer_format` has been deprecated (still works) and renamed to + `bigint_format`. + +Non-breaking changes to `ser_context`, `ser_error` and `jsonpath_error` + +- The function names `line_number` and `column_number` have been deprecated (still work) and + renamed to `line` and `column`. + +v0.124.0 +-------- + +- Fixed bug in `json_encoder` with `pad_inside_array_brackets` and `pad_inside_object_braces` options + +- Fixed issue with escape character in jsonpath quoted names. + +- Fixed pedantic level compiler warnings + +- Added doozer tests for CentOS 7.6 and Fedora release 24 + +- New macro `JSONCONS_GETTER_CTOR_TRAITS_DECL` that can be used to generate the `json_type_traits` boilerplate +from getter functions and a constructor. + +v0.123.2 +-------- + +defect fix: + +- Fixed name of JSONCONS_MEMBER_TRAITS_DECL + +v0.123.1 +-------- + +jsonpath bug fixes: + +- Fixed bug in construction of normalized paths [#177](https://github.com/danielaparker/jsoncons/issues/177). + +- Fixed bug in jsonpath recursive descent with filters which could result in too many values being returned + +v0.123.0 +-------- + +Warning fix: + +- Removed redundant macro continuation character [#176](https://github.com/danielaparker/jsoncons/pull/176) + +Non-breaking change to names (old name still works) + +- The name JSONCONS_TYPE_TRAITS_DECL has been deprecated and changed to JSONCONS_MEMBER_TRAITS_DECL + +Changes to jsonpath: + +- jsonpath unions now return distinct values (no duplicates) +- a single dot immediately followed by a left bracket now results in an error (illegal JSONPath) + +Enhancements to jsonpath + +- Union of completely separate paths are allowed, e.g. + + $[firstName,address.city] + +- Names in the dot notation may be single or double quoted + +Other enhancements: + +- `basic_json` now supports operators `<`, `<=`, `>`, `>=` + +v0.122.0 +-------- + +Changes: + +- The template parameter `CharT` has been removed from the binary encoders + `basic_bson_encoder`, `basic_cbor_encoder`, `basic_msgpack_encoder`, + and `basic_ubjson_encoder`. + +Enhancements: + +- Added macro JSONCONS_TYPE_TRAITS_FRIEND + +- Generalized the `csv_encode`, `bson_encode`, `cbor_encode`, `msgpack_encode` and `ubjson_encode` functions to convert from any type T that implements `json_type_traits` + +- Generalized the `csv_decode`, `bson_decode`, `cbor_decode`, `msgpack_decode` and `ubjson_decode` functions to convert to any type T that implements `json_type_traits` + +v0.121.1 +-------- + +Bug fix: + +- Fixed issue with cbor_reader only reading tag values 0 through 23 + +Name change + +- The name `json::semantic_tag()` has been renamed to `json::get_semantic_tag()` + +Non-breaking changes (old names still work) + +- The name `semantic_tag_type` has been deprecated and renamed to `semantic_tag` +- The names `json_serializer`, `bson_serializer`, `cbor_serializer`, `csv_serializer`, `msgpack_serializer`, + and `ubjson_serializer` have been deprecated and renamed to `json_encoder`, `bson_encoder`, + `cbor_encoder`, `csv_encoder`, `msgpack_encoder`, and `ubjson_encoder` +- The names `bson_buffer_serializer`, `cbor_buffer_serializer`, `msgpack_buffer_serializer`, + and `ubjson_buffer_serializer` have been deprecated and renamed to `bson_bytes_encoder`, + `cbor_bytes_encoder`, `msgpack_bytes_encoder`, and `ubjson_bytes_encoder` +- The names `bson_buffer_reader`, `cbor_buffer_reader`, `msgpack_buffer_reader`, + and `ubjson_buffer_reader` have been deprecated and renamed to `bson_bytes_reader`, + `cbor_bytes_reader`, `msgpack_bytes_reader`, and `ubjson_bytes_reader` + +Enhancements + +- Cleanup of `encode_json` and `decode_json` functions and increased test coverage +- Rewrote cbor_reader to avoid recursive function call +- CBOR reader supports [stringref extension to CBOR](http://cbor.schmorp.de/stringref) +- New `cbor_options` has `packed_strings` option + +v0.120.0 +-------- + +Bug fix: + +- Fixed issue with `j.as()` + +Non-breaking changes + +- The name `is_json_type_traits_impl` has been deprecated and renamed to `is_json_type_traits_declared` +- The name `serializing_context` has been deprecated and renamed to `ser_context` +- The name `serialization_error` has been deprecated and renamed to `ser_error` + +Enhancements + +- json `as_byte_string` attempts to decode string values if `semantic_tag_type` is `base64`, `base64url`, or `base16`. + +- New macro `JSONCONS_TYPE_TRAITS_DECL` that can be used to generate the `json_type_traits` boilerplate +for your own types. + +- New `basic_json` member function `get_allocator` + +v0.119.1 +-------- + +Bug fix: + +Fixed issue wjson dump() not formatting booleans correctly #174 + +v0.119.0 +-------- + +Name change: + +- The name `json_staj_reader` has been deprecated and renamed to `json_pull_reader` + +Bug fix: + +- Fixed a bug in json function `empty()` when type is `byte_string`. +- Fixed a bug with preserving semantic_tag_type when copying json values of long string type. + +Changes: + +- Removed deprecated feature `cbor_view` + +- CBOR decimal fraction and bigfloat string formatting now consistent with double string formatting + +Enhancements: + +- json `to_string()` and `to_double()` now work with CBOR bigfloat + +- JSONPath operators in filter expressions now work with `big_integer`, `big_decimal`, and `big_float` + tagged json values + +- json `is_number()` function now returns `true` if string value is tagged with `big_integer` or + `big_decimal`, or if array value is tagged with `big_float`. + +- json `as_string()` function now converts arrays tagged with `big_float` to decimal strings + +- json `as_double()` function now converts arrays tagged with `big_float` to double values + +v0.118.0 +-------- + +New features + +- New csv option `lossless_number`. If set to `true`, parse numbers with exponent and fractional parts as strings with + semantic tagging `semantic_tag_type::big_decimal` (instead of double.) Defaults to `false`. + +- A class `jsonpointer::address` has been introduced to make it simpler to construct JSON Pointer addresses + +Name change + +- The `json_options` name `dec_to_str` has been deprecated and renamed to `lossless_number`. + +v0.117.0 +-------- + +Deprecated features: + +- cbor_view has been deprecated. Rationale: The complexity of supporting and documenting this component + exceeded its benefits. + +New features + +- New `json_options` option `dec_to_str`. If set to `true`, parse decimal numbers as strings with + semantic tagging `semantic_tag_type::big_decimal` instead of double. Defaults to `false`. + +- The `ojson` (order preserving) implementation now has an index to support binary search + for retrieval. + +- Added `std::string_view` detection + +- jsoncons-CBOR semantic tagging supported for CBOR tags 32 (uri) + +Name changes (non-breaking) + +- The json options name `bignum_chars_format` has been deprecated and replaced with `big_integer_chars_format`. +- `big_integer_chars_format::integer` (`bignum_chars_format::integer`) has been deprecated and replaced with + `big_integer_chars_format::number` +- The `json_options function` `bignum_format` has been deprecated and replaced with `big_integer_format` + +Changes to floating-point printing + +- If the platform supports the IEEE 754 standard, jsoncons now uses the Grisu3 algorithm for printing floating-point numbers, + falling back to a safe method using C library functions for the estimated 0.5% of floating-point numbers that might be rejected by Grisu3. + The Grisu3 implementation follows Florian Loitsch's [grisu3_59_56](https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf) + implementation. If the platform does not support the IEEE 754 standard, the fall back method is used. + +- In previous versions, jsoncons preserved information about the format, precision, and decimal places + of the floating-point numbers that it read, and used that information when printing them. With the + current strategy, that information is no longer needed. Consequently, the `floating_point_options` + parameter in the `do_double_value` and `double_value` functions of the SAX-style interface have + been removed. + +- The `json` functions `precision()` and `decimal_places()` have been deprecated and return 0 + (as this information is no longer preserved.) + +- The constructor `json(double val, uint8_t precision)` has been deprecated. + +- Note that it is still possible to set precision as a json option when serializing. + +v0.116.0 +-------- + +New features: + +- New jsonpath functions `keys` and `tokenize`. + +- jsoncons-CBOR data item mappings supported for CBOR tags 33 (string base64url) and 34 (string base64) + +v0.115.0 +-------- + +New features: + +- bson UTC datetime associated with jsoncons `semantic_tag_type::timestamp` + +- New traits class `is_json_type_traits_impl` that addresses issues + [#133](https://github.com/danielaparker/jsoncons/issues/133) and + [#115](https://github.com/danielaparker/jsoncons/issues/115) (duplicates) + +- Following a proposal from soberich, jsonpath functions on JSONPath expressions + are no longer restricted to filter expressions. + +- New jsonpath functions `sum`, `count`, `avg`, and `prod` + +- Added `semantic_tag_type::base16`, `semantic_tag_type::base64`, `semantic_tag_type::base64url` + +Non-breaking changes: + +- The json constructor that takes a `byte_string` and a `byte_string_chars_format` + has been deprecated, use a `semantic_tag_type` to supply an encoding hint for a byte string, if any. + +- The content handler `byte_string_value` function that takes a `byte_string` and a `byte_string_chars_format` + has been deprecated, use a `semantic_tag_type` to supply an encoding hint for a byte string, if any. + +Changes: + +- The `byte_string_chars_format` parameter in the content handler `do_byte_string_value` function + has been removed, the `semantic_tag_type` parameter is now used to supply an encoding hint for a byte string, if any. + +v0.114.0 +-------- + +Bug fixes: + +- On Windows platforms, fixed issue with macro expansion of max when + including windows.h (also in 0.113.1) + +- Fixed compile issue with `j = json::make_array()` (also in 0.113.2) + +Breaking changes to jsoncons semantic tag type names: + +- semantic_tag_type::bignum to semantic_tag_type::big_integer +- semantic_tag_type::decimal_fraction to semantic_tag_type::big_decimal +- semantic_tag_type::epoch_time to semantic_tag_type::timestamp + +Non-breaking name changes: + +The following names have been deprecated and renamed (old names still work) + +- `bignum_value` to `big_integer_value` in `json_content_handler` +- `decimal_value` to `big_decimal_value` in `json_content_handler` +- `epoch_time_value` to `timestamp_value` in `json_content_handler` + +- `cbor_bytes_serializer` to `cbor_buffer_serializer` +- `msgpack_bytes_serializer` to `msgpack_buffer_serializer` + +- `json_serializing_options` to `json_options` +- `csv_serializing_options` to `csv_options` + +- `parse_error` to `serialization_error` + +The rationale for renaming `parse_error` to `serialization_error` +is that we need to use error category codes for serializer +errors as well as parser errors, so we need a more general name +for the exception type. + +Message Pack enhancements + +- New `msgpack_serializer` that supports Message Pack bin formats + +- New `msgpack_parser` that supports Message Pack bin formats + +- `encode_msgpack` and `decode_msgpack` have been + rewritten using `msgpack_serializer` and `msgpack_parser`, + and also now support bin formats. + +New features: + +- decode from and encode to the [Universal Binary JSON Specification (ubjson)](http://bsonspec.org/) data format +- decode from and encode to the [Binary JSON (bson)](http://bsonspec.org/) data format + +- The cbor, msgpack and ubjson streaming serializers now validate that the expected number of + items have been supplied in an object or array of pre-determined length. + +version 0.113.0 +--------------- + +Bug fix + +- Fixed issue with indefinite length byte strings, text strings, arrays, + and maps nested inside other CBOR items (wasn't advancing the + input pointer past the "break" indicator.) + +Changes + +- __FILE__ and __LINE__ macros removed from JSONCONS_ASSERT + if not defined _DEBUG (contributed by zhskyy.) + +- semantic_tag_type name `decimal` changed to `decimal_fraction` + +New CBOR feature + +- CBOR semantic tagging of expected conversion of byte strings + to base64, base64url and base16 are preserved and respected in JSON + serialization (unless overridden in `json_serializing_options`.) + +- CBOR semantic tagging of bigfloat preserved with `semantic_tag_type::bigfloat` + +- CBOR non text string keys converted to strings when decoding + to json values + +Changes to `json_serializing_options` + +New options + +- spaces_around_colon (defaults to `space_after`) +- spaces_around_comma (defaults to `space_after`) +- pad_inside_object_braces (defaults to `false`) +- pad_inside_array_brackets (defaults to `false`) +- line_length_limit (defaults to '120`) +- new_line_chars (for json serialization, defaults to `\n`) + +`nan_replacement`, `pos_inf_replacement`, and `neg_inf_replacement` are deprecated (still work) +These have been replaced by + +- nan_to_num/nan_to_str +- inf_to_num/inf_to_str +- neginf_to_num/neginf_to_str (default is `-` followed by inf_to_num/inf_to_str) + +`nan_to_str`, `inf_to_str` and `neginf_to_str` are also used to substitute back to `nan`, `inf` and `neginf` in the parser. + +- Long since deprecated options `array_array_block_option`, + `array_object_block_option`, `object_object_block_option` and + `object_array_block_option` have been removed. + +- The names `object_array_split_lines`, `object_object_split_lines`, + `array_array_split_lines` and `array_object_split_lines` have + been deprecated (still work) and renamed to `object_array_line_splits`, + `object_object_line_splits`, `array_array_line_splits` and `array_object_line_splits`. + Rationale: consistency with `line_split_kind` name. + +Changes to json_serializer + +- Previously the constructor of `json_serializer` took an optional argument to + indicate whether "indenting" was on. `json_serializer` now always produces + indented output, so this argument has been removed. + +- A new class `json_compressed_serializer` produces compressed json without + indenting. + + The jsoncons functions that perform serialization including `json::dump`, + `pretty_print` and the output stream operator are unaffected. + +v0.112.0 +-------- + +Changes to `json_content_handler` + +- The function `byte_string_value` no longer supports passing a byte string as + + handler.byte_string_value({'b','a','r'}); + +(shown in some of the examples.) Instead use + + handler.byte_string_value(byte_string({'b','a','r'})); + +(or a pointer to utf8_t data and a size.) + +- The function `bignum_value` no longer supports passing a CBOR signum and + byte string, `bignum_value` now accepts only a string view. If you + have a CBOR signum and byte string, you can use the bignum class to + convert it into a string. + +Name changes (non breaking) + +- The name `json_stream_reader` has been deprecated and replaced with `json_staj_reader`. +- The name `stream_event_type` has been deprecated and replaced with `staj_event_type` +- The names `basic_stream_event` (`stream_event`) have been deprecated and replaced with `basic_staj_event` (`staj_event`) +- The names `basic_stream_filter` (`stream_filter`) have been deprecated and replaced with `basic_staj_filter` (`staj_filter`) +(staj stands for "streaming API for JSON, analagous to StAX in XML) + +- The `json_parser` function `end_parse` has been deprecated and replaced with `finish_parse`. + +Enhancements + +- json double values convert to CBOR float if double to float + round trips. + +- csv_parser `ignore_empty_values` option now applies to + `m_columns` style json output. + +- json_reader and json_staj_reader can be initialized with strings + in addition to streams. + +Extension of semantic tags to other values + + - The `json_content_handler` functions `do_null_value`, `do_bool_value`, + `do_begin_array` and `do_begin_object` have been given the + semantic_tag_type parameter. + + - New tag type `semantic_tag_type::undefined` has been added + + - The `cbor_parser` encodes a CBOR undefined tag to a json null + value with a `semantic_tag_type::undefined` tag, and the + `cbor_serializer` maps that combination back to a CBOR undefined tag. + +Removed: + +- Long since deprecated `value()` functions have been removed from `json_content_handler` + +v0.111.1 +-------- + +Enhancements + +- Improved efficiency of json_decoder + +- Improved efficiency of json_proxy + +- Conversion of CBOR decimal fraction to string uses exponential + notation if exponent is positive or if the exponent plus the + number of digits in the mantissa is negative. + +Bug fix + +- Fixed issue with conversion of CBOR decimal fraction to string + when mantissa is negative + +v0.111.0 +-------- + +Bug and warning fixes: + +- A case where the json parser performed validation on a string + before all bytes of the string had been read, and failed if + missing part of a multi-byte byte sequence, is fixed. + +- An issue with reading a bignum with the pull parser +`json_stream_reader` (in the case that an integer value +overflows) has been fixed. + +- GCC and clang warnings about switch fall through have + been fixed + +Non-breaking changes: + +- The functions `json::has_key` and `cbor::has_key` have been + deprecated (but still work) and renamed to `json::contains` + and `cbor::contains`. Rationale: consistency with C++ 20 + associative map `contains` function. + +- The json function `as_integer()` is now a template function, + +```c++ +template +T as_integer(); +``` + +where T can be any integral type, signed or unsigned. The +default parameter is for backwards compatability, but is +a depreated feature, and may be removed in a future version. +Prefer j.as(). + +- The json functions `is_integer()` and `is_uinteger()` +have been deprecated and renamed to `is_int64()`, `is_uint64()`. +Prefer j.is() and j.is(). + +- The json function `as_uinteger()` has been deprecated. +Prefer j.as(). + +and `as_uinteger()` have been deprecated and renamed to +`is_int64()`, `is_uint64()`, `as_int64()` and `as_uint64()`. + +Change to pull parser API: + +- The `stream_filter` function `accept` has been changed to + take a `const stream_event&` and a `const serializing_context&`. + +- `stream_event_type::bignum_value` has been removed. `stream_event` + now exposes information about optional semantic tagging through + the `semantic_tag()` function. + +Enhancements: + +- `j.as()` has been enhanced to return a bignum value +if j is an integer, floating point value, or any string that +contains an optional minus sign character followed by a sequence +of digits. + +- `j.as()` has been enhanced to support extended integer +types that have `std::numeric_limits` specializations. In particular, +it supports GCC `__int128` and `unsigned __int128` when code is +compiled with `std=gnu++NN`, allowing a `bignum` to be returned as +an `__int128` or `unsigned __int128`. (when code is compiled with +`-std=c++NN`, `__int128` and `unsigned __int128` do not have +`std::numeric_limits` specializations.) + +New feature: + +This release accomodate the additional semantics for the +CBOR data items date-time (a string), and epoch time (a positive or +negative integer or floating point value), and decimal fraction +(converted in the jsoncons data model to a string). + +But first, some of the virtual functions in `json_content_handler` +have to be modified to preserve these semantics. Consequently, +the function signatures + + bool do_int64_value(int64_t, const serializing_context&) + + bool do_uint64_value(uint64_t, const serializing_context&) + + bool do_double_value(double, const floating_point_options&, const serializing_context&) + + bool do_string_value(const string_view_type&, const serializing_context&) + + bool do_byte_string_value(const uint8_t*, size_t, const serializing_context&) + +have been given an additonal parameter, a `semantic_tag_type`, + + bool do_int64_value(int64_t, semantic_tag_type, const serializing_context&) + + bool do_uint64_value(uint64_t, semantic_tag_type, const serializing_context&) + + bool do_double_value(double, const floating_point_options&, semantic_tag_type, const serializing_context&) + + bool do_string_value(const string_view_type&, semantic_tag_type, const serializing_context&) + + bool do_byte_string_value(const uint8_t*, size_t, semantic_tag_type, const serializing_context&) + +For consistency, the virtual function + + bool do_bignum_value(const string_view_type&, const serializing_context&) + +has been removed, and in its place `do_string_value` will be called +with semantic_tag_type::bignum_type. + +For users who have written classes that implement all or part of +`json_content_handler`, including extensions to `json_filter`, +these are breaking changes. But otherwise users should be unaffected. + +v0.110.2 +-------- + +Continuous integration: + +- jsoncons is now cross compiled for ARMv8-A architecture on Travis using + clang and executed using the emulator qemu. + +- UndefinedBehaviorSanitizer (UBSan) is enabled for selected gcc and clang builds. + +Maintenance: + +- Removed compiler warnings + +v0.110.1 +-------- + +Bug fixes contributed by Cebtenzzre + +- Fixed a case where `as_double()`, `as_integer()` etc on a `basic_json` + value led to an infinite recursion when the value was a bignum + +- Fixed undefined behavior in bignum class + +v0.110.0 +-------- + +### New features + +- A JSON pull parser, `json_stream_reader`, has been added. This + required a change to the `json_content_handler` function signatures, + the return values has been changed to bool, to indicate whether + parsing is to continue. (An earlier version on master was + called `json_event_reader`.) + +- `json_parser` has new member function `stopped()`. + +- The `json::is` function now supports `is()`, + and if your compiler has `std::string_view`, `is()` + as well. It returns `true` if the json value is a string, otherwise + `false`. + +- The `json::as` function now supports `as()`, + and if your compiler has `std::string_view`, `as()` + as well. + +### Changes to `json_content_handler` and related streaming classes + +#### Non-breaking changes + +These changes apply to users that call the public functions defined by +`json_content_handler`, e.g. begin_object, end_object, etc., but are +non-breaking because the old function signatures, while deprecated, +have been preserved. Going forward, however, users should remove +calls to `begin_document`, replace `end_document` with `flush`, +and replace `integer_value` and `end_integer_value` with `int64_value` +and `uint64_value`. + +- The public functions defined by `json_content_handler` have been changed + to return a bool value, to indicate whether parsing is to continue. + +- The function names `integer_value` and `uinteger_value` have been + changed to `int64_value` and `uint64_value`. + +- The function names `begin_document` and `end_document` have been + deprecated. The deprecated `begin_document` does nothing, and the + deprecated `end_document` calls `do_flush`. + +- The function `flush` has been added, which calls `do_flush`. + +- The `json` member function `dump_fragment` has been deprecated, as with + the dropping of `begin_document` and `end_document`, it is now + equivalent to `dump`. + +- The function `encode_fragment` has been deprecated, as with + the dropping of `begin_document` and `end_document`, it is now + equivalent to `encode_json`. + +- The `json_filter` member function `downstream_handler` has been + renamed to `destination_handler`. + +#### Breaking changes + +These changes will affect users who have written classes that implement +all or part of `json_content_handler`, including extensions to `json_filter`. + +- The virtual functions defined for `json_content_handler`, `do_begin_object`, + `do_end_object`, etc. have been changed to return a bool value, to indicate + whether serializing or deserializing is to continue. + +- The virtual functions `do_begin_document` and `do_end_document` have been removed. + A virtual function `do_flush` has been added to allow producers of json events to + flush whatever they've buffered. + +- The function names `do_integer_value` and `do_uinteger_value` have been changed to + `do_int64_value` and `do_uint64_value`. + +- The signature of `do_bignum_value` has been changed to +``` + bool do_bignum_value(const string_view_type& value, + const serializing_context& context) +``` + +v0.109.0 +-------- + +Enhancements + +- Added byte string formatting option `byte_string_chars_format::base16` + +Changes + +- Scons dropped as a build system for tests and examples, use CMake + +- Tests no longer depend on boost, boost test framework replaced by Catch2. + boost code in tests moved to `examples_boost` directory. + +- Previously, if `json_parser` encountered an unopened object or array, e.g. "1]", + this would cause a JSONCONS_ASSERT failure, resulting in an `std::runtime_error`. This has been + changed to cause a `json_parse_errc::unexpected_right_brace` or `json_parse_errc::unexpected_right_bracket` error code. + +Warning fixes + +- Eliminated vs2017 level 3 and level 4 warnings + +v0.108.0 +-------- + +Enhancements + +- `bignum_chars_format::base64` is supported + +- The incremental parser `json_parser` has been documented + +Changes (non-breaking) + +- Previously, jsonpointer::get returned values (copies) + Now, jsonpointer::get returns references if applied to `basic_json`, and values if applied to `cbor_view` + +- `bignum_chars_format::string` has been deprecated (still works) and replaced with `bignum_chars_format::base10` + +- `json_parser_errc`, `cbor_parser_errc`, and `csv_parser_errc` have been deprecated (still work) and renamed to + `json_parse_errc`, `cbor_parse_errc`, and `csv_parse_errc` + +v0.107.2 +-------- + +Bug fixes: + +- Fixed issue with `UINT_MAX` not declared in `bignum.hpp` + +v0.107.1 +-------- + +Bug fixes: + +- Fixed issue with cbor_view iterators over indefinite length arrays and maps + +Enhancements: + +- csv_serializer recognizes byte strings and bignums. + +v0.107.0 +-------- + +Enhancements + +- Support for CBOR bignums +- Added json serializing options for formatting CBOR bignums as integer, string, or base64url encoded byte string +- Added json serializing options for formatting CBOR bytes strings as base64 or base64url +- Enhanced interface for `cbor_view` including `dump`, `is`, and `as` functions + +Changes + +- If the json parser encounters an integer overflow, the value is now handled as a bignum rather than a double value. + +- The `json_content_handler` names `begin_json` and `end_json` have been + deprecated and replaced with `begin_document` and `end_document`, and the + names `do_begin_json` and `do_end_json` have been removed and replaced with + `do_begin_document`, and `do_end_document`. + Rationale: meaningfullness across JSON and other data formats including + CBOR. + +Bug fixes: + +- Fixed bug in base64url encoding of CBOR byte strings +- Fixed bug in parsing indefinite length CBOR arrays and maps + +v0.106.0 +-------- + +Changes + +- If a fractional number is read in in fixed format, serialization now preserves + that fixed format, e.g. if 0.000071 is read in, serialization gives 0.000071 + and not 7.1e-05. In previous versions, the floating point format, whether + fixed or scientific, was determined by the behavior of snprintf using the g + conversion specifier. + +Bug fix: + +- Fixed issue with parsing cbor indefinite length arrays and maps + +Warning fix: + +- Use memcpy in place of reinterpret_cast in binary data format utility + `from_big_endian` + +Compiler fix: + +- Fixed issues with g++ 4.8 + +v0.105.0 +-------- + +Enhancements + +- The CSV extension now supports multi-valued fields separated by subfield delimiters + +- New functions `decode_json` and `encode_json` convert JSON + formatted strings to C++ objects and back. These functions attempt to + perform the conversion by streaming using `json_convert_traits`, and if + streaming is not supported, fall back to using `json_type_traits`. `decode_json` + and `encode_json` will work for all types that have `json_type_traits` defined. + +- The json::parse functions and the json_parser and json_reader constructors + optionally take a json_serializing_options parameter, which allows replacing + a string that matches nan_replacement(), pos_inf_replacement(), and neg_inf_replacement(). + +Changes to Streaming + +- The `basic_json_input_handler` and `basic_json_output_handler` interfaces have been + combined into one class `basic_json_content_handler`. This greatly simplifies the + implementation of `basic_json_filter`. Also, the name `parsing_context` has been + deprecated and renamed to `serializing_context`, as it now applies to both + serializing and deserializing. + + If you have subclassed `json_filter` or have fed JSON events directlty to a + `json_serializer`, you shouldn't have to make any changes. In the less likely + case that you've implemented the `basic_json_input_handler` or + `basic_json_output_handler` interfaces, you'll need to change that to + `json_content_handler`. + +Other Changes + +- `serialization_traits` and the related `dump` free functions have been deprecated, + as their functionality has been subsumed by `json_convert_traits` and the + `encode_json` functions. + +- The option bool argument to indicate pretty printing in the `json` `dump` functions + and the `json_serializer` class has been deprecated. It is replaced by the enum class + `indenting` with enumerators `indenting::no_indent` and `indenting::indent`. + +- The name `serialization_options` has been deprecated (still works) and renamed to + `json_serializing_options`. Rationale: naming consistency. + +- The `json_reader` `max_nesting_depth` getter and setter functions have been deprecated. + Use the `json_serializing_options` `max_nesting_depth` getter and setter functions instead. + +- The name `csv_parameters` has been deprecated (still works) and renamed to + `csv_serializing_options`. Rationale: naming consistency. + +v0.104.0 +-------- + +Changes + +- `decode_csv` by default now attempts to infer null, true, false, integer and floating point values + in the CSV source. In previous versions the default was to read everything as strings, + and other types had to be specified explicitly. If the new default behavior is not desired, the + `csv_parameters` option `infer_types` can be set to `false`. Column types can still be set explicitly + if desired. + +v0.103.0 +-------- + +Changes + +- Default `string_view_type` `operator std::basic_string() const` made explicit + to be consistent with `std::string_view` + +- The virtual method `do_double_value` of `json_input_handler` and `json_output_handler` takes a `number_format` parameter + +Performance improvements + +- Faster json dump to string (avoids streams) +- Faster floating point conversions for linux and MacOSX +- Memory allocation decoding larger string values reduced by half +- Optimization to json_parser parse_string +- Improvements to json_decoder + +v0.102.1 +-------- + +Bug fix: + +Fixed an off-by-one error that could lead to an out of bounds read. Reported by mickcollyer (issue #145) + +v0.102.0 +-------- + +Bug fixes: + +Fixed issue with how jsonpath filters are applied to arrays in the presence of recursion, resulting in +duplicate results. + +Changes: + +The signatures of `jsonpointer::get`, `jsonpointer::insert`, `jsonpointer::insert_or_assign`, +`jsonpointer::remove` and `jsonpointer::replace` have been changed to be consistent +with other functions in the jsoncons library. Each of these functions now has two overloads, +one that takes an `std::error_code` parameter and uses it to report errors, and one that +throws a `jsonpointer_error` exception to report errors. + +The function `jsonpatch::patch` has been replaced by `jsonpatch::apply_patch`, which takes +a json document, a patch, and a `std::error_code&` to report errors. The function +`jsonpatch::diff` has been renamed to `jsonpatch::from_diff` + +The old signatures for `encode_cbor` and `encode_msgpack` that returned a `std::vector` +have been deprecated and replaced by new signatures that have void return values and have +an output parameter 'std::vector&'. The rationale for this change is consistency +with other functions in the jsoncons library. + +v0.101.0 +-------- + +Fixes: + +- Fixes to `string_view` code when `JSONCONS_HAS_STRING_VIEW` is defined in `jsoncons_config.hpp` + +Changes: + +- `as_double` throws if `json` value is null (previously returned NaN) + +Enhancements: + +- Added convenience functions `decode_csv` and `encode_csv` +- Support custom allocaor (currently stateless only) in `json_decoder`, `json_reader`, + `csv_reader`, `csv_parameters` + +v0.100.2 +------- + +Resolved warnings on GCC Issue #127 + +v0.100.1 +------- + +Fix for platform issue with vs2017: + +- Renamed label `minus` to `minus_sign` in `json_parser.hpp` + +Enhancements: + +- New classes `byte_string` and `byte_string_view`, to augment support for cbor byte strings in `json` values + +v0.100.0 +------- + +Changes: + +- `template json_traits` replaced with `sorted_policy` +- `template o_json_traits` replaced with `preserve_order_policy` + +- The return type for the json::get_with_default function overload for `const char*` has been + changed from `const char*` to `json::string_view_type`, which is assignable to `std::string`. + +- New functions `byte_string_value` and `do_byte_string_value` have been added to + `basic_json_input_handler` and `basic_json_output_handler` + +- json::is() and json::as() specializations (supported but never + documented) have been deprecated + +- In android specific `string_to_double`, `strtod_l` changed to `strtold_l` + +Enhancements: + +- The `json` class and the `decode_cbor` and `encode_cbor` functions now support byte strings + A `json` byte string value will, when serialized to JSON, be converted to a base64url string. + +- `version.hpp` added to `include` directory + +v0.99.9.2 +-------- + +Bug fixes: + +- Fixed issue with jsonpatch::diff (fix contributed by Alexander (rog13)) + +Enhancements: + +- New class `cbor_view` for accessing packed `cbor` values. A `cbor_view` satisfies the requirements for `jsonpointer::get`. + +Changes (non breaking) +---------------------- + +- `jsonpointer::erase` renamed to `jsonpointer::remove`, old name deprecated + +v0.99.9.1 +-------- + +New features +------------ + +- JSON Pointer implementation + +- JSON Patch implementation, includes patch and diff + +- `json::insert` function for array that inserts values from range [first, last) before pos. + +Bug fixes + +- Fixed issue with serialization of json array of objects to csv file + +Changes (non breaking) +---------------------- + +- The member function name `json::dump_body` has been deprecated and replaced with `json::dump_fragment`. +- The non member function name `dump_body` has been deprecated and replaced with `dump_fragment`. + +- The class name `rename_name_filter` has been deprecated and replaced with `rename_object_member_filter`. + +- In the documentation and examples, the existing function `json::insert_or_assign` + is now used instead of the still-supported `json::set`. The reason is that + `insert_or_assign` follows the naming convention of the C++ standard library. + +Changes +------- + +- The recently introduced class `json_stream_traits` has been renamed to `serialization_traits` + +- Removed template parameter `CharT` from class `basic_parsing_context` and renamed it to `parsing_context` + +- Removed template parameter `CharT` from class `basic_parse_error_handler` and renamed it to `parse_error_handler` + +v0.99.8.2 +-------- + +New features + +- Added `json` functions `push_back` and `insert` for appending values + to the end of a `json` array and inserting values at a specifed position + +Rationale: While these functions provide the same functionality as the existing +`json::add` function, they have the advantage of following the naming conventions +of the C++ library, and have been given prominence in the examples and documentation +(`add` is still supported.) + +v0.99.8.1 +-------- + +New features + +- cbor extension supports encoding to and decoding from the cbor binary serialization format. + +- `json_type_traits` supports `std::valarray` + +Documentation + +- Documentation is now in the repository itself. Please see the documentation + link in the README.md file + +Changed + +- Removed `CharT` template parameter from `json_stream_traits` + +v0.99.8 +------ + +Changes + +- Visual Studio 2013 is no longer supported (jsonpath uses string initilizer lists) + +- `json_input_handler` overloaded functions value(value,context)` have been deprecated. + Instead use `string_value(value,context)`, `integer_value(value,context)`, + `uinteger_value(value,context)`, `double_value(value,precision,context)`, + `bool_value(value,context)` and `null_value(context)` + +- `json_output_handler` overloaded functions value(value)` have been deprecated. + Instead use `string_value(value)`, `integer_value(value)`, `uinteger_value(value)`, + `double_value(value,precision=0)`, `bool_value(value)` and `null_value(context)` + +- For consistency, the names `jsoncons_ext/msgpack/message_pack.hpp`, + `encode_message_pack` and `decode_message_pack` have been deprecated and + replaced with `jsoncons_ext/msgpack/msgpack.hpp`, `encode_msgpack` and `decode_msg_pack` + +Bug fixes + +- Fixed operator== throws when comparing a string against an empty object + +- Fixed jsonpath issue with array 'length' (a.length worked but not a['length']) + +- `msgpack` extension uses intrinsics for determing whether to swap bytes + +New features + +- Stream supported C++ values directly to JSON output, governed by `json_stream_traits` + +- json::is() and json::as() accept template packs, which they forward to the + `json_type_traits` `is` and `as` functions. This allows user defined `json_type_traits` + implementations to resolve, for instance, a name into a C++ object looked up from a + registry. See [Type Extensibility](https://github.com/danielaparker/jsoncons), Example 2. + +- jsonpath `json_query` now supports returning normalized paths (with + optional `return_type::path` parameter) + +- New jsonpath `max` and `min` aggregate functions over numeric values + +- New `json::merge` function that inserts another json object's key-value pairs + into a json object, if they don't already exist. + +- New `json::merge_or_update` function that inserts another json object's key-value + pairs into a json object, or assigns them if they already exist. + +v0.99.7.3 +-------- + +- `json_type_traits` supports `std::pair` (convert to/from json array of size 2) + +- `parse_stream` renamed to `parse` (backwards compatible) + +- `kvp_type` renamed to `key_value_pair_type` (backwards compatible) + +- The `_json` and `_ojson` literal operators have been moved to the namespace `jsoncons::literals`. + Access to these literals now requires +```c++ + using namespace jsoncons::literals; +``` +Rationale: avoid name clashes with other `json` libraries + +- The name `owjson` has been deprecated (still works) and changed to `wojson`. Rationale: naming consistency + +- Added json array functions `emplace_back` and `emplace`, and json object functions `try_emplace` + and `insert_or_assign`, which are analagous to the standard library vector and map functions. + +v0.99.7.2 +-------- + +Bug fix + +- A bug was introduced in v0.99.7 causing the values of existing object members to not be changed wiht set or assignment operations. This has been fixed. + +Change + +- jsoncons_ext/binary changed to jsoncons_ext/msgpack +- namespace jsoncons::binary changed to jsoncons::msgpack + +v0.99.7.1 +-------- + +- Workarounds in unicode_traits and jsonpath to maintain support for vs2013 +- Added `mapping_type::n_rows`, `mapping_type::n_objects`, and `mapping_type::m_columns` options for csv to json + +v0.99.7 +------ + +Bug fixes + +- Issues with precedence in JsonPath filter evaluations have been fixed +- An issue with (a - expression) in JsonPath filter evaluations has been fixed + +New feature + +- The new binary extension supports encoding to and decoding from the MessagePack binary serialization format. +- An extension to JsonPath to allow filter expressions over a single object. +- Added support for `*` and `/` operators to jsonpath filter +- literal operators _json and _ojson have been introduced + +Non-breaking changes + +- The `json` `write` functions have been renamed to `dump`. The old names have been deprecated but still work. +- Support for stateful allocators +- json function object_range() now returns a pair of RandomAccessIterator (previously BidirectionalIterator) +- json operator [size_t i] applied to a json object now returns the ith object (previously threw) + +Breaking change (if you've implemented your own input and output handlers) + +In basic_json_input_handler, the virtual functions +```c++ +virtual void do_name(const CharT* value, size_t length, + const basic_parsing_context& context) + +virtual void do_string_value(const CharT* value, size_t length, + const basic_parsing_context& context) +``` +have been changed to +```c++ +virtual void do_name(string_view_type val, + const basic_parsing_context& context) + +virtual void do_string_value(string_view_type val, + const basic_parsing_context& context) +``` + +In basic_json_output_handler, the virtual functions +```c++ +virtual void do_name(const CharT* value, size_t length) + +virtual void do_string_value(const CharT* value, size_t length) +``` +have been changed to +```c++ +virtual void do_name(string_view_type val) + +virtual void do_string_value(string_view_type val) +``` + +Removed features: + +- The jsonx extension has been removed + +v0.99.5 +------ + +- Validations added to utf8 and utf16 string parsing to pass all [JSONTestSuite](https://github.com/nst/JSONTestSuite) tests +- The name `json_encoder` introduced in v0.99.4 has been changed to `json_decoder`. Rationale: consistencty with common usage (encoding and serialization, decoding and deserialization) + +v0.99.4a +------- + +Fixes Issue #101, In json.hpp, line 3376 change "char__type" to "char_type" +Fixes Issue #102, include cstring and json_error_category.hpp in json.hpp + +v0.99.4 +------ + +Changes + +- The deprecated class `json::any` has been removed. +- The jsoncons `boost` extension has been removed. That extension contained a sample `json_type_traits` specialization for `boost::gregorian::date`, which may still be found in the "Type Extensibility" tutorial. +- The member `json_type_traits` member function `assign` has been removed and replaced by `to_json`. if you have implemented your own type specializations, you will also have to change your `assign` function to `to_json`. +- `json_type_traits` specializations no longer require the `is_assignable` data member + +Non-breaking name changes + +- The names `json_deserializer`,`ojson_deserializer`,`wjson_deserializer`,`owjson_deserializer` have been deprecated (they still work) and replaced by `json_encoder`, `json_encoder`, `json_encoder` and `json_encoder`. +- The name `output_format` has been deprecated (still works) and renamed to `serialization_options`. +- The name `wojson` has been deprecated (still works) and renamed to `owjson`. +- The `json_filter` member function `input_handler` has been deprecated (still works) and renamed to `downstream_handler`. +- The name `elements` has been deprecated (still works) and renamed to `owjson`. +- The `json` member function `members()` has been deprecated (still works) and renamed to `object_range()`. +- The `json` member function `elements()` has been deprecated (still works) and renamed to `array_range()`. +- The `json` member_type function `name()` has been deprecated (still works) and renamed to `key()`. Rationale: consistency with more general underlying storage classes. + +New features + +- `json_filter` instances can be passed to functions that take a `json_output_handler` argument (previously only a `json_input_handler` argument) +- New `jsonpath` function `json_replace` that searches for all values that match a JsonPath expression and replaces them with a specified value. +- `json` class has new method `has_key()`, which returns `true` if a `json` value is an object and has a member with that key +- New filter class `rename_name` allows search and replace of JSON object names + +v0.99.3a +------- + +Changes + +The `json` initializer-list constructor has been removed, it gives inconsistent results when an initializer has zero elements, or one element of the type being initialized (`json`). Please replace + +`json j = {1,2,3}` with `json j = json::array{1,2,3}`, and + +`json j = {{1,2,3},{4,5,6}}` with `json j = json::array{json::array{1,2,3},json::array{4,5,6}}` + +- Initializer-list constructors are now supported in `json::object` as well as `json::array`, e.g. +```c++ +json j = json::object{{"first",1},{"second",json::array{1,2,3}}}; +``` + +- json::any has been deprecated and will be removed in the future + +- The json method `to_stream` has been renamed to `write`, the old name is still supported. + +- `output_format` `object_array_block_option`, `array_array_block_option` functions have been deprecated and replaced by + `object_array_split_lines`, `array_array_split_lines` functions. + +Enhancements + +- A new method `get_with_default`, with return type that of the default, has been added to `json` + +- A new template parameter, `JsonTraits`, has been added to the `basic_json` class template. + +- New instantiations of `basic_json`, `ojson` and `wojson`, have been added for users who wish to preserve the alphabetical sort of parsed json text and to insert new members in arbitrary name order. + +- Added support for `json` `is`, `as`, constructor, and assignment operator for any sequence container (`std::array`, `std::vector`, `std::deque`, `std::forward_list`, `std::list`) whose values are assignable to JSON types (e.g., ints, doubles, bools, strings, STL containers of same) and for associative containers (`std::set`, `std::multiset`, `std::unordered_set`, `std::unordered_multiset`.) + +- Added static method `null()` to `json` class to return null value + +- A new extension jsonx that supports serializing JSON values to [JSONx](http://www.ibm.com/support/knowledgecenter/SS9H2Y_7.5.0/com.ibm.dp.doc/json_jsonx.html) (XML) + +- json parser will skip `bom` in input if present + +Fixes: + +- Fixes to the `jsonpath` extension, including the union operator and applying index operations to string values + +- Fixes to remove warnings and issues reported by VS2015 with 4-th warnings level, PVS-Studio static analyzer tool, and UBSAN. + +v0.99.2 +------ + +- Included workaround for a C++11 issue in GCC 4.8, contributed by Alex Merry +- Fixed operator== so that json() == json(json::object()) +- Fixed issue with `json` assignment to initializer list +- Fixed issue with assignment to empty json object with multiple keys, e.g. + + json val; + val["key1"]["key2"] = 1; + +v0.99.1 +------ + +- Fix to json_filter class +- Fix to readme_examples + +v0.99 +---- + +- Fixes to deprecated json parse functions (deprecated, but still supposed to work) +- The Visual C++ specific implementation for reading floating point numbers should have freed a `_locale_t` object, fixed +- Added `json_type_traits` specialization to support assignment from non-const strings +- When parsing fractional numbers in text, floating point number precision is retained, and made available to serialization to preserve round-trip. The default output precision has been changed from 15 to 16. +- Added json `std::initializer_list` constructor for constructing arrays +- The deprecated json member constants null, an_object, and an_array have been removed +- Microsoft VC++ versions earlier than 2013 are no longer supported + +v0.98.4 +------ + +- Fixes issues with compilation with clang + +v0.98.3 +------ + +New features + +- Supports [Stefan Goessner's JsonPath](http://goessner.net/articles/JsonPath/). +- json member function `find` added +- json member function `count` added +- json array range accessor `elements()` added, which supports range-based for loops over json arrays, and replaces `begin_elements` and `end_elements` +- json object range accessor `members()` added, which supports range-based for loops over json objects, and replaces `begin_members` and `end_members` +- New version of json `add` member function that takes a parameter `array_iterator` +- json member function `shrink_to_fit` added + +API Changes + +- The json internal representation of signed and unsigned integers has been changed from `long long` and `unsigned long long` to `int64_t` and `uint64_t`. This should not impact you unless you've implemented your own `json_input_handler` or `json_output_handler`, in which case you'll need to change your `json_input_handler` function signatures + + void do_longlong_value(long long value, const basic_parsing_context& context) override + void do_ulonglong_integer_value(unsigned long long value, const basic_parsing_context& context) override + +to + + void do_integer_value(int64_t value, const basic_parsing_context& context) override + void do_uinteger_value(uint64_t value, const basic_parsing_context& context) override + +and your `json_output_handler` function signatures from + + void do_longlong_value(long long value) override + void do_ulonglong_integer_value(unsigned long long value) override + +to + + void do_integer_value(int64_t value) override + void do_uinteger_value(uint64_t value) override + +- `output_format` drops support for `floatfield` property + +Non-beaking API Changes +- remove_range has been deprecated, use erase(array_iterator first, array_iterator last) instead +- remove has been deprecated, use erase(const std::string& name ) instead +- `json::parse_string` has been renamed to `json::parse`, `parse_string` is deprecated but still works +- `json member function `is_empty` has been renamed to `empty`, `is_empty` is deprecated but still works. Rationale: consistency with C++ containers +- json member functions `begin_elements` and `end_elements` have been deprecated, instead use `elements().begin()` and `elements.end()` +- json member functions `begin_members` and `end_members` have been deprecated, instead use `members().begin()` and `members.end()` +- json member function `has_member` has been deprecated, instead use `count`. Rationale: consistency with C++ containers +- json member function `remove_member` has been deprecated, instead use `remove`. Rationale: only member function left with _element or _member suffix +- json_parse_exception renamed to parse_error, json_parse_exception typedef to parse_error +- json::parse(std::istream& is) renamed to json::parse_stream. json::parse(std::istream is) is deprecated but still works. + +v0.98.2 Release +-------------- + +- `json` constructor is now templated, so constructors now accept extended types +- Following [RFC7159](http://www.ietf.org/rfc/rfc7159.txt), `json_parser` now accepts any JSON value, removing the constraint that it be an object or array. +- The member `json_type_traits` member functions `is`, `as`, and `assign` have been changed to static functions. if you have implemented your own type specializations, you will also have to change your `is`, `as` and `assign` functions to be static. +- Removed json deprecated functions `custom_data`, `set_custom_data`, `add_custom_data` +- `json_reader` member function `max_depth` has been renamed to `max_nesting_depth`, the former name is still supported. +- `json` member function `resize_array` has been renamed to `resize`, the former name is still supported. + +jsoncons supports alternative ways for constructing `null`, `object`, and `array` values. + +null: + + json a = jsoncons::null_type(); // Using type constructor + json b = json::null_type(); // Using alias + json c(json::null); // From static data member prototype + +object: + + json a(); // Default is empty object + json b = json::object(); // Using type constructor + json c(json::an_object); // From static data member prototype + +array: + + json a = json::array(); // Using type constructor + json b = json::make_array(); // Using factory method + json c(json::an_array); // From static data member prototype + +Since C++ has possible order issues with static data members, the jsoncons examples and documentation have been changed to consistently use the other ways, and `json::null`, `json::an_object` and `json::an_array` have been, while still usable, deprecated. + +v0.98.1 Release +-------------- + +- Enhances parser for CSV files that outputs JSON, see example below. +- Adds `get_result` member function to `json_deserializer`, which returns the json value `v` stored in a `json_deserializer` as `std::move(v)`. The `root()` member function has been deprecated but is still supported. +- Adds `is_valid` member function to `json_deserializer` +- Enhances json::any class, adds type checks when casting back to original value +- Fixes some warning messages + +v0.98 Release +-------------- + +Bug fixes: + +- Fixes the noexcept specification (required for Visual Studio 2015 and later.) Fix + contributed by Rupert Steel. +- Fixes bug with proxy operator== when comparing object member values, + such as in val["field"] == json("abc") + +Enhancements: + +- Refines error codes and improves error messages + +- Renames `json_reader` method `read` to `read_next`, reflecting the fact that it supports reading a sequence of JSON texts from a stream. The + former name is deprecated but still works. + +- Adds `json_reader` method `check_done` that throws if there are unconsumed non-whitespace characters after one or more calls to `read_next`. + +- Adds getter and setter `max_depth` methods to allow setting the maximum JSON parse tree depth if desired, by default +it is arbitrarily large (limited by heap memory.) + +- Modifies `json` static methods `parse_string`, `parse_file`, and `parse` behaviour to throw if there are unconsumed non-whitespace characters after reading one JSON text. + +Changes to extensions: + +- Changes the top level namespace for the extensions from `jsoncons_ext` to `jsoncons`, e.g. `jsoncons_ext::csv::csv_reader` becomes `jsoncons::csv::csv_reader` +- Modifies csv_reader and csv_serializer so that the constructors are passed parameters in a `csv_parameters` object rather than a `json` object. +- Adds more options to csv_reader + +v0.97.2 Release +-------------- + +- Incorporates test suite files from http://www.json.org/JSON_checker/ into test suite +- The `jsoncons` parser accepts all of the JSON_checker files that its supposed to accept. +- Failures to reject incorrect exponential notation (e.g. [0e+-1]) have been fixed. +- The `jsoncons` parser now rejects all of the JSON_checker files that its supposed to reject except ones with stuff after the end of the document, e.g. + + ["Extra close"]] + + (Currently the `jsoncons` parser stops after reading a complete JSON text, and supports reading a sequence of JSON texts.) + +- Incorporates a fix to operator== on json objects, contributed by Alex Merry + +v0.97.1 Release +-------------- + +- "Transforming JSON with filters" example fixed +- Added a class-specific in-place new to the json class that is implemented in terms of the global version (required to create json objects with placement new operator.) +- Reorganized header files, removing unnecessary includes. +- Incorporates validation contributed by Alex Merry for ensuring that there is an object or array on parse head. +- Incorporates fix contributed by Milan Burda for “Switch case is in protected scope” clang build error + +v0.97 Release +------------ + +- Reversion of v0.96 change: + +The virtual methods `do_float_value`, `do_integer_value`, and `do_unsigned_value` of `json_input_handler` and `json_output_handler` have been restored to `do_double_value`, `do_longlong_value` and `do_ulonglong_value`, and their typedefed parameter types `float_type`, `integer_type`, and `unsigned_type` have been restored to `double`, `long long`, and `unsigned long long`. + +The rationale for this reversion is that the change doesn't really help to make the software more flexible, and that it's better to leave out the typedefs. There will be future enhancements to support greater numeric precision, but these will not affect the current method signatures. + +- Fix for "unused variable" warning message + +v0.96 Release +------------ + +This release includes breaking changes to interfaces. Going forward, the interfaces are expected to be stable. + +Breaking changes: + +- Renamed `error_handler` to `parse_error_handler`. + +- Renamed namespace `json_parser_error` to `json_parser_errc` + +- Renamed `value_adapter` to `json_type_traits`, if you have implemented your own type specializations, + you will have to rename `value_adapter` also. + +- Only json arrays now support `operator[](size_t)` to loop over values, this is no longer supported for `json` objects. Use a json object iterator instead. + +- The virtual methods `do_double_value`, `do_integer_value` and `do_uinteger_value` of `json_input_handler` and `json_output_handler` have been renamed to `do_float_value`, `do_integer_value`, and `do_unsigned_value`, + and their parameters have been changed from `double`, `long long`, and `unsigned long long` to typedefs `float_type`, `integer_type`, and `unsigned_type`. + The rationale for this change is to allow different configurations for internal number types (reversed in v0.97.) + +General changes + +- `json` member function `begin_object` now returns a bidirectional iterator rather than a random access iterator. + +- Static singleton `instance` methods have been added to `default_parse_error_handler` + and `empty_json_input_handler`. + +- Added to the `json` class overloaded static methods parse, parse_string + and parse_file that take a `parse_error_handler` as a parameter. + +- Added methods `last_char()` and `eof()` to `parsing_context`. + +- Enhancements to json parsing and json parse event error notification. + +- Added to `json_input_handler` and `json_output_handler` a non virtual method `value` that takes a null terminated string. + +- Added methods `is_integer`, `is_unsigned` and `is_float` to `json` to replace `is_longlong`, `is_ulonglong` and `is_double`, which have been deprecated. + +- Added methods `as_integer`, `as_unsigned` and `as_float` to `json` to replace `is_longlong`, `is_ulonglong` and `is_double`, which have been deprecated. + +Bug fixes: + +- Fixed issue with column number reported by json_reader + +- Where &s[0] and s.length() were passed to methods, &s[0] has been replaced with s.c_str(). + While this shouldn't be an issue on most implementations, VS throws an exception in debug modes when the string has length zero. + +- Fixes two issues in v0.95 reported by Alex Merry that caused errors with GCC: a superfluous typename has been removed in csv_serializer.hpp, and a JSONCONS_NOEXCEPT specifier has been added to the json_error_category_impl name method. + +- Fixed a number of typename issues in the v0.96 candidate identifed by Ignatov Serguei. + +- Fixes issues with testsuite cmake and scons reported by Alex Merry and Ignatov Serguei + +v0.95 +---- + +Enhancements: + +- Added template method `any_cast` to `json` class. + +- The allocator type parameter in basic_json is now supported, it allows you to supply a + custom allocator for dynamically allocated, fixed size small objects in the json container. + The allocator type is not used for structures including vectors and strings that use large + or variable amounts of memory, these always use the default allocators. + +Non-breaking Change: + +- `json_filter` method `parent` has been renamed to `input_handler` (old name still works) + +Breaking change (if you've implemented your own input and output handlers, or if you've +passed json events to input and output handlers directly): + +- The input handler virtual method + `name(const std::string& name, const parsing_context& context)` + has been changed to + `do_name(const char* p, size_t length, const parsing_context& context)` + +- The output handler virtual method + `name(const std::string& name)` + has been changed to + `do_name(const char* p, size_t length)` + +- The input handler virtual method + `string_value(const std::string& value, const parsing_context& context)` + has been changed to + `do_string_value(const char* p, size_t length, const parsing_context& context)` + +- The output handler virtual method + `string_value(const std::string& value)` + has been changed to + `do_string_value(const char* p, size_t length)` + +The rationale for the method parameter changes is to allow different internal +representations of strings but preserve efficiency. + +- The input and output handler virtual implementation methods begin_json, end_json, + begin_object, end_object, begin_array, end_array, name, string_value, + longlong_value, ulonglong_value, double_value, bool_value and null_value + have been renamed to do_begin_json, do_end_json, do_begin_object, do_end_object, + do_begin_array, do_end_array, do_name, do_string_value, do_longlong_value, + do_ulonglong_value, do_double_value, do_bool_value and do_null_value and have been + made private. + +- Public non-virtual interface methods begin_json, end_json, + begin_object, end_object, begin_array, end_array, name + have been added to json_input_handler and json_output_handler. + +The rationale for these changes is to follow best C++ practices by making the +json_input_handler and json_output_handler interfaces public non-virtual and +the implementations private virtual. Refer to the documentation and tutorials for details. + +- The error_handler virtual implementation methods have been renamed to `do_warning` and + `do_error`, and made private. Non virtual public interface methods `warning` and `error` + have been added. Error handling now leverages `std::error_code` to communicate parser + error events in an extendable way. + +Bug fixes: + +- Fixed bug in csv_reader + +v0.94.1 +------ + +Bug fixes: + +- Incorporates fix from Alex Merry for comparison of json objects + +v0.94 +---- + +Bug fixes + +- Incorporates contributions from Cory Fields for silencing some compiler warnings +- Fixes bug reported by Vitaliy Gusev in json object operator[size_t] +- Fixes bug in json is_empty method for empty objects + +Changes + +- json constructors that take string, double etc. are now declared explicit (assignments and defaults to get and make_array methods have their own implementation and do not depend on implicit constructors.) +- make_multi_array renamed to make_array (old name is still supported) +- Previous versions supported any type values through special methods set_custom_data, add_custom_data, and custom_data. This version introduces a new type json::any that wraps any values and works with the usual accessors set, add and as, so the specialized methods are no longer required. + +Enhancements + +- json get method with default value now accepts extended types as defaults +- json make_array method with default value now accepts extended types as defaults + +New extensions + +- Added jsoncons_ext/boost/type_extensions.hpp to collect + extensions traits for boost types, in particular, for + boost::gregorian dates. + +v0.93 Release +------------ + +New features + +- Supports wide character strings and streams with wjson, wjson_reader etc. Assumes UTF16 encoding if sizeof(wchar_t)=2 and UTF32 encoding if sizeof(wchar_t)=4. +- The empty class null_type is added to the jsoncons namespace, it replaces the member type json::null_type (json::null_type is typedefed to jsoncons::null_type for backward compatibility.) + +Defect fixes: + +- The ascii character 0x7f (del) was not being considered a control character to be escaped, this is fixed. +- Fixed two issues with serialization when the output format property escape_all_non_ascii is enabled. One, the individual bytes were being checked if they were non ascii, rather than first converting to a codepoint. Two, continuations weren't being handled when decoding. + +v0.92a Release +------------- + +Includes contributed updates for valid compilation and execution in gcc and clang environments + +v0.92 Release +------------ + +Breaking change (but only if you have subclassed json_input_handler or json_output_handler) + +- For consistency with other names, the input and output handler methods new to v0.91 - value_string, value_double, value_longlong, value_ulonglong and value_bool - have been renamed to string_value, double_value, longlong_value, ulonglong_value and bool_value. + +Non breaking changes (previous features are deprecated but still work) + +- name_value_pair has been renamed to member_type (typedefed to previous name.) + +- as_string(output_format format) has been deprecated, use the existing to_string(output_format format) instead + +Enhancements: + +- json now has extensibilty, you can access and modify json values with new types, see the tutorial Extensibility + +Preparation for allocator support: + +- The basic_json and related classes now have an Storage template parameter, which is currently just a placeholder, but will later provide a hook to allow users to control how json storage is allocated. This addition is transparent to users of the json and related classes. + +v0.91 Release +------------ + +This release should be largely backwards compatible with v0.90 and 0.83 with two exceptions: + +1. If you have used object iterators, you will need to replace uses of std::pair with name_value_pair, in particular, first becomes name() and second becomes value(). + +2. If you have subclassed json_input_handler, json_output_handler, or json_filter, and have implemented value(const std::string& ..., value(double ..., etc., you will need to modify the names to value_string(const std::string& ..., value_double(double ... (no changes if you are feeding existing implementations.) + +The changes are + +- Replaced std::pair with name_value_pair that has accessors name() and value() + +- In json_input_handler and json_output_handler, allowed for overrides of the value methods by making them non-virtual and adding virtual methods value_string, value_double, value_longlong, value_ulonglong, and value_bool + +Other new features: + +- Changed implementation of is and as, the current implementation should be user extensible + +- make_multi_array makes a multidimensional array with the number of dimensions specified as a template parameter. Replaces make_2d_array and make_3d_array, which are now deprecated. + +- Added support for is> and as> + +- Removed JSONCONS_NO_CXX11_RVALUE_REFERENCES, compiler must support move semantics + +Incorporates a number of contributions from Pedro Larroy and the developers of the clearskies_core project: + +- build system for posix systems +- GCC to list of supported compilers +- Android fix +- fixed virtual destructors missing in json_input_handler, json_output_handler and parsing_context +- fixed const_iterator should be iterator in json_object implementation + +To clean up the interface and avoid too much duplicated functionality, we've deprecated some json methods (but they still work) + + make_array +Use json val(json::an_array) or json::make_multi_array<1>(...) instead (but make_array will continue to work) + + make_2d_array + make_3d_array +Use make_multi_array<2> and make_multi_array<3> instead + + as_vector +Use as> etc. instead + + as_int + as_uint + as_char +Use as, as, and as instead + +Release v0.90a +------------- + +Fixed issue affecting clang compile + +Release v0.90 +------------ + +This release should be fully backwards compatible with 0.83. + +Includes performance enhancements to json_reader and json_deserializer + +Fixes issues with column numbers reported with exceptions + +Incorporates a number of patches contributed by Marc Chevrier: + +- Fixed issue with set member on json object when a member with that name already exists +- clang port +- cmake build files for examples and test suite +- json template method is for examining the types of json values +- json template method as for accessing json values + +v0.83 +------------ + +Optimizations (very unlikely to break earlier code) + +- get(const std::name& name) const now returns const json& if keyed value exists, otherwise a const reference to json::null + +- get(const std::string& name, const json& default_val) const now returns const json (actually a const proxy that evaluates to json if read) + +Bug fixes + +- Line number not incremented within multiline comment - fixed + +Deprecated features removed + +- Removed deprecated output_format properties (too much bagage to carry around) + +v0.82a +------------- + +- The const version of the json operator[](const std::string& name) didn't need to return a proxy, the return value has been changed to const json& (this change is transparent to the user.) + +- get(const std::name& name) has been changed to return a copy (rather than a reference), and json::null if there is no member with that name (rather than throw.) This way both get methods return default values if no keyed value exists. + +- non-const and const methods json& at(const std::name& name) have been added to replace the old single argument get method. These have the same behavior as the corresponding operator[] functions, but the non-const at is more efficient. + +v0.81 +------------ + +- Added accessor and modifier methods floatfield to output_format to provide a supported way to set the floatfield format flag to fixed or scientific with a specified number of decimal places (this can be done in older versions, but only with deprecated methods.) + +- The default constructor now constructs an empty object (rather than a null object.) While this is a change, it's unlikely to break exisitng code (all test cases passed without modification.) + +This means that instead of + + json obj(json::an_object); + obj["field"] = "field"; + +you can simply write + + json obj; + obj["field"] = "field"; + +The former notation is still supported, though. + +- Added a version of 'resize_array' to json that resizes the array to n elements and initializes them to a specified value. + +- Added a version of the static method json::make_array that takes no arguments and makes an empty json array + +Note that + + json arr(json::an_array); + +is equivalent to + + json arr = json::make_array(); + +and + + json arr(json::an_array); + arr.resize_array(10,0.0); + +is equivalent to + + json arr = json::make_array(10,0.0); + +For consistency the json::make_array notation is now favored in the documentation. + +v0.71 +------------- + +- Added resize_array method to json for resizing json arrays + +- Fixed issue with remove_range method (templated code failed to compile if calling this method.) + +- Added remove_member method to remove a member from a json object + +- Fixed issue with multiline line comments, added test case + +- Fixed issue with adding custom data to a json array using add_custom_data, added examples. + +v0.70 +------------- + +- Since 0.50, jsoncons has used snprintf for default serialization of double values to string values. This can result in invalid json output when running on a locale like German or Spanish. The period character (‘.’) is now always used as the decimal point, non English locales are ignored. + +- The output_format methods that support alternative floating point formatting, e.g. fixed, have been deprecated. + +- Added a template method as_vector to the json class. If a json value is an array and conversion is possible to the template type, returns a std::vector of that type, otherwise throws an std::exception. Specializations are provided for std::string, bool, char, int, unsigned int, long, unsigned long, long long, unsigned long long, and double. For example + + std::string s("[0,1,2,3]"); + + json val = json::parse_string(s); + + std::vector v = val.as_vector(); + +- Undeprecated the json member function precision + +v0.60b +------------- + +This release (0.60b) is fully backwards compatible with 0.50. + +A change introduced with 0.60 has been reversed. 0.60 introduced an alternative method of constructing a json arrray or object with an initial default constructor, a bug with this was fixed in 0.60a, but this feature and related documentation has been removed because it added complexity but no real value. + +### Enhancements + +- Added swap member function to json + +- Added add and add_custom_data overrides to json that take an index value, for adding a new element at the specified index and shifting all elements currently at or above that index to the right. + +- Added capacity member functions to json + +### 0.60 extensions + +- csv_serializer has been added to the csv extension + +v0.50 +------------ + +This release is fully backwards compatible with 0.4*, and mostly backwards compatible to 0.32 apart from the two name changes in 0.41 + +Bug fixes + +- When reading the escaped characters "\\b", "\\f", "\\r" and "\\t" appearing in json strings, json_reader was replacing them with the linefeed character, this has been fixed. + +Deprecated + +- Deprecated modifiers precision and fixed_decimal_places from output_format. Use set_floating_point_format instead. +- Deprecated constructor that takes indenting parameter from output_format. For pretty printing with indenting, use the pretty_print function or pass the indenting parameter in json_serializer. + +Changes + +- When serializing floating point values to a stream, previous versions defaulted to default floating point precision with a precision of 16. This has been changed to truncate trailing zeros but keep one if immediately after a decimal point. + +New features + +- For line reporting in parser error messages, json_reader now recognizes \\r\\n, \\n alone or \\r alone (\\r alone is new.) +- Added set_floating_point_format methods to output_format to give more control over floating point notation. + +Non functional enhancements + +- json_reader now estimates the minimum capacity for arrays and objects, and reports that information for the begin_array and begin_object events. This greatly reduces reallocations. + +v0.42 +------------ + +- Fixed another bug with multi line /**/ comments +- Minor fixes to reporting line and column number of errors +- Added fixed_decimal_places setter to output_format +- Added version of as_string to json that takes output_format as a parameter +- Reorganization of test cases and examples in source tree + +v0.41 +------------ + +- Added non-member overload swap(json& a, json& b) +- Fixed bug with multi line /**/ comments +- Added begin_json and end_json methods to json_output_handler +- json_deserializer should now satisfy basic exception safety (no leak guarantee) +- Moved csv_reader.hpp to jsoncons_ext/csv directory +- Changed csv_reader namespace to jsoncons::csv +- json::parse_file no longer reads the entire file into memory before parsing + (it now uses json_reader default buffering) + +v0.40 +------------ + +- json_listener renamed to json_input_handler +- json_writer renamed to json_output_handler + +- Added json_filter class + +- json get method that takes default argument now returns a value rather than a reference +- Issue in csv_reader related to get method issue fixed +- Issue with const json operator[] fixed +- Added as_char method to json +- Improved exception safety, some opportunites for memory leaks in the presence of exceptions removed + +v0.33 +------------ + +Added reserve method to json + +Added static make_3d_array method to json + +json_reader now configured for buffered reading + +Added csv_reader class for reading CSV files and producing JSON events + +Fixed bug with explicitly passing output_format in pretty_print. + +v0.32 +------------ + +Added remove_range method, operator== and operator!= to proxy and json objects + +Added static methods make_array and make_2d_array to json + +v0.31 +------------ + +error_handler method content_error renamed to error + +Added error_code to warning, error and fatal_error methods of error_handler + +v0.30 +------------ + +json_in_stream renamed to json_listener + +json_out_stream renamed to json_writer + +Added buffer accessor method to parsing_context + +v0.20 +------------ + +Added parsing_context class for providing information about the +element being parsed. + +error_handler methods take message and parsing_context parameters + +json_in_stream handlers take parsing_context parameter + +v0.19 +------------ + +Added error_handler class for json_reader + +Made json_exception a base class for all json exceptions + +Added root() method to json_deserializer to get a reference to the json value + +Removed swap_root() method from json_deserializer + +v0.18 +------------ + +Renamed serialize() class method to to_stream() in json + +Custom data serialization supported through template function specialization of serialize +(reverses change in 0.17) + + +v0.17 +------------ + +Added is_custom() method to json and proxy + +get_custom() method renamed to custom_data() in json and proxy + +Added clear() method to json and proxy + +set_member() method renamed to set() + +set_custom() method renamed to set_custom_data() + +push_back() method renamed to add() in json and proxy + +Added add_custom_data method() in json and proxy + +Custom data serialization supported through template class specialization of custom_serialization +(replaces template function specialization of serialize) + +v0.16 +------------ + +Change to json_out_stream and json_serializer: + + void value(const custom_data& value) + +removed. + +Free function serialize replaces free function to_stream for +serializing custom data. + +pretty print tidied up for nested arrays + +v0.15 +------------ + +Made eof() method on json_reader public, to support reading +multiple JSON objects from a stream. + +v0.14 +------------ + +Added pretty_print class + +Renamed json_stream_writer to json_serializer, +implements pure virtual class json_out_stream + +Renamed json_stream_listener to json_deserializer +implements pure virtual class json_in_stream + +Renamed json_parser to json_reader, parse to read. + +Changed indenting so object and array members start on new line. + +Added support for storing user data in json object, and +serializing to JSON. + +v0.13 +------------ + +Replaced simple_string union member with json_string that +wraps std::basic_string + +name() and value() event handler methods on +basic_json_stream_writer take const std::basic_string& +rather than const Char* and length. + +v0.12 +------------ + +Implemented operator<< for json::proxy + +Added to_stream methods to json::proxy + +v0.11 +------------ + +Added members to json_parser to access and modify the buffer capacity + +Added checks when parsing integer values to determine overflow for +long long and unsigned long long, and if overflow, parse them as +doubles. + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/LICENSE b/cpp/src/core/thirdparty/jsoncons-0.126.0/LICENSE new file mode 100644 index 0000000000..d508ab08e2 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/LICENSE @@ -0,0 +1,28 @@ +// Copyright Daniel Parker 2013 - 2017. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/README.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/README.md new file mode 100644 index 0000000000..9c48e800aa --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/README.md @@ -0,0 +1,951 @@ +# JSONCONS + +jsoncons is a C++, header-only library for constructing [JSON](http://www.json.org) and JSON-like +data formats such as [CBOR](http://cbor.io/). It supports + +- Parsing JSON-like text or binary formats into a tree model + that defines an interface for accessing and modifying that data. + +- Serializing the tree model into different JSON-like text or binary formats. + +- Converting from JSON-like text or binary formats to C++ data structures and back via [json_type_traits](https://github.com/danielaparker/jsoncons/blob/master/doc/ref/json_type_traits.md). + +- Streaming JSON read and write events, somewhat analogously to SAX (push parsing) and StAX (pull parsing) in the XML world. + +Compared to other JSON libraries, jsoncons has been designed to handle very large JSON texts. At its heart are +SAX style parsers and serializers. Its [json parser](https://github.com/danielaparker/jsoncons/blob/master/doc/ref/json_parser.md) is an +incremental parser that can be fed its input in chunks, and does not require an entire file to be loaded in memory at one time. +Its tree model is more compact than most, and can be made more compact still with a user-supplied +allocator. It also supports memory efficient parsing of very large JSON texts with a [pull parser](https://github.com/danielaparker/jsoncons/blob/master/doc/ref/json_cursor.md), +built on top of its incremental parser. + +The [jsoncons data model](doc/ref/data-model.md) supports the familiar JSON types - nulls, +booleans, numbers, strings, arrays, objects - plus byte strings. In addition, jsoncons +supports semantic tagging of date-time values, timestamp values, big integers, +big decimals, bigfloats and binary encodings. This allows it to preserve these type semantics when parsing +JSON-like data formats such as CBOR that have them. + +jsoncons is distributed under the [Boost Software License](http://www.boost.org/users/license.html). + +## Extensions + +- [jsonpointer](doc/ref/jsonpointer/jsonpointer.md) implements the IETF standard [JavaScript Object Notation (JSON) Pointer](https://tools.ietf.org/html/rfc6901) +- [jsonpatch](doc/ref/jsonpatch/jsonpatch.md) implements the IETF standard [JavaScript Object Notation (JSON) Patch](https://tools.ietf.org/html/rfc6902) +- [jsonpath](doc/ref/jsonpath/jsonpath.md) implements [Stefan Goessner's JSONPath](http://goessner.net/articles/JsonPath/). It also supports search and replace using JSONPath expressions. +- [cbor](doc/ref/cbor/cbor.md) implements decode from and encode to the IETF standard [Concise Binary Object Representation](http://cbor.io/) data format. +- [msgpack](doc/ref/msgpack/msgpack.md) implements decode from and encode to the [MessagePack](http://msgpack.org/index.html) data format. +- [ubjson](doc/ref/ubjson/ubjson.md) implements decode from and encode to the [Universal Binary JSON Specification](http://ubjson.org/) data format. +- [bson](doc/ref/bson/bson.md) implements decode from and encode to the [Binary JSON](http://bsonspec.org/) data format. +- [csv](doc/ref/csv/csv.md) implements reading (writing) JSON values from (to) CSV files + +## What users say + +_"I am so happy I have come across your json c++ library!"_ + +_"Im using your library for an external interface to pass data, as well as using the conversions from csv to json, which are really helpful for converting data for use in javascript ... it's a great library."_ + +_"this software is great and the ability to have an xpath like facility is so useful."_ + +_"really good"_ _"awesome project"_ _"very solid and very dependable"_ _"great job"_ _"Your repo rocks!!!!!"_ + +## Supported compilers + +jsoncons uses some features that are new to C++ 11, including [move semantics](http://thbecker.net/articles/rvalue_references/section_02.html) and the [AllocatorAwareContainer](http://en.cppreference.com/w/cpp/concept/AllocatorAwareContainer) concept. It is tested in continuous integration on [AppVeyor](https://ci.appveyor.com/project/danielaparker/jsoncons), [Travis](https://travis-ci.org/danielaparker/jsoncons), and [doozer](https://doozer.io/). + +| Compiler | Version |Architecture | Operating System | Notes | +|-------------------------|---------------------------|-------------|-------------------|-------| +| Microsoft Visual Studio | vs2015 (MSVC 19.0.24241.7)| x86,x64 | Windows 10 | | +| | vs2017 | x86,x64 | Windows 10 | | +| g++ | 4.8 and above | x64 | Ubuntu |`std::regex` isn't fully implemented in 4.8, so `jsoncons::jsonpath` regular expression filters aren't supported in 4.8 | +| | 4.8.5 | x64 | CentOS 7.6 |`std::regex` isn't fully implemented in 4.8, so `jsoncons::jsonpath` regular expression filters aren't supported in 4.8 | +| | 6.3.1 (Red Hat 6.3.1-1) | x64 | Fedora release 24 | | +| clang | 3.8 and above | x64 | Ubuntu | | +| clang xcode | 6.4 and above | x64 | OSX | | + +It is also cross compiled for ARMv8-A architecture on Travis using clang and executed using the emulator qemu. + +[UndefinedBehaviorSanitizer (UBSan)](http://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html) diagnostics are enabled for selected gcc and clang builds. + +## Get jsoncons + +Download the [latest release](https://github.com/danielaparker/jsoncons/releases) and unpack the zip file. Copy the directory `include/jsoncons` to your `include` directory. If you wish to use extensions, copy `include/jsoncons_ext` as well. + +Or, download the latest code on [master](https://github.com/danielaparker/jsoncons/archive/master.zip). + +## How to use it + +- [Quick guide](http://danielaparker.github.io/jsoncons) +- [Examples](doc/Examples.md) +- [Reference](doc/Home.md) + +As the `jsoncons` library has evolved, names have sometimes changed. To ease transition, jsoncons deprecates the old names but continues to support many of them. See the [deprecated list](doc/ref/deprecated.md) for the status of old names. The deprecated names can be suppressed by defining macro `JSONCONS_NO_DEPRECATED`, which is recommended for new code. + +## Benchmarks + +[json_benchmarks](https://github.com/danielaparker/json_benchmarks) provides some measurements about how `jsoncons` compares to other `json` libraries. + +- [JSONTestSuite and JSON_checker test suites](https://danielaparker.github.io/json_benchmarks/) + +- [Performance benchmarks with text and integers](https://github.com/danielaparker/json_benchmarks/blob/master/report/performance.md) + +- [Performance benchmarks with text and doubles](https://github.com/danielaparker/json_benchmarks/blob/master/report/performance_fp.md) + +### A simple example + +```c++ +#include +#include +#include + +// For convenience +using jsoncons::json; + +int main() +{ + json color_spaces = json::array(); + color_spaces.push_back("sRGB"); + color_spaces.push_back("AdobeRGB"); + color_spaces.push_back("ProPhoto RGB"); + + json image_sizing; // empty object + image_sizing["Resize To Fit"] = true; // a boolean + image_sizing["Resize Unit"] = "pixels"; // a string + image_sizing["Resize What"] = "long_edge"; // a string + image_sizing["Dimension 1"] = 9.84; // a double + + json export_settings; + + // create "File Format Options" as an object and put "Color Spaces" in it + export_settings["File Format Options"]["Color Spaces"] = std::move(color_spaces); + + export_settings["Image Sizing"] = std::move(image_sizing); + + // Write to stream + std::ofstream os("export_settings.json"); + os << export_settings; + + // Read from stream + std::ifstream is("export_settings.json"); + json j = json::parse(is); + + // Pretty print + std::cout << "(1)\n" << pretty_print(j) << "\n\n"; + + // Does object member exist? + std::cout << "(2) " << std::boolalpha << j.contains("Image Sizing") << "\n\n"; + + // Get reference to object member + const json& val = j["Image Sizing"]; + + // Access member as double + std::cout << "(3) " << "Dimension 1 = " << val["Dimension 1"].as() << "\n\n"; + + // Try access member with default + std::cout << "(4) " << "Dimension 2 = " << val.get_with_default("Dimension 2",0.0) << "\n"; +} +``` +Output: +```json +(1) +{ + "File Format Options": { + "Color Spaces": ["sRGB","AdobeRGB","ProPhoto RGB"], + "Image Formats": ["JPEG","PSD","TIFF","DNG"] + }, + "File Settings": { + "Color Space": "sRGB", + "Image Format": "JPEG", + "Limit File Size": true, + "Limit File Size To": 10000 + }, + "Image Sizing": { + "Dimension 1": 9.84, + "Resize To Fit": true, + "Resize Unit": "pixels", + "Resize What": "long_edge" + } +} + +(2) true + +(3) Dimension 1 = 9.8 + +(4) Dimension 2 = 0 +``` + +## About jsoncons::basic_json + +The jsoncons library provides a `basic_json` class template, which is the generalization of a `json` value for different +character types, different policies for ordering name-value pairs, etc. A `basic_json` provides a tree model +of JSON-like data formats, and defines an interface for accessing and modifying that data. +Despite its name, it is not JSON specific. + +```c++ +typedef basic_json> json; +``` +The library includes four instantiations of `basic_json`: + +- [json](doc/ref/json.md) constructs a utf8 character json value that sorts name-value members alphabetically + +- [ojson](doc/ref/ojson.md) constructs a utf8 character json value that preserves the original name-value insertion order + +- [wjson](doc/ref/wjson.md) constructs a wide character json value that sorts name-value members alphabetically + +- [wojson](doc/ref/wojson.md) constructs a wide character json value that preserves the original name-value insertion order + +## More examples + +[Encode C++ data structures to JSON, decode JSON to C++ data structures](#E1) + +[Playing around with CBOR, JSON, and CSV](#E2) + +[Query CBOR with JSONPath](#E3) + +[Pull parser example](#E4) + +[Iterate over a json stream with staj iterators](#E5) + +[Dump json content into a larger document](#E6) + +
+ +### Encode C++ data structures to JSON, decode JSON to C++ data structures + +jsoncons supports conversion between C++ data structures and JSON. The functions [encode_json](doc/ref/encode_json.md) +and [decode_json](doc/ref/decode_json.md) convert C++ data structures to JSON formatted strings or streams and back. +Encode and decode work for all C++ classes that have +[json_type_traits](https://github.com/danielaparker/jsoncons/blob/master/doc/ref/json_type_traits.md) +defined. The standard library containers are already supported, and you can specialize `json_type_traits` +for your own types in the `jsoncons` namespace. + +`JSONCONS_MEMBER_TRAITS_DECL` is a macro that simplifies the creation of the necessary boilerplate +from member data. It must be placed outside any namespace blocks. + +```c++ +#include +#include +#include + +namespace ns { + + struct reputon + { + std::string rater; + std::string assertion; + std::string rated; + double rating; + + friend bool operator==(const reputon& lhs, const reputon& rhs) + { + return lhs.rater == rhs.rater && lhs.assertion == rhs.assertion && + lhs.rated == rhs.rated && lhs.rating == rhs.rating; + } + + friend bool operator!=(const reputon& lhs, const reputon& rhs) + { + return !(lhs == rhs); + }; + }; + + class reputation_object + { + std::string application; + std::vector reputons; + + // Make json_type_traits specializations friends to give accesses to private members + JSONCONS_TYPE_TRAITS_FRIEND; + public: + reputation_object() + { + } + reputation_object(const std::string& application, const std::vector& reputons) + : application(application), reputons(reputons) + {} + + friend bool operator==(const reputation_object& lhs, const reputation_object& rhs) + { + return (lhs.application == rhs.application) && (lhs.reputons == rhs.reputons); + } + + friend bool operator!=(const reputation_object& lhs, const reputation_object& rhs) + { + return !(lhs == rhs); + }; + }; + + +} // namespace ns + +// Declare the traits. Specify which data members need to be serialized. +JSONCONS_MEMBER_TRAITS_DECL(ns::reputon, rater, assertion, rated, rating) +JSONCONS_MEMBER_TRAITS_DECL(ns::reputation_object, application, reputons) + +using namespace jsoncons; // for convenience + +int main() +{ + ns::reputation_object val("hiking", { ns::reputon{"HikingAsylum.example.com","strong-hiker","Marilyn C",0.90} }); + + std::string s; + encode_json(val, s, indenting::indent); + std::cout << s << "\n"; + + auto val2 = decode_json(s); + + assert(val2 == val); +} +``` +Output: +``` +{ + "application": "hiking", + "reputons": [ + { + "assertion": "strong-hiker", + "rated": "Marilyn C", + "rater": "HikingAsylum.example.com", + "rating": 0.9 + } + ] +} +``` + +See [examples](https://github.com/danielaparker/jsoncons/blob/master/doc/Examples.md#G1) + +
+ +### Playing around with CBOR, JSON, and CSV + +```c++ +#include +#include +#include +#include + +// For convenience +using namespace jsoncons; + +int main() +{ + // Construct some CBOR using the streaming API + std::vector b; + cbor::cbor_bytes_encoder encoder(b); + encoder.begin_array(); // indefinite length outer array + encoder.begin_array(3); // a fixed length array + encoder.string_value("foo"); + encoder.byte_string_value(byte_string{'P','u','s','s'}); // no suggested conversion + encoder.string_value("-18446744073709551617", semantic_tag::bigint); + encoder.end_array(); + encoder.end_array(); + encoder.flush(); + + // Print bytes + std::cout << "(1) "; + for (auto c : b) + { + std::cout << std::hex << std::setprecision(2) << std::setw(2) + << std::setfill('0') << static_cast(c); + } + std::cout << "\n\n"; +/* + 9f -- Start indefinte length array + 83 -- Array of length 3 + 63 -- String value of length 3 + 666f6f -- "foo" + 44 -- Byte string value of length 4 + 50757373 -- 'P''u''s''s' + c3 -- Tag 3 (negative bignum) + 49 -- Byte string value of length 9 + 010000000000000000 -- Bytes content + ff -- "break" +*/ + // Unpack bytes into a json variant value, and add some more elements + json j = cbor::decode_cbor(b); + + // Loop over the rows + std::cout << "(2)\n"; + for (const json& row : j.array_range()) + { + std::cout << row << "\n"; + } + std::cout << "\n"; + + // Get bignum value at position 0/2 using jsonpointer + json& v = jsonpointer::get(j, "/0/2"); + std::cout << "(3) " << v.as() << "\n\n"; + + // Print JSON representation with default options + std::cout << "(4)\n"; + std::cout << pretty_print(j) << "\n\n"; + + // Print JSON representation with different options + json_options options; + options.byte_string_format(byte_string_chars_format::base64) + .bigint_format(bigint_chars_format::base64url); + std::cout << "(5)\n"; + std::cout << pretty_print(j, options) << "\n\n"; + + // Add some more elements + + json another_array = json::array(); + another_array.emplace_back(byte_string({'P','u','s','s'}), + semantic_tag::base64); // suggested conversion to base64 + another_array.emplace_back("273.15", semantic_tag::bigdec); + another_array.emplace(another_array.array_range().begin(),"bar"); // place at front + + j.push_back(std::move(another_array)); + std::cout << "(6)\n"; + std::cout << pretty_print(j) << "\n\n"; + + // Get big decimal value at position /1/2 using jsonpointer + json& ref = jsonpointer::get(j, "/1/2"); + std::cout << "(7) " << ref.as() << "\n\n"; + +#if (defined(__GNUC__) || defined(__clang__)) && (!defined(__STRICT_ANSI__) && defined(_GLIBCXX_USE_INT128)) + // e.g. if code compiled with GCC and std=gnu++11 (rather than std=c++11) + __int128 i = j[1][2].as<__int128>(); +#endif + + // Get byte string value at position /1/1 as a byte_string + byte_string bs = j[1][1].as(); + std::cout << "(8) " << bs << "\n\n"; + + // or alternatively as a std::vector + std::vector u = j[1][1].as>(); + + // Repack bytes + std::vector b2; + cbor::encode_cbor(j, b2); + + // Print the repacked bytes + std::cout << "(9) "; + for (auto c : b2) + { + std::cout << std::hex << std::setprecision(2) << std::setw(2) + << std::setfill('0') << static_cast(c); + } + std::cout << "\n\n"; +/* + 82 -- Array of length 2 + 83 -- Array of length 3 + 63 -- String value of length 3 + 666f6f -- "foo" + 44 -- Byte string value of length 4 + 50757373 -- 'P''u''s''s' + c3 -- Tag 3 (negative bignum) + 49 -- Byte string value of length 9 + 010000000000000000 -- Bytes content + 83 -- Another array of length 3 + 63 -- String value of length 3 + 626172 -- "bar" + d6 - Expected conversion to base64 + 44 -- Byte string value of length 4 + 50757373 -- 'P''u''s''s' + c4 -- Tag 4 (decimal fraction) + 82 -- Array of length 2 + 21 -- -2 + 19 6ab3 -- 27315 +*/ + // Encode to CSV + csv::csv_options csv_options; + csv_options.column_names("Column 1,Column 2,Column 3"); + + std::cout << "(10)\n"; + csv::encode_csv(j, std::cout, csv_options); +} + +``` +Output: +``` +(1) 9f8363666f6f4450757373c349010000000000000000ff + +(2) +["foo","UHVzcw","-18446744073709551617"] + +(3) -18446744073709551617 + +(4) +[ + ["foo", "UHVzcw", "-18446744073709551617"] +] + +(5) +[ + ["foo", "UHVzcw==", "~AQAAAAAAAAAA"] +] + +(6) +[ + ["foo", "UHVzcw", "-18446744073709551617"], + ["bar", "UHVzcw==", "273.15"] +] + +(7) 273.15 + +(8) 50757373 + +(9) 828363666f6f4450757373c3490100000000000000008363626172d64450757373c48221196ab3 + +(10) +Column 1,Column 2,Column 3 +foo,UHVzcw,-18446744073709551617 +bar,UHVzcw==,273.15 +``` + +
+ +### Query CBOR with JSONPath +```c++ +#include +#include +#include +#include + +using namespace jsoncons; // For convenience + +int main() +{ + // Construct a json array of numbers + json j = json::array(); + + j.emplace_back(5.0); + + j.emplace_back(0.000071); + + j.emplace_back("-18446744073709551617",semantic_tag::bigint); + + j.emplace_back("1.23456789012345678901234567890", semantic_tag::bigdec); + + j.emplace_back("0x3p-1", semantic_tag::bigfloat); + + // Encode to JSON + std::cout << "(1)\n"; + std::cout << pretty_print(j); + std::cout << "\n\n"; + + // as() and as() + std::cout << "(2)\n"; + std::cout << std::dec << std::setprecision(15); + for (const auto& item : j.array_range()) + { + std::cout << item.as() << ", " << item.as() << "\n"; + } + std::cout << "\n"; + + // Encode to CBOR + std::vector v; + cbor::encode_cbor(j,v); + + std::cout << "(3)\n"; + for (auto c : v) + { + std::cout << std::hex << std::setprecision(2) << std::setw(2) + << std::setfill('0') << static_cast(c); + } + std::cout << "\n\n"; +/* + 85 -- Array of length 5 + fa -- float + 40a00000 -- 5.0 + fb -- double + 3f129cbab649d389 -- 0.000071 + c3 -- Tag 3 (negative bignum) + 49 -- Byte string value of length 9 + 010000000000000000 + c4 -- Tag 4 (decimal fraction) + 82 -- Array of length 2 + 38 -- Negative integer of length 1 + 1c -- -29 + c2 -- Tag 2 (positive bignum) + 4d -- Byte string value of length 13 + 018ee90ff6c373e0ee4e3f0ad2 + c5 -- Tag 5 (bigfloat) + 82 -- Array of length 2 + 20 -- -1 + 03 -- 3 +*/ + + // Decode back to json + json other = cbor::decode_cbor(v); + assert(other == j); + + // Query with JSONPath + std::cout << "(4)\n"; + json result = jsonpath::json_query(other,"$[?(@ < 1.5)]"); + std::cout << pretty_print(result) << "\n\n"; +``` +Output: +``` +(1) +[ + 5.0, + 7.1e-05, + "-18446744073709551617", + "1.23456789012345678901234567890", + [-1, 3] +] + +(2) +5.0, 5 +7.1e-05, 7.1e-05 +-18446744073709551617, -1.84467440737096e+19 +1.23456789012345678901234567890, 1.23456789012346 +1.5, 1.5 + +(3) +85fa40a00000fb3f129cbab649d389c349010000000000000000c482381cc24d018ee90ff6c373e0ee4e3f0ad2c5822003 + +(4) +[ + 7.1e-05, + "-18446744073709551617", + "1.23456789012345678901234567890" +] +``` + +
+ +### Pull parser example + +A typical pull parsing application will repeatedly process the `current()` +event and call `next()` to advance to the next event, until `done()` +returns `true`. + +The example JSON text, `book_catalog.json`, is used by the examples below. + +```json +[ + { + "author" : "Haruki Murakami", + "title" : "Hard-Boiled Wonderland and the End of the World", + "isbn" : "0679743464", + "publisher" : "Vintage", + "date" : "1993-03-02", + "price": 18.90 + }, + { + "author" : "Graham Greene", + "title" : "The Comedians", + "isbn" : "0099478374", + "publisher" : "Vintage Classics", + "date" : "2005-09-21", + "price": 15.74 + } +] +``` + +#### Reading the JSON stream +```c++ +std::ifstream is("book_catalog.json"); + +json_cursor reader(is); + +for (; !reader.done(); reader.next()) +{ + const auto& event = reader.current(); + switch (event.event_type()) + { + case staj_event_type::begin_array: + std::cout << "begin_array\n"; + break; + case staj_event_type::end_array: + std::cout << "end_array\n"; + break; + case staj_event_type::begin_object: + std::cout << "begin_object\n"; + break; + case staj_event_type::end_object: + std::cout << "end_object\n"; + break; + case staj_event_type::name: + // If underlying type is string, can return as string_view + std::cout << "name: " << event.as() << "\n"; + break; + case staj_event_type::string_value: + std::cout << "string_value: " << event.as() << "\n"; + break; + case staj_event_type::null_value: + std::cout << "null_value: " << event.as() << "\n"; + break; + case staj_event_type::bool_value: + std::cout << "bool_value: " << event.as() << "\n"; + break; + case staj_event_type::int64_value: + std::cout << "int64_value: " << event.as() << "\n"; + break; + case staj_event_type::uint64_value: + std::cout << "uint64_value: " << event.as() << "\n"; + break; + case staj_event_type::double_value: + // Return as string, could also use event.as() + std::cout << "double_value: " << event.as() << "\n"; + break; + default: + std::cout << "Unhandled event type\n"; + break; + } +} +``` +Output: +``` +begin_array +begin_object +name: author +string_value: Haruki Murakami +name: title +string_value: Hard-Boiled Wonderland and the End of the World +name: isbn +string_value: 0679743464 +name: publisher +string_value: Vintage +name: date +string_value: 1993-03-02 +name: price +double_value: 18.90 +end_object +begin_object +name: author +string_value: Graham Greene +name: title +string_value: The Comedians +name: isbn +string_value: 0099478374 +name: publisher +string_value: Vintage Classics +name: date +string_value: 2005-09-21 +name: price +double_value: 15.74 +end_object +end_array +``` + +
+ +#### Implementing a staj_filter + +```c++ +// A stream filter to filter out all events except name +// and restrict name to "author" + +class author_filter : public staj_filter +{ + bool accept_next_ = false; +public: + bool accept(const staj_event& event, const ser_context&) override + { + if (event.event_type() == staj_event_type::name && + event.as() == "author") + { + accept_next_ = true; + return false; + } + else if (accept_next_) + { + accept_next_ = false; + return true; + } + else + { + accept_next_ = false; + return false; + } + } +}; +``` + +#### Filtering the JSON stream + +```c++ +std::ifstream is("book_catalog.json"); + +author_filter filter; +json_cursor reader(is, filter); + +for (; !reader.done(); reader.next()) +{ + const auto& event = reader.current(); + switch (event.event_type()) + { + case staj_event_type::string_value: + std::cout << event.as() << "\n"; + break; + } +} +``` +Output: +``` +Haruki Murakami +Graham Greene +``` + +See [json_cursor](doc/ref/json_cursor.md) + +### Iterate over a json stream with staj iterators + +```c++ +const std::string example = R"( +[ + { + "employeeNo" : "101", + "name" : "Tommy Cochrane", + "title" : "Supervisor" + }, + { + "employeeNo" : "102", + "name" : "Bill Skeleton", + "title" : "Line manager" + } +] +)"; + +int main() +{ + std::istringstream is(example); + + json_cursor reader(is); + + staj_array_iterator it(reader); + + for (const auto& j : it) + { + std::cout << pretty_print(j) << "\n"; + } + std::cout << "\n\n"; +} +``` +Output: +``` +{ + "employeeNo": "101", + "name": "Tommy Cochrane", + "title": "Supervisor" +} +{ + "employeeNo": "102", + "name": "Bill Skeleton", + "title": "Line manager" +} +``` +See [staj_array_iterator](doc/ref/staj_array_iterator.md) and [staj_object_iterator](doc/ref/staj_object_iterator.md) + +
+ +### Dump json content into a larger document + +```c++ +#include + +using namespace jsoncons; + +int main() +{ + const json some_books = json::parse(R"( + [ + { + "title" : "Kafka on the Shore", + "author" : "Haruki Murakami", + "price" : 25.17 + }, + { + "title" : "Women: A Novel", + "author" : "Charles Bukowski", + "price" : 12.00 + } + ] + )"); + + const json more_books = json::parse(R"( + [ + { + "title" : "A Wild Sheep Chase: A Novel", + "author" : "Haruki Murakami", + "price" : 9.01 + }, + { + "title" : "Cutter's Way", + "author" : "Ivan Passer", + "price" : 8.00 + } + ] + )"); + + json_encoder encoder(std::cout, jsoncons::indenting::indent); // pretty print + serializer.begin_array(); + for (const auto& book : some_books.array_range()) + { + book.dump(encoder); + } + for (const auto& book : more_books.array_range()) + { + book.dump(encoder); + } + serializer.end_array(); + serializer.flush(); +} +``` +Output: +```json +[ + { + "author": "Haruki Murakami", + "price": 25.17, + "title": "Kafka on the Shore" + }, + { + "author": "Charles Bukowski", + "price": 12.0, + "title": "Women: A Novel" + }, + { + "author": "Haruki Murakami", + "price": 9.01, + "title": "A Wild Sheep Chase: A Novel" + }, + { + "author": "Ivan Passer", + "price": 8.0, + "title": "Cutter's Way" + } +] +``` + +## Building the test suite and examples with CMake + +[CMake](https://cmake.org/) is a cross-platform build tool that generates makefiles and solutions for the compiler environment of your choice. On Windows you can download a [Windows Installer package](https://cmake.org/download/). On Linux it is usually available as a package, e.g., on Ubuntu, +``` +sudo apt-get install cmake +``` +Once cmake is installed, you can build the tests: +``` +mkdir build +cd build +cmake ../ -DBUILD_TESTS=ON +cmake --build . --target test_jsoncons --config Release +``` +Run from the jsoncons tests directory: + +On Windows: +``` +..\build\tests\Release\test_jsoncons +``` + +On UNIX: +``` +../build/tests/Release/test_jsoncons +``` + +## Acknowledgements + +The jsoncons platform dependent binary configuration draws on to the excellent MIT licensed [tinycbor](https://github.com/intel/tinycbor). + +A big thanks to Milo Yip, author of [RapidJSON](http://rapidjson.org/), for raising the quality of JSON libraries across the board, by publishing [the benchmarks](https://github.com/miloyip/nativejson-benchmark), and contacting this project (among others) to share the results. + +The jsoncons implementation of the Grisu3 algorithm for printing floating-point numbers follows Florian Loitsch's MIT licensed [grisu3_59_56 implementation](http://florian.loitsch.com/publications), with minor modifications. + +The macro `JSONCONS_MEMBER_TRAITS_DECL` was inspired by Martin York's [ThorsSerializer](https://github.com/Loki-Astari/ThorsSerializer) + +Special thanks to our [contributors](https://github.com/danielaparker/jsoncons/blob/master/acknowledgements.md) + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/Roadmap.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/Roadmap.md new file mode 100644 index 0000000000..f78cdc9698 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/Roadmap.md @@ -0,0 +1,15 @@ +# Roadmap + +### For later releases + +- Generaliztion and enhancement of encode and decode functions + +At this point we'll slap a Version 1.0.0 Full Release stamp on `jsoncons` +(we've been leading up to this since 2013.) + +### Post 1.0.0 + +- Support more error recovery and introduce optional `lenient_error_handler`. + +- Implement [Concise data definition language (CDDL)](https://tools.ietf.org/html/draft-ietf-cbor-cddl-08) for schema validation in `jsoncons_ext` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/acknowledgements.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/acknowledgements.md new file mode 100644 index 0000000000..638caefcfd --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/acknowledgements.md @@ -0,0 +1,76 @@ +A big thanks to the following individuals for contributing: + +- Andrew Hutko (early code review) + +- [Marc Chevrier](https://github.com/MarkaPola) (contributed clang port, build files, json is and as methods, +and make_array template implementation.) + +- [Pedro Larroy](https://github.com/larroy) and the developers of the clearskies_core project (contributed build +system for posix systems, adding GCC to list of supported compilers, bug fixes, +Android fix) + +- [Cory Fields](https://github.com/theuni) for fixing warnings about unused variables + +- [Vitaliy Gusev](https://github.com/gusev-vitaliy) (reported error in json object operator[size_t i]) + +- [Alex Merry](https://github.com/amerry) for reporting errors with "typename" keyword experienced with gcc and providing +workaround for gcc 4.8 regex issues. + +- [Ignatov Serguei](https://github.com/sergign60) (reported issues experienced with gcc for 0.95 and +0.96 candidate and helped fix them) + +- [Milan Burda](https://github.com/miniak) for fix for clang build error + +- [Peter Tissen](https://github.com/Bigpet), for reporting and suggesting a fix for get(name,default_val) + +- [Tom Bass](https://github.com/tbass) for assistance with clang build errors + +- [Andrey Alifanov](https://github.com/AndreyAlifanov) and [Amit Naik](https://github.com/amitnaik1) for failing test cases for JSON Path + +- [Yuri Plaksyuk](https://github.com/yplaksyuk) for contributing an extension to JsonPath to allow filter +expressions over a single object. + +- [Nikolay Amiantov](https://github.com/abbradar) for fixing compilation errors and warnings by GCC and +Clang, adding read support for std::array and, most appreciated, +adding Travis CI configuration. + +- [jakalx](https://github.com/jakalx) contributed fix for operator== throws when comparing a string +against an empty object + +- [Alexander](https://github.com/rog13) for contributing fix to jsonpatch::diff + +- [Stefano Sinigardi](https://github.com/cenit) for contributing workaround for vs2017 platform issue + +- [xezon](https://github.com/danielaparker/jsoncons/pull/140) for proposing decode_csv and encode_csv functions, the +ignore_empty_lines option, and fixes to mismatched allocator types. Also for fixes and improvements in string_view code. + +- Vojtech Fried for contributing patches to JSONCONS_DEFINE_LITERAL +and to json::as_string to remove warnings + +- [Joshua Pritikin](https://github.com/jpritikin), for reporting gcc ubsan runtime warnings about +load of misaligned addresses, and verifying fix + +- [Tobias Hermann](https://github.com/Dobiasd), for reporting issue with `UINT_MAX` not declared +in `bignum.hpp`, and proposing fix. + +- [Cebtenzzre](https://github.com/Cebtenzzre), for finding and fixing an issue with conversions on +a basic_json value leading to an infinite recursion when the +value is a bignum, and for fixing undefined behavior in the bignum +class. + +- [massimo morara](https://github.com/massimomorara) for reporting numerous issues + +- [Alexander B](https://github.com/bas524), for uncovering a bug in how json_parser validated +UTF-8 strings. + +- [zhskyy](https://github.com/zhskyy), for contributing __FILE__ and __LINE__ macros removed +from JSONCONS_ASSERT if not defined _DEBUG. + +- [soberich](https://github.com/soberich), for contributing the jsonpath sum and prod functions, +and a proposal for aggregation functions that work outside a filter. + +- [patternoia](https://github.com/patternoia) for fixing the installation script +to include copying the jsoncons_ext directory into the installation place + +- [mikewallis](https://github.com/mikewallis) for removing redundant macro continuation character in JSONCONS_TYPE_TRAITS_DECL + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/appveyor.yml b/cpp/src/core/thirdparty/jsoncons-0.126.0/appveyor.yml new file mode 100644 index 0000000000..e89d60c9f1 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/appveyor.yml @@ -0,0 +1,86 @@ +build: false + +environment: + vsversion: none + arch: default + matrix: + - platform: vs + vsversion: 2015 + arch: x86 + FLAGS: "" + + - platform: vs + vsversion: 2015 + arch: x86 + FLAGS: "" + + - platform: vs + vsversion: 2015 + arch: x86 + FLAGS: "/permissive- /std:c++latest /utf-8" + + - platform: vs + vsversion: 2015 + arch: x64 + FLAGS: "" + + - platform: vs + vsversion: 2017 + arch: x64 + FLAGS: "" + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + + - platform: vs + vsversion: 2017 + arch: x64 + FLAGS: "/permissive- /std:c++latest /utf-8" + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + + - platform: vs + vsversion: 2017 + arch: ARM + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + +init: + - git config --global core.autocrlf input + +before_build: + # Remove the following from the path, as it will interfere with + # the MinGW builds + - set PATH=%PATH:C:\Program Files\Git\usr\bin;=% + - if %platform%==msvc call "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" + - if %platform%==msvc cmake -G "NMake Makefiles" -DCMAKE_INSTALL_PREFIX=%P% + - if %platform%==vs ( + set "makecommand=Visual Studio" + ) + - set "vcx=false" + - set "vcs=false" + - if %platform%==vs ( + set "vcx=true" + ) + - if %vsversion%==2015 ( + set "makecommand=%makecommand% 14 %vsversion%" + ) + - if %vsversion%==2017 ( + set "makecommand=%makecommand% 15 %vsversion%" + ) + - if %arch%==x64 ( + set "makecommand=%makecommand% Win64" + ) + - if %arch%==ARM ( + set "makecommand=%makecommand% ARM" + ) + + - cmake -G "%makecommand%" -D BUILD_TESTS=1 . + +build_script: + - cmake --build . --target test_jsoncons --config Release + - cd tests + +test_script: + - set "testplatform=%platform%" + # Can not run ARM builds on x86/x64 build images + - if %arch%==ARM ( + set "testplatform=none" + ) + - if %testplatform%==vs .\Release\test_jsoncons diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/build.sh b/cpp/src/core/thirdparty/jsoncons-0.126.0/build.sh new file mode 100755 index 0000000000..e31140ac4a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/build.sh @@ -0,0 +1,5 @@ +#!/bin/bash -x + +INSTALL_PREFIX=$(pwd)/../build + +cp -rf include/* ${INSTALL_PREFIX}/include diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/build_files/cmake/Darwin.cmake b/cpp/src/core/thirdparty/jsoncons-0.126.0/build_files/cmake/Darwin.cmake new file mode 100644 index 0000000000..e1687258a3 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/build_files/cmake/Darwin.cmake @@ -0,0 +1,7 @@ +# +# Global Configuration for MacOS platform +# + +# customize compiler flags +## Add new flags + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/build_files/cmake/Linux.cmake b/cpp/src/core/thirdparty/jsoncons-0.126.0/build_files/cmake/Linux.cmake new file mode 100644 index 0000000000..2aa24c210e --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/build_files/cmake/Linux.cmake @@ -0,0 +1,16 @@ +# +# Global Configuration for linux platform +# + +# +# GNU libstdc++ runtime is not supported because not yet C++11 compliant +# + +# customize compiler flags +## Add new flags +add_definitions (-pthread) + +set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pthread") +set (CMAKE_MODULE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pthread") +set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pthread") + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/build_files/cmake/Windows.cmake b/cpp/src/core/thirdparty/jsoncons-0.126.0/build_files/cmake/Windows.cmake new file mode 100644 index 0000000000..deb42645cc --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/build_files/cmake/Windows.cmake @@ -0,0 +1,6 @@ +# +# Global Configuration for windows platform +# + +# define some preprocessor flags +add_definitions(/DWIN32_LEAN_AND_MEAN /D_UNICODE /DUNICODE /W4) diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/build_files/cmake/config.cmake.in b/cpp/src/core/thirdparty/jsoncons-0.126.0/build_files/cmake/config.cmake.in new file mode 100644 index 0000000000..f5e390b030 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/build_files/cmake/config.cmake.in @@ -0,0 +1,13 @@ +# jsoncons cmake module +# This module sets the following variables in your project:: +# +# jsoncons_FOUND - true if jsoncons found on the system +# jsoncons_INCLUDE_DIRS - the directory containing jsoncons headers +# jsoncons_LIBRARY - empty + +@PACKAGE_INIT@ + +if(NOT TARGET @PROJECT_NAME@) + include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") + get_target_property(@PROJECT_NAME@_INCLUDE_DIRS jsoncons INTERFACE_INCLUDE_DIRECTORIES) +endif() diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/css/jsoncons.css b/cpp/src/core/thirdparty/jsoncons-0.126.0/css/jsoncons.css new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/css/jsoncons.css @@ -0,0 +1 @@ + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/Examples.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/Examples.md new file mode 100644 index 0000000000..5dd154e578 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/Examples.md @@ -0,0 +1,1554 @@ +# Examples + +### Parse and decode + +[Parse JSON from a string](#A1) +[Parse JSON from a file](#A2) +[Parse numbers without loosing precision](#A8) +[Validate JSON without incurring parse exceptions](#A3) +[How to allow comments? How not to?](#A4) +[Set a maximum nesting depth](#A5) +[Prevent the alphabetic sort of the outputted JSON, retaining the original insertion order](#A6) +[Parse a very large JSON file with json_cursor](#A7) + +### Encode + +[Encode a json value to a string](#B1) +[Encode a json value to a stream](#B2) +[Escape all non-ascii characters](#B3) +[Replace the representation of NaN, Inf and -Inf when serializing. And when reading in again.](#B4) + +### Decode JSON to C++ data structures, encode C++ data structures to JSON + +[Convert JSON to/from C++ data structures by specializing json_type_traits](#G1) +[A simple example using JSONCONS_MEMBER_TRAITS_DECL to generate the json_type_traits](#G2) +[A polymorphic example using JSONCONS_GETTER_CTOR_TRAITS_DECL to generate the json_type_traits](#G3) +[Convert JSON numbers to/from boost multiprecision numbers](#G4) + +### Construct + +[Construct a json object](#C1) +[Construct a json array](#C2) +[Insert a new value in an array at a specific position](#C3) +[Create arrays of arrays of arrays of ...](#C4) +[Merge two json objects](#C5) +[Construct a json byte string](#C6) + +### Access + +[Use string_view to access the actual memory that's being used to hold a string](#E1) +[Given a string in a json object that represents a decimal number, assign it to a double](#E2) +[Retrieve a big integer that's been parsed as a string](#E3) +[Look up a key, if found, return the value converted to type T, otherwise, return a default value of type T](#E4) +[Retrieve a value in a hierarchy of JSON objects](#E5) +[Retrieve a json value as a byte string](#E6) + +### Iterate + +[Iterate over a json array](#D1) +[Iterate over a json object](#D2) + +### Search and Replace + +[Search for and repace an object member key](#F1) +[Search for and replace a value](#F2) + +### Parse and decode + +
+ +#### Parse JSON from a string + +``` +std::string s = R"({"first":1,"second":2,"fourth":3,"fifth":4})"; + +json j = json::parse(s); +``` + +or + +```c++ +using namespace jsoncons::literals; + +json j = R"( +{ + "StartDate" : "2017-03-01", + "MaturityDate" : "2020-12-30" +} +)"_json; +``` + +
+ +#### Parse JSON from a file + +``` +std::ifstream is("myfile.json"); + +json j = json::parse(is); +``` + +
+ +#### Parse numbers without loosing precision + +By default, jsoncons parses a number with an exponent or fractional part +into a double precision floating point number. If you wish, you can +keep the number as a string with semantic tagging `bigdec`, +using the `lossless_number` option. You can then put it into a `float`, +`double`, a boost multiprecision number, or whatever other type you want. + +```c++ +#include + +int main() +{ + std::string s = R"( + { + "a" : 12.00, + "b" : 1.23456789012345678901234567890 + } + )"; + + // Default + json j = json::parse(s); + + std::cout.precision(15); + + // Access as string + std::cout << "(1) a: " << j["a"].as() << ", b: " << j["b"].as() << "\n"; + // Access as double + std::cout << "(2) a: " << j["a"].as() << ", b: " << j["b"].as() << "\n\n"; + + // Using lossless_number option + json_options options; + options.lossless_number(true); + + json j2 = json::parse(s, options); + // Access as string + std::cout << "(3) a: " << j2["a"].as() << ", b: " << j2["b"].as() << "\n"; + // Access as double + std::cout << "(4) a: " << j2["a"].as() << ", b: " << j2["b"].as() << "\n\n"; +} +``` +Output: +``` +(1) a: 12.0, b: 1.2345678901234567 +(2) a: 12, b: 1.23456789012346 + +(3) a: 12.00, b: 1.23456789012345678901234567890 +(4) a: 12, b: 1.23456789012346 +``` + +
+ +#### Validate JSON without incurring parse exceptions +```c++ +std::string s = R"( +{ + "StartDate" : "2017-03-01", + "MaturityDate" "2020-12-30" +} +)"; + +json_reader reader(s); + +// or, +// std::stringstream is(s); +// json_reader reader(is); + +std::error_code ec; +reader.read(ec); + +if (ec) +{ + std::cout << ec.message() + << " on line " << reader.line() + << " and column " << reader.column() + << std::endl; +} +``` +Output: +``` +Expected name separator ':' on line 4 and column 20 +``` + +
+ +#### How to allow comments? How not to? + +jsoncons, by default, accepts and ignores C-style comments + +```c++ +std::string s = R"( +{ + // Single line comments + /* + Multi line comments + */ +} +)"; + +// Default +json j = json::parse(s); +std::cout << "(1) " << j << std::endl; + +// Strict +try +{ + strict_parse_error_handler err_handler; + json j = json::parse(s, err_handler); +} +catch (const ser_error& e) +{ + std::cout << "(2) " << e.what() << std::endl; +} +``` +Output: +``` +(1) {} +(2) Illegal comment at line 3 and column 10 +``` + +
+ +#### Set a maximum nesting depth + +Like this, +```c++ +std::string s = "[[[[[[[[[[[[[[[[[[[[[\"Too deep\"]]]]]]]]]]]]]]]]]]]]]"; +try +{ + json_options options; + options.max_nesting_depth(20); + json j = json::parse(s, options); +} +catch (const ser_error& e) +{ + std::cout << e.what() << std::endl; +} +``` +Output: +``` +Maximum JSON depth exceeded at line 1 and column 21 +``` + +
+ +#### Prevent the alphabetic sort of the outputted JSON, retaining the original insertion order + +Use `ojson` instead of `json` (or `wojson` instead of `wjson`) to retain the original insertion order. + +```c++ +ojson j = ojson::parse(R"( +{ + "street_number" : "100", + "street_name" : "Queen St W", + "city" : "Toronto", + "country" : "Canada" +} +)"); +std::cout << "(1)\n" << pretty_print(j) << std::endl; + +// Insert "postal_code" at end +j.insert_or_assign("postal_code", "M5H 2N2"); +std::cout << "(2)\n" << pretty_print(j) << std::endl; + +// Insert "province" before "country" +auto it = j.find("country"); +j.insert_or_assign(it,"province","Ontario"); +std::cout << "(3)\n" << pretty_print(j) << std::endl; +``` +Output: +``` +(1) +{ + "street_number": "100", + "street_name": "Queen St W", + "city": "Toronto", + "country": "Canada" +} +(2) +{ + "street_number": "100", + "street_name": "Queen St W", + "city": "Toronto", + "country": "Canada", + "postal_code": "M5H 2N2" +} +(3) +{ + "street_number": "100", + "street_name": "Queen St W", + "city": "Toronto", + "province": "Ontario", + "country": "Canada", + "postal_code": "M5H 2N2" +} +``` + +
+ +### Parse a very large JSON file with json_cursor + + +A typical pull parsing application will repeatedly process the `current()` +event and call `next()` to advance to the next event, until `done()` +returns `true`. + +The example JSON text, `book_catalog.json`, is used by the examples below. + +```json +[ + { + "author" : "Haruki Murakami", + "title" : "Hard-Boiled Wonderland and the End of the World", + "isbn" : "0679743464", + "publisher" : "Vintage", + "date" : "1993-03-02", + "price": 18.90 + }, + { + "author" : "Graham Greene", + "title" : "The Comedians", + "isbn" : "0099478374", + "publisher" : "Vintage Classics", + "date" : "2005-09-21", + "price": 15.74 + } +] +``` + +#### Reading the JSON stream +```c++ +std::ifstream is("book_catalog.json"); + +json_cursor reader(is); + +for (; !reader.done(); reader.next()) +{ + const auto& event = reader.current(); + switch (event.event_type()) + { + case staj_event_type::begin_array: + std::cout << "begin_array\n"; + break; + case staj_event_type::end_array: + std::cout << "end_array\n"; + break; + case staj_event_type::begin_object: + std::cout << "begin_object\n"; + break; + case staj_event_type::end_object: + std::cout << "end_object\n"; + break; + case staj_event_type::name: + // If underlying type is string, can return as string_view + std::cout << "name: " << event.as() << "\n"; + break; + case staj_event_type::string_value: + std::cout << "string_value: " << event.as() << "\n"; + break; + case staj_event_type::null_value: + std::cout << "null_value: " << event.as() << "\n"; + break; + case staj_event_type::bool_value: + std::cout << "bool_value: " << event.as() << "\n"; + break; + case staj_event_type::int64_value: + std::cout << "int64_value: " << event.as() << "\n"; + break; + case staj_event_type::uint64_value: + std::cout << "uint64_value: " << event.as() << "\n"; + break; + case staj_event_type::double_value: + // Return as string, could also use event.as() + std::cout << "double_value: " << event.as() << "\n"; + break; + default: + std::cout << "Unhandled event type\n"; + break; + } +} +``` +Output: +``` +begin_array +begin_object +name: author +string_value: Haruki Murakami +name: title +string_value: Hard-Boiled Wonderland and the End of the World +name: isbn +string_value: 0679743464 +name: publisher +string_value: Vintage +name: date +string_value: 1993-03-02 +name: price +double_value: 18.90 +end_object +begin_object +name: author +string_value: Graham Greene +name: title +string_value: The Comedians +name: isbn +string_value: 0099478374 +name: publisher +string_value: Vintage Classics +name: date +string_value: 2005-09-21 +name: price +double_value: 15.74 +end_object +end_array +``` + +#### Implementing a staj_filter + +```c++ +// A stream filter to filter out all events except name +// and restrict name to "author" + +class author_filter : public staj_filter +{ + bool accept_next_ = false; +public: + bool accept(const staj_event& event, const ser_context&) override + { + if (event.event_type() == staj_event_type::name && + event.as() == "author") + { + accept_next_ = true; + return false; + } + else if (accept_next_) + { + accept_next_ = false; + return true; + } + else + { + accept_next_ = false; + return false; + } + } +}; +``` + +#### Filtering the JSON stream + +```c++ +std::ifstream is("book_catalog.json"); + +author_filter filter; +json_cursor reader(is, filter); + +for (; !reader.done(); reader.next()) +{ + const auto& event = reader.current(); + switch (event.event_type()) + { + case staj_event_type::string_value: + std::cout << event.as() << "\n"; + break; + } +} +``` +Output: +``` +Haruki Murakami +Graham Greene +``` + +See [json_cursor](doc/ref/json_cursor.md) + +
+ +### Decode JSON to C++ data structures, encode C++ data structures to JSON + +
+ +#### Convert JSON to/from C++ data structures by specializing json_type_traits +jsoncons supports conversion between JSON text and C++ data structures. The functions [decode_json](doc/ref/decode_json.md) +and [encode_json](doc/ref/encode_json.md) convert JSON formatted strings or streams to C++ data structures and back. +Decode and encode work for all C++ classes that have +[json_type_traits](https://github.com/danielaparker/jsoncons/blob/master/doc/ref/json_type_traits.md) +defined. The standard library containers are already supported, and you can specialize `json_type_traits` +for your own types in the `jsoncons` namespace. + +```c++ +#include +#include +#include +#include + +namespace ns { + struct book + { + std::string author; + std::string title; + double price; + }; +} // namespace ns + +namespace jsoncons { + + template + struct json_type_traits + { + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) noexcept + { + return j.is_object() && j.contains("author") && + j.contains("title") && j.contains("price"); + } + static ns::book as(const Json& j) + { + ns::book val; + val.author = j.at("author").template as(); + val.title = j.at("title").template as(); + val.price = j.at("price").template as(); + return val; + } + static Json to_json(const ns::book& val, + allocator_type allocator=allocator_type()) + { + Json j(allocator); + j.try_emplace("author", val.author); + j.try_emplace("title", val.title); + j.try_emplace("price", val.price); + return j; + } + }; +} // namespace jsoncons +``` + +To save typing and enhance readability, the jsoncons library defines macros, +so we could have written + +```c++ +JSONCONS_MEMBER_TRAITS_DECL(ns::book, author, title, price) +``` + +which expands to the code above. + +```c++ +using namespace jsoncons; // for convenience + +int main() +{ + const std::string s = R"( + [ + { + "author" : "Haruki Murakami", + "title" : "Kafka on the Shore", + "price" : 25.17 + }, + { + "author" : "Charles Bukowski", + "title" : "Pulp", + "price" : 22.48 + } + ] + )"; + + std::vector book_list = decode_json>(s); + + std::cout << "(1)\n"; + for (const auto& item : book_list) + { + std::cout << item.author << ", " + << item.title << ", " + << item.price << "\n"; + } + + std::cout << "\n(2)\n"; + encode_json(book_list, std::cout, indenting::indent); + std::cout << "\n\n"; +} +``` +Output: +``` +(1) +Haruki Murakami, Kafka on the Shore, 25.17 +Charles Bukowski, Pulp, 22.48 + +(2) +[ + { + "author": "Haruki Murakami", + "price": 25.17, + "title": "Kafka on the Shore" + }, + { + "author": "Charles Bukowski", + "price": 22.48, + "title": "Pulp" + } +] +``` + +
+ +#### A simple example using JSONCONS_MEMBER_TRAITS_DECL to generate the json_type_traits + +`JSONCONS_MEMBER_TRAITS_DECL` is a macro that can be used to generate the `json_type_traits` boilerplate +from member data. + +```c++ +#include +#include +#include + +namespace ns { + + struct reputon + { + std::string rater; + std::string assertion; + std::string rated; + double rating; + + friend bool operator==(const reputon& lhs, const reputon& rhs) + { + return lhs.rater == rhs.rater && lhs.assertion == rhs.assertion && + lhs.rated == rhs.rated && lhs.rating == rhs.rating; + } + + friend bool operator!=(const reputon& lhs, const reputon& rhs) + { + return !(lhs == rhs); + }; + }; + + class reputation_object + { + std::string application; + std::vector reputons; + + // Make json_type_traits specializations friends to give accesses to private members + JSONCONS_TYPE_TRAITS_FRIEND; + public: + reputation_object() + { + } + reputation_object(const std::string& application, const std::vector& reputons) + : application(application), reputons(reputons) + {} + + friend bool operator==(const reputation_object& lhs, const reputation_object& rhs) + { + return (lhs.application == rhs.application) && (lhs.reputons == rhs.reputons); + } + + friend bool operator!=(const reputation_object& lhs, const reputation_object& rhs) + { + return !(lhs == rhs); + }; + }; + +} // namespace ns + +// Declare the traits. Specify which data members need to be serialized. +JSONCONS_MEMBER_TRAITS_DECL(ns::reputon, rater, assertion, rated, rating) +JSONCONS_MEMBER_TRAITS_DECL(ns::reputation_object, application, reputons) + +using namespace jsoncons; // for convenience + +int main() +{ + ns::reputation_object val("hiking", { ns::reputon{"HikingAsylum.example.com","strong-hiker","Marilyn C",0.90} }); + + std::string s; + encode_json(val, s, indenting::indent); + std::cout << s << "\n"; + + auto val2 = decode_json(s); + + assert(val2 == val); +} +``` +Output: +``` +{ + "application": "hiking", + "reputons": [ + { + "assertion": "strong-hiker", + "rated": "Marilyn C", + "rater": "HikingAsylum.example.com", + "rating": 0.9 + } + ] +} +``` + +
+ +#### A polymorphic example using JSONCONS_GETTER_CTOR_TRAITS_DECL to generate the json_type_traits + +`JSONCONS_GETTER_CTOR_TRAITS_DECL` is a macro that can be used to generate the `json_type_traits` boilerplate +from getter functions and a constructor. + +```c++ +#include +#include +#include +#include + +using namespace jsoncons; + +namespace ns { + +class Employee +{ + std::string firstName_; + std::string lastName_; +public: + Employee(const std::string& firstName, const std::string& lastName) + : firstName_(firstName), lastName_(lastName) + { + } + virtual ~Employee() = default; + + virtual double calculatePay() const = 0; + + const std::string& firstName() const {return firstName_;} + const std::string& lastName() const {return lastName_;} +}; + +class HourlyEmployee : public Employee +{ + double wage_; + unsigned hours_; +public: + HourlyEmployee(const std::string& firstName, const std::string& lastName, + double wage, unsigned hours) + : Employee(firstName, lastName), + wage_(wage), hours_(hours) + { + } + HourlyEmployee(const HourlyEmployee&) = default; + HourlyEmployee(HourlyEmployee&&) = default; + HourlyEmployee& operator=(const HourlyEmployee&) = default; + HourlyEmployee& operator=(HourlyEmployee&&) = default; + + double wage() const {return wage_;} + + unsigned hours() const {return hours_;} + + double calculatePay() const override + { + return wage_*hours_; + } +}; + +class CommissionedEmployee : public Employee +{ + double baseSalary_; + double commission_; + unsigned sales_; +public: + CommissionedEmployee(const std::string& firstName, const std::string& lastName, + double baseSalary, double commission, unsigned sales) + : Employee(firstName, lastName), + baseSalary_(baseSalary), commission_(commission), sales_(sales) + { + } + CommissionedEmployee(const CommissionedEmployee&) = default; + CommissionedEmployee(CommissionedEmployee&&) = default; + CommissionedEmployee& operator=(const CommissionedEmployee&) = default; + CommissionedEmployee& operator=(CommissionedEmployee&&) = default; + + double baseSalary() const + { + return baseSalary_; + } + + double commission() const + { + return commission_; + } + + unsigned sales() const + { + return sales_; + } + + double calculatePay() const override + { + return baseSalary_ + commission_*sales_; + } +}; +} // ns + +JSONCONS_GETTER_CTOR_TRAITS_DECL(ns::HourlyEmployee, firstName, lastName, wage, hours) +JSONCONS_GETTER_CTOR_TRAITS_DECL(ns::CommissionedEmployee, firstName, lastName, baseSalary, commission, sales) + +namespace jsoncons { + +template +struct json_type_traits> +{ + static bool is(const Json& j) noexcept + { + return j.is() || j.is(); + } + static std::shared_ptr as(const Json& j) + { + if (j.at("type").as() == "Hourly") + { + return std::make_shared(j.as()); + } + else if (j.at("type").as() == "Commissioned") + { + return std::make_shared(j.as()); + } + else + { + throw std::runtime_error("Not an employee"); + } + } + static Json to_json(const std::shared_ptr& ptr) + { + if (ns::HourlyEmployee* p = dynamic_cast(ptr.get())) + { + Json j(*p); + j.try_emplace("type","Hourly"); + return j; + } + else if (ns::CommissionedEmployee* p = dynamic_cast(ptr.get())) + { + Json j(*p); + j.try_emplace("type","Commissioned"); + return j; + } + else + { + throw std::runtime_error("Not an employee"); + } + } +}; + +} // jsoncons + +int main() +{ + std::vector> v; + + v.push_back(std::make_shared("John", "Smith", 40.0, 1000)); + v.push_back(std::make_shared("Jane", "Doe", 30000, 0.25, 1000)); + + json j(v); + std::cout << pretty_print(j) << "\n\n"; + + assert(j[0].is()); + assert(!j[0].is()); + assert(!j[1].is()); + assert(j[1].is()); + + + for (size_t i = 0; i < j.size(); ++i) + { + auto p = j[i].as>(); + assert(p->firstName() == v[i]->firstName()); + assert(p->lastName() == v[i]->lastName()); + assert(p->calculatePay() == v[i]->calculatePay()); + } +} +``` +Output: +``` +[ + { + "firstName": "John", + "hours": 1000, + "lastName": "Smith", + "type": "Hourly", + "wage": 40.0 + }, + { + "baseSalary": 30000.0, + "commission": 0.25, + "firstName": "Jane", + "lastName": "Doe", + "sales": 1000, + "type": "Commissioned" + } +] +``` + +
+ +#### Convert JSON numbers to/from boost multiprecision numbers + +``` +#include +#include + +namespace jsoncons +{ + template + struct json_type_traits> + { + typedef boost::multiprecision::number multiprecision_type; + + static bool is(const Json& val) noexcept + { + if (!(val.is_string() && val.semantic_tag() == semantic_tag::bigdec)) + { + return false; + } + else + { + return true; + } + } + + static multiprecision_type as(const Json& val) + { + return multiprecision_type(val.template as()); + } + + static Json to_json(multiprecision_type val) + { + return Json(val.str(), semantic_tag::bigdec); + } + }; +} + +int main() +{ + typedef boost::multiprecision::number multiprecision_type; + + std::string s = "[100000000000000000000000000000000.1234]"; + json_options options; + options.lossless_number(true); + json j = json::parse(s, options); + + multiprecision_type x = j[0].as(); + + std::cout << "(1) " << std::setprecision(std::numeric_limits::max_digits10) + << x << "\n"; + + json j2 = json::array{x}; + std::cout << "(2) " << j2[0].as() << "\n"; +} +``` +Output: +``` +(1) 100000000000000000000000000000000.1234 +(2) 100000000000000000000000000000000.1234 +``` + +### Encode + +
+ +#### Encode a json value to a string + +``` +std::string s; + +j.dump(s); // compressed + +j.dump(s, indenting::indent); // pretty print +``` + +
+ +#### Encode a json value to a stream + +``` +j.dump(std::cout); // compressed + +j.dump(std::cout, indenting::indent); // pretty print +``` +or +``` +std::cout << j << std::endl; // compressed + +std::cout << pretty_print(j) << std::endl; // pretty print +``` + +
+ +#### Escape all non-ascii characters + +``` +json_options options; +options.escape_all_non_ascii(true); + +j.dump(std::cout, options); // compressed + +j.dump(std::cout, options, indenting::indent); // pretty print +``` +or +``` +std::cout << print(j, options) << std::endl; // compressed + +std::cout << pretty_print(j, options) << std::endl; // pretty print +``` + +
+ +#### Replace the representation of NaN, Inf and -Inf when serializing. And when reading in again. + +Set the serializing options for `nan` and `inf` to distinct string values. + +```c++ +json j; +j["field1"] = std::sqrt(-1.0); +j["field2"] = 1.79e308 * 1000; +j["field3"] = -1.79e308 * 1000; + +json_options options; +options.nan_to_str("NaN") + .inf_to_str("Inf"); + +std::ostringstream os; +os << pretty_print(j, options); + +std::cout << "(1)\n" << os.str() << std::endl; + +json j2 = json::parse(os.str(),options); + +std::cout << "\n(2) " << j2["field1"].as() << std::endl; +std::cout << "(3) " << j2["field2"].as() << std::endl; +std::cout << "(4) " << j2["field3"].as() << std::endl; + +std::cout << "\n(5)\n" << pretty_print(j2,options) << std::endl; +``` + +Output: +```json +(1) +{ + "field1": "NaN", + "field2": "Inf", + "field3": "-Inf" +} + +(2) nan +(3) inf +(4) -inf + +(5) +{ + "field1": "NaN", + "field2": "Inf", + "field3": "-Inf" +} +``` + +### Construct + +
+ +#### Construct a json object + +Start with an empty json object and insert some name-value pairs, + +```c++ +json image_sizing; +image_sizing.insert_or_assign("Resize To Fit",true); // a boolean +image_sizing.insert_or_assign("Resize Unit", "pixels"); // a string +image_sizing.insert_or_assign("Resize What", "long_edge"); // a string +image_sizing.insert_or_assign("Dimension 1",9.84); // a double +image_sizing.insert_or_assign("Dimension 2",json::null()); // a null value +``` + +or use an object initializer-list, + +```c++ +json file_settings = json::object{ + {"Image Format", "JPEG"}, + {"Color Space", "sRGB"}, + {"Limit File Size", true}, + {"Limit File Size To", 10000} +}; +``` + +
+ +#### Construct a json array + +```c++ +json color_spaces = json::array(); // an empty array +color_spaces.push_back("sRGB"); +color_spaces.push_back("AdobeRGB"); +color_spaces.push_back("ProPhoto RGB"); +``` + +or use an array initializer-list, +```c++ +json image_formats = json::array{"JPEG","PSD","TIFF","DNG"}; +``` + +
+ +#### Insert a new value in an array at a specific position + +```c++ +json cities = json::array(); // an empty array +cities.push_back("Toronto"); +cities.push_back("Vancouver"); +// Insert "Montreal" at beginning of array +cities.insert(cities.array_range().begin(),"Montreal"); + +std::cout << cities << std::endl; +``` +Output: +``` +["Montreal","Toronto","Vancouver"] +``` + +
+ +#### Create arrays of arrays of arrays of ... + +Like this: + +```c++ +json j = json::make_array<3>(4, 3, 2, 0.0); +double val = 1.0; +for (size_t i = 0; i < a.size(); ++i) +{ + for (size_t j = 0; j < j[i].size(); ++j) + { + for (size_t k = 0; k < j[i][j].size(); ++k) + { + j[i][j][k] = val; + val += 1.0; + } + } +} +std::cout << pretty_print(j) << std::endl; +``` +Output: +```json +[ + [ + [1.0,2.0], + [3.0,4.0], + [5.0,6.0] + ], + [ + [7.0,8.0], + [9.0,10.0], + [11.0,12.0] + ], + [ + [13.0,14.0], + [15.0,16.0], + [17.0,18.0] + ], + [ + [19.0,20.0], + [21.0,22.0], + [23.0,24.0] + ] +] +``` + +
+ +#### Merge two json objects + +[json::merge](ref/json/merge.md) inserts another json object's key-value pairs into a json object, +unless they already exist with an equivalent key. + +[json::merge_or_update](ref/json/merge_or_update.md) inserts another json object's key-value pairs +into a json object, or assigns them if they already exist. + +The `merge` and `merge_or_update` functions perform only a one-level-deep shallow merge, +not a deep merge of nested objects. + +```c++ +json another = json::parse(R"( +{ + "a" : "2", + "c" : [4,5,6] +} +)"); + +json j = json::parse(R"( +{ + "a" : "1", + "b" : [1,2,3] +} +)"); + +j.merge(std::move(another)); +std::cout << pretty_print(j) << std::endl; +``` +Output: +```json +{ + "a": "1", + "b": [1,2,3], + "c": [4,5,6] +} +``` + +
+ +#### Construct a json byte string + +```c++ +#include + +namespace jc=jsoncons; + +int main() +{ + byte_string bs = {'H','e','l','l','o'}; + + // default suggested encoding (base64url) + json j1(bs); + std::cout << "(1) "<< j1 << "\n\n"; + + // base64 suggested encoding + json j2(bs, semantic_tag::base64); + std::cout << "(2) "<< j2 << "\n\n"; + + // base16 suggested encoding + json j3(bs, semantic_tag::base16); + std::cout << "(3) "<< j3 << "\n\n"; +} +``` + +Output: +``` +(1) "SGVsbG8" + +(2) "SGVsbG8=" + +(3) "48656C6C6F" +``` + +### Iterate + +
+ +#### Iterate over a json array + +```c++ +json j = json::array{1,2,3,4}; + +for (auto val : j.array_range()) +{ + std::cout << val << std::endl; +} +``` + +
+ +#### Iterate over a json object + +```c++ +json j = json::object{ + {"author", "Haruki Murakami"}, + {"title", "Kafka on the Shore"}, + {"price", 25.17} +}; + +for (const auto& member : j.object_range()) +{ + std::cout << member.key() << "=" + << member.value() << std::endl; +} +``` + +### Access + +
+ +#### Use string_view to access the actual memory that's being used to hold a string + +You can use `j.as()`, e.g. +```c++ +json j = json::parse("\"Hello World\""); +auto sv = j.as(); +``` +`jsoncons::string_view` supports the member functions of `std::string_view`, including `data()` and `size()`. + +If your compiler supports `std::string_view`, you can also use `j.as()`. + +
+ +#### Given a string in a json object that represents a decimal number, assign it to a double + +```c++ +json j = json::object{ + {"price", "25.17"} +}; + +double price = j["price"].as(); +``` + +
+ +#### Retrieve a big integer that's been parsed as a string + +If an integer exceeds the range of an `int64_t` or `uint64_t`, jsoncons parses it as a string +with semantic tagging `bigint`. + +```c++ +#include +#include +#include + +using jsoncons::json; + +int main() +{ + std::string input = "-18446744073709551617"; + + json j = json::parse(input); + + // Access as string + std::string s = j.as(); + std::cout << "(1) " << s << "\n\n"; + + // Access as double + double d = j.as(); + std::cout << "(2) " << std::setprecision(17) << d << "\n\n"; + + // Access as jsoncons::bignum + jsoncons::bignum bn = j.as(); + std::cout << "(3) " << bn << "\n\n"; + + // If your compiler supports extended integral types for which std::numeric_limits is specialized +#if (defined(__GNUC__) || defined(__clang__)) && (!defined(__STRICT_ANSI__) && defined(_GLIBCXX_USE_INT128)) + __int128 i = j.as<__int128>(); + std::cout << "(4) " << i << "\n\n"; +#endif +} +``` +Output: +``` +(1) -18446744073709551617 + +(2) -1.8446744073709552e+19 + +(3) -18446744073709551617 + +(4) -18446744073709551617 +``` + +
+ +#### Look up a key, if found, return the value converted to type T, otherwise, return a default value of type T. + +```c++ +json j = json::object{ + {"price", "25.17"} +}; + +double price = j.get_with_default("price", 25.00); // returns 25.17 + +double sale_price = j.get_with_default("sale_price", 22.0); // returns 22.0 +``` + +
+ +#### Retrieve a value in a hierarchy of JSON objects + +```c++ +#include +#include +#include + +int main() +{ + json j = json::parse(R"( + { + "application": "hiking", + "reputons": [ + { + "rater": "HikingAsylum.example.com", + "assertion": "strong-hiker", + "rated": "Marilyn C", + "rating": 0.90 + } + ] + } + )"); + + // Using index or `at` accessors + std::string result1 = j["reputons"][0]["rated"].as(); + std::cout << "(1) " << result1 << std::endl; + std::string result2 = j.at("reputons").at(0).at("rated").as(); + std::cout << "(2) " << result2 << std::endl; + + // Using JSON Pointer + std::string result3 = jsonpointer::get(j, "/reputons/0/rated").as(); + std::cout << "(3) " << result3 << std::endl; + + // Using JSONPath + json result4 = jsonpath::json_query(j, "$.reputons.0.rated"); + if (result4.size() > 0) + { + std::cout << "(4) " << result4[0].as() << std::endl; + } + json result5 = jsonpath::json_query(j, "$..0.rated"); + if (result5.size() > 0) + { + std::cout << "(5) " << result5[0].as() << std::endl; + } +} +``` + +
+ +#### Retrieve a json value as a byte string + +```c++ +#include + +namespace jc=jsoncons; + +int main() +{ + json j; + j["ByteString"] = byte_string({'H','e','l','l','o'}); + j["EncodedByteString"] = json("SGVsbG8=", semantic_tag::base64); + + std::cout << "(1)\n"; + std::cout << pretty_print(j) << "\n\n"; + + // Retrieve a byte string as a jsoncons::byte_string + byte_string bs1 = j["ByteString"].as(); + std::cout << "(2) " << bs1 << "\n\n"; + + // or alternatively as a std::vector + std::vector v = j["ByteString"].as>(); + + // Retrieve a byte string from a text string containing base64 character values + byte_string bs2 = j["EncodedByteString"].as(); + std::cout << "(3) " << bs2 << "\n\n"; + + // Retrieve a byte string view to access the memory that's holding the byte string + byte_string_view bsv3 = j["ByteString"].as(); + std::cout << "(4) " << bsv3 << "\n\n"; + + // Can't retrieve a byte string view of a text string + try + { + byte_string_view bsv4 = j["EncodedByteString"].as(); + } + catch (const std::exception& e) + { + std::cout << "(5) "<< e.what() << "\n\n"; + } +} +``` +Output: +``` +(1) +{ + "ByteString": "SGVsbG8", + "EncodedByteString": "SGVsbG8=" +} + +(2) 48656c6c6f + +(3) 48656c6c6f + +(4) 48656c6c6f + +(5) Not a byte string +``` + +### Search and Replace + +
+ +#### Search for and repace an object member key + +You can rename object members with the built in filter [rename_object_member_filter](ref/rename_object_member_filter.md) + +```c++ +#include +#include +#include + +using namespace jsoncons; + +int main() +{ + std::string s = R"({"first":1,"second":2,"fourth":3,"fifth":4})"; + + json_encoder encoder(std::cout); + + // Filters can be chained + rename_object_member_filter filter2("fifth", "fourth", encoder); + rename_object_member_filter filter1("fourth", "third", filter2); + + // A filter can be passed to any function that takes a json_content_handler ... + std::cout << "(1) "; + std::istringstream is(s); + json_reader reader(is, filter1); + reader.read(); + std::cout << std::endl; + + // or + std::cout << "(2) "; + ojson j = ojson::parse(s); + j.dump(filter1); + std::cout << std::endl; +} +``` +Output: +```json +(1) {"first":1,"second":2,"third":3,"fourth":4} +(2) {"first":1,"second":2,"third":3,"fourth":4} +``` + +
+ +#### Search for and replace a value + +You can use [json_replace](ref/jsonpath/json_replace.md) in the `jsonpath` extension + +```c++ +#include +#include + +using namespace jsoncons; + +int main() +{ + json j = json::parse(R"( + { "store": { + "book": [ + { "category": "reference", + "author": "Nigel Rees", + "title": "Sayings of the Century", + "price": 8.95 + }, + { "category": "fiction", + "author": "Evelyn Waugh", + "title": "Sword of Honour", + "price": 12.99 + }, + { "category": "fiction", + "author": "Herman Melville", + "title": "Moby Dick", + "isbn": "0-553-21311-3", + "price": 8.99 + } + ] + } + } + )"); + + // Change the price of "Moby Dick" from $8.99 to $10 + jsonpath::json_replace(j,"$.store.book[?(@.isbn == '0-553-21311-3')].price",10.0); + std::cout << pretty_print(booklist) << std::endl; +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/Home.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/Home.md new file mode 100644 index 0000000000..87e082e5b5 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/Home.md @@ -0,0 +1,64 @@ +All core jsoncons classes and functions are in namespace `jsoncons`. + +#### Unpacked Representation + +[json](ref/json.md) +[json_parser](ref/json_parser.md) +[json_reader](ref/json_reader.md) +[json_decoder](ref/json_decoder.md) + +[ojson](ref/ojson.md) + +[wjson](ref/wjson.md) +[wjson_reader](ref/wjson_reader.md) + +[wojson](ref/wojson.md) + +#### C++/JSON Conversion + +[encode_json](ref/encode_json.md) +[decode_json](ref/decode_json.md) + +#### Streaming + +[json_content_handler](ref/json_content_handler.md) +[json_encoder](ref/json_encoder.md) +[json_options](ref/json_options.md) + +[wjson_encoder](ref/wjson_encoder.md) +[wjson_options](ref/wjson_options.md) + +[json_filter](ref/json_filter.md) +[rename_object_member_filter](ref/rename_object_member_filter.md) + +[json_cursor](ref/json_cursor.md) +[staj_reader](ref/staj_reader.md) +[staj_object_iterator](ref/staj_object_iterator.md) +[staj_array_iterator](ref/staj_array_iterator.md) + +### Extensions + +#### [jsonpointer](ref/jsonpointer/jsonpointer.md) + +#### [jsonpatch](ref/jsonpatch/jsonpatch.md) + +#### [jsonpath](ref/jsonpath/jsonpath.md) + +#### [cbor](ref/cbor/cbor.md) + +#### [msgpack](ref/msgpack/msgpack.md) + +#### [ubjson](ref/ubjson/ubjson.md) + +#### [msgpack](ref/msgpack/msgpack.md) + +#### [bson](ref/bson/bson.md) + +### Tutorials + +[Basics](Tutorials/Basics.md) + +[Custom Allocators](Tutorials/Custom%20Allocators.md) + +[Unicode support](Tutorials/Unicode%20support.md) + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/Pages/index.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/Pages/index.md new file mode 100644 index 0000000000..f5d894358d --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/Pages/index.md @@ -0,0 +1,812 @@ +# jsoncons: a C++ library for json construction + +[Preliminaries](#A1) + +[Reading JSON text from a file](#A2) + +[Constructing json values in C++](#A3) + +[Conversion between JSON and C++ data structures](#A4) + +[Converting CSV files to json](#A5 ) + +[Pretty print](#A6) + +[Filters](#A7) + +[JSONPath](#A8) + +[About jsoncons::json](#A9) + +[Wide character support](#A10) + +[ojson and wojson](#A11) + +
+### Preliminaries + +jsoncons is a C++, header-only library for constructing [JSON](http://www.json.org) and JSON-like +data formats such as [CBOR](http://cbor.io/). It supports + +- Parsing JSON-like text or binary formats into a tree model + that defines an interface for accessing and modifying that data (covers bignum and byte string values.) + +- Serializing the tree model into different JSON-like text or binary formats. + +- Converting from JSON-like text or binary formats to C++ data structures and back via [json_type_traits](https://github.com/danielaparker/jsoncons/blob/master/doc/ref/json_type_traits.md). + +- Streaming JSON read and write events, somewhat analogously to SAX (push parsing) and StAX (pull parsing) in the XML world. + +The jsoncons library is header-only: it consists solely of header files containing templates and inline functions, and requires no separately-compiled library binaries when linking. It has no dependence on other libraries. + +To install the librray, download the [latest release](https://github.com/danielaparker/jsoncons/releases) and unpack the zip file. Copy the directory `include/jsoncons` to your `include` directory. If you wish to use extensions, copy `include/jsoncons_ext` as well. + +Or, download the latest code on [master](https://github.com/danielaparker/jsoncons/archive/master.zip). + +Compared to other JSON libraries, jsoncons has been designed to handle very large JSON texts. At its heart are +SAX style parsers and serializers. Its [json parser](https://github.com/danielaparker/jsoncons/blob/master/doc/ref/json_parser.md) is an +incremental parser that can be fed its input in chunks, and does not require an entire file to be loaded in memory at one time. +Its tree model is more compact than most, and can be made more compact still with a user-supplied +allocator. It also supports memory efficient parsing of very large JSON texts with a [pull parser](https://github.com/danielaparker/jsoncons/blob/master/doc/ref/json_cursor.md), +built on top of its incremental parser. + +The [jsoncons data model](https://github.com/danielaparker/jsoncons/blob/master/doc/ref/data-model.md) supports the familiar JSON types - nulls, +booleans, numbers, strings, arrays, objects - plus byte strings. In addition, jsoncons +supports semantic tagging of date-time values, timestamp values, big integers, +big decimals, bigfloats and binary encodings. This allows it to preserve these type semantics when parsing +JSON-like data formats such as CBOR that have them. + +The jsoncons classes and functions are in namespace `jsoncons`. You need to include the header file +```c++ +#include +``` +and, for convenience, +```c++ +using jsoncons::json; +``` + +
+### Reading JSON text from a file + +Example file (`books.json`): +```c++ +[ + { + "title" : "Kafka on the Shore", + "author" : "Haruki Murakami", + "price" : 25.17 + }, + { + "title" : "Women: A Novel", + "author" : "Charles Bukowski", + "price" : 12.0 + }, + { + "title" : "Cutter's Way", + "author" : "Ivan Passer" + } +] +``` +It consists of an array of book elements, each element is an object with members title, author, and price. + +Read the JSON text into a `json` value, +```c++ +std::ifstream is("books.json"); +json books = json::parse(is); +``` +Loop through the book array elements, using a range-based for loop +```c++ +for (const auto& book : books.array_range()) +{ + std::string author = book["author"].as(); + std::string title = book["title"].as(); + std::cout << author << ", " << title << std::endl; +} +``` +or begin-end iterators +```c++ +for (auto it = books.array_range().begin(); + it != books.array_range().end(); + ++it) +{ + std::string author = (*it)["author"].as(); + std::string title = (*it)["title"].as(); + std::cout << author << ", " << title << std::endl; +} +``` +or a traditional for loop +```c++ +for (size_t i = 0; i < books.size(); ++i) +{ + json& book = books[i]; + std::string author = book["author"].as(); + std::string title = book["title"].as(); + std::cout << author << ", " << title << std::endl; +} +``` +Output: +``` +Haruki Murakami, Kafka on the Shore +Charles Bukowski, Women: A Novel +Ivan Passer, Cutter's Way +``` + +Loop through the members of the third book element, using a range-based for loop + +```c++ +for (const auto& member : books[2].object_range()) +{ + std::cout << member.key() << "=" + << member.value() << std::endl; +} +``` + +or begin-end iterators: + +```c++ +for (auto it = books[2].object_range().begin(); + it != books[2].object_range().end(); + ++it) +{ + std::cout << (*it).key() << "=" + << (*it).value() << std::endl; +} +``` +Output: +``` +author=Ivan Passer +title=Cutter's Way +``` + +Note that the third book, Cutter's Way, is missing a price. + +You have a choice of object member accessors: + +- `book["price"]` will throw `std::out_of_range` if there is no price +- `book.get_with_default("price",std::string("n/a"))` will return the price converted to the + default's data type, `std::string`, or `"n/a"` if there is no price. + +So if you want to show "n/a" for the missing price, you can use this accessor +```c++ +std::string price = book.get_with_default("price","n/a"); +``` +Or you can check if book has a member "price" with the method `contains`, and output accordingly, +```c++ +if (book.contains("price")) +{ + double price = book["price"].as(); + std::cout << price; +} +else +{ + std::cout << "n/a"; +} +``` +
+### Constructing json values in C++ + +The default `json` constructor produces an empty json object. For example +```c++ +json image_sizing; +std::cout << image_sizing << std::endl; +``` +produces +```json +{} +``` +To construct a json object with members, take an empty json object and set some name-value pairs +```c++ +image_sizing.insert_or_assign("Resize To Fit",true); // a boolean +image_sizing.insert_or_assign("Resize Unit", "pixels"); // a string +image_sizing.insert_or_assign("Resize What", "long_edge"); // a string +image_sizing.insert_or_assign("Dimension 1",9.84); // a double +image_sizing.insert_or_assign("Dimension 2",json::null()); // a null value +``` + +Or, use an object initializer-list: +```c++ +json file_settings = json::object{ + {"Image Format", "JPEG"}, + {"Color Space", "sRGB"}, + {"Limit File Size", true}, + {"Limit File Size To", 10000} +}; +``` + +To construct a json array, initialize with the array type +```c++ +json color_spaces = json::array(); +``` +and add some elements +```c++ +color_spaces.push_back("sRGB"); +color_spaces.push_back("AdobeRGB"); +color_spaces.push_back("ProPhoto RGB"); +``` + +Or, use an array initializer-list: +```c++ +json image_formats = json::array{"JPEG","PSD","TIFF","DNG"}; +``` + +The `operator[]` provides another way for setting name-value pairs. +```c++ +json file_export; +file_export["File Format Options"]["Color Spaces"] = + std::move(color_spaces); +file_export["File Format Options"]["Image Formats"] = + std::move(image_formats); +file_export["File Settings"] = std::move(file_settings); +file_export["Image Sizing"] = std::move(image_sizing); +``` +Note that if `file_export["File Format Options"]` doesn't exist, +```c++ +file_export["File Format Options"]["Color Spaces"] = + std::move(color_spaces) +``` +creates `"File Format Options"` as an object and puts `"Color Spaces"` in it. + +Serializing +```c++ +std::cout << pretty_print(file_export) << std::endl; +``` +produces +```json +{ + "File Format Options": { + "Color Spaces": ["sRGB","AdobeRGB","ProPhoto RGB"], + "Image Formats": ["JPEG","PSD","TIFF","DNG"] + }, + "File Settings": { + "Color Space": "sRGB", + "Image Format": "JPEG", + "Limit File Size": true, + "Limit File Size To": 10000 + }, + "Image Sizing": { + "Dimension 1": 9.84, + "Dimension 2": null, + "Resize To Fit": true, + "Resize Unit": "pixels", + "Resize What": "long_edge" + } +} +``` +
+### Conversion between JSON and C++ data structures + +jsoncons supports conversion between JSON text and C++ data structures. The functions [decode_json](https://github.com/danielaparker/jsoncons/blob/master/doc/ref/decode_json.md) +and [encode_json](https://github.com/danielaparker/jsoncons/blob/master/doc/ref/encode_json.md) convert JSON formatted strings or streams to C++ data structures and back. +Decode and encode work for all C++ classes that have +[json_type_traits](https://github.com/danielaparker/jsoncons/blob/master/doc/ref/json_type_traits.md) +defined. The standard library containers are already supported, and you can specialize `json_type_traits` +for your own types in the `jsoncons` namespace. + +`JSONCONS_MEMBER_TRAITS_DECL` is a macro that simplifies the creation of the necessary boilerplate +for your own types. + +```c++ +#include +#include +#include + +using namespace jsoncons; + +namespace ns { + + struct reputon + { + std::string rater; + std::string assertion; + std::string rated; + double rating; + + friend bool operator==(const reputon& lhs, const reputon& rhs) + { + return lhs.rater == rhs.rater && + lhs.assertion == rhs.assertion && + lhs.rated == rhs.rated && + lhs.rating == rhs.rating; + } + + friend bool operator!=(const reputon& lhs, const reputon& rhs) + { + return !(lhs == rhs); + }; + }; + + class reputation_object + { + std::string application; + std::vector reputons; + + // Make json_type_traits specializations friends to give accesses to private members + JSONCONS_TYPE_TRAITS_FRIEND; + public: + reputation_object() + { + } + reputation_object(const std::string& application, const std::vector& reputons) + : application(application), reputons(reputons) + {} + + friend bool operator==(const reputation_object& lhs, const reputation_object& rhs) + { + if (lhs.application != rhs.application) + { + return false; + } + if (lhs.reputons.size() != rhs.reputons.size()) + { + return false; + } + for (size_t i = 0; i < lhs.reputons.size(); ++i) + { + if (lhs.reputons[i] != rhs.reputons[i]) + { + return false; + } + } + return true; + } + + friend bool operator!=(const reputation_object& lhs, const reputation_object& rhs) + { + return !(lhs == rhs); + }; + }; + +} // namespace ns + +// Declare the traits. Specify which data members need to be serialized. +JSONCONS_MEMBER_TRAITS_DECL(ns::reputon, rater, assertion, rated, rating) +JSONCONS_MEMBER_TRAITS_DECL(ns::reputation_object, application, reputons) + +int main() +{ + ns::reputation_object val("hiking", { ns::reputon{"HikingAsylum.example.com","strong-hiker","Marilyn C",0.90} }); + + std::string s; + encode_json(val, s, indenting::indent); + std::cout << s << "\n"; + + auto val2 = decode_json(s); + + assert(val2 == val); +} +``` +Output: +``` +{ + "application": "hiking", + "reputons": [ + { + "assertion": "strong-hiker", + "rated": "Marilyn C", + "rater": "HikingAsylum.example.com", + "rating": 0.9 + } + ] +} +``` + +See [examples](https://github.com/danielaparker/jsoncons/blob/master/doc/Examples.md#G1) + +
+### Converting CSV files to json + +Example CSV file (tasks.csv): + +``` +project_id, task_name, task_start, task_finish +4001,task1,01/01/2003,01/31/2003 +4001,task2,02/01/2003,02/28/2003 +4001,task3,03/01/2003,03/31/2003 +4002,task1,04/01/2003,04/30/2003 +4002,task2,05/01/2003, +``` + +You can read the `CSV` file into a `json` value with the `decode_csv` function. + +```c++ +#include +#include +#include +#include + +using namespace jsoncons; + +int main() +{ + std::ifstream is("input/tasks.csv"); + + csv::csv_options options; + options.assume_header(true) + .trim(true) + .ignore_empty_values(true) + .column_types("integer,string,string,string"); + ojson tasks = csv::decode_csv(is, options); + + std::cout << "(1)\n" << pretty_print(tasks) << "\n\n"; + + std::cout << "(2)\n"; + csv::encode_csv(tasks, std::cout); +} +``` +Output: +```json +(1) +[ + { + "project_id": 4001, + "task_name": "task1", + "task_start": "01/01/2003", + "task_finish": "01/31/2003" + }, + { + "project_id": 4001, + "task_name": "task2", + "task_start": "02/01/2003", + "task_finish": "02/28/2003" + }, + { + "project_id": 4001, + "task_name": "task3", + "task_start": "03/01/2003", + "task_finish": "03/31/2003" + }, + { + "project_id": 4002, + "task_name": "task1", + "task_start": "04/01/2003", + "task_finish": "04/30/2003" + }, + { + "project_id": 4002, + "task_name": "task2", + "task_start": "05/01/2003" + } +] +``` +There are a few things to note about the effect of the parameter settings. +- `assume_header` `true` tells the csv parser to parse the first line of the file for column names, which become object member names. +- `trim` `true` tells the parser to trim leading and trailing whitespace, in particular, to remove the leading whitespace in the column names. +- `ignore_empty_values` `true` causes the empty last value in the `task_finish` column to be omitted. +- The `column_types` setting specifies that column one ("project_id") contains integers and the remaining columns strings. + +
+### Pretty print + +The `pretty_print` function applies stylistic formatting to JSON text. For example + +```c++ + json val; + + val["verts"] = json::array{1, 2, 3}; + val["normals"] = json::array{1, 0, 1}; + val["uvs"] = json::array{0, 0, 1, 1}; + + std::cout << pretty_print(val) << std::endl; +``` +produces + +```json +{ + "normals": [1,0,1], + "uvs": [0,0,1,1], + "verts": [1,2,3] +} +``` +By default, within objects, arrays of scalar values are displayed on the same line. + +The `pretty_print` function takes an optional second parameter, [json_options](https://github.com/danielaparker/jsoncons/blob/master/doc/ref/json_options.md), that allows custom formatting of output. +To display the array scalar values on a new line, set the `object_array_line_splits` property to `line_split_kind::new_line`. The code +```c++ +json_options options; +format.object_array_line_splits(line_split_kind::new_line); +std::cout << pretty_print(val,options) << std::endl; +``` +produces +```json +{ + "normals": [ + 1,0,1 + ], + "uvs": [ + 0,0,1,1 + ], + "verts": [ + 1,2,3 + ] +} +``` +To display the elements of array values on multiple lines, set the `object_array_line_splits` property to `line_split_kind::multi_line`. The code +```c++ +json_options options; +format.object_array_line_splits(line_split_kind::multi_line); +std::cout << pretty_print(val,options) << std::endl; +``` +produces +```json +{ + "normals": [ + 1, + 0, + 1 + ], + "uvs": [ + 0, + 0, + 1, + 1 + ], + "verts": [ + 1, + 2, + 3 + ] +} +``` +
+### Filters + +You can rename object member names with the built in filter [rename_object_member_filter](https://github.com/danielaparker/jsoncons/blob/master/doc/ref/rename_object_member_filter.md) + +```c++ +#include +#include +#include + +using namespace jsoncons; + +int main() +{ + std::string s = R"({"first":1,"second":2,"fourth":3,"fifth":4})"; + + json_encoder encoder(std::cout); + + // Filters can be chained + rename_object_member_filter filter2("fifth", "fourth", encoder); + rename_object_member_filter filter1("fourth", "third", filter2); + + // A filter can be passed to any function that takes + // a json_content_handler ... + std::cout << "(1) "; + std::istringstream is(s); + json_reader reader(is, filter1); + reader.read(); + std::cout << std::endl; + + // or a json_content_handler + std::cout << "(2) "; + ojson j = ojson::parse(s); + j.dump(filter1); + std::cout << std::endl; +} +``` +Output: +```json +(1) {"first":1,"second":2,"third":3,"fourth":4} +(2) {"first":1,"second":2,"third":3,"fourth":4} +``` +Or define and use your own filters. See [json_filter](https://github.com/danielaparker/jsoncons/blob/master/doc/ref/json_filter.md) for details. +
+### JSONPath + +[Stefan Goessner's JSONPath](http://goessner.net/articles/JsonPath/) is an XPATH inspired query language for selecting parts of a JSON structure. + +Example JSON file (booklist.json): +```json +{ "store": { + "book": [ + { "category": "reference", + "author": "Nigel Rees", + "title": "Sayings of the Century", + "price": 8.95 + }, + { "category": "fiction", + "author": "Evelyn Waugh", + "title": "Sword of Honour", + "price": 12.99 + }, + { "category": "fiction", + "author": "Herman Melville", + "title": "Moby Dick", + "isbn": "0-553-21311-3", + "price": 8.99 + }, + { "category": "fiction", + "author": "J. R. R. Tolkien", + "title": "The Lord of the Rings", + "isbn": "0-395-19395-8", + "price": 22.99 + } + ] + } +} +``` +JSONPath examples: +```c++ +#include + +using jsoncons::jsonpath::json_query; + +std::ifstream is("./input/booklist.json"); +json booklist = json::parse(is); + +// The authors of books that are cheaper than $10 +json result1 = json_query(booklist, "$.store.book[?(@.price < 10)].author"); +std::cout << "(1) " << result1 << std::endl; + +// The number of books +json result2 = json_query(booklist, "$..book.length"); +std::cout << "(2) " << result2 << std::endl; + +// The third book +json result3 = json_query(booklist, "$..book[2]"); +std::cout << "(3)\n" << pretty_print(result3) << std::endl; + +// All books whose author's name starts with Evelyn +json result4 = json_query(booklist, "$.store.book[?(@.author =~ /Evelyn.*?/)]"); +std::cout << "(4)\n" << pretty_print(result4) << std::endl; + +// The titles of all books that have isbn number +json result5 = json_query(booklist, "$..book[?(@.isbn)].title"); +std::cout << "(5) " << result5 << std::endl; + +// All authors and titles of books +json result6 = json_query(booklist, "$['store']['book']..['author','title']"); +std::cout << "(6)\n" << pretty_print(result6) << std::endl; +``` +Output: +```json +(1) ["Nigel Rees","Herman Melville"] +(2) [4] +(3) +[ + { + "author": "Herman Melville", + "category": "fiction", + "isbn": "0-553-21311-3", + "price": 8.99, + "title": "Moby Dick" + } +] +(4) +[ + { + "author": "Evelyn Waugh", + "category": "fiction", + "price": 12.99, + "title": "Sword of Honour" + } +] +(5) ["Moby Dick","The Lord of the Rings"] +(6) +[ + "Nigel Rees", + "Sayings of the Century", + "Evelyn Waugh", + "Sword of Honour", + "Herman Melville", + "Moby Dick", + "J. R. R. Tolkien", + "The Lord of the Rings" +] +``` +
+### About jsoncons::json + +The [json](https://github.com/danielaparker/jsoncons/blob/master/doc/ref/json.md) class is an instantiation of the `basic_json` class template that uses `char` as the character type +and sorts object members in alphabetically order. +```c++ +typedef basic_json> json; +``` +If you prefer to retain the original insertion order, use [ojson](https://github.com/danielaparker/jsoncons/blob/master/doc/ref/ojson.md) instead. + +The library includes an instantiation for wide characters as well, [wjson](https://github.com/danielaparker/jsoncons/blob/master/ref/doc/wjson.md) +```c++ +typedef basic_json> wjson; +``` +If you prefer to retain the original insertion order, use [wojson](https://github.com/danielaparker/jsoncons/blob/master/doc/ref/wojson.md) instead. + +Note that the allocator type allows you to supply a custom allocator. For example, you can use the boost [fast_pool_allocator](http://www.boost.org/doc/libs/1_60_0/libs/pool/doc/html/boost/fast_pool_allocator.html): +```c++ +#include +#include + +typedef jsoncons::basic_json> myjson; + +myjson o; + +o.insert_or_assign("FirstName","Joe"); +o.insert_or_assign("LastName","Smith"); +``` +This results in a json value being constucted with all memory being allocated from the boost memory pool. (In this particular case there is no improvement in performance over `std::allocator`.) + +Note that the underlying memory pool used by the `boost::fast_pool_allocator` is never freed. + +
+### Wide character support + +jsoncons supports wide character strings and streams with `wjson` and `wjson_reader`. It supports `UTF16` encoding if `wchar_t` has size 2 (Windows) and `UTF32` encoding if `wchar_t` has size 4. You can construct a `wjson` value in exactly the same way as a `json` value, for instance: +```c++ +using jsoncons::wjson; + +wjson root; +root[L"field1"] = L"test"; +root[L"field2"] = 3.9; +root[L"field3"] = true; + +std::wcout << root << L"\n"; +``` +which prints +```c++ +{"field1":"test","field2":3.9,"field3":true} +``` +
+### ojson and wojson + +The [ojson](https://github.com/danielaparker/jsoncons/blob/master/doc/ref/ojson.md) ([wojson](https://github.com/danielaparker/jsoncons/blob/master/doc/ref/wojson.md)) class is an instantiation of the `basic_json` class template that uses `char` (`wchar_t`) as the character type and keeps object members in their original order. +```c++ +ojson o = ojson::parse(R"( +{ + "street_number" : "100", + "street_name" : "Queen St W", + "city" : "Toronto", + "country" : "Canada" +} +)"); + +std::cout << pretty_print(o) << std::endl; +``` +Output: +```json +{ + "street_number": "100", + "street_name": "Queen St W", + "city": "Toronto", + "country": "Canada" +} +``` +Insert "postal_code" at end +```c++ +o.insert_or_assign("postal_code", "M5H 2N2"); + +std::cout << pretty_print(o) << std::endl; +``` +Output: +```json +{ + "street_number": "100", + "street_name": "Queen St W", + "city": "Toronto", + "country": "Canada", + "postal_code": "M5H 2N2" +} +``` +Insert "province" before "country" +```c++ +auto it = o.find("country"); +o.insert_or_assign(it,"province","Ontario"); + +std::cout << pretty_print(o) << std::endl; +``` +Output: +```json +{ + "street_number": "100", + "street_name": "Queen St W", + "city": "Toronto", + "province": "Ontario", + "country": "Canada", + "postal_code": "M5H 2N2" +} +``` + +For more information, consult the latest [examples](https://github.com/danielaparker/jsoncons/blob/master/doc/Examples.md), [documentation](https://github.com/danielaparker/jsoncons/blob/master/doc/Home.md) and [roadmap](https://github.com/danielaparker/jsoncons/blob/master/Roadmap.md). + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/Tutorials/Basics.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/Tutorials/Basics.md new file mode 100644 index 0000000000..d0d31ddfc5 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/Tutorials/Basics.md @@ -0,0 +1,448 @@ +## Examples + +The examples below illustrate the use of the [json](../ref/json.md) class and [json_query](../ref/jsonpath/json_query.md) function. + +### json construction + +```c++ +#include + +// For convenience +using jsoncons::json; + +// Construct a book object +json book1; + +book1["category"] = "Fiction"; +book1["title"] = "A Wild Sheep Chase: A Novel"; +book1["author"] = "Haruki Murakami"; +book1["date"] = "2002-04-09"; +book1["price"] = 9.01; +book1["isbn"] = "037571894X"; + +// Construct another using the insert_or_assign function +json book2; + +book2.insert_or_assign("category", "History"); +book2.insert_or_assign("title", "Charlie Wilson's War"); +book2.insert_or_assign("author", "George Crile"); +book2.insert_or_assign("date", "2007-11-06"); +book2.insert_or_assign("price", 10.50); +book2.insert_or_assign("isbn", "0802143415"); + +// Use insert_or_assign again, but more efficiently +json book3; + +// Reserve memory, to avoid reallocations +book3.reserve(6); + +// Insert in name alphabetical order +// Give insert_or_assign a hint where to insert the next member +auto hint = book3.insert_or_assign(book3.object_range().begin(),"author", "Haruki Murakami"); +hint = book3.insert_or_assign(hint, "category", "Fiction"); +hint = book3.insert_or_assign(hint, "date", "2006-01-03"); +hint = book3.insert_or_assign(hint, "isbn", "1400079276"); +hint = book3.insert_or_assign(hint, "price", 13.45); +hint = book3.insert_or_assign(hint, "title", "Kafka on the Shore"); + +// Construct a fourth from a string +json book4 = json::parse(R"( +{ + "category" : "Fiction", + "title" : "Pulp", + "author" : "Charles Bukowski", + "date" : "2004-07-08", + "price" : 22.48, + "isbn" : "1852272007" +} +)"); + +// Construct a booklist array + +json booklist = json::array(); + +// For efficiency, reserve memory, to avoid reallocations +booklist.reserve(4); + +// For efficency, tell jsoncons to move the contents +// of the four book objects into the array +booklist.add(std::move(book1)); +booklist.add(std::move(book2)); + +// Add the third book to the front +auto pos = booklist.add(booklist.array_range().begin(),std::move(book3)); + +// and the last one immediately after +booklist.add(pos+1,std::move(book4)); + +// See what's left of book1, 2, 3 and 4 (expect nulls) +std::cout << book1 << "," << book2 << "," << book3 << "," << book4 << std::endl; + + +++ +//Loop through the booklist elements using a range-based for loop +for (const auto& book : booklist.array_range()) +{ + std::cout << book["title"].as() + << "," + << book["price"].as() << std::endl; +} + +// The second book +json& book = booklist[1]; + +//Loop through the book's name-value pairs using a range-based for loop +for (const auto& member : book.object_range()) +{ + std::cout << member.key() + << "," + << member.value() << std::endl; +} + +auto it = book.find("author"); +if (it != book.object_range().end()) +{ + // member "author" found +} + +if (book.contains("author")) +{ + // book has a member "author" +} + +book.get("author", "author unknown").as(); +// Returns author if found, otherwise "author unknown" + +try +{ + book["ratings"].as(); +} +catch (const std::out_of_range& e) +{ + // member "ratings" not found +} + +// Add ratings +book["ratings"]["*****"] = 4; +book["ratings"]["*"] = 2; + +// Delete one-star ratings +book["ratings"].erase("*"); + +``` +```c++ + // Serialize the booklist to a file + std::ofstream os("booklist.json"); + os << pretty_print(booklist); +``` + +The JSON output `booklist.json` +```json +[ + { + "author":"Haruki Murakami", + "category":"Fiction", + "date":"2006-01-03", + "isbn":"1400079276", + "price":13.45, + "title":"Kafka on the Shore" + }, + { + "author":"Charles Bukowski", + "category":"Fiction", + "date":"2004-07-08", + "isbn":"1852272007", + "price":22.48, + "ratings": + { + "*****":4 + }, + "title":"Pulp" + }, + { + "author":"Haruki Murakami", + "category":"Fiction", + "date":"2002-04-09", + "isbn":"037571894X", + "price":9.01, + "title":"A Wild Sheep Chase: A Novel" + }, + { + "author":"George Crile", + "category":"History", + "date":"2007-11-06", + "isbn":"0802143415", + "price":10.5, + "title":"Charlie Wilson's War" + } +] +``` +### json query + +```c++ +#include +#include +#include + +// For convenience +using jsoncons::json; +using jsoncons::jsonpath::json_query; + +// Deserialize the booklist +std::ifstream is("booklist.json"); +json booklist; +is >> booklist; + +// Use a JSONPath expression to find +// +// (1) The authors of books that cost less than $12 +json result = json_query(booklist, "$[*][?(@.price < 12)].author"); +std::cout << result << std::endl; + +// (2) The number of books +result = json_query(booklist, "$.length"); +std::cout << result << std::endl; + +// (3) The third book +result = json_query(booklist, "$[2]"); +std::cout << std::endl << pretty_print(result) << std::endl; + +// (4) The authors of books that were published in 2004 +result = json_query(booklist, "$[*][?(@.date =~ /2004.*?/)].author"); +std::cout << result << std::endl; + +// (5) The titles of all books that have ratings +result = json_query(booklist, "$[*][?(@.ratings)].title"); +std::cout << result << std::endl; + +// (6) All authors and titles of books +result = json_query(booklist, "$..['author','title']"); +std::cout << pretty_print(result) << std::endl; +``` +Result: +```json +(1) ["Haruki Murakami","George Crile"] +(2) [4] +(3) +[ + { + "author":"Haruki Murakami", + "category":"Fiction", + "date":"2002-04-09", + "isbn":"037571894X", + "price":9.01, + "title":"A Wild Sheep Chase: A Novel" + } +] +(4) ["Charles Bukowski"] +(5) ["Pulp"] +(6) +[ + "Nigel Rees", + "Sayings of the Century", + "Evelyn Waugh", + "Sword of Honour", + "Herman Melville", + "Moby Dick", + "J. R. R. Tolkien", + "The Lord of the Rings" +] +``` +## Once again, this time with wide characters + +### wjson construction + +```c++ +#include + +// For convenience +using jsoncons::wjson; + +// Construct a book object +wjson book1; + +book1[L"category"] = L"Fiction"; +book1[L"title"] = L"A Wild Sheep Chase: A Novel"; +book1[L"author"] = L"Haruki Murakami"; +book1[L"date"] = L"2002-04-09"; +book1[L"price"] = 9.01; +book1[L"isbn"] = L"037571894X"; + +// Construct another using the insert_or_assign function +wjson book2; + +book2.insert_or_assign(L"category", L"History"); +book2.insert_or_assign(L"title", L"Charlie Wilson's War"); +book2.insert_or_assign(L"author", L"George Crile"); +book2.insert_or_assign(L"date", L"2007-11-06"); +book2.insert_or_assign(L"price", 10.50); +book2.insert_or_assign(L"isbn", L"0802143415"); + +// Use insert_or_assign again, but more efficiently +wjson book3; + +// Reserve memory, to avoid reallocations +book3.reserve(6); + +// Insert in name alphabetical order +// Give insert_or_assign a hint where to insert the next member +auto hint = book3.insert_or_assign(book3.object_range().begin(), L"author", L"Haruki Murakami"); +hint = book3.insert_or_assign(hint, L"category", L"Fiction"); +hint = book3.insert_or_assign(hint, L"date", L"2006-01-03"); +hint = book3.insert_or_assign(hint, L"isbn", L"1400079276"); +hint = book3.insert_or_assign(hint, L"price", 13.45); +hint = book3.insert_or_assign(hint, L"title", L"Kafka on the Shore"); + +// Construct a fourth from a string +wjson book4 = wjson::parse(LR"( +{ + "category" : "Fiction", + "title" : "Pulp", + "author" : "Charles Bukowski", + "date" : "2004-07-08", + "price" : 22.48, + "isbn" : "1852272007" +} +)"); + +// Construct a booklist array + +wjson booklist = wjson::array(); + +// For efficiency, reserve memory, to avoid reallocations +booklist.reserve(4); + +// For efficency, tell jsoncons to move the contents +// of the four book objects into the array +booklist.add(std::move(book1)); +booklist.add(std::move(book2)); + +// Add the third book to the front +auto pos = booklist.add(booklist.array_range().begin(),std::move(book3)); + +// and the last one immediately after +booklist.add(pos+1,std::move(book4)); + +// See what's left of book1, 2, 3 and 4 (expect nulls) +std::wcout << book1 << L"," << book2 << L"," << book3 << L"," << book4 << std::endl; + +++ +//Loop through the booklist elements using a range-based for loop +for (const auto& book : booklist.array_range()) +{ + std::wcout << book[L"title"].as() + << L"," + << book[L"price"].as() << std::endl; +} + +// The second book +wjson& book = booklist[1]; + +//Loop through the book's name-value pairs using a range-based for loop +for (const auto& member : book.object_range()) +{ + std::wcout << member.key() + << L"," + << member.value() << std::endl; +} + +auto it = book.find(L"author"); +if (it != book.object_range().end()) +{ + // member "author" found +} + +if (book.contains(L"author")) +{ + // book has a member "author" +} + +book.get(L"author", L"author unknown").as(); +// Returns author if found, otherwise "author unknown" + +try +{ + book[L"ratings"].as(); +} +catch (const std::out_of_range& e) +{ + // member "ratings" not found +} + +// Add ratings +book[L"ratings"][L"*****"] = 4; +book[L"ratings"][L"*"] = 2; + +// Delete one-star ratings +book[L"ratings"].erase(L"*"); + +``` +```c++ +// Serialize the booklist to a file +std::wofstream os("booklist2.json"); +os << pretty_print(booklist); +``` +### wjson query + +```c++ +// Deserialize the booklist +std::wifstream is("booklist2.json"); +wjson booklist; +is >> booklist; + +// Use a JSONPath expression to find +// +// (1) The authors of books that cost less than $12 +wjson result = json_query(booklist, L"$[*][?(@.price < 12)].author"); +std::wcout << result << std::endl; + +// (2) The number of books +result = json_query(booklist, L"$.length"); +std::wcout << result << std::endl; + +// (3) The third book +result = json_query(booklist, L"$[2]"); +std::wcout << pretty_print(result) << std::endl; + +// (4) The authors of books that were published in 2004 +result = json_query(booklist, L"$[*][?(@.date =~ /2004.*?/)].author"); +std::wcout << result << std::endl; + +// (5) The titles of all books that have ratings +result = json_query(booklist, L"$[*][?(@.ratings)].title"); +std::wcout << result << std::endl; + +// (6) All authors and titles of books +result = json_query(booklist, L"$..['author','title']"); +std::wcout << pretty_print(result) << std::endl; +``` +Result: +```json +(1) ["Haruki Murakami","George Crile"] +(2) [4] +(3) +[ + { + "author":"Haruki Murakami", + "category":"Fiction", + "date":"2002-04-09", + "isbn":"037571894X", + "price":9.01, + "title":"A Wild Sheep Chase: A Novel" + } +] +(4) ["Charles Bukowski"] +(5) ["Pulp"] +(6) +[ + "Nigel Rees", + "Sayings of the Century", + "Evelyn Waugh", + "Sword of Honour", + "Herman Melville", + "Moby Dick", + "J. R. R. Tolkien", + "The Lord of the Rings" +] +``` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/Tutorials/Custom Allocators.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/Tutorials/Custom Allocators.md new file mode 100644 index 0000000000..c2c32ad6c1 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/Tutorials/Custom Allocators.md @@ -0,0 +1,156 @@ +## Examples + +### Using `json` with boost stateless `fast_pool_allocator` +```c++ +#include +#include "jsoncons/json.hpp" + +typedef jsoncons::basic_json> bfp_json; + +bfp_json j; + +j.insert_or_assign("FirstName","Joe"); +j.insert_or_assign("LastName","Smith"); +``` + +### Using `json` with stateful Boost.Interprocess allocators + +```c++ +#include +#include +#include +#include +#include //std::system +#include + +using namespace jsoncons; + +typedef boost::interprocess::allocator shmem_allocator; + +struct boost_sorted_policy : public sorted_policy +{ + template + using sequence_container_type = boost::interprocess::vector; + + template + using key_storage = boost::interprocess::basic_string; + + template + using string_storage = boost::interprocess::basic_string; +}; + +typedef basic_json shm_json; + +int main(int argc, char *argv[]) +{ + typedef std::pair MyType; + + if(argc == 1){ //Parent process + //Remove shared memory on construction and destruction + struct shm_remove + { + shm_remove() { boost::interprocess::shared_memory_object::remove("MySharedMemory"); } + ~shm_remove(){ boost::interprocess::shared_memory_object::remove("MySharedMemory"); } + } remover; + + //Construct managed shared memory + boost::interprocess::managed_shared_memory segment(boost::interprocess::create_only, + "MySharedMemory", 65536); + + //Initialize shared memory STL-compatible allocator + const shmem_allocator allocator(segment.get_segment_manager()); + + // Create json value with all dynamic allocations in shared memory + + shm_json* j = segment.construct("my json")(shm_json::array(allocator)); + j->push_back(10); + + shm_json o(allocator); + o.insert_or_assign("category", "reference"); + o.insert_or_assign("author", "Nigel Rees"); + o.insert_or_assign("title", "Sayings of the Century"); + o.insert_or_assign("price", 8.95); + + j->push_back(o); + + shm_json a = shm_json::array(2,shm_json::object(allocator),allocator); + a[0]["first"] = 1; + + j->push_back(a); + + std::pair res; + res = segment.find("my json"); + + std::cout << "Parent:" << std::endl; + std::cout << pretty_print(*(res.first)) << std::endl; + + //Launch child process + std::string s(argv[0]); s += " child "; + if(0 != std::system(s.c_str())) + return 1; + + + //Check child has destroyed all objects + if(segment.find("my json").first) + return 1; + } + else{ + //Open managed shared memory + boost::interprocess::managed_shared_memory segment(boost::interprocess::open_only, + "MySharedMemory"); + + std::pair res; + res = segment.find("my json"); + + if (res.first != nullptr) + { + std::cout << "Child:" << std::endl; + std::cout << pretty_print(*(res.first)) << std::endl; + } + else + { + std::cout << "Result is null" << std::endl; + } + + //We're done, delete all the objects + segment.destroy("my json"); + } + return 0; +} +``` +Output: +``` +Parent: +[ + 10, + { + "author": "Nigel Rees", + "category": "reference", + "price": 8.95, + "title": "Sayings of the Century" + }, + [ + { + "first": 1 + }, + {} + ] +] +Child: +[ + 10, + { + "author": "Nigel Rees", + "category": "reference", + "price": 8.95, + "title": "Sayings of the Century" + }, + [ + { + "first": 1 + }, + {} + ] +] +``` diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/Tutorials/Unicode support.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/Tutorials/Unicode support.md new file mode 100644 index 0000000000..161716a0f1 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/Tutorials/Unicode support.md @@ -0,0 +1,182 @@ +### Narrow character support for UTF8 encoding + +In the Linux and web worlds, `UTF-8` is the dominant character encoding. + +Note that (at least in MSVS) you cannot open a Windows file with a Unicode name using the standard +```c++ +std::fstream fs(const char* filename) +``` +Instead you need to use the non standard Microsoft extension +```c++ +std::fstream fs(const wchar_t* filename) +``` + +#### Unicode escaping +```c++ +string inputStr("[\"\\u0040\\u0040\\u0000\\u0011\"]"); +std::cout << "Input: " << inputStr << std::endl; + +json arr = json::parse(inputStr); +std::string str = arr[0].as(); +std::cout << "Hex dump: ["; +for (size_t i = 0; i < str.size(); ++i) +{ + unsigned int val = static_cast(str[i]); + if (i != 0) + { + std::cout << " "; + } + std::cout << "0x" << std::setfill('0') << std::setw(2) << std::hex << val; +} +std::cout << "]" << std::endl; + +std::ostringstream os; +os << arr; +std::cout << "Output: " << os.str() << std::endl; +``` + +Output: + +``` +Input: ["\u0040\u0040\u0000\u0011"] +Hex dump: [0x40 0x40 0x00 0x11] +Output: ["@@\u0000\u0011"] +``` +Note that just the two control characters are escaped on output. + +#### Reading escaped unicode into utf8 encodings and writing back escaped unicode +```c++ +string inputStr("[\"\\u007F\\u07FF\\u0800\"]"); +std::cout << "Input: " << inputStr << std::endl; + +json arr = json::parse(inputStr); +std::string s = arr[0].as(); +std::cout << "Hex dump: ["; +for (size_t i = 0; i < s.size(); ++i) +{ + if (i != 0) + std::cout << " "; + unsigned int u(s[i] >= 0 ? s[i] : 256 + s[i] ); + std::cout << "0x" << std::hex<< std::setfill('0') << std::setw(2) << u; +} +std::cout << "]" << std::endl; + +std::ostringstream os; +json_options options; +format.escape_all_non_ascii(true); +os << print(arr,options); +std::string outputStr = os.str(); +std::cout << "Output: " << os.str() << std::endl; + +json arr2 = json::parse(outputStr); +std::string s2 = arr2[0].as(); +std::cout << "Hex dump: ["; +for (size_t i = 0; i < s2.size(); ++i) +{ + if (i != 0) + std::cout << " "; + unsigned int u(s2[i] >= 0 ? s2[i] : 256 + s2[i] ); + std::cout << "0x" << std::hex<< std::setfill('0') << std::setw(2) << u; +} +std::cout << "]" << std::endl; +``` + +Output: + +``` +Input: ["\u007F\u07FF\u0800"] +Hex dump: [0x7f 0xdf 0xbf 0xe0 0xa0 0x80] +Output: ["\u007F\u07FF\u0800"] +Hex dump: [0x7f 0xdf 0xbf 0xe0 0xa0 0x80] +``` +Since the escaped unicode consists of a control character (0x7f) and non-ascii, we get back the same text as what we started with. + +#### Reading escaped unicode into utf8 encodings and writing back escaped unicode (with continuations) +```c++ +string input = "[\"\\u8A73\\u7D30\\u95B2\\u89A7\\uD800\\uDC01\\u4E00\"]"; +json value = json::parse(input); +json_options options; +format.escape_all_non_ascii(true); +string output; +value.dump(output,options); + +std::cout << "Input:" << std::endl; +std::cout << input << std::endl; +std::cout << std::endl; +std::cout << "Output:" << std::endl; +std::cout << output << std::endl; +``` +Since all of the escaped unicode is non-ascii, we get back the same text as what we started with. +``` +Input: +["\u8A73\u7D30\u95B2\u89A7\uD800\uDC01\u4E00"] + +Output: +["\u8A73\u7D30\u95B2\u89A7\uD800\uDC01\u4E00"] +``` +### Wide character support for UTF16 and UTF32 encodings + +jsoncons supports wide character strings and streams with `wjson` and `wjson_reader`. It assumes `UTF16` encoding if `wchar_t` has size 2 (Windows) and `UTF32` encoding if `wchar_t` has size 4. + +It is necessary to deal with UTF-16 character encoding in the Windows world because of lack of UTF-8 support in the Windows system API. + +Even if you choose to use wide character streams and strings to interact with the Windows API, you can still read and write to files in the more widely supported, endiness independent, UTF-8 format. To handle that you need to imbue your streams with the facet `std::codecvt_utf8_utf16`, which encapsulates the conversion between `UTF-8` and `UTF-16`. + +Note that (at least in MSVS) you cannot open a Windows file with a Unicode name using the standard + + std::wfstream fs(const char* filename) + +Instead you need to use the non standard Microsoft extension + + std::wfstream fs(const wchar_t* filename) + +#### Constructing a wjson value +```c++ +using jsoncons::wjson; + +wjson root; +root[L"field1"] = L"test"; +root[L"field2"] = 3.9; +root[L"field3"] = true; +std::wcout << root << L"\n"; +``` +Output: +``` +{"field1":"test","field2":3.9,"field3":true} +``` +#### Escaped unicode +```c++ +wstring input = L"[\"\\u007F\\u07FF\\u0800\"]"; +std::wistringstream is(input); + +wjson val = wjson::parse(is); + +wstring s = val[0].as(); +std::cout << "length=" << s.length() << std::endl; +std::cout << "Hex dump: ["; +for (size_t i = 0; i < s.size(); ++i) +{ + if (i != 0) + std::cout << " "; + uint32_t u(s[i] >= 0 ? s[i] : 256 + s[i] ); + std::cout << "0x" << std::hex<< std::setfill('0') << std::setw(2) << u; +} +std::cout << "]" << std::endl; + +std::wofstream os("output/xxx.txt"); +os.imbue(std::locale(os.getloc(), new std::codecvt_utf8_utf16)); + +wjson_options options; +format.escape_all_non_ascii(true); + +os << pretty_print(val,options) << L"\n"; +``` +Output: +``` +length=3 +Hex dump: [0x7f 0x7ff 0x800] +``` +and the file `xxx.txt` contains +``` +["\u007F\u07FF\u0800"] +``` diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/build.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/build.md new file mode 100644 index 0000000000..41e9b7c013 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/build.md @@ -0,0 +1,6 @@ +Start Visual Studio Command prompt for x64 + +mkdir build64 & pushd build64 +cmake -G "Visual Studio 14 2015 Win64" .. +popd +cmake --build build64 --config Debug diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/big_integer_chars_format.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/big_integer_chars_format.md new file mode 100644 index 0000000000..70797ebfd7 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/big_integer_chars_format.md @@ -0,0 +1,101 @@ +### jsoncons::bigint_chars_format + +```c++ +enum class bigint_chars_format : uint8_t {number, base10, base64, base64url}; +``` + +#### Header +```c++ +#include +``` + +Specifies `bignum` formatting. + +### Examples + +#### Initializing with bignum + +```c++ +#include + +using namespace jsoncons; + +int main() +{ + std::string s = "-18446744073709551617"; + + json j(bignum(s.c_str())); + + std::cout << "(default) "; + j.dump(std::cout); + std::cout << "\n\n"; + + std::cout << "(integer) "; + json_options options1; + options1.bigint_format(bigint_chars_format::number); + j.dump(std::cout, options1); + std::cout << "\n\n"; + + std::cout << "(base64) "; + json_options options3; + options3.bigint_format(bigint_chars_format::base64); + j.dump(std::cout, options3); + std::cout << "\n\n"; + + std::cout << "(base64url) "; + json_options options4; + options4.bigint_format(bigint_chars_format::base64url); + j.dump(std::cout, options4); + std::cout << "\n\n"; +} +``` +Output: +``` +(default) "-18446744073709551617" + +(integer) -18446744073709551617 + +(base64) "~AQAAAAAAAAAA" + +(base64url) "~AQAAAAAAAAAA" +``` + +#### Integer overflow during parsing + +```c++ +#include + +using namespace jsoncons; + +int main() +{ + std::string s = "-18446744073709551617"; + + json j = json::parse(s); + + std::cout << "(1) "; + j.dump(std::cout); + std::cout << "\n\n"; + + std::cout << "(2) "; + json_options options1; + options1.bigint_format(bigint_chars_format::number); + j.dump(std::cout, options1); + std::cout << "\n\n"; + + std::cout << "(3) "; + json_options options2; + options2.bigint_format(bigint_chars_format::base64url); + j.dump(std::cout, options2); + std::cout << "\n\n"; +} +``` +Output: +``` +(1) "-18446744073709551617" + +(2) -18446744073709551617 + +(3) "~AQAAAAAAAAAB" +``` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/bignum.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/bignum.md new file mode 100644 index 0000000000..42b0502b2a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/bignum.md @@ -0,0 +1,279 @@ +### jsoncons::bignum + +```c++ +typedef basic_bignum> bignum; +``` +The `bignum` class is an instantiation of the `basic_bignum` class template that uses `std::allocator` as the allocator type. + +An arbitrary-precision integer. + +#### Header +```c++ +#include +``` + +#### Constructor + + bignum(); + + explicit bignum(const Allocator& alloc); + + explicit bignum(const char* str); +Constructs a bignum from the decimal string representation of a bignum. + + explicit bignum(const char* data, size_t length); +Constructs a bignum from the decimal string representation of a bignum. + + explicit bignum(const char* str, const Allocator& alloc); + + bignum(int signum, std::initializer_list magnitude); +Constructs a bignum from the sign-magnitude representation. +The magnitude is an unsigned integer `n` encoded as a byte string data item in big-endian byte-order. +If the value of signum is 1, the value of the bignum is `n`. +If the value of signum is -1, the value of the bignum is `-1 - n`. +An empty list means a zero value. + + bignum(int signum, std::initializer_list magnitude, const Allocator& alloc); + + bignum(const bignum& s); + + bignum(bignum&& s); + +#### Assignment + + bignum& operator=(const bignum& s); + + bignum& operator=(bignum&& s); + +#### Accessors + + template + void dump(std::basic_string& data) const + + template + void dump(int& signum, std::vector& data) const + +#### Arithmetic operators + + explicit operator bool() const + + explicit operator int64_t() const + + explicit operator uint64_t() const + + explicit operator double() const + + explicit operator long double() const + + bignum operator-() const + + bignum& operator+=( const bignum& y ) + + bignum& operator-=( const bignum& y ) + + bignum& operator*=( int64_t y ) + + bignum& operator*=( uint64_t y ) + + bignum& operator*=( bignum y ) + + bignum& operator/=( const bignum& divisor ) + + bignum& operator%=( const bignum& divisor ) + + bignum& operator<<=( uint64_t k ) + + bignum& operator>>=(uint64_t k) + + bignum& operator++() + + bignum operator++(int) + + bignum& operator--() + + bignum operator--(int) + + bignum& operator|=( const bignum& a ) + + bignum& operator^=( const bignum& a ) + + bignum& operator&=( const bignum& a ) + +#### Non-member functions + + bool operator==(const bignum& lhs, const bignum& rhs); + + bool operator!=(const bignum& lhs, const bignum& rhs); + + template + friend std::basic_ostream& operator<<(std::basic_ostream& os, const bignum& o); + +#### Global arithmetic operators + + bool operator==( const bignum& x, const bignum& y ) + + bool operator==( const bignum& x, int y ) + + bool operator!=( const bignum& x, const bignum& y ) + + bool operator!=( const bignum& x, int y ) + + bool operator<( const bignum& x, const bignum& y ) + + bool operator<( const bignum& x, int64_t y ) + + bool operator>( const bignum& x, const bignum& y ) + + bool operator>( const bignum& x, int y ) + + bool operator<=( const bignum& x, const bignum& y ) + + bool operator<=( const bignum& x, int y ) + + bool operator>=( const bignum& x, const bignum& y ) + + bool operator>=( const bignum& x, int y ) + + bignum operator+( bignum x, const bignum& y ) + + bignum operator+( bignum x, int64_t y ) + + bignum operator-( bignum x, const bignum& y ) + + bignum operator-( bignum x, int64_t y ) + + bignum operator*( int64_t x, const bignum& y ) + + bignum operator*( bignum x, const bignum& y ) + + bignum operator*( bignum x, int64_t y ) + + bignum operator/( bignum x, const bignum& y ) + + bignum operator/( bignum x, int y ) + + bignum operator%( bignum x, const bignum& y ) + + bignum operator<<( bignum u, unsigned k ) + + bignum operator<<( bignum u, int k ) + + bignum operator>>( bignum u, unsigned k ) + + bignum operator>>( bignum u, int k ) + + bignum operator|( bignum x, const bignum& y ) + + bignum operator|( bignum x, int y ) + + bignum operator|( bignum x, unsigned y ) + + bignum operator^( bignum x, const bignum& y ) + + bignum operator^( bignum x, int y ) + + bignum operator^( bignum x, unsigned y ) + + bignum operator&( bignum x, const bignum& y ) + + bignum operator&( bignum x, int y ) + + bignum operator&( bignum x, unsigned y ) + + bignum abs( const bignum& a ) + + bignum power( bignum x, unsigned n ) + + bignum sqrt( const bignum& a ) + +### Examples + + +### Examples + +#### Initializing with bignum + +```c++ +#include + +using namespace jsoncons; + +int main() +{ + std::string s = "-18446744073709551617"; + + json j(bignum(s.c_str())); + + std::cout << "(1) " << j.as() << "\n\n"; + + std::cout << "(2) " << j.as() << "\n\n"; + + std::cout << "(3) "; + j.dump(std::cout); + std::cout << "\n\n"; + + std::cout << "(4) "; + json_options options1; + options1.bigint_format(bigint_chars_format::number); + j.dump(std::cout, options1); + std::cout << "\n\n"; + + std::cout << "(5) "; + json_options options2; + options2.bigint_format(bigint_chars_format::base64url); + j.dump(std::cout, options2); + std::cout << "\n\n"; +} +``` +Output: +``` +(1) -18446744073709551617 + +(2) -18446744073709551617 + +(3) "-18446744073709551617" + +(4) -18446744073709551617 + +(5) "~AQAAAAAAAAAB" +``` + +#### Integer overflow during parsing + +```c++ +#include + +using namespace jsoncons; + +int main() +{ + std::string s = "-18446744073709551617"; + + json j = json::parse(s); + + std::cout << "(1) "; + j.dump(std::cout); + std::cout << "\n\n"; + + std::cout << "(2) "; + json_options options1; + options1.bigint_format(bigint_chars_format::number); + j.dump(std::cout, options1); + std::cout << "\n\n"; + + std::cout << "(3) "; + json_options options2; + options2.bigint_format(bigint_chars_format::base64url); + j.dump(std::cout, options2); + std::cout << "\n\n"; +} +``` +Output: +``` +(1) "-18446744073709551617" + +(2) -18446744073709551617 + +(3) "~AQAAAAAAAAAB" +``` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/bson/bson.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/bson/bson.md new file mode 100644 index 0000000000..3d9add7cbf --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/bson/bson.md @@ -0,0 +1,29 @@ +### bson extension + +The bson extension implements decode from and encode to the [Binary JSON](http://bsonspec.org/) data format. +You can either parse into or serialize from a variant-like structure, [basic_json](../json.md), or your own +data structures, using [json_type_traits](../json_type_traits.md). + +[decode_bson](decode_bson.md) + +[encode_bson](encode_bson.md) + +[bson_encoder](bson_encoder.md) + +#### jsoncons-BSON mappings + +jsoncons data item|jsoncons tag|BSON data item +--------------|------------------|--------------- +null | | null +bool | | true or false +int64 | | int32 or int64 +int64 | timestamp | datetime +uint64 | | int32 or int64 +uint64 | timestamp | datetime +double | | double +string | | string +byte_string | | binary +array | | 0x04 (array ) +object | | 0x03 (document) + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/bson/bson_encoder.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/bson/bson_encoder.md new file mode 100644 index 0000000000..9c33accf25 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/bson/bson_encoder.md @@ -0,0 +1,147 @@ +### jsoncons::bson::basic_bson_encoder + +```c++ +template< + class Result> +> class basic_bson_encoder : public jsoncons::json_content_handler +``` + +`basic_bson_encoder` is noncopyable. + +#### Header + + #include + +![bson_encoder](./diagrams/bson_encoder.png) + +Two specializations for common result types are defined: + +Type |Definition +---------------------------|------------------------------ +bson_encoder |basic_bson_encoder +bson_bytes_encoder |basic_bson_encoder + +#### Member types + +Type |Definition +---------------------------|------------------------------ +char_type |char +result_type |Result +string_view_type | + +#### Constructors + + explicit basic_bson_encoder(result_type result) +Constructs a new encoder that writes to the specified result. + +#### Destructor + + virtual ~basic_bson_encoder() + +### Inherited from [basic_json_content_handler](../json_content_handler.md) + +#### Member functions + + bool begin_object(semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool begin_object(size_t length, + semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool end_object(const ser_context& context = null_ser_context()) + + bool begin_array(semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool begin_array(semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool end_array(const ser_context& context=null_ser_context()); + + bool name(const string_view_type& name, + const ser_context& context=null_ser_context()); + + bool string_value(const string_view_type& value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool byte_string_value(const byte_string_view& b, + semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool byte_string_value(const uint8_t* p, size_t size, + semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool int64_value(int64_t value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool uint64_value(uint64_t value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool double_value(double value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool bool_value(bool value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool null_value(semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); + + void flush() + +### Examples + +#### Encode to BSON + +```c++ +#include +#include +#include + +int main() +{ + std::vector buffer; + bson::bson_bytes_encoder encoder(buffer); + encoder.begin_array(); // The total number of bytes comprising + // the bson document will be calculated + encoder.string_value("cat"); + encoder.byte_string_value(byte_string({'p','u','r','r'})); + encoder.int64_value(1431027667, semantic_tag::timestamp); + encoder.end_array(); + encoder.flush(); + + for (auto c : buffer) + { + std::cout << std::hex << std::setprecision(2) << std::setw(2) + << std::noshowbase << std::setfill('0') << static_cast(c); + } + std::cout << "\n\n"; + +/* + 22000000 -- Total number of bytes comprising the document (34 bytes) + 02 -- UTF-8 string + 3000 -- "0" + 04000000 -- number bytes in the string (including trailing byte) + 636174 -- "cat" + 00 -- trailing byte + 05 -- binary + 3100 -- "1" + 04000000 -- number of bytes + 70757272 -- 'P''u''r''r' + 09 -- datetime + 3200 -- "2" + d3bf4b55 -- 1431027667 + 00 +*/ +} +``` +Output: +``` +2200000002300004000000636174000531000400000070757272093200d3bf4b5500 +``` diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/bson/decode_bson.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/bson/decode_bson.md new file mode 100644 index 0000000000..51aa31f9ea --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/bson/decode_bson.md @@ -0,0 +1,30 @@ +### jsoncons::bson::decode_bson + +Decodes a [Binary JSON (BSON)](http://bsonspec.org/) data format into a C++ data structure. + +#### Header +```c++ +#include + +template +T decode_bson(const std::vector& v); // (1) + +template +T decode_bson(std::istream& is); // (2) +``` + +(1) Reads a BSON bytes buffer into a type T if T is an instantiation of [basic_json](../json.md) +or if T supports [json_type_traits](../json_type_traits.md). + +(2) Reads a BSON binary stream into a type T if T is an instantiation of [basic_json](../json.md) +or if T supports [json_type_traits](../json_type_traits.md). + +#### Exceptions + +Throws [ser_error](../ser_error.md) if parsing fails. + +#### See also + +- [encode_bson](encode_bson.md) encodes a json value to the [Binary JSON](http://bsonspec.org/) data format. + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/bson/diagrams/bson_encoder.png b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/bson/diagrams/bson_encoder.png new file mode 100644 index 0000000000..1bb1c73475 Binary files /dev/null and b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/bson/diagrams/bson_encoder.png differ diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/bson/diagrams/bson_encoder.xml b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/bson/diagrams/bson_encoder.xml new file mode 100644 index 0000000000..e87493a576 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/bson/diagrams/bson_encoder.xml @@ -0,0 +1 @@ +vVZdb9owFP01eexEYqD0sQXabajVOiZBn5CJbxNvjs0cA2G/fjaxSZwElUpV+1D5nuvrj3POdQjQOCseJN6kj4IAC6IeKQI0CaLoOhzp/wY4lAAa9kogkZSUUFgBc/oPLOimbSmB3JuohGCKbnwwFpxDrDwMSyn2/rRXwfxdNziBFjCPMWujC0pUWqKjQa/CvwJNUrdz2LOZDLvJFshTTMS+BqFpgMZSCFWOsmIMzHDneCnr7s9kTweTwNUlBdOnXwWfPc/TaPx3phaP2Uvx/cqussNsay+8xjmNV79zwVeaU6UXX6WYEwYyiIZM73S3NqPEjLqQ41XVwfEnxZYTMEfo6fQ+pQrmGxyb7F4bRmOpypiOwlN1/UrufCAVFDXIXvEBRAZKHvQUmx1Ztq3dQsf+vhIvdBZMa8L1LYatX5LTyhWlemBZfQfD12cYXhuGgce6YT6B2VfK2FgwIY+1CI5/Gs+VFH+glkFDdIPIx2hxkRj9zxRj1BKjRStwcmveDR3FDOdaKp9JKKhaWtLN+MWMvwxsNClqqcnBBVwffukWMEGtyoRV2TFydWc1yMVWxvC26xSWCai3+x+I9wq2Fa0pNugQzGESGFZ057+dXSraHX4Iqm92Mkzf90uEGj4or22L6k9dY52bhu9GjXVKWlrrHC11uvRFLkt2j2k0e1rin5BcLZ5nsJtBR8t/4ylIqjDXoulvIcWJxFnLerqtlG82vz254NDoZQthRhNuHKuNop8TdGealOqv2K1NZJQQs03nO+G/JB/Q+GFDgKjX0fiow0fR+xtfh9U3tFSw+iGCpv8B \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/bson/encode_bson.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/bson/encode_bson.md new file mode 100644 index 0000000000..21a0644a41 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/bson/encode_bson.md @@ -0,0 +1,25 @@ +### jsoncons::bson::encode_bson + +Encodes a C++ data structure to the [Binary JSON (BSON)](http://bsonspec.org/) data format. + +#### Header +```c++ +#include + +template +void encode_bson(const T& jval, std::vector& v); // (1) + +template +void encode_bson(const T& jval, std::ostream& os); // (2) +``` + +(1) Writes a value of type T into a bytes buffer in the BSON data format. Type T must be an instantiation of [basic_json](../json.md) +or support [json_type_traits](../json_type_traits.md). + +(2) Writes a value of type T into a binary stream in the BSON data format. Type T must be an instantiation of [basic_json](../json.md) +or support [json_type_traits](../json_type_traits.md). + +#### See also + +- [decode_bson](decode_bson) decodes a [Binary JSON](http://bsonspec.org/) data format to a json value. + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/byte_string.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/byte_string.md new file mode 100644 index 0000000000..c95c81dd4a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/byte_string.md @@ -0,0 +1,130 @@ +### jsoncons::byte_string + +```c++ +typedef basic_byte_string> byte_string; +``` +The `byte_string` class is an instantiation of the `basic_byte_string` class template that uses `std::allocator` as the allocator type. + +#### Header +```c++ +#include +``` + +#### Member types + +Member type |Definition +------------------------------------|------------------------------ +`const_iterator`| +`iterator`|Same as `const_iterator` +`size_type`|std::size_t + +#### Constructor + + byte_string(); + + explicit byte_string(const Allocator& alloc); + + byte_string(std::initializer_list init); + + byte_string(std::initializer_list init, const Allocator& alloc); + + explicit byte_string(const byte_string_view& v); + + byte_string(const byte_string_view& v, const Allocator& alloc); + + byte_string(const char* s); + + byte_string(const byte_string& s); + + byte_string(byte_string&& s); + +#### Assignment + + byte_string& operator=(const byte_string& s); + + byte_string& operator=(byte_string&& s); + +#### Iterators + + const_iterator begin() const noexcept; + + const_iterator end() const noexcept; + +#### Element access + + const uint8_t* data() const; + + uint8_t operator[](size_type pos) const; + + operator byte_string_view() const noexcept; + +#### Capacity + + size_t size() const; + + size_t length() const; + +#### Non-member functions + + bool operator==(const byte_string& lhs, const byte_string& rhs); + + bool operator!=(const byte_string& lhs, const byte_string& rhs); + + template + friend std::ostream& operator<<(std::ostream& os, const byte_string& o); + +### Examples + +#### Byte string from initializer list + +```c++ +json j(byte_string({'H','e','l','l','o'})); +byte_string bs = j.as(); + +std::cout << "(1) "<< bs << "\n\n"; + +std::cout << "(2) "; +for (auto b : bs) +{ + std::cout << (char)b; +} +std::cout << "\n\n"; + +std::cout << "(3) " << j << std::endl; +``` + +Output: +``` +(1) 0x480x650x6c0x6c0x6f + +(2) Hello + +(3) "SGVsbG8_" +``` + +#### Byte string from char array + +```c++ +json j(byte_string("Hello")); +byte_string bs = j.as(); + +std::cout << "(1) "<< bs << "\n\n"; + +std::cout << "(2) "; +for (auto b : bs) +{ + std::cout << (char)b; +} +std::cout << "\n\n"; + +std::cout << "(3) " << j << std::endl; +``` + +Output: +``` +(1) 0x480x650x6c0x6c0x6f + +(2) Hello + +(3) "SGVsbG8_" +``` diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/byte_string_chars_format.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/byte_string_chars_format.md new file mode 100644 index 0000000000..231988d1b3 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/byte_string_chars_format.md @@ -0,0 +1,58 @@ +### jsoncons::byte_string_chars_format + +```c++ +enum class byte_string_chars_format : uint8_t {base16, base64, base64url}; +``` + +#### Header +```c++ +#include +``` + +Specifies byte string formatting. + +### Examples + +#### Byte string formatting + +```c++ +#include + +using namespace jsoncons; + +int main() +{ + std::vector bytes = {'H','e','l','l','o'}; + + json j(byte_string(bytes.data(),bytes.size())); + + // default + std::cout << "(1) "<< j << "\n\n"; + + // base16 + json_options options2; + options2.byte_string_format(byte_string_chars_format::base16); + std::cout << "(2) "<< print(j, options2) << "\n\n"; + + // base64 + json_options options3; + options3.byte_string_format(byte_string_chars_format::base64); + std::cout << "(3) "<< print(j, options3) << "\n\n"; + + // base64url + json_options options4; + options4.byte_string_format(byte_string_chars_format::base64url); + std::cout << "(4) "<< print(j, options4) << "\n\n"; +} +``` +Output: +``` +(1) "SGVsbG8" + +(2) "48656C6C6F" + +(3) "SGVsbG8=" + +(4) "SGVsbG8" +``` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/cbor/cbor.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/cbor/cbor.md new file mode 100644 index 0000000000..eb2da36205 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/cbor/cbor.md @@ -0,0 +1,175 @@ +## cbor extension + +The cbor extension implements decode from and encode to the IETF standard [Concise Binary Object Representation (CBOR)](http://cbor.io/). +You can either parse into or serialize from a variant-like structure, [basic_json](../json.md), or your own +data structures, using [json_type_traits](../json_type_traits.md). + +[decode_cbor](decode_cbor.md) + +[encode_cbor](encode_cbor.md) + +[cbor_encoder](cbor_encoder.md) + +[cbor_options](cbor_options.md) + +### Tag handling and extensions + +All tags not explicitly mentioned below are ignored. + +0 (standard date/time string) +CBOR standard date/time strings are decoded into jsoncons strings tagged with `semantic_tag::datetime`. +jsoncons strings tagged with `semantic_tag::datetime` are encoded into CBOR standard date/time strings. + +1 (epoch time) +CBOR epoch times are decoded into jsoncons int64_t, uint64_t and double and tagged with `semantic_tag::timestamp`. +jsoncons int64_t, uint64_t and double tagged with `semantic_tag::timestamp` are encoded into CBOR epoch time. + +2,3 (positive and negative bignum) +CBOR positive and negative bignums are decoded into jsoncons strings and tagged with `semantic_tag::bigint`. +jsoncons strings tagged with `semantic_tag::bigint` are encoded into CBOR positive or negative bignums. + +4 (decimal fratction) +CBOR decimal fractions are decoded into jsoncons strings tagged with `semantic_tag::bigdec`. +jsoncons strings tagged with `semantic_tag::bigdec` are encoded into CBOR decimal fractions. + +5 (bigfloat) +CBOR bigfloats are decoded into a jsoncons string that consists of the following parts + +- (optional) minus sign +- 0x +- nonempty sequence of hexadecimal digits (defines mantissa) +- p followed with optional minus or plus sign and nonempty sequence of hexadecimal digits (defines base-2 exponent) + +and tagged with `semantic_tag::bigfloat`. + +jsoncons strings that consist of the following parts + +- (optional) plus or minus sign +- 0x or 0X +- nonempty sequence of hexadecimal digits optionally containing a decimal-point character +- (optional) p or P followed with optional minus or plus sign and nonempty sequence of decimal digits + +and tagged with `semantic_tag::bigfloat` are encoded into CBOR bignums. + +21, 22, 23 (byte string expected conversion is base64url, base64 or base16) +CBOR byte strings tagged with 21, 22 and 23 are decoded into jsoncons byte strings tagged with +`semantic_tag::base64url`, `semantic_tag::base64` and `semantic_tag::base16`. +jsoncons byte strings tagged with `semantic_tag::base64url`, `semantic_tag::base64` and `semantic_tag::base16` +are encoded into CBOR byte strings tagged with 21, 22 and 23. + +32 (URI) +CBOR URI strings are decoded into jsoncons strings tagged with `semantic_tag::uri`. +jsoncons strings tagged with `semantic_tag::uri` are encoded into CBOR URI strings. + +33, 34 (UTF-8 string is base64url or base64) +CBOR strings tagged with 33 and 34 are decoded into jsoncons strings tagged with `semantic_tag::base64url` and `semantic_tag::base64`. +jsoncons strings tagged with `semantic_tag::base64url` and `semantic_tag::base64` are encoded into CBOR strings tagged with 33 and 34. + +256, 25 [stringref-namespace, stringref](http://cbor.schmorp.de/stringref) +Tags 256 and 25 are automatically decoded when detected. They are encoded when CBOR option `pack_strings` is set to true. + +### jsoncons - CBOR mappings + +jsoncons data item|jsoncons tag|CBOR data item|CBOR tag +--------------|------------------|---------------|-------- +null | | null |  +null | undefined | undefined |  +bool | | true or false |  +int64 | | unsigned or negative integer |  +int64 | timestamp | unsigned or negative integer | 1 (epoch-based date/time) +uint64 | | unsigned integer |  +uint64 | timestamp | unsigned integer | 1 (epoch-based date/time) +double | | half-precision float, float, or double |  +double | timestamp | double | 1 (epoch-based date/time) +string | | string |  +string | bigint | byte string | 2 (positive bignum) or 2 (negative bignum) +string | bigdec | array | 4 (decimal fraction) +string | bigfloat | array | 5 (bigfloat) +string | datetime | string | 0 (date/time string) +string | uri | string | 32 (uri) +string | base64url | string | 33 (base64url) +string | base64 | string | 34 (base64) +byte_string | | byte string |  +byte_string | base64url | byte string | 21 (Expected conversion to base64url encoding) +byte_string | base64 | byte string | 22 (Expected conversion to base64 encoding) +byte_string | base16 | byte string | 23 (Expected conversion to base16 encoding) +array | | array |  +object | | map |  + +### Examples + +```c++ +#include +#include +#include + +using namespace jsoncons; + +int main() +{ + ojson j1 = ojson::parse(R"( + { + "application": "hiking", + "reputons": [ + { + "rater": "HikingAsylum.example.com", + "assertion": "strong-hiker", + "rated": "Marilyn C", + "rating": 0.90 + } + ] + } + )"); + + // Encode a basic_json value to a CBOR value + std::vector data; + cbor::encode_cbor(j1, data); + + // Decode a CBOR value to a basic_json value + ojson j2 = cbor::decode_cbor(data); + std::cout << "(1)\n" << pretty_print(j2) << "\n\n"; + + // Accessing the data items + + const ojson& reputons = j2["reputons"]; + + std::cout << "(2)\n"; + for (auto element : reputons.array_range()) + { + std::cout << element.at("rated").as() << ", "; + std::cout << element.at("rating").as() << "\n"; + } + std::cout << std::endl; + + // Get a CBOR value for a nested data item with jsonpointer + std::error_code ec; + const auto& rated = jsonpointer::get(j2, "/reputons/0/rated", ec); + if (!ec) + { + std::cout << "(3) " << rated.as_string() << "\n"; + } + + std::cout << std::endl; +} +``` +Output: +``` +(1) +{ + "application": "hiking", + "reputons": [ + { + "rater": "HikingAsylum.example.com", + "assertion": "strong-hiker", + "rated": "Marilyn C", + "rating": 0.9 + } + ] +} + +(2) +Marilyn C, 0.9 + +(3) Marilyn C +``` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/cbor/cbor_decode_options.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/cbor/cbor_decode_options.md new file mode 100644 index 0000000000..ade07e2c12 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/cbor/cbor_decode_options.md @@ -0,0 +1,19 @@ +### jsoncons::cbor::cbor_decode_options + +An abstract class that defines accessors for CBOR decoding options. + +#### Header +```c++ +#include +``` + +#### Implementing classes + +[cbor_options](cbor_options.md) + +#### Destructor + + virtual ~cbor_decode_options(); + +#### Accessors + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/cbor/cbor_encode_options.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/cbor/cbor_encode_options.md new file mode 100644 index 0000000000..5ecffd0980 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/cbor/cbor_encode_options.md @@ -0,0 +1,20 @@ +### jsoncons::cbor::cbor_encode_options + +An abstract class that defines accessors for CBOR encoding options. + +#### Header +```c++ +#include +``` + +#### Implementing classes + +[cbor_options](cbor_options.md) + +#### Destructor + + virtual ~cbor_encode_options(); + +#### Accessors + + bool pack_strings() const; diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/cbor/cbor_encoder.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/cbor/cbor_encoder.md new file mode 100644 index 0000000000..5cf48cf87f --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/cbor/cbor_encoder.md @@ -0,0 +1,197 @@ +### jsoncons::cbor::basic_cbor_encoder + +```c++ +template< + class Result> +> class basic_cbor_encoder : public jsoncons::json_content_handler +``` + +`basic_cbor_encoder` is noncopyable + +#### Header + + #include + +![cbor_encoder](./diagrams/cbor_encoder.png) + +Four specializations for common result types are defined: + +Type |Definition +---------------------------|------------------------------ +cbor_encoder |basic_cbor_encoder +cbor_bytes_encoder |basic_cbor_encoder + +#### Member types + +Type |Definition +---------------------------|------------------------------ +char_type |char +result_type |Result +string_view_type | + +#### Constructors + + explicit basic_cbor_encoder(result_type result) +Constructs a new encoder that writes to the specified result. + +#### Destructor + + virtual ~basic_cbor_encoder() + +### Inherited from [basic_json_content_handler](../json_content_handler.md) + +#### Member functions + + bool begin_object(semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool begin_object(size_t length, + semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool end_object(const ser_context& context = null_ser_context()) + + bool begin_array(semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool begin_array(semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool end_array(const ser_context& context=null_ser_context()); + + bool name(const string_view_type& name, + const ser_context& context=null_ser_context()); + + bool string_value(const string_view_type& value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool byte_string_value(const byte_string_view& b, + semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool byte_string_value(const uint8_t* p, size_t size, + semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool int64_value(int64_t value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool uint64_value(uint64_t value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool double_value(double value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool bool_value(bool value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool null_value(semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); + + void flush() + +### Examples + +#### Encode to CBOR buffer + +```c++ +#include +#include +#include + +int main() +{ + std::vector buffer; + cbor::cbor_bytes_encoder encoder(buffer); + + encoder.begin_array(); // Indefinite length array + encoder.string_value("cat"); + encoder.byte_string_value(byte_string({'p','u','r','r'})); + encoder.byte_string_value(byte_string({'h','i','s','s'}), + semantic_tag::base64); // suggested conversion to base64 + encoder.int64_value(1431027667, semantic_tag::timestamp); + encoder.end_array(); + encoder.flush(); + + for (auto c : buffer) + { + std::cout << std::hex << std::setprecision(2) << std::setw(2) + << std::noshowbase << std::setfill('0') << static_cast(c); + } + std::cout << "\n\n"; + +/* + 9f -- Start indefinte length array + 63 -- String value of length 3 + 636174 -- "cat" + 44 -- Byte string value of length 4 + 70757272 -- 'p''u''r''r' + d6 - Expected conversion to base64 + 44 + 68697373 -- 'h''i''s''s' + c1 -- Tag value 1 (seconds relative to 1970-01-01T00:00Z in UTC time) + 1a -- 32 bit unsigned integer + 554bbfd3 -- 1431027667 + ff -- "break" +*/ +} +``` +Output: +``` +9f636361744470757272d64468697373c11a554bbfd3ff +``` + +#### Encode to CBOR stream + +```c++ + +#include +#include +#include + +int main() +{ + std::ostringstream os; + cbor::cbor_encoder encoder(os); + + encoder.begin_array(3); // array of length 3 + encoder.string_value("-18446744073709551617", semantic_tag::bigint); + encoder.string_value("184467440737095516.16", semantic_tag::bigdec); + encoder.int64_value(1431027667, semantic_tag::timestamp); + encoder.end_array(); + encoder.flush(); + + for (auto c : os.str()) + { + std::cout << std::hex << std::setprecision(2) << std::setw(2) + << std::noshowbase << std::setfill('0') << (int)unsigned char(c); + } + std::cout << "\n\n"; + +/* + 83 -- array of length 3 + c3 -- Tag 3 (negative bignum) + 49 -- Byte string value of length 9 + 010000000000000000 -- Bytes content + c4 -- Tag 4 (decimal fraction) + 82 -- Array of length 2 + 21 -- -2 (exponent) + c2 Tag 2 (positive bignum) + 49 -- Byte string value of length 9 + 010000000000000000 + c1 -- Tag 1 (seconds relative to 1970-01-01T00:00Z in UTC time) + 1a -- 32 bit unsigned integer + 554bbfd3 -- 1431027667 +*/ +} +``` +Output: +``` +83c349010000000000000000c48221c249010000000000000000c11a554bbfd3 +``` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/cbor/cbor_options.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/cbor/cbor_options.md new file mode 100644 index 0000000000..6cae4cc9ce --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/cbor/cbor_options.md @@ -0,0 +1,43 @@ +### jsoncons::cbor::cbor_options + +Specifies options for encoding and decoding CBOR. + +#### Header +```c++ +#include +``` + +![cbor_options](./diagrams/cbor_options.png) + +#### Constructors + + cbor_options() +Constructs a `cbor_options` with default values. + +#### Modifiers + + cbor_options& pack_strings(bool value) + +If set to `true`, then encode will store text strings and +byte strings once, and use string references to represent repeated occurences +of the strings. Decoding the resulting CBOR requires a decoder +that supports the +[stringref extension to CBOR](http://cbor.schmorp.de/stringref), such as +jsoncons itself, or [Perl CBOR::XS](http://software.schmorp.de/pkg/CBOR-XS.html) + +If set to `false` (the default), then encode +will encode strings the usual CBOR way. + +This option does not affect decode - jsoncons will always decode +string references if present. + +#### Static member functions + + static const cbor_options& default_options() +Default CBOR encode and decode options. + +### See also + +[cbor_decode_options](cbor_decode_options.md) +[cbor_encode_options](cbor_encode_options.md) + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/cbor/decode_cbor.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/cbor/decode_cbor.md new file mode 100644 index 0000000000..9fd5993c5d --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/cbor/decode_cbor.md @@ -0,0 +1,240 @@ +### jsoncons::cbor::decode_cbor + +Decodes a [Concise Binary Object Representation](http://cbor.io/) data format into a C++ data structure. + +#### Header +```c++ +#include + +template +T decode_cbor(const std::vector& v); // (1) + +template +T decode_cbor(std::istream& is); // (2) +``` + +(1) Reads a CBOR bytes buffer into a type T if T is an instantiation of [basic_json](../json.md) +or if T supports [json_type_traits](../json_type_traits.md). + +(2) Reads a CBOR binary stream into a type T if T is an instantiation of [basic_json](../json.md) +or if T supports [json_type_traits](../json_type_traits.md). + +#### Exceptions + +Throws [ser_error](../ser_error.md) if parsing fails. + +### Examples + +#### Round trip (JSON to CBOR bytes back to JSON) + +```c++ +#include +#include + +using namespace jsoncons; + +int main() +{ + ojson j1 = ojson::parse(R"( + { + "application": "hiking", + "reputons": [ + { + "rater": "HikingAsylum.example.com", + "assertion": "strong-hiker", + "rated": "Marilyn C", + "rating": 0.90 + } + ] + } + )"); + + std::vector v; + cbor::encode_cbor(j1, v); + + ojson j2 = cbor::decode_cbor(v); + std::cout << pretty_print(j2) << std::endl; +} +``` +Output: +```json +{ + "application": "hiking", + "reputons": [ + { + "rater": "HikingAsylum.example.com", + "assertion": "strong-hiker", + "rated": "Marilyn C", + "rating": 0.9 + } + ] +} +``` + +#### Round trip (JSON to CBOR file back to JSON) + +```c++ +#include +#include + +using namespace jsoncons; + +int main() +{ + json j = json::parse(R"( + { + "application": "hiking", + "reputons": [ + { + "rater": "HikingAsylum.example.com", + "assertion": "strong-hiker", + "rated": "Marilyn C", + "rating": 0.90 + } + ] + } + )"); + + std::ofstream os; + os.open("./output/store.cbor", std::ios::binary | std::ios::out); + cbor::encode_cbor(j,os); + + std::vector v; + std::ifstream is; + is.open("./output/store.cbor", std::ios::binary | std::ios::in); + + json j2 = cbor::decode_cbor(is); + + std::cout << pretty_print(j2) << std::endl; +} +``` +Output: +```json +{ + "application": "hiking", + "reputons": [ + { + "assertion": "strong-hiker", + "rated": "Marilyn C", + "rater": "HikingAsylum.example.com", + "rating": 0.9 + } + ] +} +``` + +#### Decode CBOR byte string + +```c++ +#include +#include + +using namespace jsoncons; + +int main() +{ + // byte string of length 5 + std::vector buf = {0x45,'H','e','l','l','o'}; + json j = cbor::decode_cbor(buf); + + auto bs = j.as(); + + // byte_string to ostream displays as hex + std::cout << "(1) "<< bs << "\n\n"; + + // byte string value to JSON text becomes base64url + std::cout << "(2) " << j << std::endl; +} +``` +Output: +``` +(1) 0x480x650x6c0x6c0x6f + +(2) "SGVsbG8" +``` + +#### Decode CBOR byte string with base64 encoding hint + +```c++ +#include +#include + +using namespace jsoncons; + +int main() +{ + // semantic tag indicating expected conversion to base64 + // followed by byte string of length 5 + std::vector buf = {0xd6,0x45,'H','e','l','l','o'}; + json j = cbor::decode_cbor(buf); + + auto bs = j.as(); + + // byte_string to ostream displays as hex + std::cout << "(1) "<< bs << "\n\n"; + + // byte string value to JSON text becomes base64 + std::cout << "(2) " << j << std::endl; +} +``` +Output: +``` +(1) 0x480x650x6c0x6c0x6f + +(2) "SGVsbG8=" +``` + +#### Decode packed strings [stringref-namespace, stringref](http://cbor.schmorp.de/stringref) + +This example taken from [CBOR stringref extension](http://cbor.schmorp.de/stringref) shows three stringref-namespace tags, +with two nested inside another: + +```c++ +int main() +{ + std::vector v = {0xd9,0x01,0x00, // tag(256) + 0x85, // array(5) + 0x63, // text(3) + 0x61,0x61,0x61, // "aaa" + 0xd8, 0x19, // tag(25) + 0x00, // unsigned(0) + 0xd9, 0x01,0x00, // tag(256) + 0x83, // array(3) + 0x63, // text(3) + 0x62,0x62,0x62, // "bbb" + 0x63, // text(3) + 0x61,0x61,0x61, // "aaa" + 0xd8, 0x19, // tag(25) + 0x01, // unsigned(1) + 0xd9, 0x01,0x00, // tag(256) + 0x82, // array(2) + 0x63, // text(3) + 0x63,0x63,0x63, // "ccc" + 0xd8, 0x19, // tag(25) + 0x00, // unsigned(0) + 0xd8, 0x19, // tag(25) + 0x00 // unsigned(0) + }; + + ojson j = cbor::decode_cbor(v); + + std::cout << pretty_print(j) << "\n"; +} +``` +Output: +``` +[ + "aaa", + "aaa", + ["bbb", "aaa", "aaa"], + ["ccc", "ccc"], + "aaa" +] +``` + +#### See also + +- [byte_string](../byte_string.md) +- [encode_cbor](encode_cbor.md) encodes a json value to the [Concise Binary Object Representation](http://cbor.io/) data format. + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/cbor/diagrams/cbor_encoder.xml b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/cbor/diagrams/cbor_encoder.xml new file mode 100644 index 0000000000..39a9783b45 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/cbor/diagrams/cbor_encoder.xml @@ -0,0 +1 @@ +3Vffb9owEP5reGRKYmD0sYWu21CrdUyCPiE3vibeHJs5BsL++p2JQ35WbacKTfCC77Pv7Pvu43rtkUmS3Wi6jm8VA9ELPJb1yLQXBL4X+PhlkX2OkEGQA5HmzB0qgTn/A4WnQzecQVo7aJQShq/rYKikhNDUMKq12tWPPSlRv3VNI2gB85CKNrrgzMQ5Oh56Jf4ZeBQXN/ue20locdgBaUyZ2lUgct0jE62UyVdJNgFhySt4yf0+PbN7fJgGaV7jcH33I5Oz+3kcTH7PzOI2eci+9l2ULRUbl/AjTXm4+pkquUJODQZfxVQyAboXjATedPVoV5FddSGHVM2+4E+rjWRgn+Dh9i7mBuZrGtrdHSoGsdgkAi3/6F1NqXgfaANZBXIp3oBKwOg9HnG7Y8e2k5tfsL8ri+ePHBZXCjdwGHV6iY6RS0px4Vh9A8Mfn2E4fFR6lYLmVKDoT0DuExdiooTSB18Chw/iqdHqF1R2yIhcEPY+5XhVPQanrMe4VY8WrSDZpW0daIWCplitOpOQcbN0pNv1g11/GDprmlW2pvvCkPj4ZRHAGhUva5ZuB6vwe7YGqdroEF4WnqE6AvNyCwBWa4TtilYqNuwoWIFpENTwbb19dlXR3fBNcczsKJhBXS8BaeggT9s5VbtdI85FQ3fjRpycllacg6SOSb9KZdH2Ng5md0v6HaL+4n4G2xn0h2eoss5EyVmqZ9AINDqtekZnop5q7+lM9P/qPUOv0TS8f5WP39Chf1r9tGeOLzLGUcNQiT9mHMY5jTRNWqLCP+qmLqP6cCCVhMYk4SAcYiJptYgSwGGGXNkRgeMYfek2Es6YvaZzSqnPMe8wdviN9h94HWMH6VBS8PaxA81yiM8rWP4rRK7/Ag== \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/cbor/diagrams/cbor_options.png b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/cbor/diagrams/cbor_options.png new file mode 100644 index 0000000000..e9bfa09f63 Binary files /dev/null and b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/cbor/diagrams/cbor_options.png differ diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/cbor/diagrams/cbor_options.xml b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/cbor/diagrams/cbor_options.xml new file mode 100644 index 0000000000..bbde4a1822 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/cbor/diagrams/cbor_options.xml @@ -0,0 +1 @@ +zZbLbtswEEW/RssUetSPbWOnySItghpo05XAimOJjUQqFBVJ/fqS0VBPJ04Lo/XG4FxyhuSZa0JOsMnqa0ny5JOgkDq+S2sn2Dq+v/I9/WuEphWCJQqxZLSVBsKO/QIUXVRLRqEYLVRCpIrlYzESnEOkRhqRUlTjZXuRjnfNSQwzYReRdK5+Y1QlrbpeuL1+AyxO7M6eizMZsYtRKBJCRTWQgisn2EghVDvK6g2khp3l0uZ9fGG2O5gErt6SsP/a7L/kDzeP4nP4uA63l+Vtc4FVnkha4oV/kIJF4c9C8JBCpNsZilwxwQu8hWosGilKTsFUd53gskqYgl1OIjNbaS9oLVFZqiNPD+entVuDVFAPJDz9NYgMlGz0Epx9jyDRSWsMq74t3hK1ZNASm0bQCXFXuIelB8jrD9j5r7EDfs7sOlD/DV7wGrxzoeYvJ9j8A9j8f4ltOcM2gwScfjAPn46ilBQa6pgL1EzdI0Iz/m7G7xYYbevB1LaxAdeHv7cFTDDIMmGf9hzZvBd7UIhSRnDcH4rIGNTxPyHQ0TM+7+igY4sDDbOahJQo9jR+/A91EXe4E0zfrDNMZ4ZmYiBbor03Zg0f62mh1aSQNynUgpkVejZVd+2/99nqBD47tWeOesE7Ky/MHo/po/BWL6wnVvBPZQUd9p8f7fL+Gy64+g0= \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/cbor/encode_cbor.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/cbor/encode_cbor.md new file mode 100644 index 0000000000..4e97ec4f44 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/cbor/encode_cbor.md @@ -0,0 +1,273 @@ +### jsoncons::cbor::encode_cbor + +Encodes a C++ data structure to the [Concise Binary Object Representation](http://cbor.io/) data format. + +#### Header +```c++ +#include + +template +void encode_cbor(const T& val, std::vector& buffer, + const cbor_encode_options& options = cbor_options::default_options()); // (1) + +template +void encode_cbor(const T& val, std::ostream& os, + const cbor_encode_options& options = cbor_options::default_options()); // (2) +``` + +(1) Writes a value of type T into a bytes buffer in the CBOR data format. Type T must be an instantiation of [basic_json](../json.md) +or support [json_type_traits](../json_type_traits.md). Uses the [encode options](cbor_options.md) +supplied or defaults. + +(2) Writes a value of type T into a binary stream in the CBOR data format. Type T must be an instantiation of [basic_json](../json.md) +or support [json_type_traits](../json_type_traits.md). Uses the [encode options](cbor_options.md) +supplied or defaults. + +#### See also + +- [decode_cbor](decode_cbor) decodes a [Concise Binary Object Representation](http://cbor.io/) data format to a json value. + +### Examples + +#### cbor example + +```c++ +#include +#include + +using namespace jsoncons; + +int main() +{ + ojson j1; + j1["zero"] = 0; + j1["one"] = 1; + j1["two"] = 2; + j1["null"] = null_type(); + j1["true"] = true; + j1["false"] = false; + j1["max int64_t"] = (std::numeric_limits::max)(); + j1["max uint64_t"] = (std::numeric_limits::max)(); + j1["min int64_t"] = (std::numeric_limits::lowest)(); + j1["max int32_t"] = (std::numeric_limits::max)(); + j1["max uint32_t"] = (std::numeric_limits::max)(); + j1["min int32_t"] = (std::numeric_limits::lowest)(); + j1["max int16_t"] = (std::numeric_limits::max)(); + j1["max uint16_t"] = (std::numeric_limits::max)(); + j1["min int16_t"] = (std::numeric_limits::lowest)(); + j1["max int8_t"] = (std::numeric_limits::max)(); + j1["max uint8_t"] = (std::numeric_limits::max)(); + j1["min int8_t"] = (std::numeric_limits::lowest)(); + j1["max double"] = (std::numeric_limits::max)(); + j1["min double"] = (std::numeric_limits::lowest)(); + j1["max float"] = (std::numeric_limits::max)(); + j1["zero float"] = 0.0; + j1["min float"] = (std::numeric_limits::lowest)(); + j1["Key too long for small string optimization"] = "String too long for small string optimization"; + + std::vector v; + cbor::encode_cbor(j1, v); + + ojson j2 = cbor::decode_cbor(v); + + std::cout << pretty_print(j2) << std::endl; +} +``` +Output: +```json +{ + "zero": 0, + "one": 1, + "two": 2, + "null": null, + "true": true, + "false": false, + "max int64_t": 9223372036854775807, + "max uint64_t": 18446744073709551615, + "min int64_t": -9223372036854775808, + "max int32_t": 2147483647, + "max uint32_t": 4294967295, + "min int32_t": -2147483648, + "max int16_t": 32767, + "max uint16_t": 65535, + "min int16_t": -32768, + "max int8_t": 127, + "max uint8_t": 255, + "min int8_t": -128, + "max double": 1.79769313486232e+308, + "min double": -1.79769313486232e+308, + "max float": 3.40282346638529e+038, + "zero float": 0.0, + "min float": -3.40282346638529e+038, + "Key too long for small string optimization": "String too long for small string optimization" +} +``` + +#### Encode CBOR byte string + +```c++ +#include +#include + +using namespace jsoncons; + +int main() +{ + // construct byte string value + json j(byte_string("Hello")); + + std::vector buf; + cbor::encode_cbor(j, buf); + + std::cout << std::hex << std::showbase << "(1) "; + for (auto c : buf) + { + std::cout << (int)c; + } + std::cout << std::dec << "\n\n"; + + json j2 = cbor::decode_cbor(buf); + std::cout << "(2) " << j2 << std::endl; +} +``` +Output: +``` +(1) 0x450x480x650x6c0x6c0x6f + +(2) "SGVsbG8" +``` + +#### Encode byte string with encoding hint + +```c++ +#include +#include + +using namespace jsoncons; + +int main() +{ + // construct byte string value + json j1(byte_string("Hello"), semantic_tag::base64); + + std::vector buf; + cbor::encode_cbor(j1, buf); + + std::cout << std::hex << std::showbase << "(1) "; + for (auto c : buf) + { + std::cout << (int)c; + } + std::cout << std::dec << "\n\n"; + + json j2 = cbor::decode_cbor(buf); + std::cout << "(2) " << j2 << std::endl; +} +``` +Output: +``` +(1) 0xd60x450x480x650x6c0x6c0x6f + +(2) "SGVsbG8=" +``` + +#### Encode packed strings [stringref-namespace, stringref](http://cbor.schmorp.de/stringref) + +This example taken from [CBOR stringref extension](http://cbor.schmorp.de/stringref) shows how to encode a +data structure that contains many repeated strings more efficiently. + +```c++ +#include +#include +#include +#include + +using namespace jsoncons; + +int main() +{ + ojson j = ojson::parse(R"( +[ + { + "name" : "Cocktail", + "count" : 417, + "rank" : 4 + }, + { + "rank" : 4, + "count" : 312, + "name" : "Bath" + }, + { + "count" : 691, + "name" : "Food", + "rank" : 4 + } + ] +)"); + + cbor::cbor_options options; + options.pack_strings(true); + std::vector buf; + + cbor::encode_cbor(j, buf, options); + + for (auto c : buf) + { + std::cout << std::hex << std::setprecision(2) << std::setw(2) + << std::noshowbase << std::setfill('0') << static_cast(c); + } + std::cout << "\n"; + +/* + d90100 -- tag (256) + 83 -- array(3) + a3 -- map(3) + 64 -- text string (4) + 6e616d65 -- "name" + 68 -- text string (8) + 436f636b7461696c -- "Cocktail" + 65 -- text string (5) + 636f756e74 -- "count" + 1901a1 -- unsigned(417) + 64 -- text string (4) + 72616e6b -- "rank" + 04 -- unsigned(4) + a3 -- map(3) + d819 -- tag(25) + 03 -- unsigned(3) + 04 -- unsigned(4) + d819 -- tag(25) + 02 -- unsigned(2) + 190138 -- unsigned(312) + d819 -- tag(25) + 00 -- unsigned(0) + 64 -- text string(4) + 42617468 -- "Bath" + a3 -- map(3) + d819 -- tag(25) + 02 -- unsigned(2) + 1902b3 -- unsigned(691) + d819 -- tag(25) + 00 -- unsigned(0) + 64 - text string(4) + 466f6f64 -- "Food" + d819 -- tag(25) + 03 -- unsigned(3) + 04 -- unsigned(4) +*/ + + ojson j2 = cbor::decode_cbor(buf); + assert(j2 == j); +} +``` +Output: +``` +d9010083a3646e616d6568436f636b7461696c65636f756e741901a16472616e6b04a3d8190304d81902190138d819006442617468a3d819021902b3d8190064466f6f64d8190304 +``` + +#### See also + +- [byte_string](../byte_string.md) +- [decode_cbor](decode_cbor.md) decodes a [Concise Binary Object Representation](http://cbor.io/) data format to a json value. + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/chars_format.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/chars_format.md new file mode 100644 index 0000000000..3db7e79c19 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/chars_format.md @@ -0,0 +1,17 @@ +### jsoncons::chars_format + +```c++ +#if !defined(JSONCONS_NO_TO_CHARS) +using chars_format = std::chars_format; +#else +enum class chars_format : uint8_t {fixed=1,scientific=2,hex=4,general=fixed|scientific}; +#endif +``` + +#### Header +```c++ +#include +``` + +A bitmask type used to specify floating-point formatting, typedefed to [std::chars_format](http://en.cppreference.com/w/cpp/utility/chars_format) if `JSONCONS_NO_TO_CHARS` is undefined. + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/csv/csv.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/csv/csv.md new file mode 100644 index 0000000000..8e98626e22 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/csv/csv.md @@ -0,0 +1,175 @@ +### csv extension + +The csv extension implements decode from and encode to the [CSV format](https://www.rfc-editor.org/rfc/rfc4180.txt) +You can either parse into or serialize from a variant-like structure, [basic_json](../json.md), or your own +data structures, using [json_type_traits](../json_type_traits.md). + +[decode_csv](decode_csv.md) + +[encode_csv](encode_csv.md) + +[csv_options](csv_options.md) + +[csv_reader](csv_reader.md) + +[csv_encoder](csv_encoder.md) + +### Examples + +#### Decode a CSV source to a basic_json value + +Example file (sales.csv) +```csv +customer_name,has_coupon,phone_number,zip_code,sales_tax_rate,total_amount +"John Roe",true,0272561313,01001,0.05,431.65 +"Jane Doe",false,416-272-2561,55416,0.15,480.70 +"Joe Bloggs",false,"4162722561","55416",0.15,300.70 +"John Smith",FALSE,NULL,22313-1450,0.15,300.70 +``` + +```c++ +#include +#include +#include + +using namespace jsoncons; + +int main() +{ + csv::csv_options options; + options.assume_header(true) + .mapping(csv::mapping_type::n_objects); + + std::ifstream is1("input/sales.csv"); + ojson j1 = csv::decode_csv(is1,options); + std::cout << "\n(1)\n"<< pretty_print(j1) << "\n"; + + options.mapping(csv::mapping_type::n_rows); + std::ifstream is2("input/sales.csv"); + ojson j2 = csv::decode_csv(is2,options); + std::cout << "\n(2)\n"<< pretty_print(j2) << "\n"; + + options.mapping(csv::mapping_type::m_columns); + std::ifstream is3("input/sales.csv"); + ojson j3 = csv::decode_csv(is3,options); + std::cout << "\n(3)\n"<< pretty_print(j3) << "\n"; +} +``` +Output: +```json +(1) +[ + { + "customer_name": "John Roe", + "has_coupon": true, + "phone_number": "0272561313", + "zip_code": "01001", + "sales_tax_rate": 0.05, + "total_amount": 431.65 + }, + { + "customer_name": "Jane Doe", + "has_coupon": false, + "phone_number": "416-272-2561", + "zip_code": 55416, + "sales_tax_rate": 0.15, + "total_amount": 480.7 + }, + { + "customer_name": "Joe Bloggs", + "has_coupon": false, + "phone_number": "4162722561", + "zip_code": "55416", + "sales_tax_rate": 0.15, + "total_amount": 300.7 + }, + { + "customer_name": "John Smith", + "has_coupon": false, + "phone_number": null, + "zip_code": "22313-1450", + "sales_tax_rate": 0.15, + "total_amount": 300.7 + } +] + +(2) +[ + ["customer_name","has_coupon","phone_number","zip_code","sales_tax_rate","total_amount"], + ["John Roe",true,"0272561313","01001",0.05,431.65], + ["Jane Doe",false,"416-272-2561",55416,0.15,480.7], + ["Joe Bloggs",false,"4162722561","55416",0.15,300.7], + ["John Smith",false,null,"22313-1450",0.15,300.7] +] + +(3) +{ + "customer_name": ["John Roe","Jane Doe","Joe Bloggs","John Smith"], + "has_coupon": [true,false,false,false], + "phone_number": ["0272561313","416-272-2561",4162722561,null], + "zip_code": ["01001",55416,55416,"22313-1450"], + "sales_tax_rate": [0.05,0.15,0.15,0.15], + "total_amount": [431.65,480.7,300.7,300.7] +} +``` + +#### Convert a CSV source to a C++ data structure that satisfies [json_type_traits](../json_type_traits.md) requirements, and back + +```c++ +#include +#include +#include + +using namespace jsoncons; + +int main() +{ + const std::string input = R"(Date,1Y,2Y,3Y,5Y +2017-01-09,0.0062,0.0075,0.0083,0.011 +2017-01-08,0.0063,0.0076,0.0084,0.0112 +2017-01-08,0.0063,0.0076,0.0084,0.0112 +)"; + + csv::csv_options ioptions; + ioptions.header_lines(1) + .mapping(csv::mapping_type::n_rows); + + typedef std::vector> table_type; + + table_type table = csv::decode_csv(input,ioptions); + + std::cout << "(1)\n"; + for (const auto& row : table) + { + std::cout << std::get<0>(row) << "," + << std::get<1>(row) << "," + << std::get<2>(row) << "," + << std::get<3>(row) << "," + << std::get<4>(row) << "\n"; + } + std::cout << "\n"; + + std::string output; + + csv::csv_options ooptions; + ooptions.column_names("Date,1Y,2Y,3Y,5Y"); + csv::encode_csv(table, output, ooptions); + + std::cout << "(2)\n"; + std::cout << output << "\n"; +} +``` +Output: +``` +(1) +2017-01-09,0.0062,0.0075,0.0083,0.011 +2017-01-08,0.0063,0.0076,0.0084,0.011 +2017-01-08,0.0063,0.0076,0.0084,0.011 + +(2) +Date,1Y,2Y,3Y,5Y +2017-01-09,0.0062,0.0075,0.0083,0.011 +2017-01-08,0.0063,0.0076,0.0084,0.0112 +2017-01-08,0.0063,0.0076,0.0084,0.0112 +``` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/csv/csv_decode_options.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/csv/csv_decode_options.md new file mode 100644 index 0000000000..2125a1797d --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/csv/csv_decode_options.md @@ -0,0 +1,67 @@ +### jsoncons::csv::csv_decode_options + +```c++ +typedef basic_csv_decode_options csv_decode_options +``` + +An abstract class that defines accessors for CSV decode options. + +#### Header +```c++ +#include +``` + +#### Implementing classes + +[csv_options](csv_options.md) + +#### Accessors + + virtual size_t header_lines() const = 0; + + virtual bool assume_header() const = 0; + + virtual bool ignore_empty_values() const = 0; + + virtual bool ignore_empty_lines() const = 0; + + virtual bool trim_leading() const = 0; + + virtual bool trim_trailing() const = 0; + + virtual bool trim_leading_inside_quotes() const = 0; + + virtual bool trim_trailing_inside_quotes() const = 0; + + virtual bool trim() const = 0; + + virtual bool trim_inside_quotes() const = 0; + + virtual bool unquoted_empty_value_is_null() const = 0; + + virtual std::vector column_names() const = 0; + + virtual std::vector column_types() const = 0; + + virtual std::vector column_defaults() const = 0; + + virtual CharT field_delimiter() const = 0; + + virtual std::pair subfield_delimiter() const = 0; + + virtual string_type line_delimiter() const = 0; + + virtual CharT quote_char() const = 0; + + virtual bool infer_types() const = 0; + + virtual bool lossless_number() const = 0; + + virtual CharT quote_escape_char() const = 0; + + virtual CharT comment_starter() const = 0; + + virtual mapping_type mapping() const = 0; + + virtual unsigned long max_lines() const = 0; + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/csv/csv_encode_options.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/csv/csv_encode_options.md new file mode 100644 index 0000000000..078156975d --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/csv/csv_encode_options.md @@ -0,0 +1,33 @@ +### jsoncons::csv::csv_encode_options + +An abstract class that defines accessors for CSV encode options. + +#### Header +```c++ +#include +``` + +#### Implementing classes + +[csv_options](csv_options.md) + +#### Accessors + + virtual chars_format floating_point_format() const = 0; + + virtual int precision() const = 0; + + virtual std::vector column_names() const = 0; + + virtual CharT field_delimiter() const = 0; + + virtual std::pair subfield_delimiter() const = 0; + + virtual string_type line_delimiter() const = 0; + + virtual CharT quote_char() const = 0; + + virtual CharT quote_escape_char() const = 0; + + virtual quote_style_type quote_style() const = 0; + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/csv/csv_encoder.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/csv/csv_encoder.md new file mode 100644 index 0000000000..58c41e777c --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/csv/csv_encoder.md @@ -0,0 +1,260 @@ +### jsoncons::csv::basic_csv_encoder + +```c++ +template< + class CharT, + class Result + class Allocator=std::allocator=std::allocator> +> class basic_csv_encoder : public jsoncons::basic_json_content_handler +``` + +`basic_csv_encoder` and `basic_json_compressed_encoder` are noncopyable and nonmoveable. + +#### Header + + #include + +![csv_encoder](./diagrams/csv_encoder.png) + +Four specializations for common character types and result types are defined: + +Type |Definition +---------------------------|------------------------------ +csv_encoder |basic_csv_encoder> +json_string_encoder |basic_csv_encoder> +wcsv_encoder |basic_csv_encoder> +wjson_string_encoder |basic_csv_encoder> + +#### Member types + +Type |Definition +---------------------------|------------------------------ +char_type |CharT +result_type |Result +string_view_type | + +#### Constructors + + explicit basic_csv_encoder(result_type result) +Constructs a new csv encoder that is associated with the output adaptor `result`. + + basic_csv_encoder(result_type result, + const basic_csv_options& options) +Constructs a new csv encoder that is associated with the output adaptor `result` +and uses the specified [csv options](csv_options.md). + +#### Destructor + + virtual ~basic_csv_encoder() + +### Inherited from [basic_json_content_handler](../json_content_handler.md) + +#### Member functions + + bool begin_object(semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool begin_object(size_t length, + semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool end_object(const ser_context& context = null_ser_context()) + + bool begin_array(semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool begin_array(semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool end_array(const ser_context& context=null_ser_context()); + + bool name(const string_view_type& name, + const ser_context& context=null_ser_context()); + + bool string_value(const string_view_type& value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool byte_string_value(const byte_string_view& b, + semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool byte_string_value(const uint8_t* p, size_t size, + semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool int64_value(int64_t value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool uint64_value(uint64_t value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool double_value(double value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool bool_value(bool value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool null_value(semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); + + void flush() + +### Examples + +### Serializing an array of json values to a comma delimted file + +#### JSON input file +```json +[ + ["country_code","name"], + ["ABW","ARUBA"], + ["ATF","FRENCH SOUTHERN TERRITORIES, D.R. OF"], + ["VUT","VANUATU"], + ["WLF","WALLIS & FUTUNA ISLANDS"] +] +``` +Note + +- The third array element has a value that contains a comma, in the CSV file this value will be quoted. + +#### Serializing the comma delimited file with csv_encoder +```c++ +std::string in_file = "input/countries.json"; +std::ifstream is(in_file); + +json_decoder decoder; +json_reader reader(is,decoder); +reader.read(); +json countries = decoder.get_result(); + +csv_encoder encoder(std::cout); + +countries.dump(encoder); +``` +#### Output +``` +country_code,name +ABW,ARUBA +ATF,"FRENCH SOUTHERN TERRITORIES, D.R. OF" +VUT,VANUATU +WLF,WALLIS & FUTUNA ISLANDS +``` +### Serializing an array of json objects to a tab delimted file + +#### JSON input file +```json +[ + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + } +] +``` +Note + +- The names in the first object in the array will be used for the header row of the CSV file +- The fourth object has a `note` member whose value contains escaped quotes and an escaped new line character, in the CSV file, this value will be quoted, and it will contain a new line character and escaped quotes. + +#### Dump json value to a tab delimited file +```c++ +std::string in_file = "input/employees.json"; +std::ifstream is(in_file); + +json_decoder decoder; +csv_options options; +options.field_delimiter = '\t'; + +json_reader reader(is,decoder); +reader.read(); +json employees = decoder.get_result(); + +csv_encoder encoder(std::cout,options); + +employees.dump(encoder); +``` +#### Tab delimited output file +``` +dept employee-name employee-no note salary +sales Smith, Matthew 00000001 150,000.00 +sales Brown, Sarah 00000002 89,000.00 +finance Oberc, Scott 00000003 110,000.00 +sales Scott, Colette 00000004 ""Exemplary"" employee +Dependable, trustworthy 75,000.00 +``` + +#### Dump json value to csv file + +```c++ +#include +#include + +using namespace jsoncons; + +int main() +{ + const json books = json::parse(R"( + [ + { + "title" : "Kafka on the Shore", + "author" : "Haruki Murakami", + "price" : 25.17 + }, + { + "title" : "Women: A Novel", + "author" : "Charles Bukowski", + "price" : 12.00 + }, + { + "title" : "Cutter's Way", + "author" : "Ivan Passer" + } + ] + )"); + + csv_options options; + options.column_names("author,title,price"); + + csv_encoder encoder(std::cout, options); + + books.dump(encoder); +} +``` + +Output: + +```csv +author,title,price +Haruki Murakami,Kafka on the Shore,25.17 +Charles Bukowski,Women: A Novel,12.0 +Ivan Passer,Cutter's Way, +``` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/csv/csv_options.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/csv/csv_options.md new file mode 100644 index 0000000000..082d702b23 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/csv/csv_options.md @@ -0,0 +1,111 @@ +### jsoncons::csv::csv_options + +```c++ +typedef basic_csv_options csv_options +``` +Specifies options for encoding and decoding csv data. The `csv_options` class is an instantiation of the `basic_csv_options` class template that uses `char` as the character type. + +#### Header +```c++ +#include +``` + +![csv_options](./diagrams/csv_options.png) + +#### Constructors + + csv_options() +Constructs an `csv_options` with default values. + +#### Modifiers + basic_csv_options& floating_point_format(chars_format value); +Overrides [floating point format](../chars_format.md) when serializing csv from json. For a floating point value that was previously decoded from json text, preserves the original format when serializing.For a floating point value that was directly inserted into a json value, serializes with [chars_format::general](chars_format.md). + + basic_csv_options& precision(int value); +Overrides floating point precision when serializing csv from json. The default, For a floating point value that was previously decoded from json text, preserves the original precision. The fefault, For a floating point value that was directly inserted into a json value, serializes with shortest representation. + + basic_csv_options& header_lines(size_t value); +Number of header lines in the CSV text. Defaults to 1 if assume_header is true, otherwise 0 + + basic_csv_options& assume_header(bool value); +Assume first row in file is header, use field names to construct objects. Default is `false`. + + basic_csv_options& ignore_empty_values(bool value); +Do not read CSV fields that have empty values. Default is `false`. + + basic_csv_options& ignore_empty_lines(bool value); +If set to true, all lines in the file that are empty (apart from record delimiter characters) are ignored. To ignore lines with only spaces or tabs, set trim to true. Default is `true`. + + basic_csv_options& trim_leading(bool value); +Trim leading whitespace. Default is `false`. + + basic_csv_options& trim_trailing(bool value); +Trim trailing whitespace. Default is `false`. + + basic_csv_options& trim(bool value); +Trim both leading and trailing whitespace. Default is `false`. + + basic_csv_options& trim_leading_inside_quotes(bool value); +Trim leading whitespace inside quote characters. Default is `false`. + + basic_csv_options& trim_trailing_inside_quotes(bool value); +Trim trailing whitespace inside quote characters. Default is `false`. + + basic_csv_options& trim_inside_quotes(bool value); +Trim both leading and trailing whitespace inside quote characters. Default is `false`. + + basic_csv_options& unquoted_empty_value_is_null(bool value); +Replace empty field with json null value. Default is `false`. + + basic_csv_options& column_names(const string_type& names); +A comma separated list of names corresponding to the fields in the file. Example: "bool-field,float-field,string-field" + + basic_csv_options& column_types(const string_type& types); +A comma separated list of data types corresponding to the columns in the file. The following data types are supported: string, integer, float and boolean. Example: "bool,float,string"} + + basic_csv_options& column_defaults(const string_type& defaults); +A comma separated list of strings containing default json values corresponding to the columns in the file. Example: "false,0.0,"\"\"" + + basic_csv_options& field_delimiter(CharT value); +A delimiter character that indicates the end of a field. Default is `,` + + basic_csv_options& subfield_delimiter(CharT value); +A delimiter character that indicates the end of a single value in a multi-valued field. Default is no multi-valued fields. + + basic_csv_options& line_delimiter(string_type value); +String to write between records. Default is \n. + + basic_csv_options& quote_char(CharT value); +Quote character. Default is quote character " + + basic_csv_options& infer_types(bool value); +Infer null, true, false, integers and floating point values in the CSV source. Default is `true`. + + basic_csv_options& lossless_number(bool value); +If set to `true`, parse numbers with exponents and fractional parts as strings with semantic tagging `semantic_tag::bigdec`. Default is `false`. + + basic_csv_options& quote_escape_char(CharT value); +Character to escape quote character (by default the quote character is doubled). Default is quote character `"`. + + basic_csv_options& comment_starter(CharT value); +Character to comment out a line, must be at column 1. Default is no comments. + + basic_csv_options& quote_style(quote_style_type value); +quote_style_type::all, quote_style_type::minimal, quote_style_type::none, or quote_style_type::nonnumeric. Default is quote_style_type::minimal + + basic_csv_options& mapping(mapping_type value); +mapping_type::n_rows, mapping_type::n_objects, mapping_type::m_columns. If assume_header is true or column_names is not empty, defaults to mapping_type::n_rows, otherwise mapping_type::n_columns. + + basic_csv_options& max_lines(unsigned long value); +Maximum number of lines to read. Default is unlimited. + +#### Static member functions + + static const basic_csv_options& default_options() +Default CSV encode and decode options. + +### See also + +[csv_decode_options](csv_decode_options.md) +[csv_encode_options](csv_encode_options.md) + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/csv/csv_reader.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/csv/csv_reader.md new file mode 100644 index 0000000000..a5cd2fa706 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/csv/csv_reader.md @@ -0,0 +1,432 @@ +### jsoncons::csv::csv_reader + +```c++ +typedef basic_csv_reader> csv_reader +``` + +The `csv_reader` class is an instantiation of the `basic_csv_reader` class template that uses `char` as the character type +and `stream_source` as the input source. It reads a [CSV file](http://tools.ietf.org/html/rfc4180) and produces JSON parse events. + +`csv_reader` is noncopyable and nonmoveable. + +#### Member types + +Type |Definition +---------------------------|------------------------------ +char_type |CharT +source_type |Src + +#### Header +```c++ +#include +``` +#### Constructors + + template + basic_csv_reader(Source&& source, + basic_json_content_handler& handler); // (1) + + + template + basic_csv_reader(Source&& source, + basic_json_content_handler& handler, + const basic_csv_options& options); // (2) + + template + basic_csv_reader(Source&& source, + basic_json_content_handler& handler, + parse_error_handler& err_handler); // (3) + + template + basic_csv_reader(Source&& source, + basic_json_content_handler& handler, + const basic_csv_decode_options& options, + parse_error_handler& err_handler); // (4) + +(1) Constructs a `csv_reader` that reads from a character sequence or stream `source` +and a [json_content_handler](../json_content_handler.md) that receives +JSON events. Uses default [csv_options](csv_options.md). + +(2) Constructs a `csv_reader` that that reads from a character sequence or stream `source`, a [json_content_handler](../json_content_handler.md) that receives +JSON events, and [csv_options](csv_options.md). + +(3) Constructs a `csv_reader` that reads from a character sequence or stream `source`, a [json_content_handler](../json_content_handler.md) that receives +JSON events and the specified [parse_error_handler](../parse_error_handler.md). +Uses default [csv_options](csv_options.md). + +(4) Constructs a `csv_reader` that reads from a character sequence or stream `source`, a [json_content_handler](../json_content_handler.md) that receives +JSON events, [csv_options](csv_options.md), +and the specified [parse_error_handler](../parse_error_handler.md). + +Note: It is the programmer's responsibility to ensure that `basic_csv_reader` does not outlive any source, +content handler, and error handler passed in the constuctor, as `basic_csv_reader` holds pointers to but does not own these resources. + +#### Parameters + +`source` - a value from which a `jsoncons::basic_string_view` is constructible, +or a value from which a `source_type` is constructible. In the case that a `jsoncons::basic_string_view` is constructible +from `source`, `source` is dispatched immediately to the parser. Otherwise, the `csv_reader` reads from a `source_type` in chunks. + +#### Member functions + + bool eof() const +Returns `true` when there is no more data to be read from the stream, `false` otherwise + + void read() +Reports JSON related events for JSON objects, arrays, object members and array elements to a [json_content_handler](../json_content_handler.md), such as a [json_decoder](json_decoder.md). +Throws [ser_error](../ser_error.md) if parsing fails. + + size_t buffer_length() const + + void buffer_length(size_t length) + +### Examples + +#### Reading a comma delimted file into an array of json values + +#### Comma delimited input file +``` +country_code,name +ABW,ARUBA +ATF,"FRENCH SOUTHERN TERRITORIES, D.R. OF" +VUT,VANUATU +WLF,WALLIS & FUTUNA ISLANDS +``` +Note + +- The first record contains a header line, but we're going to ignore that and read the entire file as an array of arrays. +- The third record has a field value that contains an embedded comma, so it must be quoted. + +#### Code +```c++ +std::string in_file = "countries.csv"; +std::ifstream is(in_file); + +json_decoder decoder; + +csv_reader reader(is,decoder); +reader.read(); +json countries = decoder.get_result(); + +std::cout << pretty_print(countries) << std::endl; +``` +#### Output +```json +[ + ["country_code","name"], + ["ABW","ARUBA"], + ["ATF","FRENCH SOUTHERN TERRITORIES, D.R. OF"], + ["VUT","VANUATU"], + ["WLF","WALLIS & FUTUNA ISLANDS"] +] +``` +#### Reading a tab delimted file into an array of json objects + +#### Tab delimited input file +``` +employee-no employee-name dept salary note +00000001 Smith, Matthew sales 150,000.00 +00000002 Brown, Sarah sales 89,000.00 +00000003 Oberc, Scott finance 110,000.00 +00000004 Scott, Colette sales 75,000.00 """Exemplary"" employee +Dependable, trustworthy" +``` +Note + +- The first record is a header line, which will be used to associate data values with names +- The fifth record has a field value that contains embedded quotes and a new line character, so it must be quoted and the embedded quotes escaped. + +#### Code +```c++ +std::string in_file = "employees.txt"; +std::ifstream is(in_file); + +json_decoder decoder; +csv_options options; +options.field_delimiter = '\t' + .assume_header = true; + +csv_reader reader(is,decoder,options); +reader.read(); +json employees = decoder.get_result(); + +std::cout << pretty_print(employees) << std::endl; +``` + +#### Output + +```json +[ + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "note":"", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "salary":"75,000.00" + } +] +``` + +#### Reading the comma delimited file as an array of objects with user supplied columns names + +Note + +- The first record contains a header line, but we're going to ignore that and use our own names for the fields. + +#### Code +```c++ +std::string in_file = "countries.csv"; +std::ifstream is(in_file); + +json_decoder decoder; + +csv_options options; +options.column_names("Country Code,Name") + .header_lines(1); + +csv_reader reader(is,decoder,options); +reader.read(); +json countries = decoder.get_result(); + +std::cout << pretty_print(countries) << std::endl; +``` + +#### Output +```json +[ + { + "Country Code":"ABW", + "Name":"ARUBA" + }, + { + "Country Code":"ATF", + "Name":"FRENCH SOUTHERN TERRITORIES, D.R. OF" + }, + { + "Country Code":"VUT", + "Name":"VANUATU" + }, + { + "Country Code":"WLF", + "Name":"WALLIS & FUTUNA ISLANDS" + } +] +``` + + +#### Reading a comma delimited file with different mapping options + +#### Input + +```csv +Date,1Y,2Y,3Y,5Y +2017-01-09,0.0062,0.0075,0.0083,0.011 +2017-01-08,0.0063,0.0076,0.0084,0.0112 +2017-01-08,0.0063,0.0076,0.0084,0.0112 +``` + +#### Code + +```c++ +json_decoder decoder; +csv_options options; +options.assume_header(true) + .column_types("string,float,float,float,float"); + +options.mapping(mapping_type::n_rows); +std::istringstream is1("bond_yields.csv"); +csv_reader reader1(is1,decoder,options); +reader1.read(); +ojson val1 = decoder.get_result(); +std::cout << "\n(1)\n"<< pretty_print(val1) << "\n"; + +options.mapping(mapping_type::n_objects); +std::istringstream is2("bond_yields.csv"); +csv_reader reader2(is2,decoder,options); +reader2.read(); +ojson val2 = decoder.get_result(); +std::cout << "\n(2)\n"<< pretty_print(val2) << "\n"; + +options.mapping(mapping_type::m_columns); +std::istringstream is3("bond_yields.csv"); +csv_reader reader3(is3, decoder, options); +reader3.read(); +ojson val3 = decoder.get_result(); +std::cout << "\n(3)\n" << pretty_print(val3) << "\n"; +``` + +#### Output + +```json +(1) +[ + ["Date","1Y","2Y","3Y","5Y"], + ["2017-01-09",0.0062,0.0075,0.0083,0.011], + ["2017-01-08",0.0063,0.0076,0.0084,0.0112], + ["2017-01-08",0.0063,0.0076,0.0084,0.0112] +] + +(2) +[ + { + "Date": "2017-01-09", + "1Y": 0.0062, + "2Y": 0.0075, + "3Y": 0.0083, + "5Y": 0.011 + }, + { + "Date": "2017-01-08", + "1Y": 0.0063, + "2Y": 0.0076, + "3Y": 0.0084, + "5Y": 0.0112 + }, + { + "Date": "2017-01-08", + "1Y": 0.0063, + "2Y": 0.0076, + "3Y": 0.0084, + "5Y": 0.0112 + } +] + +(3) +{ + "Date": ["2017-01-09","2017-01-08","2017-01-08"], + "1Y": [0.0062,0.0063,0.0063], + "2Y": [0.0075,0.0076,0.0076], + "3Y": [0.0083,0.0084,0.0084], + "5Y": [0.011,0.0112,0.0112] +} +``` + +#### Convert CSV to json when last column repeats + +```c++ +int main() +{ + const std::string bond_yields = R"(Date,Yield +2017-01-09,0.0062,0.0075,0.0083,0.011,0.012 +2017-01-08,0.0063,0.0076,0.0084,0.0112,0.013 +2017-01-08,0.0063,0.0076,0.0084,0.0112,0.014 +)"; + + // array of arrays + json_decoder decoder1; + csv_options options1; + options1.header_lines(1); + options1.assume_header(false); + options1.column_types("string,float*"); + std::istringstream is1(bond_yields); + csv_reader reader1(is1, decoder1, options1); + reader1.read(); + ojson val1 = decoder1.get_result(); + std::cout << "\n(1)\n" << pretty_print(val1) << "\n"; + + // array of objects + json_decoder decoder2; + csv_options options2; + options2.assume_header(true); + options2.column_types("string,[float*]"); + std::istringstream is2(bond_yields); + csv_reader reader2(is2, decoder2, options2); + reader2.read(); + ojson val2 = decoder2.get_result(); + std::cout << "\n(2)\n" << pretty_print(val2) << "\n"; +} +``` + +Output: +``` +(1) +[ + ["2017-01-09",0.0062,0.0075,0.0083,0.011,0.012], + ["2017-01-08",0.0063,0.0076,0.0084,0.0112,0.013], + ["2017-01-08",0.0063,0.0076,0.0084,0.0112,0.014] +] + +(2) +[ + { + "Date": "2017-01-09", + "Yield": [0.0062,0.0075,0.0083,0.011,0.012] + }, + { + "Date": "2017-01-08", + "Yield": [0.0063,0.0076,0.0084,0.0112,0.013] + }, + { + "Date": "2017-01-08", + "Yield": [0.0063,0.0076,0.0084,0.0112,0.014] + } +] +``` + +#### Convert CSV to json when last two columns repeat + +```c++ +const std::string holidays = R"(1,CAD,2,UK,3,EUR,4,US + UK,5,US +38719,2-Jan-2006,40179,1-Jan-2010,38719,2-Jan-2006,38719,2-Jan-2006,39448,1-Jan-2008 +38733,16-Jan-2006,40270,2-Apr-2010,38733,16-Jan-2006,38733,16-Jan-2006,39468,21-Jan-2008 +)"; + + json_decoder decoder; + csv_options options; + options.column_types("[integer,string]*"); + + // Default + std::istringstream is1(holidays); + csv_reader reader1(is1, decoder, options); + reader1.read(); + ojson val1 = decoder.get_result(); + std::cout << pretty_print(val1) << "\n"; +``` + +Output: +``` +[ + [ + [1,"CAD"], + [2,"UK"], + [3,"EUR"], + [4,"US + UK"], + [5,"US"] + ], + [ + [38719,"2-Jan-2006"], + [40179,"1-Jan-2010"], + [38719,"2-Jan-2006"], + [38719,"2-Jan-2006"], + [39448,"1-Jan-2008"] + ], + [ + [38733,"16-Jan-2006"], + [40270,"2-Apr-2010"], + [38733,"16-Jan-2006"], + [38733,"16-Jan-2006"], + [39468,"21-Jan-2008"] + ] +] +``` diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/csv/decode_csv.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/csv/decode_csv.md new file mode 100644 index 0000000000..caaf623fdc --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/csv/decode_csv.md @@ -0,0 +1,338 @@ +### jsoncons::csv::decode_csv + +Decodes a [comma-separated variables (CSV)](https://en.wikipedia.org/wiki/Comma-separated_values) data format into a C++ data structure. + +#### Header +```c++ +#include + +template +T decode_csv(const std::basic_string& s, + const basic_csv_options& options = basic_csv_options::default_options())); // (1) + +template +T decode_csv(std::basic_istream& is, + const basic_csv_options& options = basic_csv_options::default_options())); // (2) +``` + +(1) Reads a CSV string value into a type T if T is an instantiation of [basic_json](../json.md) +or if T supports [json_type_traits](../json_type_traits.md). + +(2) Reads a CSV input stream into a type T if T is an instantiation of [basic_json](../json.md) +or if T supports [json_type_traits](../json_type_traits.md). + +#### Return value + +Returns a value of type `T`. + +#### Exceptions + +Throws [ser_error](ser_error.md) if parsing fails. + +### Examples + +#### Decode a CSV file with type inference (default) + +Example file (sales.csv) +```csv +customer_name,has_coupon,phone_number,zip_code,sales_tax_rate,total_amount +"John Roe",true,0272561313,01001,0.05,431.65 +"Jane Doe",false,416-272-2561,55416,0.15,480.70 +"Joe Bloggs",false,"4162722561","55416",0.15,300.70 +"John Smith",FALSE,NULL,22313-1450,0.15,300.70 +``` + +```c++ +#include +#include +#include + +using namespace jsoncons; + +int main() +{ + csv::csv_options options; + options.assume_header(true); + + options.mapping(csv::mapping_type::n_objects); + std::ifstream is1("input/sales.csv"); + ojson j1 = csv::decode_csv(is1,options); + std::cout << "\n(1)\n"<< pretty_print(j1) << "\n"; + + options.mapping(csv::mapping_type::n_rows); + std::ifstream is2("input/sales.csv"); + ojson j2 = csv::decode_csv(is2,options); + std::cout << "\n(2)\n"<< pretty_print(j2) << "\n"; + + options.mapping(csv::mapping_type::m_columns); + std::ifstream is3("input/sales.csv"); + ojson j3 = csv::decode_csv(is3,options); + std::cout << "\n(3)\n"<< pretty_print(j3) << "\n"; +} +``` +Output: +```json +(1) +[ + { + "customer_name": "John Roe", + "has_coupon": true, + "phone_number": "0272561313", + "zip_code": "01001", + "sales_tax_rate": 0.05, + "total_amount": 431.65 + }, + { + "customer_name": "Jane Doe", + "has_coupon": false, + "phone_number": "416-272-2561", + "zip_code": 55416, + "sales_tax_rate": 0.15, + "total_amount": 480.7 + }, + { + "customer_name": "Joe Bloggs", + "has_coupon": false, + "phone_number": "4162722561", + "zip_code": "55416", + "sales_tax_rate": 0.15, + "total_amount": 300.7 + }, + { + "customer_name": "John Smith", + "has_coupon": false, + "phone_number": null, + "zip_code": "22313-1450", + "sales_tax_rate": 0.15, + "total_amount": 300.7 + } +] + +(2) +[ + ["customer_name","has_coupon","phone_number","zip_code","sales_tax_rate","total_amount"], + ["John Roe",true,"0272561313","01001",0.05,431.65], + ["Jane Doe",false,"416-272-2561",55416,0.15,480.7], + ["Joe Bloggs",false,"4162722561","55416",0.15,300.7], + ["John Smith",false,null,"22313-1450",0.15,300.7] +] + +(3) +{ + "customer_name": ["John Roe","Jane Doe","Joe Bloggs","John Smith"], + "has_coupon": [true,false,false,false], + "phone_number": ["0272561313","416-272-2561",4162722561,null], + "zip_code": ["01001",55416,55416,"22313-1450"], + "sales_tax_rate": [0.05,0.15,0.15,0.15], + "total_amount": [431.65,480.7,300.7,300.7] +} +``` + +#### Decode a CSV string without type inference + +```c++ +#include +#include + +using namespace jsoncons; + +int main() +{ + std::string s = R"(employee-no,employee-name,dept,salary +00000001,"Smith,Matthew",sales,150000.00 +00000002,"Brown,Sarah",sales,89000.00 +)"; + + csv::csv_options options; + options.assume_header(true) + .infer_types(false); + ojson j = csv::decode_csv(s,options); + + std::cout << pretty_print(j) << std::endl; +} +``` +Output: +```json +[ + { + "employee-no": "00000001", + "employee-name": "Smith,Matthew", + "dept": "sales", + "salary": "150000.00" + }, + { + "employee-no": "00000002", + "employee-name": "Brown,Sarah", + "dept": "sales", + "salary": "89000.00" + } +] +``` + +#### Decode a CSV string with specified types + +```c++ +#include +#include + +using namespace jsoncons; + +int main() +{ + const std::string s = R"(Date,1Y,2Y,3Y,5Y +2017-01-09,0.0062,0.0075,0.0083,0.011 +2017-01-08,0.0063,0.0076,0.0084,0.0112 +2017-01-08,0.0063,0.0076,0.0084,0.0112 +)"; + + csv::csv_options options; + options.assume_header(true) + .column_types("string,float,float,float,float"); + + // mapping_type::n_objects + options.mapping(csv::mapping_type::n_objects); + ojson j1 = csv::decode_csv(s,options); + std::cout << "\n(1)\n"<< pretty_print(j1) << "\n"; + + // mapping_type::n_rows + options.mapping(csv::mapping_type::n_rows); + ojson j2 = csv::decode_csv(s,options); + std::cout << "\n(2)\n"<< pretty_print(j2) << "\n"; + + // mapping_type::m_columns + options.mapping(csv::mapping_type::m_columns); + ojson j3 = csv::decode_csv(s,options); + std::cout << "\n(3)\n" << pretty_print(j3) << "\n"; +} +``` +Output: +```json +(1) +[ + { + "Date": "2017-01-09", + "1Y": 0.0062, + "2Y": 0.0075, + "3Y": 0.0083, + "5Y": 0.011 + }, + { + "Date": "2017-01-08", + "1Y": 0.0063, + "2Y": 0.0076, + "3Y": 0.0084, + "5Y": 0.0112 + }, + { + "Date": "2017-01-08", + "1Y": 0.0063, + "2Y": 0.0076, + "3Y": 0.0084, + "5Y": 0.0112 + } +] + +(2) +[ + ["Date","1Y","2Y","3Y","5Y"], + ["2017-01-09",0.0062,0.0075,0.0083,0.011], + ["2017-01-08",0.0063,0.0076,0.0084,0.0112], + ["2017-01-08",0.0063,0.0076,0.0084,0.0112] +] + +(3) +{ + "Date": ["2017-01-09","2017-01-08","2017-01-08"], + "1Y": [0.0062,0.0063,0.0063], + "2Y": [0.0075,0.0076,0.0076], + "3Y": [0.0083,0.0084,0.0084], + "5Y": [0.011,0.0112,0.0112] +} +``` +#### Decode a CSV string with multi-valued fields separated by subfield delimiters + +```c++ +#include +#include + +using namespace jsoncons; + +int main() +{ + const std::string s = R"(calculationPeriodCenters,paymentCenters,resetCenters +NY;LON,TOR,LON +NY,LON,TOR;LON +"NY";"LON","TOR","LON" +"NY","LON","TOR";"LON" +)"; + json_options print_options; + print_options.array_array_line_splits(line_split_kind::same_line); + + csv::csv_options options1; + options1.assume_header(true) + .subfield_delimiter(';'); + + json j1 = csv::decode_csv(s,options1); + std::cout << "(1)\n" << pretty_print(j1,print_options) << "\n\n"; + + csv::csv_options options2; + options2.mapping(csv::mapping_type::n_rows) + .subfield_delimiter(';'); + + json j2 = csv::decode_csv(s,options2); + std::cout << "(2)\n" << pretty_print(j2,print_options) << "\n\n"; + + csv::csv_options options3; + options3.assume_header(true) + .mapping(csv::mapping_type::m_columns) + .subfield_delimiter(';'); + + json j3 = csv::decode_csv(s,options3); + std::cout << "(3)\n" << pretty_print(j3,print_options) << "\n\n"; +} +``` +Output: +```json +(1) +[ + + { + "calculationPeriodCenters": ["NY","LON"], + "paymentCenters": "TOR", + "resetCenters": "LON" + }, + { + "calculationPeriodCenters": "NY", + "paymentCenters": "LON", + "resetCenters": ["TOR","LON"] + }, + { + "calculationPeriodCenters": ["NY","LON"], + "paymentCenters": "TOR", + "resetCenters": "LON" + }, + { + "calculationPeriodCenters": "NY", + "paymentCenters": "LON", + "resetCenters": ["TOR","LON"] + } +] + +(2) +[ + + ["calculationPeriodCenters","paymentCenters","resetCenters"], + [["NY","LON"],"TOR","LON"], + ["NY","LON",["TOR","LON"]], + [["NY","LON"],"TOR","LON"], + ["NY","LON",["TOR","LON"]] +] + +(3) +{ + "calculationPeriodCenters": [["NY","LON"],"NY",["NY","LON"],"NY"], + "paymentCenters": ["TOR","LON","TOR","LON"], + "resetCenters": ["LON",["TOR","LON"],"LON",["TOR","LON"]] +} +``` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/csv/diagrams/csv_encoder.png b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/csv/diagrams/csv_encoder.png new file mode 100644 index 0000000000..9115c418ab Binary files /dev/null and b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/csv/diagrams/csv_encoder.png differ diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/csv/diagrams/csv_encoder.xml b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/csv/diagrams/csv_encoder.xml new file mode 100644 index 0000000000..3f801b99de --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/csv/diagrams/csv_encoder.xml @@ -0,0 +1 @@ +vVZdb9owFP01eeyUxIXSxxZot6FW65gEfUJufJt4c2zmGAj79bOJTeIkqFSq2ofK91xff5xzrkOAxnl5L/E6exAEWBCHpAzQJIjjq2ik/xtgXwFoGFZAKimpoKgG5vQfWNBN21AChTdRCcEUXftgIjiHRHkYllLs/Gmvgvm7rnEKHWCeYNZFF5SorEJHg7DGvwJNM7dzFNpMjt1kCxQZJmLXgNA0QGMphKpGeTkGZrhzvFR1dyeyx4NJ4Oqcgunjr5LPnuZZPP47U4uH/Ln8fmFX2WK2sRd+wQVNVr8LwVeaU6UXX2WYEwYyiIdM73T7YkapGfUhh6uqveNPig0nYI4Q6vQuowrma5yY7E4bRmOZypmOomN180rufCAVlA3IXvEeRA5K7vUUmx1Ztq3dIsf+rhYvchbMGsJdWgxbv6THlWtK9cCy+g6Gr04wnBTbFfBE98snEPtKGRsLJuShFsHhT+OFkuIPNDJoiK4R+RgpztJi8JlajDpadGgFTm7Ms6GjhOFCK+UzCSVVS0u6GT+b8ZeBjSZlIzXZu4Drwy/dAiZoVJmwLjtEru6kBoXYyATeNp3CMgX1dvsD8R7BrqINxfoEc5gEhhXd+k9nn4p2hx+C6psdDXPp+yVGLR9U17ZFzZeutc51y3ej1joVLZ11DpY6Xvosl6XbhyyePS7xT0gvFk8z2M6gp+O/8QwkVZhr0fSnkOJU4rxjPd1Wyjeb355ccGj1soUwoyk3jtVG0c8JujVNSvVH7MYmckqI2ab3nfBfko9o/LAlZNjT+KjHR/H7G1+H9Se0UrD+HYKm/wE= \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/csv/diagrams/csv_options.png b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/csv/diagrams/csv_options.png new file mode 100644 index 0000000000..19d138a26a Binary files /dev/null and b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/csv/diagrams/csv_options.png differ diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/csv/diagrams/csv_options.xml b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/csv/diagrams/csv_options.xml new file mode 100644 index 0000000000..8949391572 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/csv/diagrams/csv_options.xml @@ -0,0 +1 @@ +zZbJbtswEIafRscWWurl2thZDm1R1ECbngRGHEtEKVGhKEvq05eMhlqdOA2M1heD85MzJL/5TcgJNml9K0mefBYUuOO7tHaCreP7q0Wgf43QtEKw9Fohloy20kDYsd+AootqySgUo4VKCK5YPhYjkWUQqZFGpBTVeNle8PGuOYlhJuwiwufqD0ZV0qrrhdvrd8DixO7suTiTErsYhSIhVFQDKbh2go0UQrWjtN4AN+wslzbv5pnZ7mASMvWahP33Zv8t/3X3KL6Ej+twe1V+at5hlQPhJV74gRQsCqPiEFKIdDdDkSsmsgIvoRpLRooyo2CKu05wVSVMwS4nkZmttBW0lqiU68jTw/lh7c4gFdQDCQ9/CyIFJRu9BGc/IEc00hrDqu+Kt0QtGXTEphE0QtwV7lnpAeL6C3T+C+ggu2R0Haf/xi54gd2lQPOXE2r+EWr+v6S2nFGbQYKMfjSvno4iTgrNdMwFaqbuEaEZ/zTj9wuMtvVgatvYINOHv7cFTDDIMmGf9hTZvGd7UIhSRnDaHorIGNTpvyDQ0Rs+7+igY4sjDbOaBE4UO4xf/mNdxB2+CqZv1hmmM0MzMZAt0d4bs4Yv9bTQalLImxRqwcwKPZmqu/bbfbY6g8/O7ZmTXvAuyguzx2P6KLzWC+uJFfxzWUGH/bdHu7z/gAuu/wA= \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/csv/encode_csv.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/csv/encode_csv.md new file mode 100644 index 0000000000..c1590232d8 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/csv/encode_csv.md @@ -0,0 +1,71 @@ +### jsoncons::csv::encode_csv + +Encodes a C++ data structure into the CSV data format. + +#### Header +```c++ +#include + +template +void encode_csv(const T& val, + std::basic_string& s, + const basic_csv_options& options = basic_csv_options::default_options())); // (1) + +template +void encode_csv(const T& val, + std::basic_ostream& os, + const basic_csv_options& options = basic_csv_options::default_options())); // (2) +``` + +(1) Writes a value of type T into a string in the CSV data format. Type T must be an instantiation of [basic_json](../json.md) +or support [json_type_traits](../json_type_traits.md). Uses the [encode options](csv_options.md) +supplied or defaults. + +(2) Writes a value of type T into an output stream in the CSV data format. Type T must be an instantiation of [basic_json](../json.md) +or support [json_type_traits](../json_type_traits.md). Uses the [encode options](csv_options.md) +supplied or defaults. + +### Examples + +#### Write a json value to a CSV output stream + +```c++ +#include +#include +#include + +using namespace jsoncons; + +int main() +{ + const json books = json::parse(R"( + [ + { + "title" : "Kafka on the Shore", + "author" : "Haruki Murakami", + "price" : 25.17 + }, + { + "title" : "Women: A Novel", + "author" : "Charles Bukowski", + "price" : 12.00 + }, + { + "title" : "Cutter's Way", + "author" : "Ivan Passer" + } + ] + )"); + + csv::encode_csv(books, std::cout); +} +``` +Output: +```json +author,price,title +Haruki Murakami,00,Kafka on the Shore +Charles Bukowski,00,Women: A Novel +Ivan Passer,,Cutter's Way +``` + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/data-model.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/data-model.md new file mode 100644 index 0000000000..f5c824f1da --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/data-model.md @@ -0,0 +1,209 @@ +## jsoncons data model + +The jsoncons data model supports the familiar JSON types - nulls, +booleans, numbers, strings, arrays, objects - plus byte strings. It has + +- null +- bool +- int64 +- uint64 +- double +- string +- byte string +- array +- object + +In addition, jsoncons supports semantic tagging of date-time values, timestamp values, big integers, +big decimals, bigfloats and binary encodings. This allows it to preserve these type semantics when parsing +JSON-like data formats such as CBOR that have them, for example, the mappings between the jsoncons +and CBOR data items are shown below: + +jsoncons data item|jsoncons tag|CBOR data item|CBOR tag +--------------|------------------|---------------|-------- +null | | null |  +null | undefined | undefined |  +bool | | true or false |  +int64 | | unsigned or negative integer |  +int64 | timestamp | unsigned or negative integer | 1 (epoch-based date/time) +uint64 | | unsigned integer |  +uint64 | timestamp | unsigned integer | 1 (epoch-based date/time) +double | | half-precision float, float, or double |  +double | timestamp | double | 1 (epoch-based date/time) +string | | string |  +string | bigint | byte string | 2 (positive bignum) or 2 (negative bignum) +string | bigdec | array | 4 (decimal fraction) +string | bigfloat | array | 5 (bigfloat) +string | datetime | string | 0 (date/time string) +string | uri | string | 32 (uri) +string | base64url | string | 33 (base64url) +string | base64 | string | 34 (base64) +byte_string | | byte string |  +byte_string | base64url | byte string | 21 (Expected conversion to base64url encoding) +byte_string | base64 | byte string | 22 (Expected conversion to base64 encoding) +byte_string | base16 | byte string | 23 (Expected conversion to base16 encoding) +array | | array |  +object | | map |  + +### Examples + +#### json value to CBOR item + +```c++ +#include +#include + +using namespace jsoncons; + +int main() +{ + json j = json::array(); + + j.emplace_back("foo"); + j.emplace_back(byte_string{ 'b','a','r' }); + j.emplace_back("-18446744073709551617", semantic_tag::bigint); + j.emplace_back("273.15", semantic_tag::bigdec); + j.emplace_back("2018-10-19 12:41:07-07:00", semantic_tag::datetime); + j.emplace_back(1431027667, semantic_tag::timestamp); + j.emplace_back(-1431027667, semantic_tag::timestamp); + j.emplace_back(1431027667.5, semantic_tag::timestamp); + + std::cout << "(1)\n" << pretty_print(j) << "\n\n"; + + std::vector bytes; + cbor::encode_cbor(j, bytes); + std::cout << "(2)\n"; + for (auto c : bytes) + { + std::cout << std::hex << std::noshowbase << std::setprecision(2) << std::setw(2) + << std::setfill('0') << static_cast(c); + } + std::cout << "\n\n"; +/* +88 -- Array of length 8 + 63 -- String value of length 3 + 666f6f -- "foo" + 43 -- Byte string value of length 3 + 626172 -- 'b''a''r' + c3 -- Tag 3 (negative bignum) + 49 Byte string value of length 9 + 010000000000000000 -- Bytes content + c4 - Tag 4 (decimal fraction) + 82 -- Array of length 2 + 21 -- -2 + 19 6ab3 -- 27315 + c0 -- Tag 0 (date-time) + 78 19 -- Length (25) + 323031382d31302d31392031323a34313a30372d30373a3030 -- "2018-10-19 12:41:07-07:00" + c1 -- Tag 1 (epoch time) + 1a -- uint32_t + 554bbfd3 -- 1431027667 + c1 + 3a + 554bbfd2 + c1 + fb + 41d552eff4e00000 +*/ +} +``` +Output +``` +(1) +[ + "foo", + "YmFy", + "-18446744073709551617", + "273.15", + "2018-10-19 12:41:07-07:00", + 1431027667, + -1431027667, + 1431027667.5 +] + +(2) +8863666f6f43626172c349010000000000000000c48221196ab3c07819323031382d31302d31392031323a34313a30372d30373a3030c11a554bbfd3c13a554bbfd2c1fb41d552eff4e00000 +``` + +#### CBOR item to json value + +```c++ +#include +#include + +using namespace jsoncons; + +void main() +{ + std::vector bytes; + cbor::cbor_bytes_encoder encoder(bytes); + encoder.begin_array(); // indefinite length outer array + encoder.string_value("foo"); + encoder.byte_string_value(byte_string({'b','a','r'})); + encoder.string_value("-18446744073709551617", semantic_tag::bigint); + encoder.decimal_value("273.15"); + encoder.string_value("2018-10-19 12:41:07-07:00", semantic_tag::datetime) ; + encoder.epoch_time_value(1431027667); + encoder.int64_value(-1431027667, semantic_tag::timestamp); + encoder.double_value(1431027667.5, semantic_tag::timestamp); + encoder.end_array(); + encoder.flush(); + + std::cout << "(1)\n"; + for (auto c : bytes) + { + std::cout << std::hex << std::noshowbase << std::setprecision(2) << std::setw(2) + << std::setfill('0') << static_cast(c); + } + std::cout << "\n\n"; + +/* +9f -- Start indefinite length array + 63 -- String value of length 3 + 666f6f -- "foo" + 43 -- Byte string value of length 3 + 626172 -- 'b''a''r' + c3 -- Tag 3 (negative bignum) + 49 Byte string value of length 9 + 010000000000000000 -- Bytes content + c4 - Tag 4 (decimal fraction) + 82 -- Array of length 2 + 21 -- -2 + 19 6ab3 -- 27315 + c0 -- Tag 0 (date-time) + 78 19 -- Length (25) + 323031382d31302d31392031323a34313a30372d30373a3030 -- "2018-10-19 12:41:07-07:00" + c1 -- Tag 1 (epoch time) + 1a -- uint32_t + 554bbfd3 -- 1431027667 + c1 + 3a + 554bbfd2 + c1 + fb + 41d552eff4e00000 + ff -- "break" +*/ + + json j = cbor::decode_cbor(bytes); + + std::cout << "(2)\n" << pretty_print(j) << "\n\n"; +} +``` +Output: +``` +(1) +9f63666f6f43626172c349010000000000000000c48221196ab3c07819323031382d31302d31392031323a34313a30372d30373a3030c11a554bbfd3c13a554bbfd2c1fb41d552eff4e00000ff + +(2) +[ + "foo", + "YmFy", + "-18446744073709551617", + "273.15", + "2018-10-19 12:41:07-07:00", + 1431027667, + -1431027667, + 1431027667.5 +] +``` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/decode_json.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/decode_json.md new file mode 100644 index 0000000000..d07dbe3576 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/decode_json.md @@ -0,0 +1,78 @@ +### jsoncons::decode_json + +Decodes a JSON data format to a C++ data structure. `decode_json` will +work for all C++ classes that have [json_type_traits](https://github.com/danielaparker/jsoncons/blob/master/doc/ref/json_type_traits.md) defined. + +#### Header + +```c++ +#include + +template +T decode_json(std::basic_istream& is, + const basic_json_decode_options& options = basic_json_options::default_options()); // (1) + +template +T decode_json(const std::basic_string& s, + const basic_json_decode_options& options = basic_json_options::default_options()); // (2) + + +template +T decode_json(const basic_json& j, + std::basic_istream& is, + const basic_json_decode_options& options = basic_json_options::default_options()); // (3) + +template +T decode_json(const basic_json& j, + const std::basic_string& s, + const basic_json_decode_options& options = basic_json_options::default_options()); // (4) +``` + +(1) Reads a JSON string value into a type T if T is an instantiation of [basic_json](../json.md) +or if T supports [json_type_traits](../json_type_traits.md). + +(2) Reads a JSON input stream into a type T if T is an instantiation of [basic_json](../json.md) +or if T supports [json_type_traits](../json_type_traits.md). + +Functions (1)-(2) perform encodings using the default json type `basic_json`. +Functions (3)-(4) are the same but perform encodings using the supplied `basic_json`. + +### Examples + +#### Map with string-tuple pairs + +```c++ +#include +#include +#include +#include + +int main() +{ + typedef std::map> employee_collection; + + std::string s = R"( + { + "Jane Doe": ["Commission","Sales",20000.0], + "John Smith": ["Hourly","Software Engineer",10000.0] + } + )"; + + employee_collection employees = jsoncons::decode_json(s); + + for (const auto& pair : employees) + { + std::cout << pair.first << ": " << std::get<1>(pair.second) << std::endl; + } +} +``` +Output: +``` +Jane Doe: Sales +John Smith: Software Engineer +``` + +#### See also + +- [encode_json](encode_json.md) + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/default_parse_error_handler.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/default_parse_error_handler.md new file mode 100644 index 0000000000..8f3790d5af --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/default_parse_error_handler.md @@ -0,0 +1,21 @@ +### jsoncons::default_parse_error_handler + +```c++ +class default_parse_error_handler; +``` + +#### Header + + #include + +#### Base class + +[parse_error_handler](parse_error_handler.md) + +##### Private virtual implementation methods + + bool do_error(std::error_code ec, const ser_context& context) override; + +Returns `true` if `ec` indicates a comment, otherwise `false` + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/deprecated.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/deprecated.md new file mode 100644 index 0000000000..547e2786c1 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/deprecated.md @@ -0,0 +1,110 @@ +## Deprecated Features + +As the `jsoncons` library has evolved, names have sometimes changed. To ease transition, jsoncons deprecates the old names but continues to support many of them. The deprecated names can be suppressed by defining macro JSONCONS_NO_DEPRECATED, which is recommended for new code. + +In the table, indicates that the old name is still supported. + +Component or location|Old name, now deprecated||New name +--------|-----------|--------------|------------------------ +class parse_error|`parse_error`||`serialization_error` +class basic_json|`object_iterator`||`object_iterator_type` +class basic_json|`const_object_iterator`||`const_object_iterator_type` +class basic_json|`array_iterator`||`array_iterator_type` +class basic_json|`const_array_iterator`||`const_array_iterator_type` +class basic_json|add(size_t index, const json& val)||`insert(array_iterator pos, const json& val)` +class basic_json|add(size_t index, json&& val)||`insert(array_iterator pos, json&& val)` +class basic_json|dump_body||`dump` +class basic_json|remove_range(size_t from_index, size_t to_index)||`erase(array_iterator first, array_iterator last)` +class basic_json|remove(const std::string& name)||`erase(const string_view_type& name)` +class basic_json|parse_stream(std::istream& is)||`parse(std::istream& is)` +class basic_json|parse_stream(std::istream& is, parse_error_handler& err_handler)||`parse(std::istream& is, parse_error_handler& err_handler)` +class basic_json|as_int() const||`as` +class basic_json|as_uint() const||`as` +class basic_json|as_long() const||`as` +class basic_json|as_ulong() const||`as` +class basic_json|as_longlong() const||`as` +class basic_json|as_ulonglong() const||`as` +class basic_json|is_longlong() const||is() +class basic_json|is_ulonglong() const||is() +class basic_json|is_numeric() const||`is_number()` +class basic_json|remove_member(const std::string& name)||erase(const string_view_type& name) +class basic_json|const json& get(const std::string& name) const||Use const json get(const std::string& name, T default_val) const with default `json::null_type()` +class basic_json|has_member(const std::string& name) const||Use `contains(const string_view_type& name)` +class basic_json|has_key(const std::string& name) const||Use `contains(const string_view_type& name)` +class basic_json|add||`push_back` +class basic_json|set||`insert_or_assign` +class basic_json|members()||object_range() +class basic_json|elements()||array_range() +class basic_json|begin_members()||Use object_range().begin() +class basic_json|end_members()||Use object_range().end() +class basic_json|begin_elements()||Use array_range().begin() +class basic_json|end_elements()||Use array_range().end() +class basic_json|is_empty() const||`empty()` +class basic_json|parse_string(const std::string& s)||parse(const std::string& s) +class basic_json|parse_string(const std::string& s,parse_error_handler& err_handler)||Use parse(const std::string& s,parse_error_handler& err_handler) +class basic_json|resize_array(size_t n)||resize(size_t n) +class basic_json|resize_array(size_t n, const json& val)||resize(size_t n, const json& val) +class basic_json|to_stream||Use dump +class basic_json|write||Use dump +class basic_json|`json` initializer-list constructor||Construct from `json::array` with initializer-list +class basic_json_deserializer|json_deserializer||Use json_decoder` +class basic_json_deserializer|wjson_deserializer||Use `json_decoder` +class basic_json_deserializer|ojson_deserializer||Use `json_decoder` +class basic_json_deserializer|wojson_deserializer||Use `json_decoder` +class basic_json|owjson||wojson` +class basic_json|member_type name()||key() +class basic_json|rename_name_filter||rename_object_member_filter` +class basic_json|any||removed +class basic_json|member_type||key_value_pair_type +class basic_json|kvp_type||key_value_pair_type +class basic_json|null||Constant removed. Use static member function `json::null()` +class basic_json|an_object||Constant removed. Use the default constructor `json()` instead. +class basic_json|an_array||Constant removed. Use assignment to `json::array()` or `json::make_array()` instead. +class json_decoder|root()||get_result() +class json_content_handler|begin_json||Removed +class json_content_handler|end_json||`flush` +class json_content_handler|begin_document||Removed +class json_content_handler|end_document||`flush` +class json_content_handler|do_begin_json||Remove +class json_content_handler|do_end_json||Remove +class json_content_handler|do_begin_document||Remove +class json_content_handler|do_end_document||Remove +class output_format|`output_format`||`json_serializing_options` +class serialization_options|`serialization_options`||Use `json_serializing_options` +class json_reader|max_depth(),max_depth(value)||Use `json_serializing_options::max_nesting_depth` +class json_reader|max_nesting_depth(),max_nesting_depth(value)||Use `json_serializing_options::max_nesting_depth` +class json_reader|json_input_handler& parent()||Use json_input_handler& input_handler() +json_input_handler class|do_longlong_value(long long value, const parsing_context& context)||Override do_integer_value(int64_t value, const parsing_context& context) +class json_reader|do_ulonglong_value(unsigned long long value, const parsing_context& context)||Removed, override do_uinteger_value(uint64_t value, const parsing_context& context) +class json_reader|do_double_value(double value, const basic_parsing_context& context)||Removed, override do_double_value(double value, uint8_t precision, const basic_parsing_context& context) +class json_reader|`value(value,context)`| |Use `string_value(value,context)`, `integer_value(value,context)`, `uinteger_value(value,context)`, `double_value(value,precision,context)`, `bool_value(value,context)`, `null_value(context)` +class json_output_handler class|do_longlong_value(long long value)||Removed, override do_integer_value(int64_t value) + |do_ulonglong_value(unsigned long long value)||Removed, override do_uinteger_value(uint64_t value) + |do_double_value(double value)||Removed, override do_double_value(double value, uint8_t precision) + |`value(value)`||Use `string_value(value)`, `integer_value(value)`, `uinteger_value(value)`, `double_value(value,precision=0)`, `bool_value(value)`, `null_value(context)` +basic_parsing_context|last_char()||Use current_char() +json_filter|parent()||Use downstream_handler() + |input_handler()||Use downstream_handler() +file `csv_parameters.hpp`| ||Use `csv_options.hpp` +file `csv_serializing_options.hpp`| ||Use `csv_serializing_options.hpp` +class `csv_parameters`|`csv_parameters`| |Use `csv_serializing_options` +class `csv_serializing_options`|`csv_parameters`| |Use `csv_options` +class `csv_options`|`header(std::string value)`| |Use `column_names(const std::string& value)` +class `csv_options`|`column_names(std::vector> value)`||Use `column_names(const std::string& value)` +class `csv_options`|`data_types(std::string value)`||Use `column_types(const std::string& value)` +class `csv_options`|`column_types(std::vector> value)`||Use `column_types(const std::string& value)` +class `csv_options`|`column_defaults(std::vector> value)`||Use `column_defaults(const std::string& value)` +file `output_format.hpp`| | |Use `json_serializing_options.hpp` +file `json_serializing_options`.hpp| | |Use `json_options.hpp` +class json_options|`array_array_block_option accessor and modifier` accessor and modifier| |Use `array_array_line_splits` accessor and modifier +class json_options|`array_object_block_option accessor and modifier`| |Use `array_object_line_splits` accessor and modifier +class json_options|`object_array_block_option accessor and modifier`| |Use `object_array_line_splits` accessor and modifier +class json_options|`object_object_line_splits accessor and modifier`| |Use `object_object_line_splits` accessor and modifier +class json_options|`array_array_line_splits accessor and modifier` accessor and modifier||Use `array_array_line_splits` accessor and modifier +class json_options|`array_object_line_splits accessor and modifier`||Use `array_object_line_splits` accessor and modifier +class json_options|`object_array_line_splits accessor and modifier`||Use `object_array_line_splits` accessor and modifier +class json_options|`object_object_line_splits accessor and modifier`||Use `object_object_line_splits` accessor and modifier +msgpack|`jsoncons_ext/msgpack/message_pack.hpp` header file||Use `jsoncons_ext/msgpack/msgpack.hpp` + |`encode_message_pack`||Use `encode_msgpack` + |`decode_message_pack`||Use `decode_msgpack` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/diagrams/json_decoder.png b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/diagrams/json_decoder.png new file mode 100644 index 0000000000..d013c26a94 Binary files /dev/null and b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/diagrams/json_decoder.png differ diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/diagrams/json_decoder.xml b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/diagrams/json_decoder.xml new file mode 100644 index 0000000000..7fb77ba227 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/diagrams/json_decoder.xml @@ -0,0 +1 @@ +3VdNc9owEP01PtKxLaDkmABJW4ZMUzoDOTGKtbHVyhKVBZj++kq2jD8zIW2G6cAF7Vvtyvv0vCwOGsfpncSbaC4IMMd3SeqgieP7nut7+ssghxxBfT8HQkmJ3VQCC/obikiLbimBpLZRCcEU3dTBQHAOgaphWEqxr297Fqx+6gaH0AIWAWZtdEmJinJ0NHBL/BPQMCpO9lzriXGx2QJJhInYVyA0ddBYCqHyVZyOgRnyCl7yuNsXvMcHk8DVKQHT++8pnz0sIn/8a6aW8/gx/dKzWXaYbW3BTzihwfpHIvhac6p08nWEOWEgHX/I9Ek3T2YVmlUXkpWqDgV/Umw5AfMIrnbvI6pgscGB8e61YjQWqZhpyztGV0sqng+kgrQC2RLvQMSg5EFvsd6RZdvKzSvY35eX5w0tFlUurm8xbPUSHjOXlOqFZfUNDH9sMZxxSyDQ70onp//C4DNlbCyYkFksguyj8URJ8RMqHjREV4i8D+cnkT44J+mjFuktWoGTa9MftBUwnGjR15mElKqVJd2sH836w8Bak7TimhwKg+uHXxUJjFGJMmYZlllF3It3kIitDOB1dSksQ1Cvv+dAat2ufaOVG+u6sAKTwLCiu3qP7LpFe8JXQXVlR8H063rxUUMHedk2qNrSGnmuGrobNfLktLTyZJI6Fn2SysLdPPJn9yv8DcLe8mEGuxn0Bheoss5C0UWqp99INDyveoYXop5q7+ks9P/qPQO30TTcv5WP19Chd179tAeLzzwCSRXm+mXWEzfFocRxS1T6R13VZVQfDrjg0JgkLIQZDbnRopaAHl3QjRkRqJ6Vr60jpoSYYzqnlPoc8w5jh9do/77bMXagDiX5bx87tFlO6vkNlv930PQP \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/diagrams/json_encoder.png b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/diagrams/json_encoder.png new file mode 100644 index 0000000000..49dc6e5763 Binary files /dev/null and b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/diagrams/json_encoder.png differ diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/diagrams/json_encoder.xml b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/diagrams/json_encoder.xml new file mode 100644 index 0000000000..d0418f60c9 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/diagrams/json_encoder.xml @@ -0,0 +1 @@ +vVbBctowEP0aH9OxLSBwTAxNW4ZMUzoDOTGKtbHVyhKVBZh+fSUsY8t2GjLNNIeM9q12Jb19u8ZDUVbcSbxNF4IA80KfFB6aemF4HYz1fwMcS2DgT0ogkZSUUFADS/obLOhbdEcJ5M5GJQRTdOuCseAcYuVgWEpxcLc9C+aeusUJdIBljFkXXVGi0hIdD/0a/wQ0SauTA996MlxttkCeYiIODQjNPBRJIVS5yooImOGu4qWM+/iC93wxCVxdEjC7/17w+cMyDaNfc7VaZI/FlyubZY/Zzj74Cec03vzIBd9oTpVOvkkxJwykF46YPun2yawSs+pDTk9Vx4o/KXacgLmCr92HlCpYbnFsvActGI2lKmPaCs7RzSdV9wOpoGhA9ol3IDJQ8qi3WO/Ysm3lFlTsH+riBSOLpY3CDSyGrV6Sc+aaUr2wrL6B4eu/MQw81g3Ty+y/8PhMGYsEE/IUi+D0p/FcSfETGh40QhNE3of5i6gf/E/qxx3qO7QCJzdmSmgrZjjXhXGZhIKqtSXdrB/N+sPQWtOi4ZoeK4Pry6+rBMZoRBmzDjtZVdyLNcjFTsbwusYUlgmo17sdiDPzuhVtVGzYU7AKk8Cwont3UvZV0Z7wVVD9srNgBq5eQtTSQflsG9QcbK08k5buxq08JS2dPCdJnR99kcqS/SIN5/dr/A2Sq9XDHPZz6GnwzzwFSRXmumj6y0dxInHWkZ5uK+WKzW1PLji0etlCmNGEG8VqoejhgW5Nk1L9zbqxjowSYo7pnRPuJHmHxg9aBQj9nsZHPToK39742qy/mGUF658daPYH \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/diagrams/json_filter.png b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/diagrams/json_filter.png new file mode 100644 index 0000000000..8132c736a2 Binary files /dev/null and b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/diagrams/json_filter.png differ diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/diagrams/json_filter.xml b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/diagrams/json_filter.xml new file mode 100644 index 0000000000..edd7f9edaf --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/diagrams/json_filter.xml @@ -0,0 +1 @@ +3VdRb9owEP41PDIlMTD62ALrNkS1jknQJ+TG18SbYzPHQNivn00cEidpSydUTfCC77PvnPvuy3F00CjJbiVexzNBgHUCj2QdNO4Ege8Fvv4yyD5HUC/IgUhSYg+VwJz+gcLTohtKIHUOKiGYomsXDAXnECoHw1KKnXvsSTD31jWOoAHMQ8ya6IISFefosO+V+GegUVzc7Ht2J8HFYQukMSZiV4HQpINGUgiVr5JsBMyQV/CS+316Zvf4YBK4OsVhcvcj49P7eRyMfk/VYpY8ZF+7NsoWs41N+BGnNFz9TAVfaU6VDr6KMScMZCcYMH3TzaNZRWZlE1P7gi0pNpyAudDT27uYKpivcWh2d1ofGotVwrTlH72rCRRPA1JBVoFsQrcgElByr4/Y3aHl1orLL7jelaXyBxaLK2XqWQxbdUTHyCWBemE5fAOfH1/i84kydX4adVQ2EkzIgy+Cw0fjqZLiF1R20ABdIXIe4k9ivv+ezA8bzDdoBU6uTUvQVshwquviMgkZVUtLulk/mPWHvrXGWWVrvC8Mrh9+WQQwRsXLmKXbwSr8nq1BKjYyhNclprCMQL3+agNxGlyzopWKtRWswCQwrOjWbYttVbQ3fBNUZ3YUTM/VS4BqOsjTtk7VLlaLc1XT3bAWJ6elEecgqWPSJ6ks2s7iYHq3xN8h6i7up7CdQrd/gSprTRRdpHp6tUCD91XP4ELUU+09rYn+X72n79Wahvev8vFrOvTfVz/N6eILj0FShbl+mfWQTXEkcdIQlf5RV66M3OGACw61ScJCmNGIGy1qCejRBd2YEYHq8fjabiSUEHNN65TizjFnGDv8WvsPvJaxA7UoKXj72KHNcjjPK1j+xUGTvw== \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/diagrams/json_options.png b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/diagrams/json_options.png new file mode 100644 index 0000000000..cb6f824ad3 Binary files /dev/null and b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/diagrams/json_options.png differ diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/diagrams/json_options.xml b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/diagrams/json_options.xml new file mode 100644 index 0000000000..cf5f77254d --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/diagrams/json_options.xml @@ -0,0 +1 @@ +zVbJbtswEP0aHVtIVLxcGztNDm1R1ECbngRGHEtsKVKhqEjq15eMSK1OnAZG6osx82Yh+eZ5IC/cZPW1xHn6WRBgHvJJ7YVbD6EVCvSvAZoWuAj8FkgkJS0U9MCO/gELurSSEihGiUoIpmg+BmPBOcRqhGEpRTVO2ws2PjXHCcyAXYzZHP1BiUpbdL3we/wGaJK6kwPfRjLski1QpJiIagCFV164kUKo1srqDTDDneOlrfv4RLS7mASuXlKw/97sv+W/b+7Fl+h+HW0vy0/NO9vlAbPSPvgOFzSOfhWCRwRiPc5I5IoKXthXqMZRI0XJCZjuvhdeVilVsMtxbKKV1oLGUpUx7QXanN/WHQ1SQT2A7O2vQWSgZKNTbPTCEmmVtLZu1Y8lWFosHYzElWGrhKRr3JOlDcvXP3CHnuMO+Dlz1xH138gLnyPvXFhDywlt6ABt6C1pW85om5EEnHwwi097McOFJnXMC9RU3VoKjf3T2O8X1tvWg9C2cQ7Xl791DYwzqDJuX/boubonZ1CIUsZwXB8KywTU8T8hkNEan090MLHFgYE5TALDij6Ml/+hKdoTvgqqX9YJphNDMxGQa9G+21YNl/W00WrSKJg0aomZNXoUVffs1+tsdQKdnVozR7UQnJUWZstjuhReqoX1RAroVFLQbv/50ab333Dh1V8= \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/diagrams/rename_object_member_filter.png b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/diagrams/rename_object_member_filter.png new file mode 100644 index 0000000000..054a06ff4f Binary files /dev/null and b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/diagrams/rename_object_member_filter.png differ diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/diagrams/rename_object_member_filter.xml b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/diagrams/rename_object_member_filter.xml new file mode 100644 index 0000000000..7c39b3d9d1 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/diagrams/rename_object_member_filter.xml @@ -0,0 +1 @@ +5VddU9swEPw1eaTjWEkIjxAopRloaZgB+pJR7MMWlaVUVhKHX88plvxNoQwtnSkvSCudZO3trZQemSTZqaLL+FyGwHu+F2Y9ctzz/b7nj/CfQbY5QgaDHIgUC+2kEpixB3CRFl2xENLaRC0l12xZBwMpBAS6hlGl5KY+7U7y+q5LGkELmAWUt9FrFuo4R8dDr8Q/AYtit3PfsyMJdZMtkMY0lJsKRE56ZKKk1HkrySbADXmOlzzu4xOjxYcpEPolAScXV5mYXs5if/Jzqq/Pk9vs855dZU35yh54QVMWzO9TKeZ3jGtQPX/EcYOjhWlFpmXPo7eOJCVXIgSzj4fDm5hpmC1pYEY3KAvEYp1w7PWL6Op3u48ApSGrQPYcpyAT0GqLU+yoP7acWlH1HcebMkUFFlfSM7AYtaqIiqVL4rBhufsNHvef4BEPSROYy8U9inOeQLIA9Yd4xVX5RHKpdrEEdn+Ip1rJH1AZISNyQMK3ycRg8HwmfO9vZmLcykSLVhDhobEG7AWcppinOpOQMX1jSTftW9P+MLS946wydLx1HYEff+MWMJ1KlOmWYbuei3syB6lcqQCel5ymKgL9fIlDWDO6dkYrGRt2JMxhCjjVbF23x64s2h2+SoYnK0vXqwvGJw0h5Oe2UVU7ay40bChv3FgoJ6a10E5UxbFfpLNofR7704sb+g2ivevLKayn0FHxZyIGxTQVmDa88BiNFE1a4sPC0nW51QtUSAGNarYQ5SwSRrMoFbQPcmTKlOFVdWgHEhaGZptOp6h7yVuY8P6wnkmvw4RJh5L8Nyj90e2Xq71+P/2+PfQeSHa23h/FHZeZ89h0SYVz2coFh48GjQTMYyqQuMKRcfNqwLtfd+/psZ1E+/+Lx7oXZ8Vjf6W8f8RjG68j/+CVFltUr1uoKahXWyx2y4dvPr38+UBOHgE= \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/diagrams/ser_error.png b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/diagrams/ser_error.png new file mode 100644 index 0000000000..e0ee8fee08 Binary files /dev/null and b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/diagrams/ser_error.png differ diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/diagrams/ser_error.xml b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/diagrams/ser_error.xml new file mode 100644 index 0000000000..e0023da8ce --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/diagrams/ser_error.xml @@ -0,0 +1 @@ +7Vhdb9owFP01PHYKcWjhsQXabajVOia1faqs+Dbx5tjMMRD262cT59NAWwkVtIEQso/ta/vcc+8l6aBhkt1IPItvBQHW8T2SddCo4/uDwUD/GmCVA4FngUhSkkPdCpjSP2BBz6JzSiBtTFRCMEVnTTAUnEOoGhiWUiyb014Ea+46wxE4wDTEzEUfKFFxjvZ7XoV/BhrFxc5dz44kuJhsgTTGRCxrEBp30FAKofJWkg2BGe4KXvJ111tGy4NJ4OotC8Z3PzI+uZ/G/vD3RD3cJk/Z1zNrZYHZ3F44VXr+pf5CFsJMUcHt8dWq4ESKOSdgzHoddLWMqYLpDIdmdKlFoLFYJUz3urrpHrPYE6SCrAbZY9+ASEDJlZ5iR88tg1ZC3YLRZeWQkva45ozAYthqICotVzTphmXqHaxdbGdNzrmiCTyD1p48OHO+d2zU9R3qHJKAk0sTuboXMpymNGzyAhlVj5ZC034y7U892xtltaHRquhwffjHwoDp1FaZbrVs3SvWbfVBKuYyhNc1orCMQL0egUAaecj1aM1jvQ0OKzAJDCu6aGavTV60O3wTVN+sFEzQ1IuPWjrIr20X1ZNNy86gpbt+y05Oi2NnLany0m9SWbS4jf3J3SP+DtHZw/0EFhPYldbSVaogOZL4RMEB43Mjc/4/GJ+7JPJqfF6c4nP/8Ync+AS5j5h8oYwNBdNmzFoE64/GUyXFL6iNoHM0QGQ/UdxrVdm+G8SDj4zhwGH3Zyr48/H8oWunveDQWa/3v2Q95Ga9XRI6Zb19Zr3zk8o21uAjURlqPWeWz53vlVnQbRnqfqzO3MfTLzwGSRXm2m2+RyiOJE4c8ensrZpya5ZNLji0aqyFMKMRN5rVUgGNX5laQEPMLu1AQgkx22wsLs3ys4f60n5jUDqgXmDQBiX57y8wulu9w8k9WL0IQ+O/ \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/encode_json.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/encode_json.md new file mode 100644 index 0000000000..358c9ef696 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/encode_json.md @@ -0,0 +1,200 @@ +### jsoncons::encode_json + +Encode a C++ data structure to a JSON formatted string or stream. `encode_json` will work for all types that +have [json_type_traits](https://github.com/danielaparker/jsoncons/blob/master/doc/ref/json_type_traits.md) defined. + +#### Header +```c++ +#include + +template +void encode_json(const T& val, + std::basic_ostream& os, + const basic_json_encode_options& options = basic_json_options::default_options(), + indenting line_indent = indenting::no_indent); // (1) + +template +void encode_json(const T& val, + std::basic_ostream& os, + indenting line_indent); // (2) + +template +void encode_json(const T& val, + std::basic_string& s, + const basic_json_encode_options& options = basic_json_options::default_options(), + indenting line_indent = indenting::no_indent); // (3) + +template +void encode_json(const T& val, + std::basic_string& s, + indenting line_indent); // (4) + +template +void encode_json(const T& val, + basic_json_content_handler& receiver); // (5) + +template +void encode_json(const basic_json& j, + const T& val, + std::basic_ostream& os, + const basic_json_encode_options& options = basic_json_options::default_options(), + indenting line_indent = indenting::no_indent); // (6) + +template +void encode_json(const basic_json& j, + const T& val, + std::basic_ostream& os, + indenting line_indent); // (7) + +template +void encode_json(const basic_json& j, + const T& val, + std::basic_string& s, + const basic_json_encode_options& options = basic_json_options::default_options(), + indenting line_indent = indenting::no_indent); // (8) + +template +void encode_json(const basic_json& j, + const T& val, + std::basic_string& s, + indenting line_indent); // (9) + +template +void encode_json(const basic_json& j, + const T& val, + basic_json_content_handler& receiver); // (10) +``` + +(1) Encode `val` to output stream with the specified options and line indenting. + +(2) Encode `val` to output stream with the specified line indenting. + +(3) Encode `val` to string with the specified options and line indenting. + +(4) Encode `val` to string with the specified line indenting. + +(5) Convert `val` to json events and stream through content handler. + +Functions (1)-(5) perform encodings using the default json type `basic_json`. +Functions (6)-(10) are the same but perform encodings using the supplied `basic_json`. + +#### Parameters + + + + + + + + + + + + + + + + + + + + + + +
valC++ data structure
handlerJSON output handler
optionsSerialization options
osOutput stream
indentingindenting::indent to pretty print, indenting::no_indent for compact output
+ +#### Return value + +None + +#### See also + +- [json_content_handler](json_content_handler.md) +- [json_options](json_options.md) + +### Examples + +#### Map with string-tuple pairs + +```c++ +#include +#include +#include +#include + +using namespace jsoncons; + +int main() +{ + typedef std::map> employee_collection; + + employee_collection employees = + { + {"John Smith",{"Hourly","Software Engineer",10000}}, + {"Jane Doe",{"Commission","Sales",20000}} + }; + + std::cout << "(1)\n" << std::endl; + encode_json(employees,std::cout); + std::cout << "\n\n"; + + std::cout << "(2) Again, with pretty print\n" << std::endl; + encode_json(employees, std::cout, jsoncons::indenting::indent); +} +``` +Output: +``` +(1) + +{"Jane Doe":["Commission","Sales",20000.0],"John Smith":["Hourly","Software Engineer",10000.0]} + +(2) Again, with pretty print + +{ + "Jane Doe": ["Commission","Sales",20000.0], + "John Smith": ["Hourly","Software Engineer",10000.0] +} +``` + +#### Contain JSON output in an object + +```c++ +#include +#include +#include +#include + +using namespace jsoncons; + +int main() +{ + std::map> employees = + { + {"John Smith",{"Hourly","Software Engineer",10000}}, + {"Jane Doe",{"Commission","Sales",20000}} + }; + + json_encoder encoder(std::cout, jsoncons::indenting::indent); + + encoder.begin_object(); + encoder.write_name("Employees"); + encode_json(employees, encoder); + encoder.end_object(); + encoder.flush(); +} +``` +Output: +```json +{ + "Employees": { + "Jane Doe": ["Commission","Sales",20000.0], + "John Smith": ["Hourly","Software Engineer",10000.0] + } +} +``` + +#### See also + +- [decode_json](decode_json.md) + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/indenting.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/indenting.md new file mode 100644 index 0000000000..d52d953a1e --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/indenting.md @@ -0,0 +1,13 @@ +### jsoncons::indenting + +```c++ +enum class indenting {no_indent, indent} +``` + +#### Header +```c++ +#include +``` + +Specifies indentation options for the [json_encoder](json_encoder.md) + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json.md new file mode 100644 index 0000000000..08ccf62c1b --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json.md @@ -0,0 +1,397 @@ +### jsoncons::json + +```c++ +typedef basic_json> json +``` +The class `json` is an instantiation of the `basic_json` class template that uses `char` as the character type. The order of an object's name/value pairs is not preserved, they are sorted alphabetically by name. If you want to preserve the original insertion order, use [ojson](ojson.md) instead. + +The class `json` resembles a union. An instance of `json` holds a data item of one of its alternative types: + +- null +- bool +- int64 +- uint64 +- double +- string +- byte string +- array +- object + +The data item may be tagged with a [semantic_tag](semantic_tag.md) that provides additional +information about the data item. + +When assigned a new value, the old value is overwritten. The type of the new value may be different from the old value. + +The `jsoncons` library will rebind the supplied allocator from the template parameter to internal data structures. + +#### Header +```c++ +#include +``` + +#### Member types + +Member type |Definition +------------------------------------|------------------------------ +`json_type`|json +`reference`|json& +`const_reference`|const json& +`pointer`|json* +`const_pointer`|const json* +`allocator_type`|Allocator type +`char_allocator`|String allocator type +`array_allocator`|Array allocator type +`object_allocator`|Object allocator +`string_view_type`|A non-owning view of a string, holds a pointer to character data and length. Supports conversion to and from strings. Will be typedefed to the C++ 17 [string view](http://en.cppreference.com/w/cpp/string/basic_string_view) if `JSONCONS_HAS_STRING_VIEW` is defined in `jsoncons_config.hpp`, otherwise proxied. +`key_value_type`|[key_value_type](json/key_value.md) is a class that stores a name and a json value +`object`|json object type +`array`|json array type +`object_iterator`|A [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator) to [key_value_type](json/key_value.md) +`const_object_iterator`|A const [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator) to const [key_value_type](json/key_value.md) +`array_iterator`|A [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator) to `json` +`const_array_iterator`|A const [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator) to `const json` + +### Static member functions + + + + + + + + + + + + + + +
parseParses JSON.
make_arrayMakes a multidimensional json array.
const json& null()Returns a null value
+ +### Member functions + + + + + + + + + + + + + +
(constructor)constructs the json value
(destructor)destructs the json value
operator=assigns values
+ + allocator_type get_allocator() const +Returns the allocator associated with the json value. + +#### Ranges and Iterators + + + + + + + + + + +
array_rangeReturns a "range" that supports a range-based for loop over the elements of a `json` array.
obect_rangeReturns a "range" that supports a range-based for loop over the key-value pairs of a `json` object.
+ +#### Capacity + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
size_t size() const noexceptReturns the number of elements in a json array, or the number of members in a json object, or `zero`
bool empty() const noexceptReturns true if a json string, object or array has no elements, otherwise false
size_t capacity() constReturns the size of the storage space currently allocated for a json object or array
void reserve(size_t n)Increases the capacity of a json object or array to allow at least `n` members or elements
void resize(size_t n)Resizes a json array so that it contains `n` elements
void resize(size_t n, const json& val)Resizes a json array so that it contains `n` elements that are initialized to `val`
void shrink_to_fit()Requests the removal of unused capacity
+ +#### Accessors + + + + + + + + + + + + + + + + + + +
bool contains(const string_view_type& key) constReturns true if an object has a member with the given `key`, otherwise false
bool count(const string_view_type& key) constReturns the number of object members that match `key`
isChecks if a json value matches a type.
asAttempts to convert a json value to a value of a type.
+ + semantic_tag get_semantic_tag() const +Returns the [semantic_tag](semantic_tag.md) associated with this value + + json& operator[](size_t i) + const json& operator[](size_t i) const +Returns a reference to the value at position i in a json object or array. +Throws `std::runtime_error` if not an object or array. + + json& operator[](const string_view_type& name) +Returns a proxy to a keyed value. If written to, inserts or updates with the new value. If read, evaluates to a reference to the keyed value, if it exists, otherwise throws. +Throws `std::runtime_error` if not an object. +If read, throws `std::out_of_range` if the object does not have a member with the specified name. + + const json& operator[](const string_view_type& name) const +If `name` matches the name of a member in the json object, returns a reference to the json object, otherwise throws. +Throws `std::runtime_error` if not an object. +Throws `std::out_of_range` if the object does not have a member with the specified name. + + object_iterator find(const string_view_type& name) + const_object_iterator find(const string_view_type& name) const +Returns an object iterator to a member whose name compares equal to `name`. If there is no such member, returns `end_member()`. +Throws `std::runtime_error` if not an object. + + json& at(const string_view_type& name) + const json& at(const string_view_type& name) const +Returns a reference to the value with the specifed name in a json object. +Throws `std::runtime_error` if not an object. +Throws `std::out_of_range` if the object does not have a member with the specified name. + + json& at(size_t i) + const json& at(size_t i) const +Returns a reference to the element at index `i` in a json array. +Throws `std::runtime_error` if not an array. +Throws `std::out_of_range` if the index is outside the bounds of the array. + + template + T get_with_default(const string_view_type& name, + const T& default_val) const +If `name` matches the name of a member in the json object, returns the member value converted to the default's data type, otherwise returns `default_val`. +Throws `std::runtime_error` if not an object. + + template + T get_with_default(const string_view_type& name, + const char_type* default_val) const +Make `get_with_default` do the right thing for string literals. +Throws `std::runtime_error` if not an object. + +#### Modifiers + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void clear()Remove all elements from an array or members from an object, otherwise do nothing
eraseErases array elements and object members
push_backAdds a value to the end of a json array
insertInserts elements
emplace_backConstructs a value in place at the end of a json array
emplaceConstructs a value in place before a specified position in a json array
try_emplaceConstructs a key-value pair in place in a json object if the key does not exist, does nothing if the key exists
insert_or_assignInserts a key-value pair in a json object if the key does not exist, or assigns a new value if the key already exists
mergeInserts another json object's key-value pairs into a json object, if they don't already exist.
merge_or_updateInserts another json object's key-value pairs into a json object, or assigns them if they already exist.
void swap(json& val)Exchanges the content of the json value with the content of val, which is another json value
+ +#### Serialization + + + + + + +
dumpSerializes json value to a string, stream, or output handler.
+ +#### Non member functions + + + + + + + + + + + + + + + + + + + + + + + + + + +
bool operator==(const json& lhs, const json& rhs)Returns true if two json objects compare equal, false otherwise.
bool operator!=(const json& lhs, const json& rhs)Returns true if two json objects do not compare equal, false otherwise.
bool operator<(const json& lhs, const json& rhs)Compares the contents of lhs and rhs lexicographically.
bool operator<=(const json& lhs, const json& rhs)Compares the contents of lhs and rhs lexicographically.
bool operator>(const json& lhs, const json& rhs)Compares the contents of lhs and rhs lexicographically.
bool operator>=(const json& lhs, const json& rhs)Compares the contents of lhs and rhs lexicographically.
+ + std::istream& operator>> (std::istream& os, json& val) +Reads a `json` value from a stream. + + std::ostream& operator<< (std::ostream& os, const json& val) +Inserts json value into stream. + + std::ostream& print(const json& val) + std::ostream& print(const json& val, const json_options& options) +Inserts json value into stream using the specified [json_options](json_options.md) if supplied. + + std::ostream& pretty_print(const json& val) + std::ostream& pretty_print(const json& val, const json_options& options) +Inserts json value into stream using the specified [json_options](json_options.md) if supplied. + + void swap(json& a, json& b) +Exchanges the values of `a` and `b` + +#### Deprecated names + +As the `jsoncons` library has evolved, names have sometimes changed. To ease transition, jsoncons deprecates the old names but continues to support many of them. See the [deprecated list](deprecated.md) for the status of old names. The deprecated names can be suppressed by defining macro JSONCONS_NO_DEPRECATED, which is recommended for new code. + +#### See also + +- [ojson](ojson.md) constructs a json value that preserves the original name-value insertion order + +- [wjson](wjson.md) constructs a wide character json value that sorts name-value members alphabetically + +- [wojson](wojson.md) constructs a wide character json value that preserves the original name-value insertion order + +### Examples + +#### Accessors and defaults +```c++ +json val; + +val["field1"] = 1; +val["field3"] = "Toronto"; + +double x1 = obj.contains("field1") ? val["field1"].as() : 10.0; +double x2 = obj.contains("field2") ? val["field2"].as() : 20.0; + +std::string x3 = obj.get_with_default("field3","Montreal"); +std::string x4 = obj.get_with_default("field4","San Francisco"); + +std::cout << "x1=" << x1 << '\n'; +std::cout << "x2=" << x2 << '\n'; +std::cout << "x3=" << x3 << '\n'; +std::cout << "x4=" << x4 << '\n'; +``` +Output: +```c++ +x1=1 +x2=20 +x3=Toronto +x4=San Francisco +``` +#### Nulls +```c++ +json obj; +obj["field1"] = json::null(); +std::cout << obj << std::endl; +``` +Output: +```json +{"field1":null} +``` +#### Constructing json structures +```c++ +json root; + +root["persons"] = json::array(); + +json person; +person["first_name"] = "John"; +person["last_name"] = "Smith"; +person["birth_date"] = "1972-01-30"; + +json address; +address["city"] = "Toronto"; +address["country"] = "Canada"; + +person["address"] = std::move(address); + +root["persons"].push_back(std::move(person)); + +std::cout << pretty_print(root) << std::endl; +``` +Output: +```c++ +{ + "persons": + [ + { + "address": + { + "city":"Toronto", + "country":"Canada" + }, + "birth_date":"1972-01-30", + "first_name":"John", + "last_name":"Smith" + } + ] +} +``` diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/array_range.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/array_range.md new file mode 100644 index 0000000000..d7f2b9cfb0 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/array_range.md @@ -0,0 +1,45 @@ +### jsoncons::json::array_range + +```c++ +range array_range(); +range array_range() const; +``` +Returns a "range" that supports a range-based for loop over the elements of a `json` array +Throws `std::runtime_error` if not an array. + +### Examples + +#### Range-based for loop + +```c++ +json j = json::array{"Toronto", "Vancouver", "Montreal"}; + +for (const auto& val : j.array_range()) +{ + std::cout << val.as() << std::endl; +} +``` +Output: +```json +Toronto +Vancouver +Montreal +``` + +#### Array iterator +```c++ +json j = json::array{"Toronto", "Vancouver", "Montreal"}; + +for (auto it = j.array_range().begin(); it != j.array_range().end(); ++it) +{ + std::cout << it->as() << std::endl; +} +``` +Output: +```json +Toronto +Vancouver +Montreal +``` + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/as.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/as.md new file mode 100644 index 0000000000..4c62964feb --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/as.md @@ -0,0 +1,120 @@ +### jsoncons::json::as + +```c++ +template +T as(Args&&... args) const; // (1) + +bool as_bool() const; // (2) + +template +T as_integer() const; // (3) + +double as_double() const; // (4) + +string_view_type as_string_view() const; // (5) + +std::string as_string() const; // (6) + +byte_string as_byte_string() const; // (7) + +bignum as_bignum() const; // (8) +``` + +(1) Generic get `as` type `T`. Attempts to convert the json value to the template value type using [json_type_traits](../json_type_traits.md). + + std::string as() const noexcept + std::string as(const char_allocator& allocator) const noexcept +If value is string, returns value, otherwise returns result of [dump](dump.md). + + as>() +If the type `X` is not `std::basic_string` but otherwise satisfies [SequenceContainer](http://en.cppreference.com/w/cpp/concept/SequenceContainer), `as>()` returns the `json` value as an `X` if the `json` value is an array and each element is convertible to type `T`, otherwise throws. + + as>() +If the type 'X' satisfies [AssociativeContainer](http://en.cppreference.com/w/cpp/concept/AssociativeContainer) or [UnorderedAssociativeContainer](http://en.cppreference.com/w/cpp/concept/UnorderedAssociativeContainer), `as>()` returns the `json` value as an `X` if the `json` value is an object and if each member value is convertible to type `T`, otherwise throws. + +(2) Same as `as()`. +Returns `true` if value is `bool` and `true`, or if value is integral and non-zero, or if value is floating point and non-zero, or if value is string and parsed value evaluates as `true`. +Returns `false` if value is `bool` and `false`, or if value is integral and zero, or if value is floating point and zero, or if value is string and parsed value evaluates as `false`. +Otherwise throws `std::runtime_exception` + +(3) Same as `as()` for integral type T. +Returns integer value if value is integral, performs cast if value has double type, returns 1 or 0 if value has bool type, attempts conversion if value is string, otherwise throws. + +(4) Same as `as()`. +Returns value cast to double if value is integral, returns `NaN` if value is `null`, attempts conversion if value is string, otherwise throws. + +### Examples + +#### Accessing integral, floating point, and boolean values + +```c++ +json j = json::parse(R"( +{ + "k1" : 2147483647, + "k2" : 2147483648, + "k3" : -10, + "k4" : 10.5, + "k5" : true, + "k6" : "10.5" +} +)"); + +std::cout << "(1) " << j["k1"].as() << '\n'; +std::cout << "(2) " << j["k2"].as() << '\n'; +std::cout << "(3) " << j["k2"].as() << '\n'; +std::cout << "(4) " << j["k3"].as() << '\n'; +std::cout << "(5) " << j["k3"].as() << '\n'; +std::cout << "(6) " << j["k4"].as() << '\n'; +std::cout << "(7) " << j["k4"].as() << '\n'; +std::cout << std::boolalpha << "(8) " << j["k5"].as() << '\n'; +std::cout << std::boolalpha << "(9) " << j["k5"].as() << '\n'; +std::cout << "(10) " << j["k6"].as() << '\n'; + +``` +Output: +``` + +(1) 2147483647 +(2) -2147483648 +(3) 2147483648 +(4) +(5) 4294967286 +(6) 10 +(7) 10.5 +(8) 1 +(9) true +(10) 10.5 +``` + +#### Accessing a `json` array value as a `std::vector` +```c++ +std::string s = "{\"my-array\" : [1,2,3,4]}"; +json val = json::parse(s); +std::vector v = val["my-array"].as>(); +for (size_t i = 0; i < v.size(); ++i) +{ + if (i > 0) + { + std::cout << ","; + } + std::cout << v[i]; +} +std::cout << std::endl; +``` +Output: +``` +1,2,3,4 +``` + +#### Accessing a `json` byte string as a [byte_string](../byte_string.md) +```c++ +json j(byte_string("Hello")); +byte_string bs = j.as(); + +std::cout << bs << std::endl; +``` +Output: +``` +0x480x650x6c0x6c0x6f +``` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/constructor.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/constructor.md new file mode 100644 index 0000000000..ac3abbed65 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/constructor.md @@ -0,0 +1,150 @@ +### `jsoncons::json::json` + +```c++ +json(); // (1) + +json(const allocator_type& allocator); // (2) + +json(std::initializer_list list, const allocator_type& allocator); // (3) + +json(const json& val); // (4) + +json(const json& val, const allocator_type& allocator); // (5) + +json(json&& val) noexcept; // (6) + +json(json&& val, const allocator_type& allocator) noexcept; // (7) + +json(const array& val); // (8) + +json(array&& val) noexcept; // (9) + +json(const object& val); // (10) + +json(object&& val) noexcept; // (11) + +template +json(const T& val); // (12) + +template +json(const T& val, const allocator_type& allocator); // (13) + +json(const char* val); // (14) + +json(const char* val, const allocator_type& allocator); // (15) + +json(const byte_string_view& bs, + semantic_tag tag = semantic_tag::none); // (16) + +json(const byte_string_view& bs, + semantic_tag tag = semantic_tag::none, + const allocator_type& allocator); // (17) + +json(const bignum& n); // (18) + +json(const bignum& n, const allocator_type& allocator); // (19) +``` + +(1) Constructs a `json` value that holds an empty json object. + +(2) Constructs a `json` value that holds a json object. + +(3) Constructs a `json` array with the elements of the initializer-list `init`. + +(4) Constructs a copy of val + +(5) Copy with allocator + +(6) Acquires the contents of val, leaving val a `null` value + +(7) Move with allocator + +(8) Constructs a `json` value from a json array + +(9) Acquires the contents of a json array + +(10) Constructs a `json` value from a json object + +(11) Acquires the contents of a json object + +(12) Constructs a `json` value for types supported in [json_type_traits](json_type_traits.md). + +(13) Constructs a `json` value for types supported in [json_type_traits](json_type_traits.md) with allocator. + +(14) Constructs a `json` value for a text string. + +(15) Constructs a `json` value for a text string with supplied allocator. + +(16) Constructs a `json` value for a [byte_string](../byte_string.md). + +(17) Constructs a `json` value for a [byte_string](../byte_string.md) with supplied allocator. + +(18) Constructs a `json` value for a [bignum](../bignum.md). + +(19) Constructs a `json` value for a [bignum](../bignum.md) with supplied allocator. + +### Examples + +```c++ +#include +#include +#include +#include +#include + +using namespace jsoncons; +int main() +{ + json j1; // An empty object + std::cout << "(1) " << j1 << std::endl; + + json j2 = json::object({{"baz", "qux"}, {"foo", "bar"}}); // An object + std::cout << "(2) " << j2 << std::endl; + + json j3 = json::array({"bar", "baz"}); // An array + std::cout << "(3) " << j3 << std::endl; + + json j4(json::null()); // A null value + std::cout << "(4) " << j4 << std::endl; + + json j5(true); // A boolean value + std::cout << "(5) " << j5 << std::endl; + + double x = 1.0/7.0; + + json j6(x); // A double value + std::cout << "(6) " << j6 << std::endl; + + json j7(x,4); // A double value with specified precision + std::cout << "(7) " << j7 << std::endl; + + json j8("Hello"); // A text string + std::cout << "(8) " << j8 << std::endl; + + const uint8_t bs[] = {'H','e','l','l','o'}; + json j9(byte_string("Hello")); // A byte string + std::cout << "(9) " << j9 << std::endl; + + std::vector v = {10,20,30}; + json j10 = v; // From a sequence container + std::cout << "(10) " << j10 << std::endl; + + std::map m{ {"one", 1}, {"two", 2}, {"three", 3} }; + json j11 = m; // From an associative container + std::cout << "(11) " << j11 << std::endl; +} +``` + +``` +(1) {} +(2) {"baz":"qux","foo":"bar"} +(3) ["bar","baz"] +(4) null +(5) true +(6) 0.142857142857143 +(7) 0.1429 +(8) "Hello" +(9) "SGVsbG8_" +(10) [10,20,30] +(11) {"one":1,"three":3,"two":2} +``` diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/destructor.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/destructor.md new file mode 100644 index 0000000000..1b6d7489d1 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/destructor.md @@ -0,0 +1,9 @@ +### `jsoncons::json::json` + +```c++ +~json(); +``` + +Destroys all values and deletes all memory allocated for strings, arrays, and objects. + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/dump.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/dump.md new file mode 100644 index 0000000000..71fb4553d8 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/dump.md @@ -0,0 +1,177 @@ +### `jsoncons::json::dump` + +```c++ +template +void dump(std::basic_string& s) const; // (1) + +template +void dump(std::basic_string& s, + indenting line_indent) const; // (2) + +template +void dump(std::basic_string& s, + const json_options& options) const; // (3) + +template +void dump(std::basic_string& s, + const basic_json_options& options, + indenting line_indent) const; // (4) + +void dump(std::ostream& os) const; // (5) + +void dump(std::ostream os, indenting line_indent) const; // (6) + +void dump(std::ostream os, const json_options& options) const; // (7) + +void dump(std::ostream os, const json_options& options, indenting line_indent) const; // (8) + +void dump(basic_json_content_handler& content_handler) const; // (9) +``` + +(1) Dumps json value to string using default json_options. + +(2) Dumps json value to string using default serialization options and the specified [indenting](../indenting.md). + +(3) Dumps json value to string using specified [json_options](../json_options.md). + +(4) Dumps json value to string using the specified [json_options](../json_options.md) and [indenting](../indenting.md). + +(5) Dumps json value to stream with default serialization options. + +(6) Dumps json value to stream using default serialization options and the specified [indenting](../indenting.md). + +(7) Dumps json value to stream using specified [json_options](../json_options.md). + +(8) Dumps json value to stream using the specified [json_options](../json_options.md) and [indenting](../indenting.md). + +(9) Emits json value to the [json_content_handler](../json_content_handler.md). + +### Examples + +#### Dump json value to csv file + +```c++ +#include +#include + +using namespace jsoncons; + +int main() +{ + const json books = json::parse(R"( + [ + { + "title" : "Kafka on the Shore", + "author" : "Haruki Murakami", + "price" : 25.17 + }, + { + "title" : "Women: A Novel", + "author" : "Charles Bukowski", + "price" : 12.00 + }, + { + "title" : "Cutter's Way", + "author" : "Ivan Passer" + } + ] + )"); + + csv_options options; + options.column_names("author,title,price"); + + csv_encoder encoder(std::cout, options); + + books.dump(encoder); +} +``` + +Output: + +```csv +author,title,price +Haruki Murakami,Kafka on the Shore,25.17 +Charles Bukowski,Women: A Novel,12.0 +Ivan Passer,Cutter's Way, +``` + +#### Dump json content into a larger document + +```c++ +#include + +using namespace jsoncons; + +int main() +{ + const json some_books = json::parse(R"( + [ + { + "title" : "Kafka on the Shore", + "author" : "Haruki Murakami", + "price" : 25.17 + }, + { + "title" : "Women: A Novel", + "author" : "Charles Bukowski", + "price" : 12.00 + } + ] + )"); + + const json more_books = json::parse(R"( + [ + { + "title" : "A Wild Sheep Chase: A Novel", + "author" : "Haruki Murakami", + "price" : 9.01 + }, + { + "title" : "Cutter's Way", + "author" : "Ivan Passer", + "price" : 8.00 + } + ] + )"); + + json_encoder encoder(std::cout, jsoncons::indenting::indent); // pretty print + encoder.begin_array(); + for (const auto& book : some_books.array_range()) + { + book.dump(encoder); + } + for (const auto& book : more_books.array_range()) + { + book.dump(encoder); + } + encoder.end_array(); + encoder.flush(); +} +``` + +Output: + +```json +[ + { + "author": "Haruki Murakami", + "price": 25.17, + "title": "Kafka on the Shore" + }, + { + "author": "Charles Bukowski", + "price": 12.0, + "title": "Women: A Novel" + }, + { + "author": "Haruki Murakami", + "price": 9.01, + "title": "A Wild Sheep Chase: A Novel" + }, + { + "author": "Ivan Passer", + "price": 8.0, + "title": "Cutter's Way" + } +] +``` diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/emplace.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/emplace.md new file mode 100644 index 0000000000..b94fe964fa --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/emplace.md @@ -0,0 +1,44 @@ +### jsoncons::json::emplace + +```c++ +template +array_iterator emplace(Args&&... args); + +template +array_iterator emplace(const_array_iterator pos, Args&&... args); +``` + +Constructs a new json element at the specified position of a json array, shifting all elements currently at or above that position to the right. + +#### Parameters + + pos +Iterator that identifies the position in the array to construct the new json value + + args +Arguments to forward to the constructor of the json value + +#### Return value + +Array iterator pointing to the emplaced value. + +#### Exceptions + +Throws `std::runtime_error` if not a json array. + +### Example + +```c++ +json a = json::array(); +a.emplace_back("Toronto"); +a.emplace_back("Vancouver"); +a.emplace(a.array_range().begin(),"Montreal"); + +std::cout << a << std::endl; +``` +Output: + +```json +["Montreal","Toronto","Vancouver"] +``` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/emplace_back.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/emplace_back.md new file mode 100644 index 0000000000..f01713f87d --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/emplace_back.md @@ -0,0 +1,35 @@ +### jsoncons::json::emplace_back +```c++ +template +json& emplace_back(Args&&... args); +``` + +#### Parameters + + args +Arguments to forward to the constructor of the json value + +#### Return value + +A reference to the emplaced json value. + +#### Exceptions + +Throws `std::runtime_error` if not a json array. + +### Example + +```c++ +json arr = json::array(); +arr.emplace_back(10); +arr.emplace_back(20); +arr.emplace_back(30); + +std::cout << arr << std::endl; +``` +Output: + +```json +[10,20,30] +``` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/erase.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/erase.md new file mode 100644 index 0000000000..8f37d6f31b --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/erase.md @@ -0,0 +1,29 @@ +### `jsoncons::json::erase` + +```c++ +void erase(const_array_iterator pos); // (1) + +void erase(const_array_iterator first, const_array_iterator last); // (2) + +void erase(const_object_iterator pos); // (3) + +void erase(const_object_iterator first, const_object_iterator last); // (4) + +void erase(const string_view_type& name); // (5) +``` + +(1) Remove an element from an array at the specified position. +Throws `std::runtime_error` if not an array. + +(2) Remove the elements from an array in the range '[first,last)'. +Throws `std::runtime_error` if not an array. + +(3) Remove a member from an object at the specified position. +Throws `std::runtime_error` if not an object. + +(4) Remove the members from an object in the range '[first,last)'. +Throws `std::runtime_error` if not an object. + +(5) Remove a member with the specified name from an object +Throws `std::runtime_error` if not an object. + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/insert.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/insert.md new file mode 100644 index 0000000000..698c2138c9 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/insert.md @@ -0,0 +1,125 @@ +### jsoncons::json::insert + +```c++ +template +array_iterator insert(const_array_iterator pos, T&& val); // (1) + +template +array_iterator insert(const_array_iterator pos, InputIt first, InputIt last); // (2) +``` +(1) Adds a new json element at the specified position of a json array, shifting all elements currently at or above that position to the right. +The argument `val` is forwarded to the `json` constructor as `std::forward(val)`. +Returns an `array_iterator` that points to the new value +Throws `std::runtime_error` if not an array. + +(2) Inserts elements from range [first, last) before pos. + +``` +template +void insert(InputIt first, InputIt last); // (3) +``` + +(3) Inserts elements from range `[first, last)` into a json object. + If multiple elements in the range have the same key, the first element in the range is inserted. + The function template parameter `InputIt` represents an input + iterator type that iterates over elements of type `key_value`, + or alternatively over elements of type `std::pair` where `T1` is convertible to `string_type` and `T2` is convertible to `json_type`. + +#### See also + +- [push_back](json/push_back.md) + +### Examples + +#### Creating an array of elements +```c++ +json cities = json::array(); // an empty array +std::cout << cities << std::endl; // output is "[]" + +cities.push_back("Toronto"); +cities.push_back("Vancouver"); +// Insert "Montreal" at beginning of array +cities.insert(cities.array_range().begin(),"Montreal"); + +std::cout << cities << std::endl; +``` +Output: +``` +[] +["Montreal","Toronto","Vancouver"] +``` +#### Creating an array of elements with reserved storage +```c++ +json cities = json::array(); +cities.reserve(10); // storage is reserved +std::cout << "capacity=" << cities.capacity() + << ", size=" << cities.size() << std::endl; + +cities.push_back("Toronto"); +cities.push_back("Vancouver"); +cities.insert(cities.array_range().begin(),"Montreal"); +std::cout << "capacity=" << cities.capacity() + << ", size=" << cities.size() << std::endl; + +std::cout << cities << std::endl; +``` +Output: +``` +capacity=10, size=0 +capacity=10, size=3 +["Montreal","Toronto","Vancouver"] +``` + +### Copy two std::map's into a json + +```c++ +std::map m1 = {{"f",4},{"e",5},{"d",6}}; +std::map m2 = {{"c",1},{"b",2},{"a",3}}; + +json j; +j.insert(m1.begin(),m1.end()); +j.insert(m2.begin(),m2.end()); + +std::cout << j << "\n"; +``` +Output: +``` +{"a":3.0,"b":2.0,"c":1.0,"d":6.0,"e":5.0,"f":4.0} +``` + +### Copy two std::map's into an ojson + +```c++ +std::map m1 = {{"f",4},{"e",5},{"d",6}}; +std::map m2 = {{"c",1},{"b",2},{"a",3}}; + +ojson j; +j.insert(m1.begin(),m1.end()); +j.insert(m2.begin(),m2.end()); + +std::cout << j << "\n"; +``` +Output: +``` +{"d":6.0,"e":5.0,"f":4.0,"a":3.0,"b":2.0,"c":1.0} +``` + +### Move two std::map's into a json + +```c++ +std::map m1 = {{"a",1},{"b",2},{"c",3}}; +std::map m2 = {{"d",4},{"e",5},{"f",6}}; + +json j; +j.insert(std::make_move_iterator(m1.begin()),std::make_move_iterator(m1.end())); +j.insert(std::make_move_iterator(m2.begin()),std::make_move_iterator(m2.end())); + +std::cout << j << "\n"; +``` +Output: +``` +{"a":1.0,"b":2.0,"c":3.0,"d":4.0,"e":5.0,"f":6.0} +``` + + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/insert_or_assign.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/insert_or_assign.md new file mode 100644 index 0000000000..07255a207f --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/insert_or_assign.md @@ -0,0 +1,36 @@ +### jsoncons::json::insert_or_assign + +```c++ +template +pair insert_or_assign(const string_view_type& key, T&& value); // (1) + +template +object_iterator insert_or_assign(const_object_iterator hint, const string_view_type& key, + T&& value); // (2) +``` + +#### Parameters + + key +The member name used to look up and, if not found, to insert + + hint +An object iterator that provides a hint where to insert the new json value + + value +Value to insert or assign + +#### Return value + +(1) returns a pair consisting of first, an iterator to the inserted value +or the already existing value, +and second, a bool indicating whether the insertion took place +(true for insertion, false for no insertion.) + +(2) returns an iterator to the inserted value +or the already existing value. + +#### Exceptions + +Throws `std::runtime_error` if not a json object. + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/is.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/is.md new file mode 100644 index 0000000000..de8d45ad09 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/is.md @@ -0,0 +1,107 @@ +### jsoncons::json::is + +```c++ +template +bool is(Args&&... args) const noexcept; // (1) + +bool is_null() const noexcept; // (2) + +bool is_string() const noexcept; // (3) + +bool is_int64() const noexcept; // (4) + +bool is_uint64() const noexcept; // (5) + +bool is_double() const noexcept; // (6) + +bool is_number() const noexcept; // (7) + +bool is_bool() const noexcept; // (8) + +bool is_byte_string() const; // (9) + +bool is_bignum() const; // (10) + +bool is_array() const noexcept; // (11) + +bool is_object() const noexcept; // (12) +``` + +(1) Generic `is` equivalent to type `T`. Returns `true` if the json value is the same as type `T` according to [json_type_traits](../json_type_traits.md), `false` otherwise. + + bool is> const noexcept +If the type `X` is not `std::basic_string` but otherwise satisfies [SequenceContainer](http://en.cppreference.com/w/cpp/concept/SequenceContainer), `is>()` returns `true` if the json value is an array and each element is the "same as" type `T` according to [json_type_traits](json_type_traits.md), `false` otherwise. + bool is> const noexcept +If the type 'X' satisfies [AssociativeContainer](http://en.cppreference.com/w/cpp/concept/AssociativeContainer) or [UnorderedAssociativeContainer](http://en.cppreference.com/w/cpp/concept/UnorderedAssociativeContainer), `is>()` returns `true` if the json value is an object and each mapped value is the "same as" `T` according to [json_type_traits](json_type_traits.md), `false` otherwise. + +(2) Same as `is()`. +Returns `true` if the json value is null, `false` otherwise. + +(3) Same as `is()`. +Returns `true` if the json value is of string type, `false` otherwise. + +(4) Same as `is()`. +Returns `true` if the json value is integral and within the range of `int64_t`, `false` otherwise. + +(5) Same as `is()`. +Returns `true` if the json value is integral and within the range of `uint64_t`, `false` otherwise. + +(6) Same as `is()`. +Returns `true` if the json value is floating point and within the range of `double`, `false` otherwise. + +(7) Same as `is() || is() || is()`. + +(8) Same as `is()`. +Returns `true` if the json value is of boolean type, `false` otherwise. + +(10) Same as `is()`. +Returns `true` if `is() || is() is `true`, or if +`is()` is `true` and the string holds an integer value, +otherwise `false`. + +(11) Same as `is()`. +Returns `true` if the json value is an array, `false` otherwise. + +(12) Same as `is()`. +Returns `true` if the json value is an object, `false` otherwise. + +### Examples + +```c++ +json j = json::parse(R"( +{ + "k1" : 2147483647, + "k2" : 2147483648, + "k3" : -10, + "k4" : 10.5, + "k5" : true, + "k6" : "10.5" +} +)"); + +std::cout << std::boolalpha << "(1) " << j["k1"].is() << '\n'; +std::cout << std::boolalpha << "(2) " << j["k2"].is() << '\n'; +std::cout << std::boolalpha << "(3) " << j["k2"].is() << '\n'; +std::cout << std::boolalpha << "(4) " << j["k3"].is() << '\n'; +std::cout << std::boolalpha << "(5) " << j["k3"].is() << '\n'; +std::cout << std::boolalpha << "(6) " << j["k4"].is() << '\n'; +std::cout << std::boolalpha << "(7) " << j["k4"].is() << '\n'; +std::cout << std::boolalpha << "(8) " << j["k5"].is() << '\n'; +std::cout << std::boolalpha << "(9) " << j["k5"].is() << '\n'; +std::cout << std::boolalpha << "(10) " << j["k6"].is() << '\n'; + +``` +Output: +``` +(1) true +(2) false +(3) true +(4) true +(5) false +(6) false +(7) true +(8) false +(9) true +(10) false + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/key_value.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/key_value.md new file mode 100644 index 0000000000..44526a44e1 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/key_value.md @@ -0,0 +1,53 @@ +### jsoncons::json::key_value + +```c++ +template +class key_value +``` + +`key_value` stores a key (name) and a json value + +#### Member types + +Member type |Definition +------------------------------------|------------------------------ +`string_view_type`|A non-owning view of a string, holds a pointer to character data and length. Supports conversion to and from strings. Will be typedefed to the C++ 17 [string view](http://en.cppreference.com/w/cpp/string/basic_string_view) if `JSONCONS_HAS_STRING_VIEW` is defined in `jsoncons_config.hpp`, otherwise proxied. + +#### Accessors + + string_view_type key() const + + const json& value() const + + json& value() + +#### Non member functions + + + + + + + + + + + + + + + + + + + + + + + + + + +
bool operator==(const key_value& lhs, const key_value& rhs)Returns true if two key_value objects compare equal, false otherwise.
bool operator!=(const key_value& lhs, const key_value& rhs)Returns true if two key_value objects do not compare equal, false otherwise.
bool operator<(const key_value& lhs, const key_value& rhs)Compares the contents of lhs and rhs lexicographically.
bool operator<=(const key_value& lhs, const key_value& rhs)Compares the contents of lhs and rhs lexicographically.
bool operator>(const key_value& lhs, const key_value& rhs)Compares the contents of lhs and rhs lexicographically.
bool operator>=(const key_value& lhs, const key_value& rhs)Compares the contents of lhs and rhs lexicographically.
+ + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/make_array.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/make_array.md new file mode 100644 index 0000000000..b5e12f70b6 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/make_array.md @@ -0,0 +1,94 @@ +### jsoncons::json::make_array + +```c++ +template +static json make_array(size_ n, const T& val) + +template +static json make_array(size_ n, const T& val, + const allocator_type& alloc = allocator_type()) + +template +static json make_array(size_t size1 ... size_t sizeN) + +template +static json make_array(size_t size1 ... size_t sizeN, const T& val) + +template +static json make_array(size_t size1 ... size_t sizeN, const T& val, + const allocator_type& alloc) +``` +Makes a multidimensional array with the number of dimensions specified as a template parameter. The size of each dimension is passed as a parameter, and optionally an inital value. If no initial value, the default is an empty json object. The elements may be accessed using familiar C++ native array syntax. + +### Examples + +#### Make an array of size 10 initialized with zeros +```c++ +json a = json::make_array<1>(10,0); +a[1] = 1; +a[2] = 2; +std::cout << pretty_print(a) << std::endl; +``` +Output: +```json +[0,1,2,0,0,0,0,0,0,0] +``` +#### Make a two dimensional array of size 3x4 initialized with zeros +```c++ +json a = json::make_array<2>(3,4,0); +a[0][0] = "Tenor"; +a[0][1] = "ATM vol"; +a[0][2] = "25-d-MS"; +a[0][3] = "25-d-RR"; +a[1][0] = "1Y"; +a[1][1] = 0.20; +a[1][2] = 0.009; +a[1][3] = -0.006; +a[2][0] = "2Y"; +a[2][1] = 0.18; +a[2][2] = 0.009; +a[2][3] = -0.005; + +std::cout << pretty_print(a) << std::endl; +``` +Output: +```json +[ + ["Tenor","ATM vol","25-d-MS","25-d-RR"], + ["1Y",0.2,0.009,-0.006], + ["2Y",0.18,0.009,-0.005] +] +``` +#### Make a three dimensional array of size 4x3x2 initialized with zeros +```c++ +json a = json::make_array<3>(4,3,2,0); +a[0][2][0] = 2; +a[0][2][1] = 3; +std::cout << pretty_print(a) << std::endl; +``` +Output: +```json +[ + [ + [0,0], + [0,0], + [2,3] + ], + [ + [0,0], + [0,0], + [0,0] + ], + [ + [0,0], + [0,0], + [0,0] + ], + [ + [0,0], + [0,0], + [0,0] + ] +] +``` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/merge.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/merge.md new file mode 100644 index 0000000000..2603436ddf --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/merge.md @@ -0,0 +1,60 @@ +### jsoncons::json::merge + +```c++ +void merge(const json& source); // (1) +void merge(json&& source); // (2) +void merge(object_iterator hint, const json& source); // (3) +void merge(object_iterator hint, json&& source); // (4) +``` + +Copies the key-value pairs in source json object into json object. If there is a member in source json object with key equivalent to the key of a member in json object, +then that member is not copied. + +The `merge` function performs only a one-level-deep shallow merge, not a deep merge of nested objects. + +#### Parameters + + + + + + +
source`json` object value
+ +#### Return value + +None + +#### Exceptions + +Throws `std::runtime_error` if source or *this are not json objects. + +### Examples + +#### Merge `json` + +```c++ +json j = json::parse(R"( +{ + "a" : 1, + "b" : 2 +} +)"); + +const json source = json::parse(R"( +{ + "a" : 2, + "c" : 3 +} +)"); + +j1.merge(source); + +std::cout << j << endl; +``` +Output: + +```json +{"a":1,"b":2,"c":3} +``` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/merge_or_update.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/merge_or_update.md new file mode 100644 index 0000000000..eaeb41e7ea --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/merge_or_update.md @@ -0,0 +1,59 @@ +### jsoncons::json::merge_or_update + +```c++ +void merge_or_update(const json& source); // (1) +void merge_or_update(json&& source); // (2) +void merge_or_update(object_iterator hint, const json& source); // (3) +void merge_or_update(object_iterator hint, json&& source); // (4) +``` + +Inserts another json object's key-value pairs into a json object, or assigns them if they already exist. + +The `merge_or_update` function performs only a one-level-deep shallow merge, not a deep merge of nested objects. + +#### Parameters + + + + + + +
source`json` object value
+ +#### Return value + +None + +#### Exceptions + +Throws `std::runtime_error` if source or *this are not json objects. + +### Examples + +#### Merge or update `json` + +```c++ +json j = json::parse(R"( +{ + "a" : 1, + "b" : 2 +} +)"); + +const json source = json::parse(R"( +{ + "a" : 2, + "c" : 3 +} +)"); + +j1.merge_or_update(source); + +std::cout << j << endl; +``` +Output: + +```json +{"a":2,"b":2,"c":3} +``` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/object_range.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/object_range.md new file mode 100644 index 0000000000..6733e0e60e --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/object_range.md @@ -0,0 +1,63 @@ +### jsoncons::json::object_range + +```c++ +range object_range(); +range object_range() const; +``` +Returns a "range" that supports a range-based for loop over the key-value pairs of a `json` object +Throws `std::runtime_error` if not an object. + +### Examples + +#### Range-based for loop over key-value pairs of an object + +```c++ +#include + +int main() +{ + json j = json::parse(R"( +{ + "category" : "Fiction", + "title" : "Pulp", + "author" : "Charles Bukowski", + "date" : "2004-07-08", + "price" : 22.48, + "isbn" : "1852272007" +} +)"); + + for (const auto& member : j.object_range()) + { + std::cout << member.key() << " => " << member.value().as() << std::endl; + } +} +``` +Output: +```json +author => Charles Bukowski +category => Fiction +date => 2004-07-08 +isbn => 1852272007 +price => 22.48 +title => Pulp +``` +#### Object iterator +```c++ +json j; +j["city"] = "Toronto"; +j["province"] = "Ontario"; +j["country"] = "Canada"; + +for (auto it = j.object_range().begin(); it != j.object_range().end(); ++it) +{ + std::cout << it->key() << " => " << it->value().as() << std::endl; +} +``` +Output: +```c++ +city => Toronto +country => Canada +province => Ontario +``` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/operator=.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/operator=.md new file mode 100644 index 0000000000..4e9d2c8337 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/operator=.md @@ -0,0 +1,16 @@ +### `jsoncons::json::operator=` + +```c++ +json& operator=(const json& rhs); +json& operator=(json&& rhs) noexcept; // (1) + +template +json& operator=(const T& rhs); // (2) + +json& operator=(const char_type* rhs); // (3) +``` + +(1) Assigns a new `json` value to a `json` variable, replacing it's current contents. + +(2) Assigns the templated value to a `json` variable using [json_type_traits](json_type_traits.md). + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/parse.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/parse.md new file mode 100644 index 0000000000..c229598cbf --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/parse.md @@ -0,0 +1,113 @@ +### jsoncons::json::parse + +```c++ +static json parse(const string_view_type& s); // (1) + +static json parse(const string_view_type& s, + const json_options& options); // (2) + +static json parse(const string_view_type& s, + parse_error_handler& err_handler); // (3) + +static json parse(const string_view_type& s, + const json_options& options, + parse_error_handler& err_handler); // (4) + +static json parse(std::istream& is); // (5) + +static json parse(std::istream& is, + const json_options& options); // (6) + +static json parse(std::istream& is, + const json_options& options, + parse_error_handler& err_handler); // (7) + +static json parse(std::istream& is, + const json_options& options, + parse_error_handler& err_handler); // (8) +``` +(1) - (4) Parses a string of JSON text and returns a json object or array value. +Throws [ser_error](ser_error.md) if parsing fails. + +(5) - (8) Parses an input stream of JSON text and returns a json object or array value. +Throws [ser_error](ser_error.md) if parsing fails. + +### Examples + +#### Parse from stream + +Input example.json: + +```json +{"File Format Options":{"Color Spaces":["sRGB","AdobeRGB","ProPhoto RGB"]}} +``` + +```c++ +std::ifstream is("example.json"); +json j = json::parse(is); + +std::cout << pretty_print(j) << std::endl; +``` + +Output: + +```json +{ + "File Format Options": { + "Color Spaces": ["sRGB","AdobeRGB","ProPhoto RGB"] + } +} +``` + +#### Parse from string + +```c++ +try +{ + json val = json::parse("[1,2,3,4,]"); +} +catch(const jsoncons::ser_error& e) +{ + std::cout << e.what() << std::endl; +} +``` +Output: +``` +Extra comma at line 1 and column 10 +``` + +#### Parse from string with serializing options + +```c++ +std::string s = R"({"field1":"NaN","field2":"PositiveInfinity","field3":"NegativeInfinity"})"; + +json_options options; +options.nan_to_str("NaN") + .inf_to_str("PositiveInfinity") + .neginf_to_str("NegativeInfinity"); + +json j = json::parse(s,options); + +std::cout << "\n(1)\n" << pretty_print(j) << std::endl; + +std::cout << "\n(2)\n" << pretty_print(j,options) << std::endl; +``` +Output: +``` +(1) +{ + "field1": null, + "field2": null, + "field3": null +} + +(2) +{ + "field1": "NaN", + "field2": "PositiveInfinity", + "field3": "NegativeInfinity" +} +``` + + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/push_back.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/push_back.md new file mode 100644 index 0000000000..070bde16f1 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/push_back.md @@ -0,0 +1,50 @@ +### jsoncons::json::push_back + +```c++ +template +void push_back(T&& val) +``` +Adds a new json element at the end of a json array. The argument `val` is forwarded to the `json` constructor as `std::forward(val)`. +Throws `std::runtime_error` if not an array. + +### Examples + +#### Creating an array of elements +```c++ +json cities = json::array(); // an empty array +std::cout << cities << std::endl; // output is "[]" + +cities.push_back("Toronto"); +cities.push_back("Vancouver"); +// Insert "Montreal" at beginning of array +cities.insert(cities.array_range().begin(),"Montreal"); + +std::cout << cities << std::endl; +``` +Output: +``` +[] +["Montreal","Toronto","Vancouver"] +``` +#### Creating an array of elements with reserved storage +```c++ +json cities = json::array(); +cities.reserve(10); // storage is reserved +std::cout << "capacity=" << cities.capacity() + << ", size=" << cities.size() << std::endl; + +cities.push_back("Toronto"); +cities.push_back("Vancouver"); +cities.insert(cities.array_range().begin(),"Montreal"); +std::cout << "capacity=" << cities.capacity() + << ", size=" << cities.size() << std::endl; + +std::cout << cities << std::endl; +``` +Output: +``` +capacity=10, size=0 +capacity=10, size=3 +["Montreal","Toronto","Vancouver"] +``` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/try_emplace.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/try_emplace.md new file mode 100644 index 0000000000..cf25de74bb --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json/try_emplace.md @@ -0,0 +1,57 @@ +### jsoncons::json::try_emplace + +```c++ +template +pair try_emplace(const string_view_type& key, + Args&&... args); // (1) + +template +object_iterator try_emplace(const_object_iterator hint, + const string_view_type& key, + Args&&... args); // (2) +``` + +#### Parameters + + key +The key used both to look up and to insert if not found + + hint +Iterator to the position before which the new element will be inserted + + args +Arguments to forward to the constructor of the element + +#### Return value + +(1) returns a pair consisting of first, an iterator to the inserted value +or the already existing value, +and second, a bool indicating whether the insertion took place +(true for insertion, false for no insertion.) + +(2) returns an iterator to the inserted value +or the already existing value. + +#### Exceptions + +Throws `std::runtime_error` if not a json object. + +### Example + +```c++ +json a; + +a.try_emplace("object1",json()); +a.try_emplace("field1","value1"); +a["object1"].try_emplace("field2","value2"); + +std::cout << a << std::endl; +``` +Output: + +```json +{"field1":"value1","object1":{"field2":"value2"}} +``` + + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json_content_handler.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json_content_handler.md new file mode 100644 index 0000000000..e44c6ee118 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json_content_handler.md @@ -0,0 +1,245 @@ +### jsoncons::json_content_handler + +```c++ +typedef basic_json_content_handler json_content_handler +``` + +Defines an interface for receiving JSON events. The `json_content_handler` class is an instantiation of the `basic_json_content_handler` class template that uses `char` as the character type. + +#### Header +```c++ +#include +``` +#### Member types + +Member type |Definition +------------------------------------|------------------------------ +`string_view_type`|A non-owning view of a string, holds a pointer to character data and length. Supports conversion to and from strings. Will be typedefed to the C++ 17 [string view](http://en.cppreference.com/w/cpp/string/basic_string_view) if `JSONCONS_HAS_STRING_VIEW` is defined in `jsoncons_config.hpp`, otherwise proxied. + +#### Public producer interface + + bool begin_object(semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); +Indicates the begining of an object of indefinite length. Contextual information including +line and column number is provided in the [context](ser_context.md) parameter. +Returns `true` if the producer should continue streaming events, `false` otherwise. +Throws a [ser_error](ser_error.md) to indicate an error. + + bool begin_object(size_t length, + semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); +Indicates the begining of an object of known length. Contextual information including +line and column number is provided in the [context](ser_context.md) parameter. +Returns `true` if the producer should continue streaming events, `false` otherwise. +Throws a [ser_error](ser_error.md) to indicate an error. + + bool end_object(const ser_context& context = null_ser_context()) +Indicates the end of an object. Contextual information including +line and column number is provided in the [context](ser_context.md) parameter. +Returns `true` if the producer should continue streaming events, `false` otherwise. +Throws a [ser_error](ser_error.md) to indicate an error. + + bool begin_array(semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); +Indicates the beginning of an indefinite length array. Contextual information including +line and column number is provided in the [context](ser_context.md) parameter. +Returns `true` if the producer should continue streaming events, `false` otherwise. +Throws a [ser_error](ser_error.md) to indicate an error. + + bool begin_array(semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); +Indicates the beginning of an array of known length. Contextual information including +line and column number is provided in the [context](ser_context.md) parameter. +Returns `true` if the producer should continue streaming events, `false` otherwise. + + bool end_array(const ser_context& context=null_ser_context()); +Indicates the end of an array. Contextual information including +line and column number is provided in the [context](ser_context.md) parameter. +Returns `true` if the producer should continue streaming events, `false` otherwise. +Throws a [ser_error](ser_error.md) to indicate an error. + + bool name(const string_view_type& name, + const ser_context& context=null_ser_context()); +Writes the name part of a name-value pair inside an object. Contextual information including +line and column number is provided in the [context](ser_context.md) parameter. +Returns `true` if the producer should continue streaming events, `false` otherwise. +Throws a [ser_error](ser_error.md) to indicate an error. + + bool string_value(const string_view_type& value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); +Writes a string value. Contextual information including +line and column number is provided in the [context](ser_context.md) parameter. +Returns `true` if the producer should continue streaming events, `false` otherwise. +Throws a [ser_error](ser_error.md) to indicate an error. + + bool byte_string_value(const byte_string_view& b, + semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); +Writes a byte string value. Contextual information including +line and column number is provided in the [context](ser_context.md) parameter. +Returns `true` if the producer should continue streaming events, `false` otherwise. +Throws a [ser_error](ser_error.md) to indicate an error. + + bool byte_string_value(const uint8_t* p, size_t size, + semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); +Writes a byte string value. Contextual information including +line and column number is provided in the [context](ser_context.md) parameter. +Returns `true` if the producer should continue streaming events, `false` otherwise. +Throws a [ser_error](ser_error.md) to indicate an error. + + bool int64_value(int64_t value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); +Writes a signed integer value. Contextual information including +line and column number is provided in the [context](ser_context.md) parameter. +Returns `true` if the producer should continue streaming events, `false` otherwise. +Throws a [ser_error](ser_error.md) to indicate an error. + + bool uint64_value(uint64_t value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); +Writes a non-negative integer value. Contextual information including +line and column number is provided in the [context](ser_context.md) parameter. +Returns `true` if the producer should continue streaming events, `false` otherwise. +Throws a [ser_error](ser_error.md) to indicate an error. + + bool double_value(double value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); +Writes a floating point value. Contextual information including +line and column number is provided in the [context](ser_context.md) parameter. +Returns `true` if the producer should continue streaming events, `false` otherwise. +Throws a [ser_error](ser_error.md) to indicate an error. + + bool bool_value(bool value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); +Writes a boolean value. Contextual information including +line and column number is provided in the [context](ser_context.md) parameter. +Returns `true` if the producer should continue streaming events, `false` otherwise. +Throws a [ser_error](ser_error.md) to indicate an error. + + bool null_value(semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); +Writes a null value. Contextual information including +line and column number is provided in the [context](ser_context.md) parameter. +Returns `true` if the producer should continue streaming events, `false` otherwise. +Throws a [ser_error](ser_error.md) to indicate an error. + + void flush() +Flushes whatever is buffered to the destination. + +#### Private virtual consumer interface + + virtual bool do_begin_object(semantic_tag tag, + const ser_context& context) = 0; +Handles the beginning of an object of indefinite length. Contextual information including +line and column number is provided in the [context](ser_context.md) parameter. +Returns `true` if the producer should continue streaming events, `false` otherwise. +Sets `ec` to indicate an error. + + virtual bool do_begin_object(size_t length, + semantic_tag tag, + const ser_context& context) = 0; +Handles the beginning of an object of known length. Contextual information including +line and column number is provided in the [context](ser_context.md) parameter. +Returns `true` if the producer should continue streaming events, `false` otherwise. +Sets `ec` to indicate an error. + + virtual bool do_end_object(const ser_context& context) = 0; +Handles the end of an object. Contextual information including +line and column number is provided in the [context](ser_context.md) parameter. +Returns `true` if the producer should continue streaming events, `false` otherwise. +Sets `ec` to indicate an error. + + virtual bool do_begin_array(semantic_tag tag, + const ser_context& context) = 0; +Handles the beginning of an array of indefinite length. Contextual information including +line and column number is provided in the [context](ser_context.md) parameter. +Returns `true` if the producer should continue streaming events, `false` otherwise. +Sets `ec` to indicate an error. + + virtual bool do_begin_array(size_t length, + const ser_context& context); +Handles the beginning of an array of known length. Defaults to calling `do_begin_array(semantic_tag, const ser_context& context)`. Contextual information including +line and column number is provided in the [context](ser_context.md) parameter. +Returns `true` if the producer should continue streaming events, `false` otherwise. +Sets `ec` to indicate an error. + + virtual bool do_end_array(const ser_context& context) = 0; +Handles the end of an array. Contextual information including +line and column number is provided in the [context](ser_context.md) parameter. +Returns `true` if the producer should continue streaming events, `false` otherwise. +Sets `ec` to indicate an error. + + virtual bool do_name(const string_view_type& name, + const ser_context& context) = 0; +Handles the name part of a name-value pair inside an object. Contextual information including +line and column number is provided in the [context](ser_context.md) parameter. +Returns `true` if the producer should continue streaming events, `false` otherwise. +Sets `ec` to indicate an error. + + virtual bool do_string_value(const string_view_type& val, + semantic_tag tag, + const ser_context& context) = 0; +Handles a string value. Contextual information including +line and column number is provided in the [context](ser_context.md) parameter. +Returns `true` if the producer should continue streaming events, `false` otherwise. +Sets `ec` to indicate an error. + + virtual bool do_byte_string_value(const byte_string_view& b, + semantic_tag tag, + const ser_context& context) = 0; +Handles a byte string value. Contextual information including +line and column number is provided in the [context](ser_context.md) parameter. +Returns `true` if the producer should continue streaming events, `false` otherwise. +Sets `ec` to indicate an error. + + virtual bool do_int64_value(int64_t value, + semantic_tag tag, + const ser_context& context) = 0; +Handles a signed integer value. Contextual information including +line and column number is provided in the [context](ser_context.md) parameter. +Returns `true` if the producer should continue streaming events, `false` otherwise. +Sets `ec` to indicate an error. + + virtual bool do_uint64_value(uint64_t value, + semantic_tag tag, + const ser_context& context) = 0; +Handles a non-negative integer value. Contextual information including +line and column number is provided in the [context](ser_context.md) parameter. +Returns `true` if the producer should continue streaming events, `false` otherwise. +Sets `ec` to indicate an error. + + virtual bool do_double_value(double value, + semantic_tag tag, + const ser_context& context) = 0; +Handles a floating point value. Contextual information including +line and column number is provided in the [context](ser_context.md) parameter. +Returns `true` if the producer should continue streaming events, `false` otherwise. +Sets `ec` to indicate an error. + + virtual bool do_bool_value(bool value, + semantic_tag tag, + const ser_context& context) = 0; +Handles a boolean value. Contextual information including +line and column number is provided in the [context](ser_context.md) parameter. +Returns `true` if the producer should continue streaming events, `false` otherwise. +Sets `ec` to indicate an error. + + virtual bool do_null_value(semantic_tag tag, + const ser_context& context) = 0; +Handles a null value. Contextual information including +line and column number is provided in the [context](ser_context.md) parameter. +Returns `true` if the producer should continue streaming events, `false` otherwise. +Sets `ec` to indicate an error. + + virtual void do_flush() = 0; +Allows producers of json events to flush whatever they've buffered. + +#### See also + +- [semantic_tag](../semantic_tag.md) + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json_cursor.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json_cursor.md new file mode 100644 index 0000000000..23c170c309 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json_cursor.md @@ -0,0 +1,358 @@ +### jsoncons::json_cursor + +```c++ +typedef basic_json_cursor json_cursor +``` + +A pull parser for parsing json events. A typical application will +repeatedly process the `current()` event and call the `next()` +function to advance to the next event, until `done()` returns `true`. + +`json_cursor` is noncopyable and nonmoveable. + +#### Header +```c++ +#include +``` + +### Implemented interfaces + +[staj_reader](staj_reader.md) + +#### Constructors + + template + basic_json_cursor(Source&& source); // (1) + + template + basic_json_cursor(Source&& source, + basic_staj_filter& filter); // (2) + + template + basic_json_cursor(Source&& source, + parse_error_handler& err_handler); // (3) + + template + basic_json_cursor(Source&& source, + basic_staj_filter& filter, + parse_error_handler& err_handler); // (4) + + template + basic_json_cursor(Source&& source, + const basic_json_decode_options& options); // (5) + + template + basic_json_cursor(Source&& source, + basic_staj_filter& filter, + const basic_json_decode_options& options); // (6) + + template + basic_json_cursor(Source&& source, + basic_staj_filter& filter, + const basic_json_decode_options& options, + parse_error_handler& err_handler); // (7) + +Constructors (1)-(7) read from a character sequence or stream and throw a +[ser_error](ser_error.md) if a parsing error is encountered +while processing the initial event. + +(1) Constructs a `json_cursor` that reads from a character sequence or stream `source`, uses default [json_decode_options](json_decode_options.md) +and a default [parse_error_handler](parse_error_handler.md). + +(2) Constructs a `json_cursor` that reads from a character sequence or stream `source`, applies a [staj_filter](staj_filter.md) to the JSON events, uses default [json_decode_options](json_decode_options.md) +and a default [parse_error_handler](parse_error_handler.md). + +(3) Constructs a `json_cursor` that reads from a character sequence or stream `source`, +uses the specified [json_decode_options](json_decode_options.md) +and a default [parse_error_handler](parse_error_handler.md). + +(4) Constructs a `json_cursor` that reads from a character sequence or stream `source`, +applies a [staj_filter](staj_filter.md) to the JSON events, +uses the specified [json_decode_options](json_decode_options.md) +and a default [parse_error_handler](parse_error_handler.md). + +(5) Constructs a `json_cursor` that reads from a character sequence or stream `source`, +uses default [json_decode_options](json_decode_options.md) +and a specified [parse_error_handler](parse_error_handler.md). + +(6) Constructs a `json_cursor` that reads from a character sequence or stream `source`, +applies a [staj_filter](staj_filter.md) to the JSON events, +uses default [json_decode_options](json_decode_options.md) +and a specified [parse_error_handler](parse_error_handler.md). + +(7) Constructs a `json_cursor` that reads from a character sequence or stream `source`, +applies a [staj_filter](staj_filter.md) to the JSON events, +uses the specified [json_decode_options](json_decode_options.md) +and a specified [parse_error_handler](parse_error_handler.md). + + template + basic_json_cursor(Source&& source, + std::error_code& ec); // (8) + + template + basic_json_cursor(Source&& source, + basic_staj_filter& filter, + std::error_code& ec) // (9) + + template + basic_json_cursor(Source&& source, + parse_error_handler& err_handler, + std::error_code& ec) // (10) + + template + basic_json_cursor(Source&& source, + basic_staj_filter& filter, + parse_error_handler& err_handler, + std::error_code& ec) // (11) + + template + basic_json_cursor(Source&& source, + const basic_json_decode_options& options, + std::error_code& ec) // (12) + + template + basic_json_cursor(Source&& source, + basic_staj_filter& filter, + const basic_json_decode_options& options, + std::error_code& ec) // (13) + + template + basic_json_cursor(Source&& source, + basic_staj_filter& filter, + const basic_json_decode_options& options, + parse_error_handler& err_handler, + std::error_code& ec) // (14) + +Constructors (8)-(14) read from a character sequence or stream and set `ec` +if a parsing error is encountered while processing the initial event. + +Note: It is the programmer's responsibility to ensure that `basic_json_cursor` does not outlive any source, +content handler, and error handler passed in the constuctor, as `basic_json_cursor` holds pointers to but does not own these resources. + +#### Parameters + +`source` - a value from which a `jsoncons::basic_string_view` is constructible, +or a value from which a `source_type` is constructible. In the case that a `jsoncons::basic_string_view` is constructible +from `source`, `source` is dispatched immediately to the parser. Otherwise, the `json_cursor` reads from a `source_type` in chunks. + +#### Member functions + + bool done() const override; +Checks if there are no more events. + + const staj_event& current() const override; +Returns the current [staj_event](staj_event.md). + + void accept(json_content_handler& handler) override +Sends the parse events from the current event to the +matching completion event to the supplied [handler](json_content_handler.md) +E.g., if the current event is `begin_object`, sends the `begin_object` +event and all inbetween events until the matching `end_object` event. +If a parsing error is encountered, throws a [ser_error](ser_error.md). + + void accept(json_content_handler& handler, + std::error_code& ec) override +Sends the parse events from the current event to the +matching completion event to the supplied [handler](json_content_handler.md) +E.g., if the current event is `begin_object`, sends the `begin_object` +event and all inbetween events until the matching `end_object` event. +If a parsing error is encountered, sets `ec`. + + void next() override; +Advances to the next event. If a parsing error is encountered, throws a +[ser_error](ser_error.md). + + void next(std::error_code& ec) override; +Advances to the next event. If a parsing error is encountered, sets `ec`. + + const ser_context& context() const override; +Returns the current [context](ser_context.md) + +### Examples + +The example JSON text, `book_catalog.json`, is used by the examples below. + +```json +[ + { + "author" : "Haruki Murakami", + "title" : "Hard-Boiled Wonderland and the End of the World", + "isbn" : "0679743464", + "publisher" : "Vintage", + "date" : "1993-03-02", + "price": 18.90 + }, + { + "author" : "Graham Greene", + "title" : "The Comedians", + "isbn" : "0099478374", + "publisher" : "Vintage Classics", + "date" : "2005-09-21", + "price": 15.74 + } +] +``` + +#### Reading a JSON stream + +```c++ +#include +#include +#include + +using namespace jsoncons; + +int main() +{ + std::ifstream is("book_catalog.json"); + + json_cursor reader(is); + + for (; !reader.done(); reader.next()) + { + const auto& event = reader.current(); + switch (event.event_type()) + { + case staj_event_type::begin_array: + std::cout << "begin_array\n"; + break; + case staj_event_type::end_array: + std::cout << "end_array\n"; + break; + case staj_event_type::begin_object: + std::cout << "begin_object\n"; + break; + case staj_event_type::end_object: + std::cout << "end_object\n"; + break; + case staj_event_type::name: + // If underlying type is string, can return as string_view + std::cout << "name: " << event.as() << "\n"; + break; + case staj_event_type::string_value: + std::cout << "string_value: " << event.as() << "\n"; + break; + case staj_event_type::null_value: + std::cout << "null_value: " << event.as() << "\n"; + break; + case staj_event_type::bool_value: + std::cout << "bool_value: " << event.as() << "\n"; + // or std::cout << "bool_value: " << event.as() << "\n"; + break; + case staj_event_type::int64_value: + std::cout << "int64_value: " << event.as() << "\n"; + // or std::cout << "int64_value: " << event.as() << "\n"; + break; + case staj_event_type::uint64_value: + std::cout << "uint64_value: " << event.as() << "\n"; + // or std::cout << "int64_value: " << event.as() << "\n"; + break; + case staj_event_type::double_value: + std::cout << "double_value: " << event.as() << "\n"; + // or std::cout << "double_value: " << event.as() << "\n"; + break; + default: + std::cout << "Unhandled event type\n"; + break; + } + } +} +``` +Output: +``` +begin_array +begin_object +name: author +string_value: Haruki Murakami +name: title +string_value: Hard-Boiled Wonderland and the End of the World +name: isbn +string_value: 0679743464 +name: publisher +string_value: Vintage +name: date +string_value: 1993-03-02 +name: price +double_value: 18.90 +end_object +begin_object +name: author +string_value: Graham Greene +name: title +string_value: The Comedians +name: isbn +string_value: 0099478374 +name: publisher +string_value: Vintage Classics +name: date +string_value: 2005-09-21 +name: price +double_value: 15.74 +end_object +end_array +``` + +#### Filtering a JSON stream + +```c++ +#include +#include +#include + +using namespace jsoncons; + +class author_filter : public staj_filter +{ + bool accept_next_ = false; +public: + bool accept(const staj_event& event, const ser_context&) override + { + if (event.event_type() == staj_event_type::name && + event.as() == "author") + { + accept_next_ = true; + return false; + } + else if (accept_next_) + { + accept_next_ = false; + return true; + } + else + { + accept_next_ = false; + return false; + } + } +}; + +int main() +{ + std::ifstream is("book_catalog.json"); + + author_filter filter; + json_cursor reader(is, filter); + + for (; !reader.done(); reader.next()) + { + const auto& event = reader.current(); + switch (event.event_type()) + { + case staj_event_type::string_value: + std::cout << event.as() << "\n"; + break; + } + } +} +``` +Output: +``` +Haruki Murakami +Graham Greene +``` + +#### See also + +- [staj_array_iterator](staj_array_iterator.md) +- [staj_object_iterator](staj_object_iterator.md) + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json_decode_options.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json_decode_options.md new file mode 100644 index 0000000000..5858a8d99f --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json_decode_options.md @@ -0,0 +1,47 @@ +### jsoncons::json_decode_options + +```c++ +typedef basic_json_decode_options json_decode_options +``` + +An abstract class that defines accessors for JSON decode options. The `json_decode_options` class is an instantiation of the `basic_json_decode_options` class template that uses `char` as the character type. + +#### Header +```c++ +#include +``` + +#### Implementing classes + +[json_options](json_options.md) + +#### Destructor + + virtual ~json_decode_options(); + +#### Accessors + + virtual bool is_str_to_nan() const = 0; +Indicates `NaN` replacement for string when parsing. + + virtual std::string nan_to_str() const = 0; +When parsing JSON text, replace string with a `NaN` if `is_nan_to_str()` returns `true`. + + virtual bool is_str_to_inf() const = 0; +Indicates `Infinity` replacement for string when parsing. + + virtual const std::string& inf_to_str() const = 0; +When parsing JSON text, replace string with infinity if `is_inf_to_str()` returns `true`. + + virtual bool is_str_to_neginf() const = 0; +Indicates `Negative Infinity` replacement for string when parsing. + + virtual const std::string& neginf_to_str() const = 0; +When parsing JSON text, replace string with minus infinity if `is_neginf_to_str()` returns true. + + virtual bool lossless_number() const = 0; +If set to `true`, parse decimal numbers as strings with semantic tagging `semantic_tag::bigdec` instead of double. + + virtual size_t max_nesting_depth() = 0; + Maximum nesting depth when parsing JSON. + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json_decoder.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json_decoder.md new file mode 100644 index 0000000000..3d930dd83d --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json_decoder.md @@ -0,0 +1,39 @@ +### jsoncons::json_decoder + +```c++ +template +json_decoder +``` + +#### Header +```c++ +#include +``` + +![json_decoder](./diagrams/json_decoder.png) + +#### Member types + +Member type |Definition +------------------------------------|------------------------------ +`allocator_type`|Json::allocator_type + +#### Constructors + + json_decoder(const allocator_type allocator = allocator_type()) + +#### Member functions + + allocator_type get_allocator() const +Returns the allocator associated with the json value. + + bool is_valid() const +Checks if the `deserializer` contains a valid json_type value. The initial `is_valid()` is false, becomes `true` when a `do_end_document` event is received, and becomes false when `get_result()` is called. + + Json get_result() +Returns the json value `v` stored in the `deserializer` as `std::move(v)`. If before calling this function `is_valid()` is false, the behavior is undefined. After `get_result()` is called, 'is_valid()' becomes false. + +### See also + +- [json_content_handler](json_content_handler.md) + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json_encode_options.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json_encode_options.md new file mode 100644 index 0000000000..f76f2575e9 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json_encode_options.md @@ -0,0 +1,105 @@ +### jsoncons::json_encode_options + +```c++ +typedef basic_json_encode_options json_encode_options +``` + +An abstract class that defines accessors for JSON encoding options. The `json_encode_options` class is an instantiation of the `basic_json_encode_options` class template that uses `char` as the character type. + +#### Header +```c++ +#include +``` + +#### Implementing classes + +[json_options](json_options.md) + +#### Destructor + + virtual ~json_encode_options(); + +#### Accessors + + virtual size_t indent_size() const = 0; +The indent size, the default is 4. + + virtual spaces_option spaces_around_colon() const = 0; +Indicates [space option](spaces_option.md) for name separator (`:`). Default +is space after. + + virtual spaces_option spaces_around_comma() const = 0; +Indicates [space option](spaces_option.md) for array value and object name/value pair separators (`,`). Default +is space after. + + virtual bool pad_inside_object_braces() const = 0; +Default is `false` + + virtual bool pad_inside_array_brackets() const = 0; +Default is `false` + + virtual chars_format floating_point_format() const = 0 +Overrides [floating point format](chars_format.md) when serializing json. +The default, for a floating point value that was previously decoded from json text, is to preserve the original format when serializing. +The default, for a floating point value that was directly inserted into a json value, to serialize with [chars_format::general](chars_format.md). + + virtual bigint_chars_format bigint_format() const = 0 +Overrides [bignum format](bigint_chars_format.md) when serializing json. +The default is [bigint_chars_format::base10](bigint_chars_format.md). + + virtual byte_string_chars_format byte_string_format() const = 0 +Overrides [byte string format](byte_string_chars_format.md) when serializing json. +The default is [byte_string_chars_format::base64url](byte_string_chars_format.md). + + virtual int precision() const = 0 +Overrides floating point precision when serializing json. +The default, for a floating point value that was previously decoded from json text, is to preserve the original precision. +The fefault, for a floating point value that was directly inserted into a json value, to serialize with shortest representation. + + virtual bool escape_all_non_ascii() const = 0 +Escape all non-ascii characters. The default is `false`. + + virtual bool escape_solidus() const = 0 +Escape the solidus ('/') character. The default is `false`. + + virtual bool is_nan_to_num() const = 0; + virtual bool is_nan_to_str() const = 0; + virtual const std::string& nan_to_num() const = 0 + virtual const std::string& nan_to_str() const = 0 +Replace `NaN` with a number, if `is_nan_to_num()` returns `true`, +or a string, if `is_nan_to_str()` returns `true`. If both +return `false`, replace `NaN` with `null`. + + virtual bool is_inf_to_num() const = 0; + virtual bool is_inf_to_str() const = 0; + virtual const std::string& inf_to_num() const = 0 + virtual const std::string& inf_to_str() const = 0 +Replace positive infinity with a number, if `is_inf_to_num()` returns `true`, +or a string, if `is_inf_to_str()` returns `true`. If both +return `false`, replace positive infinity with `null`. + + virtual bool is_neginf_to_num() const = 0 + virtual bool is_neginf_to_str() const = 0 + virtual const std::string& neginf_to_num() const = 0 + virtual const std::string& neginf_to_str() const = 0 +Replace negative infinity with a number, if `is_neginf_to_num()` returns `true`, +or a string, if `is_neginf_to_str()` returns true. If both +return `false`, replace negative infinity with `null`. + + virtual std::string new_line_chars() const = 0 +Defaults to "\n" + + virtual size_t line_length_limit() const = 0 + + virtual line_split_kind object_object_line_splits() const = 0; +For an object whose parent is an object, indicates whether that object is split on a new line, or if its members are split on multiple lines. The default is [line_split_kind::multi_line](line_split_kind.md). + + virtual line_split_kind array_object_line_splits() const = 0; +For an object whose parent is an array, indicates whether that object is split on a new line, or if its members are split on multiple lines. The default is [line_split_kind::multi_line](line_split_kind.md). + + virtual line_split_kind object_array_line_splits() const = 0; +For an array whose parent is an object, indicates whether that array is split on a new line, or if its elements are split on multiple lines. The default is [line_split_kind::same_line](line_split_kind.md). + + virtual line_split_kind array_array_line_splits() const = 0; +For an array whose parent is an array, indicates whether that array is split on a new line, or if its elements are split on multiple lines. The default is [line_split_kind::new_line](line_split_kind.md). + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json_encoder.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json_encoder.md new file mode 100644 index 0000000000..36ae6eff88 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json_encoder.md @@ -0,0 +1,160 @@ +### jsoncons::basic_json_encoder + +```c++ +template< + class CharT, + class Result> +> basic_json_encoder : public jsoncons::basic_json_content_handler + +template< + class CharT, + class Result> +> basic_json_compressed_encoder : public jsoncons::basic_json_content_handler +``` + +`basic_json_encoder` and `basic_json_compressed_encoder` are noncopyable and nonmoveable. + +#### Header + + #include + +![json_encoder](./diagrams/json_encoder.png) + +Four specializations for common character types and result types are defined +for both the pretty print and compressed serializers: + +Type |Definition +---------------------------|------------------------------ +json_encoder |basic_json_encoder> +json_string_encoder |basic_json_encoder> +wjson_encoder |basic_json_encoder> +wjson_string_encoder |basic_json_encoder> +json_compressed_encoder |basic_json_compressed_encoder> +json_compressed_string_encoder |basic_json_compressed_encoder> +wjson_compressed_encoder |basic_json_compressed_encoder> +wjson_compressed_string_encoder |basic_json_compressed_encoder> + +#### Member types + +Type |Definition +---------------------------|------------------------------ +char_type |CharT +result_type |Result +string_view_type | + +#### Constructors + + explicit basic_json_encoder(result_type result) +Constructs a new encoder that is associated with the output adaptor `result`. + + basic_json_encoder(result_type result, + const basic_json_encode_options& options) +Constructs a new encoder that is associated with the output adaptor `result` +and uses the specified [json options](json_options.md). + +#### Destructor + + virtual ~basic_json_encoder() + +### Inherited from [basic_json_content_handler](../json_content_handler.md) + +#### Member functions + + bool begin_object(semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool begin_object(size_t length, + semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool end_object(const ser_context& context = null_ser_context()) + + bool begin_array(semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool begin_array(semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool end_array(const ser_context& context=null_ser_context()); + + bool name(const string_view_type& name, + const ser_context& context=null_ser_context()); + + bool string_value(const string_view_type& value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool byte_string_value(const byte_string_view& b, + semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool byte_string_value(const uint8_t* p, size_t size, + semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool int64_value(int64_t value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool uint64_value(uint64_t value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool double_value(double value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool bool_value(bool value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool null_value(semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); + + void flush() + +### Examples + +### Feeding json events directly to a `json_encoder` +```c++ +#include +#include +#include + +using namespace jsoncons; +using boost::numeric::ublas::matrix; + +int main() +{ + matrix A(2, 2); + A(0, 0) = 1; + A(0, 1) = 2; + A(1, 0) = 3; + A(1, 1) = 4; + + json_options options; + json_encoder os(std::cout, options); + os.begin_array(); + for (size_t i = 0; i < A.size1(); ++i) + { + os.begin_array(); + for (size_t j = 0; j < A.size2(); ++j) + { + os.double_value(A(i, j)); + } + os.end_array(); + } + os.end_array(); + + return 0; +} +``` + +Output: + +```json +[ + [1,2], + [3,4] +] +``` diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json_error.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json_error.md new file mode 100644 index 0000000000..1ed89614dd --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json_error.md @@ -0,0 +1,38 @@ +### jsoncons::json_errc + +The constant integer values scoped by `jsoncons::json_errc` define the values for json text error codes. + +#### Header + + #include + +### Member constants + +constant |Description +------------------------------------|------------------------------ +`unexpected_eof` |Unexpected end of file +`invalid_json_text` |Invalid JSON text +`extra_character` |Unexpected non-whitespace character after JSON text +`max_depth_exceeded` |Maximum JSON depth exceeded +`single_quote` |JSON strings cannot be quoted with single quotes +`illegal_character_in_string` |Illegal character in string +`extra_comma` |Extra comma +`expected_name` |Expected object member name +`expected_value` |Expected value +`invalid_value` |Invalid value +`expected_colon` |Expected name separator ':' +`illegal_control_character` |Illegal control character in string +`illegal_escaped_character` |Illegal escaped character in string +`expected_codepoint_surrogate_pair` |Invalid codepoint, expected another \\u token to begin the second half of a codepoint surrogate pair. +`invalid_hex_escape_sequence` |Invalid codepoint, expected hexadecimal digit. +`invalid_unicode_escape_sequence` |Invalid codepoint, expected four hexadecimal digits. +`leading_zero` |A number cannot have a leading zero +`invalid_number` |Invalid number +`expected_comma_or_right_brace` |Expected comma or right brace ']' +`expected_comma_or_right_bracket` |Expected comma or right bracket '}' +`unexpected_right_brace` |Unexpected right brace '}' +`unexpected_right_bracket` |Unexpected right bracket ']' + + + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json_filter.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json_filter.md new file mode 100644 index 0000000000..ea22808cbc --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json_filter.md @@ -0,0 +1,210 @@ +### jsoncons::json_filter + +```c++ +typedef basic_json_filter json_filter +``` + +The `json_filter` class is an instantiation of the `basic_json_filter` class template that uses `char` as the character type. + +`json_filter` is noncopyable and nonmoveable. + +#### Header + + #include + +![json_filter](./diagrams/json_filter.png) + +#### Member types + +Member type |Definition +------------------------------------|------------------------------ +`string_view_type`|A non-owning view of a string, holds a pointer to character data and length. Supports conversion to and from strings. Will be typedefed to the C++ 17 [string view](http://en.cppreference.com/w/cpp/string/basic_string_view) if `JSONCONS_HAS_STRING_VIEW` is defined in `jsoncons_config.hpp`, otherwise proxied. + +#### Constructors + + json_filter(json_content_handler& handler) +All JSON events that pass through the `json_filter` go to the specified `json_content_handler` (e.g. another filter.) +You must ensure that the `handler` exists as long as does `json_filter`, as `json_filter` holds a pointer to but does not own this object. + +#### Accessors + + json_content_handler& to_handler() +Returns a reference to the JSON handler that sends json events to a destination handler. + +### See also + +- [json_content_handler](json_content_handler.md) + +### Examples + +#### Rename object member names with the built in filter [rename_object_member_filter](rename_object_member_filter.md) + +```c++ +#include +#include +#include + +using namespace jsoncons; + +int main() +{ + std::string s = R"({"first":1,"second":2,"fourth":3,"fifth":4})"; + + json_encoder encoder(std::cout); + + // Filters can be chained + rename_object_member_filter filter2("fifth", "fourth", encoder); + rename_object_member_filter filter1("fourth", "third", filter2); + + // A filter can be passed to any function that takes + // a json_content_handler ... + std::cout << "(1) "; + std::istringstream is(s); + json_reader reader(is, filter1); + reader.read(); + std::cout << std::endl; + + // or a json_content_handler + std::cout << "(2) "; + ojson j = ojson::parse(s); + j.dump(filter1); + std::cout << std::endl; +} +``` +Output: +```json +(1) {"first":1,"second":2,"third":3,"fourth":4} +(2) {"first":1,"second":2,"third":3,"fourth":4} +``` + +#### Fix up names in an address book JSON file + +Example address book file (`address-book.json`): +```json +{ + "address-book" : + [ + { + "name":"Jane Roe", + "email":"jane.roe@example.com" + }, + { + "name":"John", + "email" : "john.doe@example.com" + } + ] +} +``` + +Suppose you want to break the name into a first name and last name, and report a warning when `name` does not contain a space or tab separated part. + +You can achieve the desired result by subclassing the [json_filter](json_filter.md) class, overriding the default methods for receiving name and string value events, and passing modified events on to the parent [json_content_handler](json_content_handler.md) (which in this example will forward them to a [json_encoder](json_encoder.md).) +```c++ +#include +#include +#include + +using namespace jsoncons; + + +class name_fix_up_filter : public json_filter +{ + std::string member_name_; + +public: + name_fix_up_filter(json_content_handler& handler) + : json_filter(handler) + { + } + +private: + bool do_name(const string_view_type& name, + const ser_context& context) override + { + member_name_ = name; + if (member_name_ != "name") + { + this->to_handler().write_name(name, context); + } + return true; + } + + bool do_string_value(const string_view_type& s, + const ser_context& context) override + { + if (member_name_ == "name") + { + size_t end_first = val.find_first_of(" \t"); + size_t start_last = val.find_first_not_of(" \t", end_first); + this->to_handler().write_name("first-name", context); + string_view_type first = val.substr(0, end_first); + this->to_handler().value(first, context); + if (start_last != string_view_type::npos) + { + this->to_handler().write_name("last-name", context); + string_view_type last = val.substr(start_last); + this->to_handler().value(last, context); + } + else + { + std::cerr << "Incomplete name \"" << s + << "\" at line " << context.line() + << " and column " << context.column() << std::endl; + } + } + else + { + this->to_handler().value(s, context); + } + return true; + } +}; +``` +Configure a [rename_object_member_filter](rename_object_member_filter.md) to emit json events to a [json_encoder](json_encoder.md). +```c++ +std::ofstream os("output/new-address-book.json"); +json_encoder encoder(os, jsoncons::indenting::indent); +name_fix_up_filter filter(encoder); +``` +Parse the input and send the json events into the filter ... +```c++ +std::cout << "(1) "; +std::ifstream is("input/address-book.json"); +json_reader reader(is, filter); +reader.read(); +std:: << "\n"; +``` +or read into a json value and write to the filter +```c++ +std::cout << "(2) "; +json j; +is >> j; +j.dump(filter); +std:: << "\n"; +``` +Output: +``` +(1) Incomplete name "John" at line 9 and column 26 +(2) Incomplete name "John" at line 0 and column 0 +``` +Note that when filtering `json` events written from a `json` value to an output handler, contexual line and column information in the original file has been lost. +``` + +The new address book (`address-book-new.json`) with name fixes is +```json +{ + "address-book": + [ + { + "first-name":"Jane", + "last-name":"Roe", + "email":"jane.roe@example.com" + }, + { + "first-name":"John", + "email":"john.doe@example.com" + } + ] +} +``` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json_options.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json_options.md new file mode 100644 index 0000000000..3048d3117d --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json_options.md @@ -0,0 +1,390 @@ +### jsoncons::json_options + +```c++ +typedef basic_json_options json_options +``` + +Specifies options for encoding and decoding JSON text. The `json_options` class is an instantiation of the `basic_json_options` class template that uses `char` as the character type. + +The default floating point formatting for a floating point value that was previously decoded from json text is to preserve the original format and precision. This ensures round-trip for both format and precision, e.g. 1.1 read will remain `1.1` when written, and not become `1.1000000000000001` (an equivalent but longer representation.) + +The default floating point formatting for a floating point value that was directly inserted into a json value is [chars_format::general](chars_format.md) with shortest representation. Trailing zeros are removed, except one immediately following the decimal point. The period character (.) is always used as the decimal point, non English locales are ignored. + +#### Header +```c++ +#include +``` + +![json_options](./diagrams/json_options.png) + +#### Member constants + + static const size_t indent_size_default = 4; +The default size indent is 4 + + static const size_t line_length_limit_default = 120; +The default line length limit is 120 + +#### Constructors + + json_options() +Constructs an `json_options` with default values. + +#### Modifiers + + json_options& indent(size_t value) +The indent size, the default is 4. + + json_options & spaces_around_colon(spaces_option value) +Indicates [space option](spaces_option.md) for name separator (`:`). Default +is space after. + + json_options & spaces_around_comma(spaces_option value) +Indicates [space option](spaces_option.md) for array value and object name/value pair separators (`,`). Default +is space after. + + json_options & pad_inside_object_braces(bool value) +Default is `false` + + json_options & pad_inside_array_brackets(bool value) +Default is `false` + + json_options& bigint_format(bigint_chars_format value) +Overrides [bignum format](bigint_chars_format.md) when serializing json. +The default is [bigint_chars_format::base10](bigint_chars_format.md). + + json_options& byte_string_format(byte_string_chars_format value) +Overrides [byte string format](byte_string_chars_format.md) when serializing json. +The default is [byte_string_chars_format::base64url](byte_string_chars_format.md). + + json_options& precision(int value) +Overrides floating point precision when serializing json. +The default, for a floating point value that was previously decoded from json text, is to preserve the original precision. +The default, for a floating point value that was directly inserted into a json value, to serialize with shortest representation. + + json_options& escape_all_non_ascii(bool value) +Escape all non-ascii characters. The default is `false`. + + json_options& escape_solidus(bool value) +Escape the solidus ('/') character. The default is `false`. + + json_options& nan_to_num(const std::string& value); +Sets a number replacement for `NaN` when writing JSON + + json_options& inf_to_num(const std::string& value); +Sets a number replacement for `Infinity` when writing JSON + + json_options& neginf_to_num(const std::string& value); +Sets a number replacement for `Negative Infinity` when writing JSON + + json_options& nan_to_str(const std::string& value, bool is_str_to_nan = true); +Sets a string replacement for `NaN` when writing JSON, and indicate whether it is also +to be used when reading JSON. + + json_options& inf_to_str(const std::string& value, bool is_str_to_inf = true); +Sets a string replacement for infinity when writing JSON, and indicate whether it is also +to be used when reading JSON. + + json_options& neginf_to_str(const std::string& value, bool is_str_to_neginf = true); // (4) +Sets a string replacement for negative infinity when writing JSON, and indicate whether it is also +to be used when reading JSON. + + json_options& lossless_number(bool value); +If set to `true`, parse numbers with exponents and fractional parts as strings with semantic tagging `semantic_tag::bigdec`. +Defaults to `false`. + + json_options& new_line_chars(const std::string& value) +Defaults to "\n" + + json_options & line_length_limit(size_t value) + + void max_nesting_depth(size_t depth) +The maximum nesting depth allowed when parsing JSON. By default `jsoncons` can read a `JSON` text of arbitrarily large depth. + + json_options& object_object_line_splits(line_split_kind value) +For an object whose parent is an object, set whether that object is split on a new line, or if its members are split on multiple lines. The default is [line_split_kind::multi_line](line_split_kind.md). + + json_options& array_object_line_splits(line_split_kind value) +For an object whose parent is an array, set whether that object is split on a new line, or if its members are split on multiple lines. The default is [line_split_kind::multi_line](line_split_kind.md). + + json_options& object_array_line_splits(line_split_kind value) +For an array whose parent is an object, set whether that array is split on a new line, or if its elements are split on multiple lines. The default is [line_split_kind::same_line](line_split_kind.md). + + json_options& array_array_line_splits(line_split_kind value) +For an array whose parent is an array, set whether that array is split on a new line, or if its elements are split on multiple lines. The default is [line_split_kind::new_line](line_split_kind.md). + +#### Static member functions + + static const basic_json_options& default_options() +Default JSON encode and decode options. + +### See also + +[json_decode_options](json_decode_options.md) +[json_encode_options](json_encode_options.md) + +### Examples + +#### Default NaN and inf replacement +```c++ +json obj; +obj["field1"] = std::sqrt(-1.0); +obj["field2"] = 1.79e308*1000; +obj["field3"] = -1.79e308*1000; +std::cout << obj << std::endl; +``` +Output: +```json +{"field1":null,"field2":null,"field3":null} +``` +#### User specified `Nan` and `Inf` replacement + +```c++ +json obj; +obj["field1"] = std::sqrt(-1.0); +obj["field2"] = 1.79e308*1000; +obj["field3"] = -1.79e308*1000; + +json_options options; +format.nan_to_num("null"); // default is "null" +format.inf_to_num("1e9999"); // default is "null" + +std::cout << pretty_print(obj,options) << std::endl; +``` + +Output: +```json + { + "field1":null, + "field2":1e9999, + "field3":-1e9999 + } +``` + +#### Decimal precision + +By default, jsoncons parses a number with an exponent or fractional part +into a double precision floating point number. If you wish, you can +keep the number as a string with semantic tagging `bigdec`, +using the `lossless_number` option. You can then put it into a `float`, +`double`, a boost multiprecision number, or whatever other type you want. + +```c++ +int main() +{ + std::string s = R"( + { + "a" : 12.00, + "b" : 1.23456789012345678901234567890 + } + )"; + + // Default + json j = json::parse(s); + + std::cout.precision(15); + + // Access as string + std::cout << "(1) a: " << j["a"].as() << ", b: " << j["b"].as() << "\n"; + // Access as double + std::cout << "(2) a: " << j["a"].as() << ", b: " << j["b"].as() << "\n\n"; + + // Using lossless_number option + json_options options; + options.lossless_number(true); + + json j2 = json::parse(s, options); + // Access as string + std::cout << "(3) a: " << j2["a"].as() << ", b: " << j2["b"].as() << "\n"; + // Access as double + std::cout << "(4) a: " << j2["a"].as() << ", b: " << j2["b"].as() << "\n\n"; +} +``` +Output: +``` +(1) a: 12.0, b: 1.2345678901234567 +(2) a: 12, b: 1.23456789012346 + +(3) a: 12.00, b: 1.23456789012345678901234567890 +(4) a: 12, b: 1.23456789012346 +``` + +#### Object-array block formatting + +```c++ + json val; + + val["verts"] = json::array{1, 2, 3}; + val["normals"] = json::array{1, 0, 1}; + val["uvs"] = json::array{0, 0, 1, 1}; + + std::cout << "Default (same line)" << std::endl; + std::cout << pretty_print(val) << std::endl; + + std::cout << "New line" << std::endl; + json_options options1; + format1.object_array_line_splits(line_split_kind::new_line); + std::cout << pretty_print(val,options1) << std::endl; + + std::cout << "Multi line" << std::endl; + json_options options2; + format2.object_array_line_splits(line_split_kind::multi_line); + std::cout << pretty_print(val,options2) << std::endl; +``` + +Output: + +Default (same line) + +```json +{ + "normals": [1,0,1], + "uvs": [0,0,1,1], + "verts": [1,2,3] +} +``` + +New line + +```json +{ + "normals": [ + 1,0,1 + ], + "uvs": [ + 0,0,1,1 + ], + "verts": [ + 1,2,3 + ] +} +``` +Multi line +```json +{ + "normals": [ + 1, + 0, + 1 + ], + "uvs": [ + 0, + 0, + 1, + 1 + ], + "verts": [ + 1, + 2, + 3 + ] +} +``` + +#### Array-array block formatting + +```c++ + json val; + val["data"]["id"] = json::array{0,1,2,3,4,5,6,7}; + val["data"]["item"] = json::array{json::array{2}, + json::array{4,5,2,3}, + json::array{4}, + json::array{4,5,2,3}, + json::array{2}, + json::array{4,5,3}, + json::array{2}, + json::array{4,3}}; + + std::cout << "Default (new line)" << std::endl; + std::cout << pretty_print(val) << std::endl; + + std::cout << "Same line" << std::endl; + json_options options1; + format1.array_array_line_splits(line_split_kind::same_line); + std::cout << pretty_print(val, options1) << std::endl; + + std::cout << "Multi line" << std::endl; + json_options options2; + format2.array_array_line_splits(line_split_kind::multi_line); + std::cout << pretty_print(val, options2) << std::endl; +``` + +Output: + +Default (new line) + +```json +{ + "data": { + "id": [0,1,2,3,4,5,6,7], + "item": [ + [2], + [4,5,2,3], + [4], + [4,5,2,3], + [2], + [4,5,3], + [2], + [4,3] + ] + } +} +``` +Same line + +```json +{ + "data": { + "id": [0,1,2,3,4,5,6,7], + "item": [[2],[4,5,2,3],[4],[4,5,2,3],[2],[4,5,3],[2],[4,3]] + } +} +``` + +Multi line + +```json +{ + "data": { + "id": [ + 0,1,2,3,4,5,6,7 + ], + "item": [ + [ + 2 + ], + [ + 4, + 5, + 2, + 3 + ], + [ + 4 + ], + [ + 4, + 5, + 2, + 3 + ], + [ + 2 + ], + [ + 4, + 5, + 3 + ], + [ + 2 + ], + [ + 4, + 3 + ] + ] + } +} +``` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json_parser.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json_parser.md new file mode 100644 index 0000000000..b86c77bdc2 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json_parser.md @@ -0,0 +1,272 @@ +### jsoncons::json_parser + +```c++ +typedef basic_json_parser json_parser +``` +`json_parser` is an incremental json parser. It can be fed its input +in chunks, and does not require an entire file to be loaded in memory +at one time. + +A buffer of text is supplied to the parser with a call to `update(buffer)`. +If a subsequent call to `parse_some` reaches the end of the buffer in the middle of parsing, +say after digesting the sequence 'f', 'a', 'l', member function `stopped()` will return `false` +and `source_exhausted()` will return `true`. Additional JSON text can be supplied to the parser, +`parse_some` called again, and parsing will resume from where it left off. + +A typical application will repeatedly call the `parse_some` function +until `stopped()` returns true. A stopped state indicates that a content +handler function returned `false`, an error occured, or a complete JSON +text has been consumed. If the latter, `done() `will return `true`. + +As an alternative to repeatedly calling `parse_some()` until `stopped()` +returns `true`, when `source_exhausted()` is `true` and there is +no more input, `finish_parse` may be called. + +`check_done` can be called to check if the input has any unconsumed +non-whitespace characters, which would normally be considered an error. + +`json_parser` is used by the push parser [json_reader](json_reader.md), +and by the pull parser [json_cursor](json_cursor.md). + +`json_parser` is noncopyable and nonmoveable. + +#### Header +```c++ +#include +``` +#### Constructors + + json_parser(); // (1) + + json_parser(const json_decode_options& options); // (2) + + json_parser(parse_error_handler& err_handler); // (3) + + json_parser(const json_decode_options& options, + parse_error_handler& err_handler); // (4) + +(1) Constructs a `json_parser` that uses default [json_decode_options](json_decode_options.md) +and a default [parse_error_handler](parse_error_handler.md). + +(2) Constructs a `json_parser` that uses the specified [json_decode_options](json_decode_options.md) +and a default [parse_error_handler](parse_error_handler.md). + +(3) Constructs a `json_parser` that uses default [json_decode_options](json_decode_options.md) +and a specified [parse_error_handler](parse_error_handler.md). + +(4) Constructs a `json_parser` that uses the specified [json_decode_options](json_decode_options.md) +and a specified [parse_error_handler](parse_error_handler.md). + +Note: It is the programmer's responsibility to ensure that `json_reader` does not outlive any error handler passed in the constuctor. + +#### Member functions + + void update(const string_view_type& sv) + void update(const char* data, size_t length) +Update the parser with a chunk of JSON + + bool done() const +Returns `true` when the parser has consumed a complete JSON text, `false` otherwise + + bool stopped() const +Returns `true` if the parser is stopped, `false` otherwise. +The parser may enter a stopped state as a result of a content handler +function returning `false`, an error occurred, +or after having consumed a complete JSON text. + + bool finished() const +Returns `true` if the parser is finished parsing, `false` otherwise. + + bool source_exhausted() const +Returns `true` if the input in the source buffer has been exhausted, `false` otherwise + + void parse_some(json_content_handler& handler) +Parses the source until a complete json text has been consumed or the source has been exhausted. +Parse events are sent to the supplied `handler`. +Throws [ser_error](ser_error.md) if parsing fails. + + void parse_some(json_content_handler& handler, + std::error_code& ec) +Parses the source until a complete json text has been consumed or the source has been exhausted. +Parse events are sent to the supplied `handler`. +Sets `ec` to a [json_errc](jsoncons::json_errc.md) if parsing fails. + + void finish_parse(json_content_handler& handler) +Called after `source_exhausted()` is `true` and there is no more input. +Repeatedly calls `parse_some(handler)` until `finished()` returns `true` +Throws [ser_error](ser_error.md) if parsing fails. + + void finish_parse(json_content_handler& handler, + std::error_code& ec) +Called after `source_exhausted()` is `true` and there is no more input. +Repeatedly calls `parse_some(handler)` until `finished()` returns `true` +Sets `ec` to a [json_errc](jsoncons::json_errc.md) if parsing fails. + + void skip_bom() +Reads the next JSON text from the stream and reports JSON events to a [json_content_handler](json_content_handler.md), such as a [json_decoder](json_decoder.md). +Throws [ser_error](ser_error.md) if parsing fails. + + void check_done() +Throws if there are any unconsumed non-whitespace characters in the input. +Throws [ser_error](ser_error.md) if parsing fails. + + void check_done(std::error_code& ec) +Sets `ec` to a [json_errc](jsoncons::json_errc.md) if parsing fails. + + size_t reset() const +Resets the state of the parser to its initial state. In this state +`stopped()` returns `false` and `done()` returns `false`. + + size_t restart() const +Resets the `stopped` state of the parser to `false`, allowing parsing +to continue. + +### Examples + +#### Incremental parsing + +```c++ +int main() +{ + json_parser parser; + jsoncons::json_decoder decoder; + try + { + parser.update("10"); + parser.parse_some(decoder); + std::cout << "(1) done: " << std::boolalpha << parser.done() << ", source_exhausted: " << parser.source_exhausted() << "\n\n"; + + parser.update(".5"); + parser.parse_some(decoder); // This is the end, but the parser can't tell + std::cout << "(2) done: " << std::boolalpha << parser.done() << ", source_exhausted: " << parser.source_exhausted() << "\n\n"; + + parser.finish_parse(decoder); // Indicates that this is the end + std::cout << "(3) done: " << std::boolalpha << parser.done() << ", source_exhausted: " << parser.source_exhausted() << "\n\n"; + + parser.check_done(); // Checks if there are any unconsumed + // non-whitespace characters in the input + std::cout << "(4) done: " << std::boolalpha << parser.done() << ", source_exhausted: " << parser.source_exhausted() << "\n\n"; + + json j = decoder.get_result(); + std::cout << "(5) " << j << "\n"; + } + catch (const ser_error& e) + { + std::cout << e.what() << std::endl; + } +} +``` + +Output: + +``` +(1) done: false, source_exhausted: true + +(2) done: false, source_exhausted: true + +(3) done: true, source_exhausted: true + +(4) done: true, source_exhausted: true + +(5) 10.5 +``` + +#### Incremental parsing with unconsumed non-whitespace characters + +```c++ +int main() +{ + json_parser parser; + jsoncons::json_decoder decoder; + try + { + parser.update("[10"); + parser.parse_some(decoder); + std::cout << "(1) done: " << std::boolalpha << parser.done() << ", source_exhausted: " << parser.source_exhausted() << "\n\n"; + + parser.update(".5]{}"); + parser.parse_some(decoder); // The parser reaches the end at ']' + std::cout << "(2) done: " << std::boolalpha << parser.done() << ", source_exhausted: " << parser.source_exhausted() << "\n\n"; + + parser.finish_parse(decoder); // Indicates that this is the end + std::cout << "(3) done: " << std::boolalpha << parser.done() << ", source_exhausted: " << parser.source_exhausted() << "\n\n"; + + parser.check_done(); // Checks if there are any unconsumed + // non-whitespace characters in the input + // (there are) + } + catch (const ser_error& e) + { + std::cout << "(4) " << e.what() << std::endl; + } +} +``` + +Output: + +``` +(1) done: false, source_exhausted: true + +(2) done: true, source_exhausted: false + +(3) done: true, source_exhausted: false + +(4) Unexpected non-whitespace character after JSON text at line 1 and column 7 +``` + +#### nan, inf, and -inf substitition + +```c++ +int main() +{ + std::string s = R"( + { + "A" : "NaN", + "B" : "Infinity", + "C" : "-Infinity" + } + )"; + + json_options options; // Implements json_decode_options + options.nan_to_str("NaN") + .inf_to_str("Infinity"); + + json_parser parser(options); + jsoncons::json_decoder decoder; + try + { + parser.update(s); + parser.parse_some(decoder); + parser.finish_parse(decoder); + parser.check_done(); + } + catch (const ser_error& e) + { + std::cout << e.what() << std::endl; + } + + json j = decoder.get_result(); // performs move + if (j["A"].is()) + { + std::cout << "A: " << j["A"].as() << std::endl; + } + if (j["B"].is()) + { + std::cout << "B: " << j["B"].as() << std::endl; + } + if (j["C"].is()) + { + std::cout << "C: " << j["C"].as() << std::endl; + } +} +``` + +Output: + +``` +A: nan +B: inf +C: -inf +``` + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json_reader.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json_reader.md new file mode 100644 index 0000000000..ee7cad527f --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json_reader.md @@ -0,0 +1,239 @@ +### jsoncons::basic_json_reader + +```c++ +template< + class CharT, + class Src=jsoncons::stream_source, + class Allocator=std::allocator +> +class basic_json_reader +``` +`basic_json_reader` uses the incremental parser [basic_json_parser](json_parser.md) +to read arbitrarily large files in chunks. +A `basic_json_reader` can read a sequence of JSON texts from a stream, using `read_next()`, +which omits the check for unconsumed non-whitespace characters. + +`basic_json_reader` is noncopyable and nonmoveable. + +#### Header +```c++ +#include +``` + +Four specializations for common character types and result types are defined: + +Type |Definition +---------------------------|------------------------------ +json_reader |basic_json_reader +wjson_reader |basic_json_reader + +#### Member types + +Type |Definition +---------------------------|------------------------------ +char_type |CharT +source_type |Src +string_view_type | + +#### Constructors + + template + explicit basic_json_reader(Source&& source); // (1) + + template + basic_json_reader(Source&& source, + const basic_json_decode_options& options); // (2) + + template + basic_json_reader(Source&& source, + parse_error_handler& err_handler); // (3) + + template + basic_json_reader(Source&& source, + const basic_json_decode_options& options, + parse_error_handler& err_handler); // (4) + + template + basic_json_reader(Source&& source, + basic_json_content_handler& handler); // (5) + + template + basic_json_reader(Source&& source, + basic_json_content_handler& handler, + const basic_json_decode_options& options); // (6) + + template + basic_json_reader(Source&& source, + basic_json_content_handler& handler, + parse_error_handler& err_handler); // (7) + + template + basic_json_reader(Source&& source, + basic_json_content_handler& handler, + const basic_json_decode_options& options, + parse_error_handler& err_handler); // (8) + +Constructors (1)-(4) use a default [json_content_handler](json_content_handler.md) that discards the JSON parse events, and are for validation only. + +(1) Constructs a `basic_json_reader` that reads from a character sequence or stream `source`, uses default [options](json_decode_options.md) and a default [parse_error_handler](parse_error_handler.md). + +(2) Constructs a `basic_json_reader` that reads from a character sequence or stream `source`, +uses the specified [options](json_decode_options.md) +and a default [parse_error_handler](parse_error_handler.md). + +(3) Constructs a `basic_json_reader` that reads from a character sequence or stream `source`, +uses default [options](json_decode_options.md) +and a specified [parse_error_handler](parse_error_handler.md). + +(4) Constructs a `basic_json_reader` that reads from a character sequence or stream `source`, +uses the specified [options](json_decode_options.md) +and a specified [parse_error_handler](parse_error_handler.md). + +Constructors (5)-(8) take a user supplied [json_content_handler](json_content_handler.md) that receives JSON parse events, such as a [json_decoder](json_decoder). + +(5) Constructs a `basic_json_reader` that reads from a character sequence or stream `source`, +emits JSON parse events to the specified +[json_content_handler](json_content_handler.md), and uses default [options](json_decode_options.md) +and a default [parse_error_handler](parse_error_handler.md). + +(6) Constructs a `basic_json_reader` that reads from a character sequence or stream `source`, +emits JSON parse events to the specified [json_content_handler](json_content_handler.md) +and uses the specified [options](json_decode_options.md) +and a default [parse_error_handler](parse_error_handler.md). + +(7) Constructs a `basic_json_reader` that reads from a character sequence or stream `source`, +emits JSON parse events to the specified [json_content_handler](json_content_handler.md) +and uses default [options](json_decode_options.md) +and a specified [parse_error_handler](parse_error_handler.md). + +(8) Constructs a `basic_json_reader` that reads from a character sequence or stream `source`, +emits JSON parse events to the specified [json_content_handler](json_content_handler.md) and +uses the specified [options](json_decode_options.md) +and a specified [parse_error_handler](parse_error_handler.md). + +Note: It is the programmer's responsibility to ensure that `basic_json_reader` does not outlive any source, +content handler, and error handler passed in the constuctor, as `basic_json_reader` holds pointers to but does not own these resources. + +#### Parameters + +`source` - a value from which a `jsoncons::basic_string_view` is constructible, +or a value from which a `source_type` is constructible. In the case that a `jsoncons::basic_string_view` is constructible +from `source`, `source` is dispatched immediately to the parser. Otherwise, the `json_reader` reads from a `source_type` in chunks. + +#### Member functions + + bool eof() const +Returns `true` when there are no more JSON texts to be read from the stream, `false` otherwise + + void read(); // (1) + void read(std::error_code& ec); // (2) +Reads the next JSON text from the stream and reports JSON events to a [json_content_handler](json_content_handler.md), such as a [json_decoder](json_decoder.md). +Override (1) throws if parsing fails, or there are any unconsumed non-whitespace characters left in the input. +Override (2) sets `ec` to a [json_errc](jsoncons::json_errc.md) if parsing fails or if there are any unconsumed non-whitespace characters left in the input. + + void read_next() + void read_next(std::error_code& ec) +Reads the next JSON text from the stream and reports JSON events to a [json_content_handler](json_content_handler.md), such as a [json_decoder](json_decoder.md). +Override (1) throws [ser_error](ser_error.md) if parsing fails. +Override (2) sets `ec` to a [json_errc](jsoncons::json_errc.md) if parsing fails. + + void check_done(); // (1) + void check_done(std::error_code& ec); // (2) +Override (1) throws if there are any unconsumed non-whitespace characters in the input. +Override (2) sets `ec` to a [json_errc](jsoncons::json_errc.md) if there are any unconsumed non-whitespace characters left in the input. + + size_t buffer_length() const + + void buffer_length(size_t length) + + size_t line() const + + size_t column() const + +### Examples + +#### Parsing JSON text with exceptions +``` +std::string input = R"({"field1"{}})"; + +json_decoder decoder; +json_reader reader(input,decoder); + +try +{ + reader.read(); + json j = decoder.get_result(); +} +catch (const ser_error& e) +{ + std::cout << e.what() << std::endl; +} + +``` +Output: +``` +Expected name separator ':' at line 1 and column 10 +``` + +#### Parsing JSON text with error codes +``` +std::string input = R"({"field1":ru})"; +std::istringstream is(input); + +json_decoder decoder; +json_reader reader(is,decoder); + +std::error_code ec; +reader.read(ec); + +if (!ec) +{ + json j = decoder.get_result(); +} +else +{ + std::cerr << ec.message() + << " at line " << reader.line() + << " and column " << reader.column() << std::endl; +} +``` +Output: +``` +Expected value at line 1 and column 11 +``` + +#### Reading a sequence of JSON texts from a stream + +`jsoncons` supports reading a sequence of JSON texts, such as shown below (`json-texts.json`): +```json +{"a":1,"b":2,"c":3} +{"a":4,"b":5,"c":6} +{"a":7,"b":8,"c":9} +``` +This is the code that reads them: +```c++ +std::ifstream is("json-texts.json"); +if (!is.is_open()) +{ + throw std::runtime_error("Cannot open file"); +} + +json_decoder decoder; +json_reader reader(is,decoder); + +while (!reader.eof()) +{ + reader.read_next(); + if (!reader.eof()) + { + json val = decoder.get_result(); + std::cout << val << std::endl; + } +} +``` +Output: +```json +{"a":1,"b":2,"c":3} +{"a":4,"b":5,"c":6} +{"a":7,"b":8,"c":9} +``` diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json_type_traits.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json_type_traits.md new file mode 100644 index 0000000000..602ed487f2 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/json_type_traits.md @@ -0,0 +1,826 @@ +### jsoncons::json_type_traits + +`json_type_traits` defines a compile time template based interface for accessing and modifying `basic_json` values. + +#### Header +```c++ +#include +``` + +The default definition provided by the `jsoncons` library is + +```c++ +template +struct json_type_traits +{ + typedef typename Json::allocator_type allocator_type; + + static constexpr bool is_compatible = false; + + static constexpr bool is(const Json&) + { + return false; + } + + static T as(const Json&); + + static Json to_json(const T&, allocator_type = allocator_type()); +}; +``` + +You can interact with a new type using `is`, `as`, construction and assignment by specializing `json_type_traits` in the `jsoncons` namespace. + +If you try to specialize `json_type_traits` for a type that is already +specialized in the jsoncons library, for example, a custom container +type that satisfies the conditions for a sequence container, you +may see a compile error "more than one partial specialization matches the template argument list". +For these situations `jsoncons` provides the traits class +```c++ +template +struct is_json_type_traits_declared : public false_type {}; +``` +which inherits from [false_type](http://www.cplusplus.com/reference/type_traits/false_type/). +This traits class may be specialized for a user-defined type with a [true_type](http://www.cplusplus.com/reference/type_traits/true_type/) value to +inform the `jsoncons` library that the type is already specialized. + +`JSONCONS_MEMBER_TRAITS_DECL` is a macro that simplifies the creation of the necessary boilerplate +from member data. If used, it must be placed outside any namespace blocks. + +`JSONCONS_GETTER_CTOR_TRAITS_DECL` is a macro that simplifies the creation of the necessary boilerplate +from getter functions and a constructor. If used, it must be placed outside any namespace blocks. + +### Specializations + +`T`|`j.is()`|`j.as()`|j is assignable from `T` +--------|-----------|--------------|--- +`Json`|`true`|self| +`Json::object`|`true` if `j.is_object()`, otherwise `false`|Compile-time error| +`Json::array`|`true` if `j.is_array()`, otherwise `false`|Compile-time error| +`bool`|`true` if `j.is_bool()`, otherwise `false`|as `bool`| +`null_type`|`true` if `j.is_null()`, otherwise `false`|`null_type()` value if j.is_null(), otherwise throws| +`const char_type*`|`true` if string, otherwise `false`|as `const char_type*`| +`char_type*`|`true` if `j.is_string()`, otherwise `false`|Compile-time error| +`integral types`|`true` if `j.is_int64()` or `j.is_uint64()` and value is in range, otherwise `false`|j numeric value cast to `T`| +`floating point types`|`true` if j.is_double() and value is in range, otherwise `false`|j numeric value cast to `T`| +`string`|`true` if j.is_string(), otherwise `false`|as string| +STL sequence container (other than string) e.g. std::vector|`true` if array and each value is assignable to a `Json` value, otherwise `false`|if array and each value is convertible to `value_type`, as container, otherwise throws| +STL associative container e.g. std::map|`true` if object and each `mapped_type` is assignable to `Json`, otherwise `false`|if object and each member value is convertible to `mapped_type`, as container| +`std::tuple`|`true` if `j.is_array()` and each array element is assignable to the corresponding `tuple` element, otherwise false|tuple with array elements converted to tuple elements| +`std::pair`|`true` if `j.is_array()` and `j.size()==2` and each array element is assignable to the corresponding pair element, otherwise false|pair with array elements converted to pair elements| + +### Examples + +[Convert from and to standard library sequence containers](#A1) +[Convert from and to standard library associative containers](#A2) +[Convert from and to std::tuple](#A3) +[Extend json_type_traits to support `boost::gregorian` dates.](#A4) +[Specialize json_type_traits to support a book class.](#A5) +[Using JSONCONS_MEMBER_TRAITS_DECL to generate the json_type_traits](#A6) +[A polymorphic example using JSONCONS_GETTER_CTOR_TRAITS_DECL to generate the json_type_traits](#A7) +[Specialize json_type_traits for a container type that the jsoncons library also supports](#A8) +[Convert JSON to/from boost matrix](#A9) + +
+ +#### Convert from and to standard library sequence containers + +```c++ + std::vector v{1, 2, 3, 4}; + json j(v); + std::cout << "(1) "<< j << std::endl; + std::deque d = j.as>(); +``` +Output: +``` +(1) [1,2,3,4] +``` + +
+ +#### Convert from and to standard library associative containers + +```c++ + std::map m{{"one",1},{"two",2},{"three",3}}; + json j(m); + std::cout << j << std::endl; + std::unordered_map um = j.as>(); +``` +Output: +``` +{"one":1,"three":3,"two":2} +``` + +
+ +#### Convert from and to std::tuple + +```c++ + auto t = std::make_tuple(false,1,"foo"); + json j(t); + std::cout << j << std::endl; + auto t2 = j.as>(); +``` +Output: +``` +[false,1,"foo"] +``` + +
+ +#### Extend json_type_traits to support `boost::gregorian` dates. + +```c++ +#include +#include "boost/datetime/gregorian/gregorian.hpp" + +namespace jsoncons +{ + template + struct json_type_traits + { + static const bool is_assignable = true; + + static bool is(const Json& val) noexcept + { + if (!val.is_string()) + { + return false; + } + std::string s = val.template as(); + try + { + boost::gregorian::from_simple_string(s); + return true; + } + catch (...) + { + return false; + } + } + + static boost::gregorian::date as(const Json& val) + { + std::string s = val.template as(); + return boost::gregorian::from_simple_string(s); + } + + static Json to_json(boost::gregorian::date val) + { + return Json(to_iso_extended_string(val)); + } + }; +} +``` +```c++ +namespace ns +{ + using jsoncons::json; + using boost::gregorian::date; + + json deal = json::parse(R"( + { + "Maturity":"2014-10-14", + "ObservationDates": ["2014-02-14","2014-02-21"] + } + )"); + + deal["ObservationDates"].push_back(date(2014,2,28)); + + date maturity = deal["Maturity"].as(); + std::cout << "Maturity: " << maturity << std::endl << std::endl; + + std::cout << "Observation dates: " << std::endl << std::endl; + + for (auto observation_date: deal["ObservationDates"].array_range()) + { + std::cout << observation_date << std::endl; + } + std::cout << std::endl; +} +``` +Output: +``` +Maturity: 2014-Oct-14 + +Observation dates: + +2014-Feb-14 +2014-Feb-21 +2014-Feb-28 +``` + +
+ +#### Specialize json_type_traits to support a book class. + +```c++ +#include +#include +#include +#include + +namespace ns { + struct book + { + std::string author; + std::string title; + double price; + }; +} // namespace ns + +namespace jsoncons { + + template + struct json_type_traits + { + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) noexcept + { + return j.is_object() && j.contains("author") && + j.contains("title") && j.contains("price"); + } + static ns::book as(const Json& j) + { + ns::book val; + val.author = j.at("author").template as(); + val.title = j.at("title").template as(); + val.price = j.at("price").template as(); + return val; + } + static Json to_json(const ns::book& val, + allocator_type allocator=allocator_type()) + { + Json j(allocator); + j.try_emplace("author", val.author); + j.try_emplace("title", val.title); + j.try_emplace("price", val.price); + return j; + } + }; +} // namespace jsoncons +``` + +To save typing and enhance readability, the jsoncons library defines macros, +so we could have written + +```c++ +JSONCONS_MEMBER_TRAITS_DECL(ns::book, author, title, price) +``` + +which expands to the code above. + +```c++ +using namespace jsoncons; // for convenience + +int main() +{ + const std::string s = R"( + [ + { + "author" : "Haruki Murakami", + "title" : "Kafka on the Shore", + "price" : 25.17 + }, + { + "author" : "Charles Bukowski", + "title" : "Pulp", + "price" : 22.48 + } + ] + )"; + + std::vector book_list = decode_json>(s); + + std::cout << "(1)\n"; + for (const auto& item : book_list) + { + std::cout << item.author << ", " + << item.title << ", " + << item.price << "\n"; + } + + std::cout << "\n(2)\n"; + encode_json(book_list, std::cout, indenting::indent); + std::cout << "\n\n"; +} +``` +Output: +``` +(1) +Haruki Murakami, Kafka on the Shore, 25.17 +Charles Bukowski, Pulp, 22.48 + +(2) +[ + { + "author": "Haruki Murakami", + "price": 25.17, + "title": "Kafka on the Shore" + }, + { + "author": "Charles Bukowski", + "price": 22.48, + "title": "Pulp" + } +] +``` + +
+ +#### Using JSONCONS_MEMBER_TRAITS_DECL to generate the json_type_traits + +`JSONCONS_MEMBER_TRAITS_DECL` is a macro that can be used to generate the `json_type_traits` boilerplate +for your own types. + +```c++ +#include +#include +#include + +using namespace jsoncons; + +namespace ns { + + struct reputon + { + std::string rater; + std::string assertion; + std::string rated; + double rating; + + friend bool operator==(const reputon& lhs, const reputon& rhs) + { + return lhs.rater == rhs.rater && lhs.assertion == rhs.assertion && + lhs.rated == rhs.rated && lhs.rating == rhs.rating; + } + + friend bool operator!=(const reputon& lhs, const reputon& rhs) + { + return !(lhs == rhs); + }; + }; + + class reputation_object + { + std::string application; + std::vector reputons; + + // Make json_type_traits specializations friends to give accesses to private members + JSONCONS_TYPE_TRAITS_FRIEND; + public: + reputation_object() + { + } + reputation_object(const std::string& application, const std::vector& reputons) + : application(application), reputons(reputons) + {} + + friend bool operator==(const reputation_object& lhs, const reputation_object& rhs) + { + return (lhs.application == rhs.application) && (lhs.reputons == rhs.reputons); + } + + friend bool operator!=(const reputation_object& lhs, const reputation_object& rhs) + { + return !(lhs == rhs); + }; + }; + + +} // namespace ns + +// Declare the traits. Specify which data members need to be serialized. +JSONCONS_MEMBER_TRAITS_DECL(ns::reputon, rater, assertion, rated, rating) +JSONCONS_MEMBER_TRAITS_DECL(ns::reputation_object, application, reputons) + +int main() +{ + ns::reputation_object val("hiking", { ns::reputon{"HikingAsylum.example.com","strong-hiker","Marilyn C",0.90} }); + + std::string s; + encode_json(val, s, indenting::indent); + std::cout << s << "\n"; + + auto val2 = decode_json(s); + + assert(val2 == val); +} +``` +Output: +``` +{ + "application": "hiking", + "reputons": [ + { + "assertion": "strong-hiker", + "rated": "Marilyn C", + "rater": "HikingAsylum.example.com", + "rating": 0.9 + } + ] +} +``` + +
+ +#### A polymorphic example using JSONCONS_GETTER_CTOR_TRAITS_DECL to generate the json_type_traits + +`JSONCONS_GETTER_CTOR_TRAITS_DECL` is a macro that can be used to generate the `json_type_traits` boilerplate +from getter functions and a constructor. + +```c++ +#include +#include +#include +#include + +using namespace jsoncons; + +namespace ns { + +class Employee +{ + std::string firstName_; + std::string lastName_; +public: + Employee(const std::string& firstName, const std::string& lastName) + : firstName_(firstName), lastName_(lastName) + { + } + virtual ~Employee() = default; + + virtual double calculatePay() const = 0; + + const std::string& firstName() const {return firstName_;} + const std::string& lastName() const {return lastName_;} +}; + +class HourlyEmployee : public Employee +{ + double wage_; + unsigned hours_; +public: + HourlyEmployee(const std::string& firstName, const std::string& lastName, + double wage, unsigned hours) + : Employee(firstName, lastName), + wage_(wage), hours_(hours) + { + } + HourlyEmployee(const HourlyEmployee&) = default; + HourlyEmployee(HourlyEmployee&&) = default; + HourlyEmployee& operator=(const HourlyEmployee&) = default; + HourlyEmployee& operator=(HourlyEmployee&&) = default; + + double wage() const {return wage_;} + + unsigned hours() const {return hours_;} + + double calculatePay() const override + { + return wage_*hours_; + } +}; + +class CommissionedEmployee : public Employee +{ + double baseSalary_; + double commission_; + unsigned sales_; +public: + CommissionedEmployee(const std::string& firstName, const std::string& lastName, + double baseSalary, double commission, unsigned sales) + : Employee(firstName, lastName), + baseSalary_(baseSalary), commission_(commission), sales_(sales) + { + } + CommissionedEmployee(const CommissionedEmployee&) = default; + CommissionedEmployee(CommissionedEmployee&&) = default; + CommissionedEmployee& operator=(const CommissionedEmployee&) = default; + CommissionedEmployee& operator=(CommissionedEmployee&&) = default; + + double baseSalary() const + { + return baseSalary_; + } + + double commission() const + { + return commission_; + } + + unsigned sales() const + { + return sales_; + } + + double calculatePay() const override + { + return baseSalary_ + commission_*sales_; + } +}; +} // ns + +JSONCONS_GETTER_CTOR_TRAITS_DECL(ns::HourlyEmployee, firstName, lastName, wage, hours) +JSONCONS_GETTER_CTOR_TRAITS_DECL(ns::CommissionedEmployee, firstName, lastName, baseSalary, commission, sales) + +namespace jsoncons { + +template +struct json_type_traits> +{ + static bool is(const Json& j) noexcept + { + return j.is() || j.is(); + } + static std::shared_ptr as(const Json& j) + { + if (j.at("type").as() == "Hourly") + { + return std::make_shared(j.as()); + } + else if (j.at("type").as() == "Commissioned") + { + return std::make_shared(j.as()); + } + else + { + throw std::runtime_error("Not an employee"); + } + } + static Json to_json(const std::shared_ptr& ptr) + { + if (ns::HourlyEmployee* p = dynamic_cast(ptr.get())) + { + Json j(*p); + j.try_emplace("type","Hourly"); + return j; + } + else if (ns::CommissionedEmployee* p = dynamic_cast(ptr.get())) + { + Json j(*p); + j.try_emplace("type","Commissioned"); + return j; + } + else + { + throw std::runtime_error("Not an employee"); + } + } +}; + +} // jsoncons + +int main() +{ + std::vector> v; + + v.push_back(std::make_shared("John", "Smith", 40.0, 1000)); + v.push_back(std::make_shared("Jane", "Doe", 30000, 0.25, 1000)); + + json j(v); + std::cout << pretty_print(j) << "\n\n"; + + assert(j[0].is()); + assert(!j[0].is()); + assert(!j[1].is()); + assert(j[1].is()); + + + for (size_t i = 0; i < j.size(); ++i) + { + auto p = j[i].as>(); + assert(p->firstName() == v[i]->firstName()); + assert(p->lastName() == v[i]->lastName()); + assert(p->calculatePay() == v[i]->calculatePay()); + } +} +``` +Output: +``` +[ + { + "firstName": "John", + "hours": 1000, + "lastName": "Smith", + "type": "Hourly", + "wage": 40.0 + }, + { + "baseSalary": 30000.0, + "commission": 0.25, + "firstName": "Jane", + "lastName": "Doe", + "sales": 1000, + "type": "Commissioned" + } +] +``` + +
+ +#### Specialize json_type_traits for a container type that the jsoncons library also supports + +```c++ +#include +#include +#include +#include + +//own vector will always be of an even length +struct own_vector : std::vector { using std::vector::vector; }; + +namespace jsoncons { + +template +struct json_type_traits +{ + static bool is(const Json& j) noexcept + { + return j.is_object() && j.size() % 2 == 0; + } + static own_vector as(const Json& j) + { + own_vector v; + for (auto& item : j.object_range()) + { + std::string s(item.key()); + v.push_back(std::strtol(s.c_str(),nullptr,10)); + v.push_back(item.value().template as()); + } + return v; + } + static Json to_json(const own_vector& val){ + Json j; + for(size_t i=0;i +struct is_json_type_traits_declared : public std::true_type +{}; +} // jsoncons + +using jsoncons::json; + +int main() +{ + json j = json::object{ {"1",2},{"3",4} }; + assert(j.is()); + auto v = j.as(); + json j2 = v; + + std::cout << j2 << "\n"; +} +``` +Output: +``` +{"1":2,"3":4} +``` + +
+ +#### Convert JSON to/from boost matrix + +```c++ +#include +#include + +namespace jsoncons { + + template + struct json_type_traits> + { + static bool is(const Json& val) noexcept + { + if (!val.is_array()) + { + return false; + } + if (val.size() > 0) + { + size_t n = val[0].size(); + for (const auto& a: val.array_range()) + { + if (!(a.is_array() && a.size() == n)) + { + return false; + } + for (auto x: a.array_range()) + { + if (!x.template is()) + { + return false; + } + } + } + } + return true; + } + + static boost::numeric::ublas::matrix as(const Json& val) + { + if (val.is_array() && val.size() > 0) + { + size_t m = val.size(); + size_t n = 0; + for (const auto& a : val.array_range()) + { + if (a.size() > n) + { + n = a.size(); + } + } + + boost::numeric::ublas::matrix A(m,n,T()); + for (size_t i = 0; i < m; ++i) + { + const auto& a = val[i]; + for (size_t j = 0; j < a.size(); ++j) + { + A(i,j) = a[j].template as(); + } + } + return A; + } + else + { + boost::numeric::ublas::matrix A; + return A; + } + } + + static Json to_json(const boost::numeric::ublas::matrix& val) + { + Json a = Json::template make_array<2>(val.size1(), val.size2(), T()); + for (size_t i = 0; i < val.size1(); ++i) + { + for (size_t j = 0; j < val.size1(); ++j) + { + a[i][j] = val(i,j); + } + } + return a; + } + }; +} // jsoncons + +using namespace jsoncons; +using boost::numeric::ublas::matrix; + +int main() +{ + matrix A(2, 2); + A(0, 0) = 1.1; + A(0, 1) = 2.1; + A(1, 0) = 3.1; + A(1, 1) = 4.1; + + json a = A; + + std::cout << "(1) " << std::boolalpha << a.is>() << "\n\n"; + + std::cout << "(2) " << std::boolalpha << a.is>() << "\n\n"; + + std::cout << "(3) \n\n" << pretty_print(a) << "\n\n"; + + matrix B = a.as>(); + + std::cout << "(4) \n\n"; + for (size_t i = 0; i < B.size1(); ++i) + { + for (size_t j = 0; j < B.size2(); ++j) + { + if (j > 0) + { + std::cout << ","; + } + std::cout << B(i, j); + } + std::cout << "\n"; + } + std::cout << "\n\n"; +} +``` +Output: +``` +(1) true + +(2) false + +(3) + +[ + [1.1,2.1], + [3.1,4.1] +] + +(4) + +1.1,2.1 +3.1,4.1 +``` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpatch/apply_patch.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpatch/apply_patch.md new file mode 100644 index 0000000000..098bda9985 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpatch/apply_patch.md @@ -0,0 +1,100 @@ +### jsoncons::jsonpatch::apply_patch + +Applies a patch to a `json` document. + +#### Header +```c++ +#include + +template +void apply_patch(Json& target, const Json& patch); // (1) + +template +void apply_patch(Json& target, const Json& patch, std::error_code& ec); // (2) +``` + +#### Return value + +None + +#### Exceptions + +(1) Throws a [jsonpatch_error](jsonpatch_error.md) if `apply_patch` fails. + +(2) Sets the `std::error_code&` to the [jsonpatch_error_category](jsonpatch_errc.md) if `apply_patch` fails. + +### Examples + +#### Apply a JSON Patch with two add operations + +```c++ +#include +#include + +using namespace jsoncons::literals; +namespace jp = jsoncons::jsonpatch; + +int main() +{ + jsoncons::json target = R"( + { "foo": "bar"} + )"_json; + + jsoncons::json patch = R"( + [ + { "op": "add", "path": "/baz", "value": "qux" }, + { "op": "add", "path": "/foo", "value": [ "bar", "baz" ] } + ] + )"_json; + + std::error_code ec; + jp::apply_patch(target,patch,ec); + + std::cout << pretty_print(target) << std::endl; +} +``` +Output: +``` +{ + "baz": "qux", + "foo": ["bar","baz"] +} +``` + +#### Apply a JSON Patch with three add operations, the last one fails + +```c++ +#include +#include + +using namespace jsoncons::literals; +namespace jp = jsoncons::jsonpatch; + +int main() +{ + jsoncons::json target = R"( + { "foo": "bar"} + )"_json; + + jsoncons::json patch = R"( + [ + { "op": "add", "path": "/baz", "value": "qux" }, + { "op": "add", "path": "/foo", "value": [ "bar", "baz" ] }, + { "op": "add", "path": "/baz/bat", "value": "qux" } // nonexistent target + ] + )"_json; + + std::error_code ec; + jp::apply_patch(target, patch, ec); + + std::cout << "(1) " << ec.message() << std::endl; + std::cout << "(2) " << target << std::endl; +} +``` +Output: +``` +(1) JSON Patch add operation failed +(2) {"foo":"bar"} +``` +Note that all JSON Patch operations have been rolled back, and target is in its original state. + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpatch/diagrams/jsonpatch_error.png b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpatch/diagrams/jsonpatch_error.png new file mode 100644 index 0000000000..6bfb6391be Binary files /dev/null and b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpatch/diagrams/jsonpatch_error.png differ diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpatch/diagrams/jsonpatch_error.xml b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpatch/diagrams/jsonpatch_error.xml new file mode 100644 index 0000000000..4d39d6a91e --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpatch/diagrams/jsonpatch_error.xml @@ -0,0 +1 @@ +7Vhdb9owFP01PHZK4kDpI6Uf2xDVOibRPlVWfJt4c2zmGAj79bOJ8x1Kq6KxaSAk7GP72j733HtJemgcp7cSL6KpIMB6nkPSHrrqeZ7reK7+McgmQ5DvZUAoKbGTSmBGf0G+0qJLSiCpTVRCMEUXdTAQnEOgahiWUqzr054Fq++6wCG0gFmAWRudU6KiDB32nRL/CDSM8p1dx47EOJ9sgSTCRKwrELruobEUQmWtOB0DM+TlvGTrbnaMFgeTwNVrFlzffUv55H4WeeOfEzWfxo/p5zNrZYXZ0l44UXr+SH8hDWChqOD2+GqTcyLFkhMwZp0eulxHVMFsgQMzutYq0FikYqZ7rm62j5nvCVJBWoHssW9BxKDkRk+xowPLoJWQmzO6Lh1S0B5VnOFbDFsNhIXlkibdsEy9gbXz3azJJVc0hifQ2pNHZ85z/jbqhi3qWiQBJyMTuboXMJwkNKjzAilVD5ZC03407Q9927tKK0NXm7zD9eEfcgOmU1lluuWybS9ft9MHiVjKAPZrRGEZgtofgUBqeajt0YrH+h0OyzEJDCu6qmevLi/aHb4Iqm9WCMav68VDDR1k17aLqsmmYeeiobthw05GS8vOVlLFpV+lsnA1jbzJ3QP+CuHZ/H4Cqwm8lNaSTaIgPlx8toKxQy474xP5R4zPTua8fzE+G8GzN2Bf0szegD0/xee74xO1VPY9EXyBVRAdIjKfKWNjwbQZsxbB9qPxREnxAyojaIAuEDlMLPcbtXZ47FD2O0l+Ouj/uoNmP//YjPX/2+SH2slvt6ZOye9dyW9wUtkelR31LzBqPG4Wj59vlZnvNgy5f1Zn7afUTzwCSRXm2kueQygOJY5b4tMJXdXlVq+bXHBoFFkLYUZDbjSrlQEavzTlgQaYjexATAkx23QWl3r5OUB9ab44KBxQLTCoQ0ne2wuM7pavcjIPli/E0PVv \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpatch/from_diff.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpatch/from_diff.md new file mode 100644 index 0000000000..edebaed1d3 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpatch/from_diff.md @@ -0,0 +1,72 @@ +### jsoncons::jsonpatch::from_diff + +Create a JSON Patch from a diff of two json documents. + +#### Header +```c++ +#include + +template +Json from_diff(const Json& source, const Json& target) +``` + +#### Return value + +Returns a JSON Patch. + +### Examples + +#### Create a JSON Patch + +```c++ +#include +#include + +using namespace jsoncons::literals; +namespace jp = jsoncons::jsonpatch; + +int main() +{ + jsoncons::json source = R"( + {"/": 9, "foo": "bar"} + )"_json; + + jsoncons::json target = R"( + { "baz":"qux", "foo": [ "bar", "baz" ]} + )"_json; + + auto patch = jp::from_diff(source, target); + + std::error_code ec; + jp::apply_patch(source, patch, ec); + + std::cout << "(1) " << pretty_print(patch) << std::endl; + std::cout << "(2) " << pretty_print(source) << std::endl; +} +``` +Output: +``` +(1) +[ + { + "op": "remove", + "path": "/~1" + }, + { + "op": "replace", + "path": "/foo", + "value": ["bar","baz"] + }, + { + "op": "add", + "path": "/baz", + "value": "qux" + } +] +(2) +{ + "baz": "qux", + "foo": ["bar","baz"] +} +``` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpatch/jsonpatch.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpatch/jsonpatch.md new file mode 100644 index 0000000000..ab528d01a1 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpatch/jsonpatch.md @@ -0,0 +1,87 @@ +### jsonpatch extension + +The jsonpatch extension implements the IETF standard [JavaScript Object Notation (JSON) Patch](https://tools.ietf.org/html/rfc6902) + + + + + + + + + + +
apply_patchApply JSON Patch operations to a JSON document.
from_diffCreate a JSON patch from a diff of two JSON documents.
+ +The JSON Patch IETF standard requires that the JSON Patch method is atomic, so that if any JSON Patch operation results in an error, the target document is unchanged. +The patch function implements this requirement by generating the inverse commands and building an undo stack, which is executed if any part of the patch fails. + +### Examples + +```c++ +#include +#include + +using namespace jsoncons; + +int main() +{ + // Apply a JSON Patch + + json doc = R"( + { "foo": "bar"} + )"_json; + + json doc2 = doc; + + json patch = R"( + [ + { "op": "add", "path": "/baz", "value": "qux" }, + { "op": "add", "path": "/foo", "value": [ "bar", "baz" ] } + ] + )"_json; + + std::error_code ec; + jsonpatch::apply_patch(doc, patch, ec); + + std::cout << "(1)\n" << pretty_print(doc) << std::endl; + + // Create a JSON Patch from two JSON documents + + auto patch2 = jsonpatch::from_diff(doc2,doc); + + std::cout << "(2)\n" << pretty_print(patch2) << std::endl; + + jsonpatch::apply_patch(doc2, patch2, ec); + + std::cout << "(3)\n" << pretty_print(doc2) << std::endl; +} +``` +Output: +``` +(1) +{ + "baz": "qux", + "foo": ["bar","baz"] +} +(2) +[ + { + "op": "replace", + "path": "/foo", + "value": ["bar","baz"] + }, + { + "op": "add", + "path": "/baz", + "value": "qux" + } +] +(3) +{ + "baz": "qux", + "foo": ["bar","baz"] +} +``` + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpatch/jsonpatch_errc.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpatch/jsonpatch_errc.md new file mode 100644 index 0000000000..01e1eb8f9e --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpatch/jsonpatch_errc.md @@ -0,0 +1,25 @@ +### jsoncons::jsonpatch::jsonpatch_errc + +The constant integer values scoped by `jsonpatch_errc` define the values for jsonpatch error codes. + +#### Header + +```c++ +#include +``` + +### Member constants + +constant |Description +---------------------|------------------------------ +`invalid_patch` |Invalid JSON Patch document +`test_failed` |JSON Patch test operation failed +`add_failed` |JSON Patch add operation failed +`remove_failed` |JSON Patch remove operation failed +`replace_failed` |JSON Patch replace operation failed +`move_failed` |JSON Patch move operation failed +`copy_failed` |JSON Patch copy operation failed + + + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpatch/jsonpatch_error.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpatch/jsonpatch_error.md new file mode 100644 index 0000000000..19b7b36b35 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpatch/jsonpatch_error.md @@ -0,0 +1,65 @@ +### jsoncons::jsonpatch::jsonpatch_error + +#### Header + + #include + +`jsoncons::jsonpatch::jsonpatch_error` defines an exception type for reporting failures in jsonpatch operations. + +![jsonpatch_error](./diagrams/jsonpatch_error.png) + +#### Constructors + + jsonpatch_error(std::error_code ec) + + jsonpatch_error(const jsonpatch_error& other) + +#### Member functions + + const char* what() const noexcept +Returns a message for this exception + +#### Inherited from std::system_error + + const std::error_code code() const noexcept +Returns an error code for this exception + +### Example + +```c++ +#include +#include + +using jsoncons::json; + +int main() +{ + json target = R"( + { "foo": "bar"} + )"_json; + + json patch = R"( + [ + { "op": "add", "path": "/baz", "value": "qux" }, + { "op": "add", "path": "/foo", "value": [ "bar", "baz" ] }, + { "op": "add", "path": "/baz/bat", "value": "qux" } // nonexistent target + ] + )"_json; + + try + { + jsonpatch::apply_patch(target, patch); + } + catch (const jsonpatch::jsonpatch_error& e) + { + std::cout << "(1) " << e.what() << std::endl; + std::cout << "(2) " << target << std::endl; + } +} +``` + +Output: +``` +(1) JSON Patch add operation failed +(2) {"foo":"bar"} +``` diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpath/diagrams/jsonpath_error.png b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpath/diagrams/jsonpath_error.png new file mode 100644 index 0000000000..aa314a1f4d Binary files /dev/null and b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpath/diagrams/jsonpath_error.png differ diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpath/diagrams/jsonpath_error.xml b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpath/diagrams/jsonpath_error.xml new file mode 100644 index 0000000000..e3bac0fc06 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpath/diagrams/jsonpath_error.xml @@ -0,0 +1 @@ +7Vhdb9owFP01PHZK4kDpI6Uf2xDVOibRPlVWfJt4c2zmGAj79bOJ8x1Kq6KxaVRItY/ta/vcc+9N0kPjOL2VeBFNBQHW8xyS9tBVz/Ncx3P1P4NsMgT5XgaEkhI7qQRm9BfkKy26pASS2kQlBFN0UQcDwTkEqoZhKcW6Pu1ZsPquCxxCC5gFmLXROSUqytBh3ynxj0DDKN/ZdexIjPPJFkgiTMS6AqHrHhpLIVTWitMxMENezku27mbHaHEwCVy9ZsH13beUT+5nkTf+OVHzafyYfj6zVlaYLe2FE6Xnj/QP0gAWigpuj682OSdSLDkBY9bpoct1RBXMFjgwo2utAo1FKma65+pm+5j5niAVpBXIHvsWRAxKbvQUOzqwDFoJuTmj69IhBe1RxRm+xbDVQFhYLmnSDcvUG1g7382aXHJFY3gCrT15dOY852+jbtiirkUScDIykat7AcNJQoM6L5BS9WApNO1H0/7Qt72rtDJ0tck7XB/+ITdgOpVVplsu2/bydTt9kIilDGC/RhSWIaj9EQiklofaHq14rN/hsByTwLCiq3r26vKi3eGLoPpmhWD8ul481NBBdm27qJpsGnYuGrobNuxktLTsbCVVXPpVKgtX08ib3D3grxCeze8nsJrAS2kt2SQK4sPFZysYO+SyMz6Rf8T47GTO+xfjsxE8ewP2Jc3sDdjzU3y+Oz5RS2XfE8EX+pHpEIH5TBkbC6bNmLUItn8aT5QUP6AyggboApHDhHK/UWqHx45kv5Pjp4M+1h00+fnHZqz/3+Y+1M59uzV1yn3vyn2Dk8r2qOyoT8Co8bZZvH2+VWa+2zDk/lmdtV9SP/EIJFWYay95DqE4lDhuiU8ndFWXW71ucsGhUWQthBkNudGsVgZo/NKUBxpgNrIDMSXEbNNZXOrl5wD1pfndoHBAtcCgDiV5by8wult+yck8WH4PQ9e/AQ== \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpath/json_query.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpath/json_query.md new file mode 100644 index 0000000000..18ea519aaa --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpath/json_query.md @@ -0,0 +1,356 @@ +### jsoncons::jsonpath::json_query + +Returns a `json` array of values or normalized path expressions selected from a root `json` structure. + +#### Header +```c++ +#include + +enum class result_type {value,path}; + +template +Json json_query(const Json& root, + const typename Json::string_view_type& path, + result_type result_t = result_type::value); +``` +#### Parameters + + + + + + + + + + + + + + +
rootJSON value
pathJSONPath expression string
result_tIndicates whether results are matching values (the default) or normalized path expressions
+ +#### Return value + +Returns a `json` array containing either values or normalized path expressions matching the input path expression. +Returns an empty array if there is no match. + +#### Exceptions + +Throws [jsonpath_error](jsonpath_error.md) if JSONPath evaluation fails. + +#### Note +Stefan Goessner's javascript implemention returns `false` in case of no match, but in a note he suggests an alternative is to return an empty array. The `jsoncons` implementation takes that alternative and returns an empty array in case of no match. +#### + +### Store examples + +The examples below use the JSON text from [Stefan Goessner's JSONPath](http://goessner.net/articles/JsonPath/) (booklist.json). + +```json +{ "store": { + "book": [ + { "category": "reference", + "author": "Nigel Rees", + "title": "Sayings of the Century", + "price": 8.95 + }, + { "category": "fiction", + "author": "Evelyn Waugh", + "title": "Sword of Honour", + "price": 12.99 + }, + { "category": "fiction", + "author": "Herman Melville", + "title": "Moby Dick", + "isbn": "0-553-21311-3", + "price": 8.99 + }, + { "category": "fiction", + "author": "J. R. R. Tolkien", + "title": "The Lord of the Rings", + "isbn": "0-395-19395-8", + "price": 22.99 + } + ], + "bicycle": { + "color": "red", + "price": 19.95 + } + } +} +``` + +#### Return values + +```c++ +#include +#include +#include + +using namespace jsoncons; + +int main() +{ + std::ifstream is("./input/booklist.json"); + json booklist = json::parse(is); + + // The authors of books that are cheaper than $10 + json result1 = jsonpath::json_query(booklist, "$.store.book[?(@.price < 10)].author"); + std::cout << "(1) " << result1 << "\n"; + + // The number of books + json result2 = jsonpath::json_query(booklist, "$..book.length"); + std::cout << "(2) " << result2 << "\n"; + + // The third book + json result3 = jsonpath::json_query(booklist, "$..book[2]"); + std::cout << "(3)\n" << pretty_print(result3) << "\n"; + + // All books whose author's name starts with Evelyn + json result4 = jsonpath::json_query(booklist, "$.store.book[?(@.author =~ /Evelyn.*?/)]"); + std::cout << "(4)\n" << pretty_print(result4) << "\n"; + + // The titles of all books that have isbn number + json result5 = jsonpath::json_query(booklist, "$..book[?(@.isbn)].title"); + std::cout << "(5) " << result5 << "\n"; + + // All authors and titles of books + json result6 = jsonpath::json_query(booklist, "$['store']['book']..['author','title']"); + std::cout << "(6)\n" << pretty_print(result6) << "\n"; + + // Union of two ranges of book titles + json result7 = jsonpath::json_query(booklist, "$..book[1:2,2:4].title"); + std::cout << "(7)\n" << pretty_print(result7) << "\n"; + + // Union of a subset of book titles identified by index + json result8 = jsonpath::json_query(booklist, "$.store[book[0].title,book[1].title,book[3].title]"); + std::cout << "(8)\n" << pretty_print(result8) << "\n"; + + // Union of third book title and all book titles with price > 10 + json result9 = jsonpath::json_query(booklist, "$.store[book[3].title,book[?(@.price > 10)].title]"); + std::cout << "(9)\n" << pretty_print(result9) << "\n"; + + // Intersection of book titles with category fiction and price < 15 + json result10 = jsonpath::json_query(booklist, "$.store.book[?(@.category == 'fiction')][?(@.price < 15)].title"); + std::cout << "(10)\n" << pretty_print(result10) << "\n"; + + // Normalized path expressions + json result11 = jsonpath::json_query(booklist, "$.store.book[?(@.author =~ /Evelyn.*?/)]", jsonpath::result_type::path); + std::cout << "(11)\n" << pretty_print(result11) << "\n"; + + // All titles whose author's second name is 'Waugh' + json result12 = jsonpath::json_query(booklist,"$.store.book[?(tokenize(@.author,'\\\\s+')[1] == 'Waugh')].title"); + std::cout << "(12)\n" << result12 << "\n"; + + // All keys in the second book + json result13 = jsonpath::json_query(booklist,"keys($.store.book[1])[*]"); + std::cout << "(13)\n" << result13 << "\n"; +} +``` +Output: +``` +(1) [[1,2,3,4],[3,4,5,6]] +(2) [[1,2,3,4]] +(3) [[1,2,3,4],[3,4,5,6]] +["John","Nara"] +(1) ["Nigel Rees","Herman Melville"] +(2) [4] +(3) +[ + { + "author": "Herman Melville", + "category": "fiction", + "isbn": "0-553-21311-3", + "price": 8.99, + "title": "Moby Dick" + } +] +(4) +[ + { + "author": "Evelyn Waugh", + "category": "fiction", + "price": 12.99, + "title": "Sword of Honour" + } +] +(5) ["Moby Dick","The Lord of the Rings"] +(6) +[ + "Evelyn Waugh", + "Herman Melville", + "J. R. R. Tolkien", + "Moby Dick", + "Nigel Rees", + "Sayings of the Century", + "Sword of Honour", + "The Lord of the Rings" +] +(7) +[ + "Sword of Honour", + "Moby Dick", + "The Lord of the Rings" +] +(8) +[ + "Sayings of the Century", + "Sword of Honour", + "The Lord of the Rings" +] +(9) +[ + "Sword of Honour", + "The Lord of the Rings" +] +(10) +[ + "Sword of Honour", + "Moby Dick" +] +(11) +[ + "$['store']['book'][1]" +] +(12) +["Sword of Honour"] +(13) +["author","category","price","title"] +``` + +#### Return normalized path expressions + +```c++ +using namespace jsoncons; + +int main() +{ + std::string path = "$.store.book[?(@.price < 10)].title"; + json result = jsonpath::json_query(store,path,result_type::path); + + std::cout << pretty_print(result) << std::endl; +} +``` +Output: +```json +[ + "$['store']['book'][0]['title']", + "$['store']['book'][2]['title']" +] +``` + +### More examples + +```c++ +#include +#include + +using namespace jsoncons; + +int main() +{ + const json j = json::parse(R"( + [ + { + "root": { + "id" : 10, + "second": [ + { + "names": [ + 2 + ], + "complex": [ + { + "names": [ + 1 + ], + "panels": [ + { + "result": [ + 1 + ] + }, + { + "result": [ + 1, + 2, + 3, + 4 + ] + }, + { + "result": [ + 1 + ] + } + ] + } + ] + } + ] + } + }, + { + "root": { + "id" : 20, + "second": [ + { + "names": [ + 2 + ], + "complex": [ + { + "names": [ + 1 + ], + "panels": [ + { + "result": [ + 1 + ] + }, + { + "result": [ + 3, + 4, + 5, + 6 + ] + }, + { + "result": [ + 1 + ] + } + ] + } + ] + } + ] + } + } + ] + )"); + + // Find all arrays of elements where result.length is 4 + json result1 = jsonpath::json_query(j,"$..[?(@.result.length == 4)].result"); + std::cout << "(1) " << result1 << std::endl; + + // Find array of elements that has id 10 and result.length is 4 + json result2 = jsonpath::json_query(j,"$..[?(@.id == 10)]..[?(@.result.length == 4)].result"); + std::cout << "(2) " << result2 << std::endl; + + // Find all arrays of elements where result.length is 4 and that have value 3 + json result3 = jsonpath::json_query(j,"$..[?(@.result.length == 4 && (@.result[0] == 3 || @.result[1] == 3 || @.result[2] == 3 || @.result[3] == 3))].result"); + std::cout << "(3) " << result3 << std::endl; +} +``` +Output: + +``` +(1) [[1,2,3,4],[3,4,5,6]] +(2) [[1,2,3,4]] +(3) [[1,2,3,4],[3,4,5,6]] +``` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpath/json_replace.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpath/json_replace.md new file mode 100644 index 0000000000..4c4beba4ad --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpath/json_replace.md @@ -0,0 +1,112 @@ +### jsoncons::jsonpath::json_replace + +Searches for all values that match a JSONPath expression and replaces them with the specified value + +#### Header +```c++ +#include +``` + +```c++ +template +void json_replace(Json& root, + const typename Json::string_view_type& path, + T&& new_value) +``` +#### Parameters + + + + + + + + + + + + + + +
rootJSON value
pathJSONPath expression string
new_valueThe value to use as replacement
+ +#### Exceptions + +Throws [jsonpath_error](jsonpath_error.md) if JSONPath evaluation fails. + +### Examples + +#### Change the price of a book + +Example file (booklist.json): +```json +{ "store": { + "book": [ + { "category": "reference", + "author": "Nigel Rees", + "title": "Sayings of the Century", + "price": 8.95 + }, + { "category": "fiction", + "author": "Evelyn Waugh", + "title": "Sword of Honour", + "price": 12.99 + }, + { "category": "fiction", + "author": "Herman Melville", + "title": "Moby Dick", + "isbn": "0-553-21311-3", + "price": 8.99 + } + ] + } +} +``` +```c++ +#include +#include + +using namespace jsoncons; +using namespace jsoncons::jsonpath; + +int main() +{ + std::ifstream is("input/booklist.json"); + json booklist; + is >> booklist; + + // Change the price of "Moby Dick" + json_replace(booklist,"$.store.book[?(@.isbn == '0-553-21311-3')].price",10.0); + std::cout << pretty_print(booklist) << std::endl; + +} +``` +Output: +```json +{ + "store": { + "book": [ + { + "author": "Nigel Rees", + "category": "reference", + "price": 8.95, + "title": "Sayings of the Century" + }, + { + "author": "Evelyn Waugh", + "category": "fiction", + "price": 12.99, + "title": "Sword of Honour" + }, + { + "author": "Herman Melville", + "category": "fiction", + "isbn": "0-553-21311-3", + "price": 10.0, + "title": "Moby Dick" + } + ] + } +} +``` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpath/jsoncons-jsonpath-abnf.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpath/jsoncons-jsonpath-abnf.md new file mode 100644 index 0000000000..af151146ff --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpath/jsoncons-jsonpath-abnf.md @@ -0,0 +1,48 @@ +``` +Path = AbsolutePath / RelativePath + +AbsolutePath = Root S *AdditionalElements + +Root = "$" + +RelativePath = S NameOrWildcard S *AdditionalElements + +NameOrWildcard = Name / Wildcard + +S = *( WSP / CR / LF ) + +AdditionalElements = (("." / "..") NameOrWildcard) / Predicate + +Predicate = "[" S Expr S "]" + +Name = UnquotedName / SingleQuotedName / DoubleQuotedName + +Expr = RelativePath / Slice / Union / Filter + +Wildcard = "*" + +Name = UnquotedName / SingleQuotedName / DoubleQuotedName + +UnquotedName = UnquotedNameCharacter *AdditionalUnquotedNameCharacter + +SingleQuotedName = "'" *SingleQuotedNameCharacter "'" + +DoubleQuotedName = '"' *DoubleQuotedNameCharacter '"' + +UnquotedNameCharacter = ? any unicode character except *, spaces, '.' and '[' ? + +AdditionalUnquotedNameCharacter = ? any unicode character except spaces, '.' and '[' ? + +SingleQuotedNameCharacter = ? any unicode character except an unescaped "'" (single quote) ? + +DoubleQuotedNameCharacter = ? any unicode character except an unescaped '"' (double quote) ? + +Slice = [ SignedInteger ] ":" [ SignedInteger ] [ ":" [ NonZeroSignedInteger ] ] + +Filter = "?(" FilterExpr ")" + +Union = RelativePathOrFilter / "," RelativePathOrFilter *("," RelativePathOrFilter) + +RelativePathOrFilter = RelativePath / Filter +``` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpath/jsonpath.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpath/jsonpath.md new file mode 100644 index 0000000000..995894243d --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpath/jsonpath.md @@ -0,0 +1,225 @@ +### jsonpath extension + +The jsonpath extension implements [Stefan Goessner's JSONPath](http://goessner.net/articles/JsonPath/). +It provides functions for search and "search and replace" using JSONPath expressions: + +[json_query](json_query.md) + +[json_replace](json_replace.md) + +### Stefan Goessner's JSONPath + +[JSONPath](http://goessner.net/articles/JsonPath/), a loosely standardized syntax for querying JSON, is a creation of Stefan Goessner. +JSONPath expressions refer to a JSON text in the same way as XPath expressions refer to an XML document. + +The [Jayway JSONPath Evaluator](https://jsonpath.herokuapp.com/) and [JSONPATH Expression Tester](https://jsonpath.curiousconcept.com/) +are good online evaluators for checking JSONPath expressions. + +### jsoncons JSONPath + +The jsoncons implementation follows these [ABNF rules](jsoncons-jsonpath-abnf.md). + +#### Differences with Stefan Goessner's implementation + +- Stefan Goessner's implemention returns `false` in case of no match, but in a note he suggests an alternative is to return an empty array. + The `jsoncons` implementation takes that alternative and returns an empty array in case of no match. +- Names in both the dot notation and the bracket notation may be unquoted (no spaces), single-quoted, or double-quoted. +- Wildcards are allowed in the dot notation +- Unions produce real unions with no duplicates instead of concatenated results +- Union of completely separate paths are allowed, e.g. + + $..[firstName,address.city] + +#### Paths + +JSONPath uses paths to select a set of nodes in a JSON value. Paths can use the dot-notation or the bracket-notation. + +Select the first (indexed 0) book using the dot notation: + + $.store.book.0 + +or + + $. store . book . 0 + +or + + store.book.0 + +or + + $.'store'.'book'.0 + +or + + $."store"."book".0 + +The leading `$` represents the root JSON value. The jsoncons implementation +allows the `$.` to be omitted, and allows single and double quoted as well as +unquoted names. Unquoted names must not contain spaces, and spaces before +and after the name are ignored. + +Select the first (indexed 0) book using the bracket-notation: + + $[store][book][0] + +or + + $['store']['book'][0] + +or + + $["store"]["book"][0] + +Recursively select all book titles under `'$.store'`: + + $.'store'..'title' + +Union of a subset of books identified by index: + + $.store[book[0],book[1],book[3]] + +Union of the fourth book and all books with price > 10: + + $.store[book[3],book[?(@.price > 10)]] + +JSONPath| Description +--------|-------------------------------- +`$`| Represents the root JSON value +`@`| Represents the current node being processed by a filter predicate. +`.` or `[]`| Child operator +`..` |Recursive descent. JSONPath borrows this syntax from [E4X](https://en.wikipedia.org/wiki/ECMAScript_for_XML). +`*` | Wildcard. All objects/elements regardless their names. +`[]` |Subscript operator. +`[,]` |Union. +`[start:end:step]` |Array slice operator borrowed from [ES4](http://wiki.ecmascript.org/doku.php?id=proposals:slice_syntax&s=array+slice). +`()` |Filter expression. +`?()` |Applies a filter expression. + +#### Filter predicates + +JSONPath uses filter predicates to restrict the set of nodes returned by a path. + +[Stefan Goessner's JSONPath](http://goessner.net/articles/JsonPath/) does not provide any specification for the allowable filter expressions, simply stating that expressions can be anything that the underlying script engine can handle. `jsoncons` expressions support the following comparision and arithmetic operators. + +Operator| Description +--------|-------------------------------- +`*` |Left times right +`/` |Left divided by right +`+` |Left plus right +`-` |Left minus right +`&&` |Left and right +|| |Left or right +`==` |Left is equal to right +`!=` |Left is not equal to right +`<` |Left is less than right +`<=` |Left is less or equal to right +`>` |Left is greater than right +`>=` |Left is greater than or equal to right +'=~' |Left matches regular expression [?(@.author =~ /Evelyn.*?/)] + +Unary operators + +Operator| Description +--------|-------------------------------- +`!` |Not right +`-` |Negates right + +Operator precedence + +Precedence|Operator|Associativity +----------|--------|----------- +1 |`!` unary `-` |Right +2 |`=~` |Left +3 |`*` `/` |Left +4 |`+` `-` |Left +5 |`<` `>` `<=` `>=`|Left +6 |`==` `!=` |Left +7 |`&&` |Left +8 ||| |Left + +#### Functions + +Support for functions is a jsoncons extension. + +Functions can be passed JSONPath paths and JSON expressions. +Outside a filter predicate, functions can be passed paths that select from +the root JSON value `$`. Within a filter predicate, functions can be passed either a +path that selects from the root JSON value `$`, or a path that selects from the current node `@`. + +Function|Description|Result|Example +----------|--------|-------|--- +`max(array)`|Returns the maximum value of an array of numbers|`double`|`max($.store.book[*].price)` +`min(array)`|Returns the minimum value of an array of numbers|`double`|`min($.store.book[*].price)` +`count(array)`|Returns the number of items in an array|`uint64_t`|`count($.store.book[*])` +`sum(array)`|Returns the sum value of an array of numbers|`double`|`$.store.book[?(@.price > sum($.store.book[*].price) / count($.store.book[*]))].title` +`avg(array)`|Returns the arithmetic average of each item of an array of numbers. If the input is an empty array, returns `null`.|`double`|`$.store.book[?(@.price > avg($.store.book[*].price))].title` +`prod(array)`|Returns the product of the elements in an array of numbers.|`double`|`$.store.book[?(479373 < prod($..price) && prod($..price) < 479374)].title` +`keys(object)`|Returns an array of keys.|`array of string`|`keys($.store.book[0])[*]` +`tokenize(string,pattern)`|Returns an array of strings formed by splitting the input string into an array of strings, separated by substrings that match the regular expression `pattern`.|`array of string`|`$.store.book[?(tokenize(@.author,'\\s+')[1] == 'Waugh')].title` + +### Examples + +The examples below use the JSON text from [Stefan Goessner's JSONPath](http://goessner.net/articles/JsonPath/) (booklist.json). + +```json +{ "store": { + "book": [ + { "category": "reference", + "author": "Nigel Rees", + "title": "Sayings of the Century", + "price": 8.95 + }, + { "category": "fiction", + "author": "Evelyn Waugh", + "title": "Sword of Honour", + "price": 12.99 + }, + { "category": "fiction", + "author": "Herman Melville", + "title": "Moby Dick", + "isbn": "0-553-21311-3", + "price": 8.99 + }, + { "category": "fiction", + "author": "J. R. R. Tolkien", + "title": "The Lord of the Rings", + "isbn": "0-395-19395-8", + "price": 22.99 + } + ], + "bicycle": { + "color": "red", + "price": 19.95 + } + } +} +``` + +JSONPath |Result|Notes +---------|--------------------------------------------------------|------ +`$..book.length` |The number of books|`length` is a property of an array +`$.store.*` |Everything in the store, including books and a bicycle.|`*` is a wildcard symbol +`$..author` |All authors|Recursive descent starting from root ($) to find all authors +`$.store.book[*].author` |All authors of books in the store| +`$.store..price` |The prices of everything in the store.| +`$..book[2]` |The third book|Indices start at `0` +`$..book.2` |The third book|Using the dot notation +`$..book[(@.length-1)]` |The last book in order.|Expressions () can be used as an alternative to explicit names or indices +`$..book[-1:]` |The last book in order.|A negative `start` becomes `start` + `length`. A missing `end` defaults to `length`. +`$..book[0,1]` |The first two books +`$..book[:2]` |All books from index 0 (inclusive) to index 2 (exclusive)|`start` defaults to 0 +`$..book[1:2]` |All books from index 1 (inclusive) to index 2 (exclusive) +`$..book[-2:]` |Last two books|The start index `-2` becomes `-2+4=2`, `end` defaults to `length` (`4`). +`$..book[2:]` |Last two books|`end` defaults to `length` +`$..book[?(@.isbn)]` |All books that have isbn number +`$..book[?(@.price<10)]` |All books that are cheaper than $10 +`$..*` |Everything in the store. +`$.store.book[ ?((@.author == 'Nigel Rees')` || (@.author == 'Evelyn Waugh')) ].title`|The titles of all books by Nigel Rees and Evelyn Waugh +`$.store.book[?(@.author =~ /Evelyn.*?/)]`|All books whose author's name starts with Evelyn +`$.store.book[?((@.author =~ /evelyn.*?/i))]`|All books whose author's name starts with Evelyn, evelyn etc.|`i` indicates case insensitive +`$.store.book[?(!(@.author =~ /Evelyn.*?/))]`|All books whose author's name does not start with Evelyn +`$['store']['book']..['author','title']`|All authors and titles of books in the store +`$.store.book[?(@.price < max($.store.book[*].price))].title`|The titles of all books that are priced less than the most expensive book in the store +`$.store.book[?(@.price > min($.store.book[*].price))].title`|The titles of all books that are priced higher than the cheapest book in the store + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpath/jsonpath_error.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpath/jsonpath_error.md new file mode 100644 index 0000000000..916802be57 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpath/jsonpath_error.md @@ -0,0 +1,39 @@ +### jsoncons::jsonpath_error + +#### Header + + #include + +`jsoncons::jsonpath::jsonpath_error` defines an exception type for reporting failures in jsonpath queries. + +![jsonpath_error](./diagrams/jsonpath_error.png) + +#### Constructors + + jsonpath_error(std::error_code ec); + + jsonpath_error(std::error_code ec, size_t line, size_t column); + + jsonpath_error(const jsonpath_error& other); + +#### Member functions + + size_t line() const noexcept +Returns the line number to the end of the text where the exception occurred. +Line numbers start at 1. + + size_t column() const noexcept +Returns the column number to the end of the text where the exception occurred. +Column numbers start at 1. + + const char* what() const noexcept +Constructs an error message, including line and column position + +#### Inherited from std::system_error + + const std::error_code code() const noexcept +Returns an error code for this exception + +### Example + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/address.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/address.md new file mode 100644 index 0000000000..a5cd00cf36 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/address.md @@ -0,0 +1,206 @@ +### jsoncons::jsonpointer::basic_address + +``` +template +class basic_address +``` +#### Header +```c++ +#include +``` + +Two specializations for common character types are defined: + +Type |Definition +----------|------------------------------ +path |`basic_address` +wpath |`basic_address` + +Objects of type `basic_address` represent JSON Pointer strings. + +Addreses are implicitly convertible to string views, +which makes it possible to use them with `jsonpointer::get`, +`jsonpointer::insert_or_assign` etc, which expect string views. + +#### Member types +Type |Definition +------------|------------------------------ +char_type | `CharT` +string_type | `std::basic_string` +string_view_type | `jsoncons::basic_string_view` +const_iterator | A constant [LegacyInputIterator](https://en.cppreference.com/w/cpp/named_req/InputIterator) with a `value_type` of `std::basic_string` +iterator | An alias to `const_iterator` + +#### Header +```c++ +#include +``` + +#### Constructors + + basic_address(); +Constructs an address with an empty string, which points to the root of a json document. + + explicit basic_address(const string_type& s); + explicit basic_address(string_type&& s); + explicit basic_address(const CharT* s); +Constructs an address from a JSON Pointer string + + basic_address(const basic_address&); + + basic_address(basic_address&&); + +#### operator= + + basic_address& operator=(const basic_address&); + + basic_address& operator=(basic_address&&); + +#### Modifiers + + basic_address& operator/=(const string_type& s) +First, appends the JSON Pointer separator `/` to the path. Then appends the string token s, escaping any `/` or `~` characters. + + basic_address& operator+=(const basic_address& p) +Concatenates the current path and the specified path `p`. + +#### Iterators + + iterator begin() const; + iterator end() const; +Iterator access to the tokens in the path. + +#### Accessors + + bool empty() const +Checks if the path is empty + + const string_type& string() const +Returns the string representation of the JSON Pointer by reference. + + operator string_view_type() const; +Returns a string view representation of the JSON Pointer. + +#### Non-member functions + basic_address operator/(const basic_address& lhs, const string_type& rhs); +Concatenates a JSON Pointer path and a token. Effectively returns basic_address(lhs) /= rhs. + + basic_address operator+( const basic_address& lhs, const basic_address& rhs ); +Concatenates two JSON Pointer addresses. Effectively returns basic_address(lhs) += rhs. + + bool operator==(const basic_address& lhs, const basic_address& rhs); + + bool operator!=(const basic_address& lhs, const basic_address& rhs); + + std::basic_ostream& + operator<<(std::basic_ostream& os, const basic_address& p); +Performs stream output + +### Examples + +#### Iterate over the tokens in a JSON Pointer + +```c++ +#include +#include + +namespace jp = jsoncons::jsonpointer; + +int main() +{ + jp::address addr("/store/book/1/author"); + + std::cout << "(1) " << addr << "\n\n"; + + std::cout << "(2)\n"; + for (const auto& token : addr) + { + std::cout << token << "\n"; + } + + std::cout << "\n"; +} +``` +Output: +``` +(1) /store/book/1/author + +(2) +store +book +1 +author +``` + +#### Append tokens to a JSON Pointer + +```c++ +#include +#include + +namespace jp = jsoncons::jsonpointer; + +int main() +{ + jp::address addr; + + addr /= "a/b"; + addr /= ""; + addr /= "m~n"; + + std::cout << "(1) " << addr << "\n\n"; + + std::cout << "(2)\n"; + for (const auto& token : addr) + { + std::cout << token << "\n"; + } + + std::cout << "\n"; +} +``` +Output: +``` +(1) /a~1b//m~0n + +(2) +a/b + +m~n +``` + +#### Concatentate two JSON Pointers + +```c++ +#include +#include + +namespace jp = jsoncons::jsonpointer; + +int main() +{ + jp::address addr("/a~1b"); + + addr += jp::address("//m~0n"); + + std::cout << "(1) " << addr << "\n\n"; + + std::cout << "(2)\n"; + for (const auto& token : addr) + { + std::cout << token << "\n"; + } + + std::cout << "\n"; +} +``` +Output: +``` +(1) /a~1b//m~0n + +(2) +a/b + +m~n +``` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/address.md.orig b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/address.md.orig new file mode 100644 index 0000000000..eb9a6ec364 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/address.md.orig @@ -0,0 +1,275 @@ +<<<<<<< HEAD:doc/ref/jsonpointer/address.md +### jsoncons::jsonpointer::basic_address + +``` +template +class basic_address +======= +### jsoncons::jsonpointer::address + +``` +template +class address +>>>>>>> efc18942efb17086d3de2d1d853d56a11666ebb0:doc/ref/jsonpointer/address.md +``` +#### Header +```c++ +#include +``` + +<<<<<<< HEAD:doc/ref/jsonpointer/address.md +Two specializations for common character types are defined: + +Type |Definition +----------|------------------------------ +path |`basic_address` +wpath |`basic_address` + +Objects of type `basic_address` represent JSON Pointer strings. + +Addreses are implicitly convertible to string views, +which makes it possible to use them with `jsonpointer::get`, +`jsonpointer::insert_or_assign` etc, which expect string views. +======= +Objects of type `address` represent JSON Pointer addresses. +>>>>>>> efc18942efb17086d3de2d1d853d56a11666ebb0:doc/ref/jsonpointer/address.md + +#### Member types +Type |Definition +------------|------------------------------ +char_type | `CharT` +string_type | `std::basic_string` +string_view_type | `jsoncons::basic_string_view` +const_iterator | A constant [LegacyInputIterator](https://en.cppreference.com/w/cpp/named_req/InputIterator) with a `value_type` of `std::basic_string` +iterator | An alias to `const_iterator` + +#### Header +```c++ +#include +``` + +#### Constructors + +<<<<<<< HEAD:doc/ref/jsonpointer/address.md + basic_address(); +Constructs an address with an empty string, which points to the root of a json document. + + explicit basic_address(const string_type& s); + explicit basic_address(string_type&& s); + explicit basic_address(const CharT* s); +Constructs an address from a JSON Pointer string + + basic_address(const basic_address&); + + basic_address(basic_address&&); + +#### operator= + + basic_address& operator=(const basic_address&); + + basic_address& operator=(basic_address&&); + +#### Modifiers + + basic_address& operator/=(const string_type& s) +First, appends the JSON Pointer separator `/` to the path. Then appends the string token s, escaping any `/` or `~` characters. + + basic_address& operator+=(const basic_address& p) +Concatenates the current path and the specified path `p`. +======= + address(); + + explicit address(const string_type& s); + + explicit address(string_type&& s); + + explicit address(const CharT* s); + + address(const address&); + + address(address&&); + +#### operator= + + address& operator=(const address&); + + address& operator=(address&&); + +#### Modifiers + + address& operator/=(const string_type& s) +First, appends the JSON Pointer separator `/` to the path. Then appends the string token s, escaping any `/` or `~` characters. + + address& operator+=(const address& p) +Concatenates the current address and the specified address `p`. +>>>>>>> efc18942efb17086d3de2d1d853d56a11666ebb0:doc/ref/jsonpointer/address.md + +#### Iterators + + iterator begin() const; + iterator end() const; +Iterator access to the tokens in the path. + +#### Accessors + + bool empty() const +Checks if the address is empty + + const string_type& string() const +Returns the string representation of the JSON Pointer by reference. + + operator string_view_type() const; +Returns a string view representation of the JSON Pointer. + +#### Non-member functions +<<<<<<< HEAD:doc/ref/jsonpointer/address.md + basic_address operator/(const basic_address& lhs, const string_type& rhs); +Concatenates a JSON Pointer path and a token. Effectively returns basic_address(lhs) /= rhs. + + basic_address operator+( const basic_address& lhs, const basic_address& rhs ); +Concatenates two JSON Pointer addresses. Effectively returns basic_address(lhs) += rhs. + + bool operator==(const basic_address& lhs, const basic_address& rhs); + + bool operator!=(const basic_address& lhs, const basic_address& rhs); + + std::basic_ostream& + operator<<(std::basic_ostream& os, const basic_address& p); +======= + address operator/(const address& lhs, const string_type& rhs); +Concatenates a JSON Pointer address and a token. Effectively returns address(lhs) /= rhs. + + address operator+( const address& lhs, const address& rhs ); +Concatenates two JSON Pointer paths. Effectively returns address(lhs) += rhs. + + bool operator==(const address& lhs, const address& rhs); + + bool operator!=(const address& lhs, const address& rhs); + + std::ostream& + operator<<(std::ostream& os, const address& p); +>>>>>>> efc18942efb17086d3de2d1d853d56a11666ebb0:doc/ref/jsonpointer/address.md +Performs stream output + +### Examples + +#### Iterate over the tokens in a JSON Pointer + +```c++ +#include +#include + +namespace jp = jsoncons::jsonpointer; + +int main() +{ +<<<<<<< HEAD:doc/ref/jsonpointer/address.md + jp::address addr("/store/book/1/author"); +======= + jp::address p("/store/book/1/author"); +>>>>>>> efc18942efb17086d3de2d1d853d56a11666ebb0:doc/ref/jsonpointer/address.md + + std::cout << "(1) " << addr << "\n\n"; + + std::cout << "(2)\n"; + for (const auto& token : addr) + { + std::cout << token << "\n"; + } + + std::cout << "\n"; +} +``` +Output: +``` +(1) /store/book/1/author + +(2) +store +book +1 +author +``` + +#### Append tokens to a JSON Pointer + +```c++ +#include +#include + +namespace jp = jsoncons::jsonpointer; + +int main() +{ +<<<<<<< HEAD:doc/ref/jsonpointer/address.md + jp::address addr; +======= + jp::address p; +>>>>>>> efc18942efb17086d3de2d1d853d56a11666ebb0:doc/ref/jsonpointer/address.md + + addr /= "a/b"; + addr /= ""; + addr /= "m~n"; + + std::cout << "(1) " << addr << "\n\n"; + + std::cout << "(2)\n"; + for (const auto& token : addr) + { + std::cout << token << "\n"; + } + + std::cout << "\n"; +} +``` +Output: +``` +(1) /a~1b//m~0n + +(2) +a/b + +m~n +``` + +#### Concatentate two JSON Pointers + +```c++ +#include +#include + +namespace jp = jsoncons::jsonpointer; + +int main() +{ +<<<<<<< HEAD:doc/ref/jsonpointer/address.md + jp::address addr("/a~1b"); + + addr += jp::address("//m~0n"); +======= + jp::address p("/a~1b"); + + p += jp::address("//m~0n"); +>>>>>>> efc18942efb17086d3de2d1d853d56a11666ebb0:doc/ref/jsonpointer/address.md + + std::cout << "(1) " << addr << "\n\n"; + + std::cout << "(2)\n"; + for (const auto& token : addr) + { + std::cout << token << "\n"; + } + + std::cout << "\n"; +} +``` +Output: +``` +(1) /a~1b//m~0n + +(2) +a/b + +m~n +``` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/contains.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/contains.md new file mode 100644 index 0000000000..387d3a36af --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/contains.md @@ -0,0 +1,55 @@ +### jsoncons::jsonpointer::contains + +Returns `true` if the json doc contains the given JSON Pointer, otherwise `false' + +#### Header +```c++ +#include + +template +bool contains(const Json& doc, const typename Json::string_view_type& path); + +``` + +#### Return value + +Returns `true` if the json doc contains the given JSON Pointer, otherwise `false' + +### Examples + +#### Examples from [RFC6901](https://tools.ietf.org/html/rfc6901) + +```c++ +#include +#include + +namespace jp = jsoncons::jsonpointer; + +int main() +{ + // Example from RFC 6901 + auto j = jsoncons::json::parse(R"( + { + "foo": ["bar", "baz"], + "": 0, + "a/b": 1, + "c%d": 2, + "e^f": 3, + "g|h": 4, + "i\\j": 5, + "k\"l": 6, + " ": 7, + "m~n": 8 + } + )"); + + std::cout << "(1) " << jp::contains(j, "/foo/0") << std::endl; + std::cout << "(2) " << jp::contains(j, "e^g") << std::endl; +} +``` +Output: +```json +(1) true +(2) false +``` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/diagrams/jsonpointer_error.html b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/diagrams/jsonpointer_error.html new file mode 100644 index 0000000000..a3f4cd9821 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/diagrams/jsonpointer_error.html @@ -0,0 +1,12 @@ + + + + +jsonpointer_error + + + +
+ + + \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/diagrams/jsonpointer_error.png b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/diagrams/jsonpointer_error.png new file mode 100644 index 0000000000..28d4e6602e Binary files /dev/null and b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/diagrams/jsonpointer_error.png differ diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/diagrams/jsonpointer_error.xml b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/diagrams/jsonpointer_error.xml new file mode 100644 index 0000000000..f8b5221762 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/diagrams/jsonpointer_error.xml @@ -0,0 +1 @@ +7Vhdb9owFP01PHZK4kDpY0e7bkOt1jEJ+lRZ8W3izbGZYyDs188mzncoRY3GphUhYR/b1/a5595LMkCTOL2ReBndCgJs4DkkHaCrgee5jufqH4NsMwT5XgaEkhI7qQRm9BfkKy26ogSS2kQlBFN0WQcDwTkEqoZhKcWmPu1JsPquSxxCC5gFmLXROSUqytDx0Cnxj0DDKN/ZdexIjPPJFkgiTMSmAqHrAZpIIVTWitMJMENezku27sOe0eJgErh6yYLru28pn97PIm/yc6rmt/FD+vnMWlljtrIXTpSef6m/kAawVFRwe3y1zTmRYsUJGLPOAL3fRFTBbIkDM7rRKtBYpGKme65uto+Z7wlSQVqB7LFvQMSg5FZPsaMjy6CVkJszuikdUtAeVZzhWwxbDYSF5ZIm3bBMHcHa+X7W5IorGsMjaO3JkzPnOX8bdeMWdS2SgJNLE7m6FzCcJDSo8wIpVQtLoWk/mPa7oe1dpZWhq23e4frwi9yA6VRWmW65bNfL1+31QSJWMoDDGlFYhqAORyCQWh5qe7TisWGHw3JMAsOKruvZq8uLdocvguqbFYLx63rxUEMH2bXtomqyadi5aOhu3LCT0dKys5NUcekXqSxc30be9G6Bv0J4Nr+fwnoKz6W1ZJsoiPuLz1Ywdshlb3wi/4Tx2cmc9y/GZyN4Dgbsc5o5GLDnb/H56vhELZV9TwRfmu1A9hGbT5SxiWDajFmLYPfReKKk+AGVETRCF4j0E83DRrUdnzqY/U6aH3v9Z9dr/vNPzdjwv01/qJ3+9mvqLf29Kv2N3lR2QGUn/ROMGg+cxQPosTLz3YYh98/qrP2c+olHIKnCXHvJcwjFocRxS3w6oau63Op1kwsOjSJrIcxoyI1mwVRyDZjyQAPMLu1ATAkx23QWl3r56aG+NF8dFA6oFhjUoSTv+AKju+XLnMyD5SsxdP0b \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/get.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/get.md new file mode 100644 index 0000000000..da291af819 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/get.md @@ -0,0 +1,284 @@ +### jsoncons::jsonpointer::get + +Selects a `json` value. + +#### Header +```c++ +#include + +template +typename std::enable_if::value,J&>::type +get(J& root, const typename J::string_view_type& path); // (1) + +template +typename std::enable_if::value,const J&>::type +get(const J& root, const typename J::string_view_type& path); // (2) + +template +typename std::enable_if::value,J>::type +get(const J& root, const typename J::string_view_type& path); // (3) + +template +typename std::enable_if::value,J&>::type +get(J& root, const typename J::string_view_type& path, std::error_code& ec); // (4) + +template +typename std::enable_if::value,const J&>::type +get(const J& root, const typename J::string_view_type& path, std::error_code& ec); // (5) + +template +typename std::enable_if::value,J>::type +get(const J& root, const typename J::string_view_type& path, std::error_code& ec); // (6) +``` + +#### Return value + +(1) On success, returns the selected item by reference. + + json j = json::array{"baz","foo"}; + json& item = jsonpointer::get(j,"/0"); // "baz" + +(2) On success, returns the selected item by const reference. + + const json j = json::array{"baz","foo"}; + const json& item = jsonpointer::get(j,"/1"); // "foo" + +(3) On success, returns the selected item by reference, otherwise an undefined item by reference. + + json j = json::array{"baz","foo"}; + std::error_code ec; + json& item = jsonpointer::get(j,"/1",ec); // "foo" + +(4) On success, returns the selected item by const reference, otherwise an undefined item by const reference. + + const json j = json::array{"baz","foo"}; + std::error_code ec; + const json& item = jsonpointer::get(j,"/0",ec); // "baz" + +### Exceptions + +(1) Throws a [jsonpointer_error](jsonpointer_error.md) if get fails. + +(2) Throws a [jsonpointer_error](jsonpointer_error.md) if get fails. + +(3) Throws a [jsonpointer_error](jsonpointer_error.md) if get fails. + +(4) Sets the `std::error_code&` to the [jsonpointer_error_category](jsonpointer_errc.md) if get fails. + +(5) Sets the `std::error_code&` to the [jsonpointer_error_category](jsonpointer_errc.md) if get fails. + +(6) Sets the `std::error_code&` to the [jsonpointer_error_category](jsonpointer_errc.md) if get fails. + +#### Requirements + +The type J satisfies the requirements for `jsonpointer::get` if it defines the following types + +name |type |notes +------------------|----------------------|--------------- +`value_type` |`J::value_type` | +`reference` |`J::reference` | +`const_reference` |`J::const_reference` | +`pointer` |`J::pointer` | +`const_pointer` |`J::const_pointer` | +`string_type` |`J::string_type` | +`string_view_type`|`J::string_view_type` | + +and given + +- a value `index` of type `size_t` +- a value `key` of type `string_view_type` +- an rvalue expression `j` of type `J` + +the following expressions are valid + +expression |return type |effects +---------------|---------------------------|--------------- +is_array() |`bool` | +is_object() |`bool` | +size() |`size_t` | +contains(key) |`bool` | +at(index) |`reference` or `value_type`| +at(key) |`reference` or `value_type`| + +### See also + +[basic_address](address.md) + +### Examples + +#### Select author from second book + +```c++ +#include +#include + +namespace jp = jsoncons::jsonpointer; + +int main() +{ + auto j = jsoncons::json::parse(R"( + [ + { "category": "reference", + "author": "Nigel Rees", + "title": "Sayings of the Century", + "price": 8.95 + }, + { "category": "fiction", + "author": "Evelyn Waugh", + "title": "Sword of Honour", + "price": 12.99 + } + ] + )"); + + // Using exceptions to report errors + try + { + jsoncons::json result = jp::get(j, "/1/author"); + std::cout << "(1) " << result << std::endl; + } + catch (const jp::jsonpointer_error& e) + { + std::cout << e.what() << std::endl; + } + + // Using error codes to report errors + std::error_code ec; + const jsoncons::json& result = jp::get(j, "/0/title", ec); + + if (ec) + { + std::cout << ec.message() << std::endl; + } + else + { + std::cout << "(2) " << result << std::endl; + } +} +``` +Output: +```json +(1) "Evelyn Waugh" +(2) "Sayings of the Century" +``` + +#### Using addresses with jsonpointer::get + +```c++ +#include +#include + +namespace jp = jsoncons::jsonpointer; + +int main() +{ + auto j = jsoncons::json::parse(R"( + { + "a/b": ["bar", "baz"], + "m~n": ["foo", "qux"] + } + )"); + + jp::address addr; + addr /= "m~n"; + addr /= "1"; + + std::cout << "(1) " << addr << "\n\n"; + + std::cout << "(2)\n"; + for (const auto& item : addr) + { + std::cout << item << "\n"; + } + std::cout << "\n"; + + jsoncons::json item = jp::get(j, addr); + std::cout << "(3) " << item << "\n"; +} +``` +Output: +``` +(1) /m~0n/1 + +(2) +m~n +1 + +(3) "qux" +``` + +#### Examples from [RFC6901](https://tools.ietf.org/html/rfc6901) + +```c++ +#include +#include + +namespace jp = jsoncons::jsonpointer; + +int main() +{ + auto j = jsoncons::json::parse(R"( + { + "foo": ["bar", "baz"], + "": 0, + "a/b": 1, + "c%d": 2, + "e^f": 3, + "g|h": 4, + "i\\j": 5, + "k\"l": 6, + " ": 7, + "m~n": 8 + } + )"); + + try + { + const jsoncons::json& result1 = jp::get(j, ""); + std::cout << "(1) " << result1 << std::endl; + const jsoncons::json& result2 = jp::get(j, "/foo"); + std::cout << "(2) " << result2 << std::endl; + const jsoncons::json& result3 = jp::get(j, "/foo/0"); + std::cout << "(3) " << result3 << std::endl; + const jsoncons::json& result4 = jp::get(j, "/"); + std::cout << "(4) " << result4 << std::endl; + const jsoncons::json& result5 = jp::get(j, "/a~1b"); + std::cout << "(5) " << result5 << std::endl; + const jsoncons::json& result6 = jp::get(j, "/c%d"); + std::cout << "(6) " << result6 << std::endl; + const jsoncons::json& result7 = jp::get(j, "/e^f"); + std::cout << "(7) " << result7 << std::endl; + const jsoncons::json& result8 = jp::get(j, "/g|h"); + std::cout << "(8) " << result8 << std::endl; + const jsoncons::json& result9 = jp::get(j, "/i\\j"); + std::cout << "(9) " << result9 << std::endl; + const jsoncons::json& result10 = jp::get(j, "/k\"l"); + std::cout << "(10) " << result10 << std::endl; + const jsoncons::json& result11 = jp::get(j, "/ "); + std::cout << "(11) " << result11 << std::endl; + const jsoncons::json& result12 = jp::get(j, "/m~0n"); + std::cout << "(12) " << result12 << std::endl; + } + catch (const jp::jsonpointer_error& e) + { + std::cerr << e.what() << std::endl; + } +} +``` +Output: +```json +(1) {"":0," ":7,"a/b":1,"c%d":2,"e^f":3,"foo":["bar","baz"],"g|h":4,"i\\j":5,"k\"l":6,"m~n":8} +(2) ["bar","baz"] +(3) "bar" +(4) 0 +(5) 1 +(6) 2 +(7) 3 +(8) 4 +(9) 5 +(10) 6 +(11) 7 +(12) 8 +``` + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/get.md.orig b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/get.md.orig new file mode 100644 index 0000000000..63db4f2bec --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/get.md.orig @@ -0,0 +1,288 @@ +### jsoncons::jsonpointer::get + +Selects a `json` value. + +#### Header +```c++ +#include + +template +typename std::enable_if::value,J&>::type +get(J& root, const typename J::string_view_type& path); // (1) + +template +typename std::enable_if::value,const J&>::type +get(const J& root, const typename J::string_view_type& path); // (2) + +template +typename std::enable_if::value,J>::type +get(const J& root, const typename J::string_view_type& path); // (3) + +template +typename std::enable_if::value,J&>::type +get(J& root, const typename J::string_view_type& path, std::error_code& ec); // (4) + +template +typename std::enable_if::value,const J&>::type +get(const J& root, const typename J::string_view_type& path, std::error_code& ec); // (5) + +template +typename std::enable_if::value,J>::type +get(const J& root, const typename J::string_view_type& path, std::error_code& ec); // (6) +``` + +#### Return value + +(1) On success, returns the selected item by reference. + + json j = json::array{"baz","foo"}; + json& item = jsonpointer::get(j,"/0"); // "baz" + +(2) On success, returns the selected item by const reference. + + const json j = json::array{"baz","foo"}; + const json& item = jsonpointer::get(j,"/1"); // "foo" + +(3) On success, returns the selected item by reference, otherwise an undefined item by reference. + + json j = json::array{"baz","foo"}; + std::error_code ec; + json& item = jsonpointer::get(j,"/1",ec); // "foo" + +(4) On success, returns the selected item by const reference, otherwise an undefined item by const reference. + + const json j = json::array{"baz","foo"}; + std::error_code ec; + const json& item = jsonpointer::get(j,"/0",ec); // "baz" + +### Exceptions + +(1) Throws a [jsonpointer_error](jsonpointer_error.md) if get fails. + +(2) Throws a [jsonpointer_error](jsonpointer_error.md) if get fails. + +(3) Throws a [jsonpointer_error](jsonpointer_error.md) if get fails. + +(4) Sets the `std::error_code&` to the [jsonpointer_error_category](jsonpointer_errc.md) if get fails. + +(5) Sets the `std::error_code&` to the [jsonpointer_error_category](jsonpointer_errc.md) if get fails. + +(6) Sets the `std::error_code&` to the [jsonpointer_error_category](jsonpointer_errc.md) if get fails. + +#### Requirements + +The type J satisfies the requirements for `jsonpointer::get` if it defines the following types + +name |type |notes +------------------|----------------------|--------------- +`value_type` |`J::value_type` | +`reference` |`J::reference` | +`const_reference` |`J::const_reference` | +`pointer` |`J::pointer` | +`const_pointer` |`J::const_pointer` | +`string_type` |`J::string_type` | +`string_view_type`|`J::string_view_type` | + +and given + +- a value `index` of type `size_t` +- a value `key` of type `string_view_type` +- an rvalue expression `j` of type `J` + +the following expressions are valid + +expression |return type |effects +---------------|---------------------------|--------------- +is_array() |`bool` | +is_object() |`bool` | +size() |`size_t` | +contains(key) |`bool` | +at(index) |`reference` or `value_type`| +at(key) |`reference` or `value_type`| + +### See also + +<<<<<<< HEAD +[basic_address](address.md) +======= +[path](address.md) +>>>>>>> efc18942efb17086d3de2d1d853d56a11666ebb0 + +### Examples + +#### Select author from second book + +```c++ +#include +#include + +namespace jp = jsoncons::jsonpointer; + +int main() +{ + auto j = jsoncons::json::parse(R"( + [ + { "category": "reference", + "author": "Nigel Rees", + "title": "Sayings of the Century", + "price": 8.95 + }, + { "category": "fiction", + "author": "Evelyn Waugh", + "title": "Sword of Honour", + "price": 12.99 + } + ] + )"); + + // Using exceptions to report errors + try + { + jsoncons::json result = jp::get(j, "/1/author"); + std::cout << "(1) " << result << std::endl; + } + catch (const jp::jsonpointer_error& e) + { + std::cout << e.what() << std::endl; + } + + // Using error codes to report errors + std::error_code ec; + const jsoncons::json& result = jp::get(j, "/0/title", ec); + + if (ec) + { + std::cout << ec.message() << std::endl; + } + else + { + std::cout << "(2) " << result << std::endl; + } +} +``` +Output: +```json +(1) "Evelyn Waugh" +(2) "Sayings of the Century" +``` + +#### Using addresses with jsonpointer::get + +```c++ +#include +#include + +namespace jp = jsoncons::jsonpointer; + +int main() +{ + auto j = jsoncons::json::parse(R"( + { + "a/b": ["bar", "baz"], + "m~n": ["foo", "qux"] + } + )"); + + jp::address addr; + addr /= "m~n"; + addr /= "1"; + + std::cout << "(1) " << addr << "\n\n"; + + std::cout << "(2)\n"; + for (const auto& item : addr) + { + std::cout << item << "\n"; + } + std::cout << "\n"; + + jsoncons::json item = jp::get(j, addr); + std::cout << "(3) " << item << "\n"; +} +``` +Output: +``` +(1) /m~0n/1 + +(2) +m~n +1 + +(3) "qux" +``` + +#### Examples from [RFC6901](https://tools.ietf.org/html/rfc6901) + +```c++ +#include +#include + +namespace jp = jsoncons::jsonpointer; + +int main() +{ + auto j = jsoncons::json::parse(R"( + { + "foo": ["bar", "baz"], + "": 0, + "a/b": 1, + "c%d": 2, + "e^f": 3, + "g|h": 4, + "i\\j": 5, + "k\"l": 6, + " ": 7, + "m~n": 8 + } + )"); + + try + { + const jsoncons::json& result1 = jp::get(j, ""); + std::cout << "(1) " << result1 << std::endl; + const jsoncons::json& result2 = jp::get(j, "/foo"); + std::cout << "(2) " << result2 << std::endl; + const jsoncons::json& result3 = jp::get(j, "/foo/0"); + std::cout << "(3) " << result3 << std::endl; + const jsoncons::json& result4 = jp::get(j, "/"); + std::cout << "(4) " << result4 << std::endl; + const jsoncons::json& result5 = jp::get(j, "/a~1b"); + std::cout << "(5) " << result5 << std::endl; + const jsoncons::json& result6 = jp::get(j, "/c%d"); + std::cout << "(6) " << result6 << std::endl; + const jsoncons::json& result7 = jp::get(j, "/e^f"); + std::cout << "(7) " << result7 << std::endl; + const jsoncons::json& result8 = jp::get(j, "/g|h"); + std::cout << "(8) " << result8 << std::endl; + const jsoncons::json& result9 = jp::get(j, "/i\\j"); + std::cout << "(9) " << result9 << std::endl; + const jsoncons::json& result10 = jp::get(j, "/k\"l"); + std::cout << "(10) " << result10 << std::endl; + const jsoncons::json& result11 = jp::get(j, "/ "); + std::cout << "(11) " << result11 << std::endl; + const jsoncons::json& result12 = jp::get(j, "/m~0n"); + std::cout << "(12) " << result12 << std::endl; + } + catch (const jp::jsonpointer_error& e) + { + std::cerr << e.what() << std::endl; + } +} +``` +Output: +```json +(1) {"":0," ":7,"a/b":1,"c%d":2,"e^f":3,"foo":["bar","baz"],"g|h":4,"i\\j":5,"k\"l":6,"m~n":8} +(2) ["bar","baz"] +(3) "bar" +(4) 0 +(5) 1 +(6) 2 +(7) 3 +(8) 4 +(9) 5 +(10) 6 +(11) 7 +(12) 8 +``` + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/insert.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/insert.md new file mode 100644 index 0000000000..410c3e6f08 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/insert.md @@ -0,0 +1,188 @@ +### jsoncons::jsonpointer::insert + +Adds a `json` value. + +#### Header +```c++ +#include + +template +void insert(J& target, const typename J::string_view_type& path, const J& value); // (1) + +template +void insert(J& target, const typename J::string_view_type& path, const J& value, std::error_code& ec); // (2) +``` + +Inserts a value into the target at the specified path, if the path doesn't specify an object member that already has the same key. + +- If `path` specifies an array index, a new value is inserted into the array at the specified index. + +- If `path` specifies an object member that does not already exist, a new member is added to the object. + +#### Return value + +None + +### Exceptions + +(1) Throws a [jsonpointer_error](jsonpointer_error.md) if `insert` fails. + +(2) Sets the `std::error_code&` to the [jsonpointer_error_category](jsonpointer_errc.md) if `insert` fails. + +### Examples + +#### Add a member to a target location that does not already exist + +```c++ +#include +#include + +namespace jp = jsoncons::jsonpointer; + +int main() +{ + auto target = jsoncons::json::parse(R"( + { "foo": "bar"} + )"); + + std::error_code ec; + jp::insert(target, "/baz", jsoncons::json("qux"), ec); + if (ec) + { + std::cout << ec.message() << std::endl; + } + else + { + std::cout << target << std::endl; + } +} +``` +Output: +```json +{"baz":"qux","foo":"bar"} +``` + +#### Insert an element to the second position in an array + +```c++ +#include +#include + +namespace jp = jsoncons::jsonpointer; + +int main() +{ + auto target = jsoncons::json::parse(R"( + { "foo": [ "bar", "baz" ] } + )"); + + std::error_code ec; + jp::insert(target, "/foo/1", jsoncons::json("qux"), ec); + if (ec) + { + std::cout << ec.message() << std::endl; + } + else + { + std::cout << target << std::endl; + } +} +``` +Output: +```json +{"foo":["bar","qux","baz"]} +``` + +#### Insert a value at the end of an array + +```c++ +#include +#include + +namespace jp = jsoncons::jsonpointer; + +int main() +{ + auto target = jsoncons::json::parse(R"( + { "foo": [ "bar", "baz" ] } + )"); + + std::error_code ec; + jp::insert(target, "/foo/-", jsoncons::json("qux"), ec); + if (ec) + { + std::cout << ec.message() << std::endl; + } + else + { + std::cout << target << std::endl; + } +} +``` +Output: +```json +{"foo":["bar","baz","qux"]} +``` + +#### Attempt to insert object member at a location that already exists + +```c++ +#include +#include + +namespace jp = jsoncons::jsonpointer; + +int main() +{ + auto target = jsoncons::json::parse(R"( + { "foo": "bar", "baz" : "abc"} + )"); + + std::error_code ec; + jp::insert(target, "/baz", jsoncons::json("qux"), ec); + if (ec) + { + std::cout << ec.message() << std::endl; + } + else + { + std::cout << target << std::endl; + } +} +``` +Output: +``` +Key already exists +``` + +#### Attempt to insert value to a location in an array that exceeds the size of the array + +```c++ +#include +#include + +namespace jp = jsoncons::jsonpointer; + +int main() +{ + auto target = jsoncons::json::parse(R"( + { "foo": [ "bar", "baz" ] } + )"); + + std::error_code ec; + jp::insert_or_assign(target, "/foo/3", jsoncons::json("qux"), ec); + if (ec) + { + std::cout << ec.message() << std::endl; + } + else + { + std::cout << target << std::endl; + } +} +``` +Output: +``` +Index exceeds array size +``` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/insert_or_assign.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/insert_or_assign.md new file mode 100644 index 0000000000..1cb949ac54 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/insert_or_assign.md @@ -0,0 +1,67 @@ +### jsoncons::jsonpointer::insert_or_assign + +Adds a `json` value. + +#### Header +```c++ +#include + +template +void insert_or_assign(J& target, const typename J::string_view_type& path, const J& value); // (1) + +template +void insert_or_assign(J& target, const typename J::string_view_type& path, const J& value, std::error_code& ec); // (2) +``` + +Inserts a value into the target at the specified path, or if the path specifies an object member that already has the same key, assigns the new value to that member + +- If `path` specifies an array index, a new value is inserted into the array at the specified index. + +- If `path` specifies an object member that does not already exist, a new member is added to the object. + +- If `path` specifies an object member that does exist, that member's value is replaced. + +#### Return value + +None + +### Exceptions + +(1) Throws a [jsonpointer_error](jsonpointer_error.md) if `insert_or_assign` fails. + +(2) Sets the `std::error_code&` to the [jsonpointer_error_category](jsonpointer_errc.md) if `insert_or_assign` fails. + +### Examples + +#### Insert or assign an object member at a location that already exists + +```c++ +#include +#include + +namespace jp = jsoncons::jsonpointer; + +int main() +{ + auto target = jsoncons::json::parse(R"( + { "foo": "bar", "baz" : "abc"} + )"); + + std::error_code ec; + jp::insert_or_assign(target, "/baz", jsoncons::json("qux"), ec); + if (ec) + { + std::cout << ec.message() << std::endl; + } + else + { + std::cout << target << std::endl; + } +} +``` +Output: +```json +{"baz":"qux","foo":"bar"} +``` + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/jsonpointer.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/jsonpointer.md new file mode 100644 index 0000000000..562a6c343e --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/jsonpointer.md @@ -0,0 +1,153 @@ +### jsonpointer extension + +[JSON Pointer](https://tools.ietf.org/html/rfc6901) defines a string syntax to locate a specific value in a JSON document. +A JSON Pointer is a string of zero or more tokens, each token prefixed by `/` characters. +These tokens denote keys in JSON objects or indexes in JSON arrays. An empty string with zero tokens points +to the root of a json document. + +The characters `~` and `/` have special meanings in JSON Pointer, +so if a key in a JSON object has these characters, `~` needs to be escaped as `~0`, +and `/` needs to be escaped as `~1`. + +When applied to a JSON array, the character `-` indicates one past the last element in the array. + +### Classes + + + + + +
basic_addressObjects of type basic_address represent JSON Pointer addresses.
+ +### Non-member functions + + + + + + + + + + + + + + + + + + + + + + + + + + +
containsReturns true if the json document contains the given JSON Pointer
getGet a value from a JSON document using JSON Pointer path notation.
insertInserts a value in a JSON document using JSON Pointer path notation, if the path doesn't specify an object member that already has the same key.
insert_or_assignInserts a value in a JSON document using JSON Pointer path notation, or if the path specifies an object member that already has the same key, assigns the new value to that member.
removeRemoves a value from a JSON document using JSON Pointer path notation.
replaceReplaces a value in a JSON document using JSON Pointer path notation.
+ +### Examples + +#### Select author from second book + +```c++ +#include +#include + +using namespace jsoncons; + +int main() +{ + auto j = json::parse(R"( + [ + { "category": "reference", + "author": "Nigel Rees", + "title": "Sayings of the Century", + "price": 8.95 + }, + { "category": "fiction", + "author": "Evelyn Waugh", + "title": "Sword of Honour", + "price": 12.99 + } + ] + )"); + + // Using exceptions to report errors + try + { + json result = jsonpointer::get(j, "/1/author"); + std::cout << "(1) " << result << std::endl; + } + catch (const jsonpointer::jsonpointer_error& e) + { + std::cout << e.what() << std::endl; + } + + // Using error codes to report errors + std::error_code ec; + const json& result = jsonpointer::get(j, "/0/title", ec); + + if (ec) + { + std::cout << ec.message() << std::endl; + } + else + { + std::cout << "(2) " << result << std::endl; + } +} +``` +Output: +```json +(1) "Evelyn Waugh" +(2) "Sayings of the Century" +``` + +#### Using addresses with jsonpointer::get + +```c++ +#include +#include + +using namespace jsoncons; + +int main() +{ + auto j = json::parse(R"( + { + "a/b": ["bar", "baz"], + "m~n": ["foo", "qux"] + } + )"); + + jsonpointer::address addr; + addr /= "m~n"; + addr /= "1"; + + std::cout << "(1) " << addr << "\n\n"; + + std::cout << "(2)\n"; + for (const auto& item : addr) + { + std::cout << item << "\n"; + } + std::cout << "\n"; + + json item = jsonpointer::get(j, addr); + std::cout << "(3) " << item << "\n"; +} +``` +Output: +``` +(1) /m~0n/1 + +(2) +m~n +1 + +(3) "qux" +``` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/jsonpointer_errc.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/jsonpointer_errc.md new file mode 100644 index 0000000000..cb1971a878 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/jsonpointer_errc.md @@ -0,0 +1,26 @@ +### jsoncons::jsonpointer::jsonpointer_errc + +The constant integer values scoped by `jsonpointer_errc` define the values for jsonpointer error codes. + +#### Header + +```c++ +#include +``` + +### Member constants + +constant |Description +------------------------------------|------------------------------ +`expected_slash` |Expected / +`index_exceeds_array_size` |Index exceeds array size +`expected_0_or_1` |Expected '0' or '1' after escape character '~' +`invalid_index` |Invalid array index +`name_not_found` |Name not found +`key_already_exists` |Key already exists +`expected_object_or_array` |Expected object or array +`end_of_input` |Unexpected end of input + + + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/jsonpointer_error.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/jsonpointer_error.md new file mode 100644 index 0000000000..95f063228a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/jsonpointer_error.md @@ -0,0 +1,55 @@ +### jsoncons::jsonpointer::jsonpointer_error + +#### Header + + #include + +`jsoncons::jsonpointer::jsonpointer_error` defines an exception type for reporting failures in jsonpointer operations. + +![jsonpointer_error](./diagrams/jsonpointer_error.png) + +#### Constructors + + jsonpointer_error(std::error_code ec) + + jsonpointer_error(const jsonpointer_error& other) + +#### Member functions + + const char* what() const noexcept +Returns an error message + +#### Inherited from std::system_error + + const std::error_code code() const noexcept +Returns an error code for this exception + +### Example + +```c++ +#include +#include + +using jsoncons::json; + +int main() +{ + string s = "[1,2,3,4,]"; + try + { + jsoncons::json val = jsoncons::json::parse(s); + } + catch(const jsoncons::jsonpointer_error& e) + { + std::cout << "Caught jsonpointer_error with category " + << e.code().category().name() + << ", code " << e.code().value() + << " and message " << e.what() << std::endl; + } +} +``` + +Output: +``` +Caught jsonpointer_error with category jsoncons.jsonpointer, code 0x6 and message "Name not found" +``` diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/pointer.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/pointer.md new file mode 100644 index 0000000000..c079c1c78f --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/pointer.md @@ -0,0 +1,200 @@ +### jsoncons::jsonpointer::basic_pointer + +``` +template +class basic_pointer +``` +#### Header +```c++ +#include +``` + +Two specializations for common character types are defined: + +Type |Definition +----------|------------------------------ +pointer |`basic_pointer` +wpointer |`basic_pointer` + +Objects of type `basic_pointer` represent a JSON Pointer. + +#### Member types +Type |Definition +------------|------------------------------ +char_type | `CharT` +string_type | `std::basic_string` +string_view_type | `jsoncons::basic_string_view` +const_iterator | A constant [LegacyInputIterator](https://en.cppreference.com/w/cpp/named_req/InputIterator) with a `value_type` of `std::basic_string` +iterator | An alias to `const_iterator` + +#### Header +```c++ +#include +``` + +#### Constructors + + basic_pointer(); + + explicit basic_pointer(const string_type& pointer); + + explicit basic_pointer(string_type&& pointer); + + explicit basic_pointer(const CharT* s); + + basic_pointer(const basic_pointer&); + + basic_pointer(basic_pointer&&); + +#### operator= + + basic_pointer& operator=(const basic_pointer&); + + basic_pointer& operator=(basic_pointer&&); + +#### Modifiers + + basic_pointer& operator/=(const string_type& s) +First, appends the JSON Pointer separator `/`. Then appends the token s, escaping any `/` or `~` characters. + + basic_pointer& operator+=(const basic_pointer& p) +Concatenates the current pointer and the specified pointer `p`. + +#### Iterators + + iterator begin() const; + iterator end() const; +Iterator access to the tokens in the pointer. + +#### Accessors + + bool empty() const +Checks if the pointer is empty + + const string_view_type& string_view() const + operator string_view_type() const; +Access the JSON Pointer pointer as a string view. + +#### Non-member functions + basic_pointer operator/(const basic_pointer& lhs, const string_type& rhs); +Concatenates a JSON Pointer pointer and a token. Effectively returns basic_pointer(lhs) /= rhs. + + basic_pointer operator+( const basic_pointer& lhs, const basic_pointer& rhs ); +Concatenates two JSON Pointers. Effectively returns basic_pointer(lhs) += rhs. + + bool operator==(const basic_pointer& lhs, const basic_pointer& rhs); + + bool operator!=(const basic_pointer& lhs, const basic_pointer& rhs); + + std::basic_ostream& + operator<<(std::basic_ostream& os, const basic_pointer& p); +Performs stream output + +### Examples + +#### Iterate over the tokens in a JSON Pointer + +```c++ +#include +#include + +namespace jp = jsoncons::jsonpointer; + +int main() +{ + jp::pointer p("/store/book/1/author"); + + std::cout << "(1) " << p << "\n\n"; + + std::cout << "(2)\n"; + for (const auto& token : p) + { + std::cout << token << "\n"; + } + + std::cout << "\n"; +} +``` +Output: +``` +(1) /store/book/1/author + +(2) +store +book +1 +author +``` + +#### Append tokens to a JSON Pointer + +```c++ +#include +#include + +namespace jp = jsoncons::jsonpointer; + +int main() +{ + jp::pointer p; + + p /= "a/b"; + p /= ""; + p /= "m~n"; + + std::cout << "(1) " << p << "\n\n"; + + std::cout << "(2)\n"; + for (const auto& token : p) + { + std::cout << token << "\n"; + } + + std::cout << "\n"; +} +``` +Output: +``` +(1) /a~1b//m~0n + +(2) +a/b + +m~n +``` + +#### Concatentate two JSON Pointers + +```c++ +#include +#include + +namespace jp = jsoncons::jsonpointer; + +int main() +{ + jp::pointer p("/a~1b"); + + p += jp::pointer("//m~0n"); + + std::cout << "(1) " << p << "\n\n"; + + std::cout << "(2)\n"; + for (const auto& token : p) + { + std::cout << token << "\n"; + } + + std::cout << "\n"; +} +``` +Output: +``` +(1) /a~1b//m~0n + +(2) +a/b + +m~n +``` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/remove.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/remove.md new file mode 100644 index 0000000000..cab575697a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/remove.md @@ -0,0 +1,92 @@ +### jsoncons::jsonpointer::remove + +Removes a `json` element. + +#### Header +```c++ +#include + +template +void remove(J& target, const typename J::string_view_type& path); // (1) + +template +void remove(J& target, const typename J::string_view_type& path, std::error_code& ec); // (2) +``` + +Removes the value at the location specifed by `path`. + +#### Return value + +None + +### Exceptions + +(1) Throws a [jsonpointer_error](jsonpointer_error.md) if `remove` fails. + +(2) Sets the `std::error_code&` to the [jsonpointer_error_category](jsonpointer_errc.md) if `remove` fails. + +### Examples + +#### Remove an object member + +```c++ +#include +#include + +namespace jp = jsoncons::jsonpointer; + +int main() +{ + auto target = jsoncons::json::parse(R"( + { "foo": "bar", "baz" : "qux"} + )"); + + std::error_code ec; + jp::remove(target, "/baz", ec); + if (ec) + { + std::cout << ec.message() << std::endl; + } + else + { + std::cout << target << std::endl; + } +} +``` +Output: +```json +{"foo":"bar"} +``` + +#### Remove an array element + +```c++ +#include +#include + +namespace jp = jsoncons::jsonpointer; + +int main() +{ + auto target = jsoncons::json::parse(R"( + { "foo": [ "bar", "qux", "baz" ] } + )"); + + std::error_code ec; + jp::remove(target, "/foo/1", ec); + if (ec) + { + std::cout << ec.message() << std::endl; + } + else + { + std::cout << target << std::endl; + } +} +``` +Output: +```json +{"foo":["bar","baz"]} +``` + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/replace.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/replace.md new file mode 100644 index 0000000000..08a64d280c --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/jsonpointer/replace.md @@ -0,0 +1,100 @@ +### jsoncons::jsonpointer::replace + +Replace a `json` element or member. + +#### Header +```c++ +#include + +template +void replace(J& target, const typename J::string_view_type& path, const J& value); + +template +void replace(J& target, const typename J::string_view_type& path, const J& value, std::error_code& ec); +``` + +Replaces the value at the location specified by `path` with a new value. + +#### Return value + +None + +#### Exceptions + +(1) Throws a [jsonpointer_error](jsonpointer_error.md) if `replace` fails. + +(2) Sets the `std::error_code&` to the [jsonpointer_error_category](jsonpointer_errc.md) if `replace` fails. + +### Examples + +#### Replace an object value + +```c++ +#include +#include + +namespace jp = jsoncons::jsonpointer; + +int main() +{ + auto target = jsoncons::json::parse(R"( + { + "baz": "qux", + "foo": "bar" + } + )"); + + std::error_code ec; + jp::replace(target, "/baz", jsoncons::json("boo"), ec); + if (ec) + { + std::cout << ec.message() << std::endl; + } + else + { + std::cout << target << std::endl; + } +} +``` +Output: +```json +{ + "baz": "boo", + "foo": "bar" +} +``` + +#### Replace an array value + +```c++ +#include +#include + +namespace jp = jsoncons::jsonpointer; + +int main() +{ + auto target = jsoncons::json::parse(R"( + { "foo": [ "bar", "baz" ] } + )"); + + std::error_code ec; + jp::replace(target, "/foo/1", jsoncons::json("qux"), ec); + if (ec) + { + std::cout << ec.message() << std::endl; + } + else + { + std::cout << pretty_print(target) << std::endl; + } +} +``` +Output: +```json +{ + "foo": ["bar","qux"] +} +``` + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/line_split_kind.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/line_split_kind.md new file mode 100644 index 0000000000..bf7fd6fe93 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/line_split_kind.md @@ -0,0 +1,6 @@ +### jsoncons::line_split_kind + +```c++ +enum class line_split_kind{same_line,new_line,multi_line}; +``` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/msgpack/decode_msgpack.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/msgpack/decode_msgpack.md new file mode 100644 index 0000000000..77f2cc4567 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/msgpack/decode_msgpack.md @@ -0,0 +1,30 @@ +### jsoncons::msgpack::decode_msgpack + +Decodes a [MessagePack](http://msgpack.org/index.html) data format into a C++ data structure. + +#### Header +```c++ +#include + +template +T decode_msgpack(const std::vector& v); // (1) + +template +T decode_msgpack(std::istream& is); // (2) +``` + +(1) Reads a MessagePack bytes buffer into a type T if T is an instantiation of [basic_json](../json.md) +or if T supports [json_type_traits](../json_type_traits.md). + +(2) Reads a MessagePack binary stream into a type T if T is an instantiation of [basic_json](../json.md) +or if T supports [json_type_traits](../json_type_traits.md). + +#### Exceptions + +Throws [ser_error](../ser_error.md) if parsing fails. + +#### See also + +- [encode_msgpack](encode_msgpack.md) encodes a json value to the [MessagePack](http://msgpack.org/index.html) data format. + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/msgpack/diagrams/msgpack_encoder.png b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/msgpack/diagrams/msgpack_encoder.png new file mode 100644 index 0000000000..b2171a8ea6 Binary files /dev/null and b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/msgpack/diagrams/msgpack_encoder.png differ diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/msgpack/diagrams/msgpack_encoder.xml b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/msgpack/diagrams/msgpack_encoder.xml new file mode 100644 index 0000000000..c486dc72df --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/msgpack/diagrams/msgpack_encoder.xml @@ -0,0 +1 @@ +vVZRb9owEP41eeyUxIXSxxZYt6FW65gEfUJufE28OjZzDIT9+tnEJnESVCpV7UPl+853tr/77kKAxnl5J/E6uxcEWBCHpAzQJIjjq2ik/xtgXwFoGFZAKimpoKgG5vQfWNBt21AChbdRCcEUXftgIjiHRHkYllLs/G0vgvmnrnEKHWCeYNZFF5SorEJHg7DGvwFNM3dyFFpPjt1mCxQZJmLXgNA0QGMphKpWeTkGZrhzvFRxX094jxeTwNU5AdOH3yWfPc6zePx3phb3+VP548Jm2WK2sQ9+xgVNVn8KwVeaU6WTrzLMCQMZxEOmT7p9NqvUrPqQw1PV3vEnxYYTMFcItXuXUQXzNU6Md6cFo7FM5Uxb0TG6+SR3P5AKygZkn3gHIgcl93qL9Y4s21ZukWN/VxcvchLMGoW7tBi2ekmPmWtK9cKy+g6Gr04wnBep5uF1BTzRPfMJ5L5QxsaCCXmIRXD403ihpHiFhgcN0TUiH1OOs+ox+Mx6jDr16NAKnNyY0aGthOFCV8tnEkqqlpZ0s34y6y8Da03KhmuydwbXl1+6BMZoRBmzDjtYLu5kDQqxkQm8LTyFZQrq7REAxBuE3Yo2KtZXMIdJYFjRrT8++6poT/gpqH7ZUTCXvl5i1NJB9Wwb1Jx2rTzXLd2NWnkqWjp5DpI6PvoslaXb+yyePSzxL0gvFo8z2M6gp+u/8wwkVZjrounPIcWpxHlHerqtlC82vz254NDqZQthRlNuFKuFoscJujVNSvWH7MY6ckqIOaZ3TviT5CMaP2wVMuxpfNSjo/j9ja/N+jNaVbD+LYKm/wE= \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/msgpack/encode_msgpack.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/msgpack/encode_msgpack.md new file mode 100644 index 0000000000..7344c0fbdb --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/msgpack/encode_msgpack.md @@ -0,0 +1,103 @@ +### jsoncons::msgpack::encode_msgpack + +Encodes a C++ data structure into the [MessagePack](http://msgpack.org/index.html) data format. + +#### Header +```c++ +#include + +template +void encode_msgpack(const T& jval, std::vector& v); // (1) + +template +void encode_msgpack(const T& jval, std::ostream& os); // (2) +``` + +(1) Writes a value of type T into a bytes buffer in the MessagePack data format. Type T must be an instantiation of [basic_json](../json.md) +or support [json_type_traits](../json_type_traits.md). + +(2) Writes a value of type T into a binary stream in the MessagePack data format. Type T must be an instantiation of [basic_json](../json.md) +or support [json_type_traits](../json_type_traits.md). + +#### See also + +- [decode_msgpack](decode_msgpack) decodes a [MessagePack](http://msgpack.org/index.html) data format to a json value. + +### Examples + +#### MessagePack example + +```c++ +#include +#include + +using namespace jsoncons; +using namespace jsoncons::msgpack; + +int main() +{ + ojson j1; + j1["zero"] = 0; + j1["one"] = 1; + j1["two"] = 2; + j1["null"] = null_type(); + j1["true"] = true; + j1["false"] = false; + j1["max int64_t"] = (std::numeric_limits::max)(); + j1["max uint64_t"] = (std::numeric_limits::max)(); + j1["min int64_t"] = (std::numeric_limits::lowest)(); + j1["max int32_t"] = (std::numeric_limits::max)(); + j1["max uint32_t"] = (std::numeric_limits::max)(); + j1["min int32_t"] = (std::numeric_limits::lowest)(); + j1["max int16_t"] = (std::numeric_limits::max)(); + j1["max uint16_t"] = (std::numeric_limits::max)(); + j1["min int16_t"] = (std::numeric_limits::lowest)(); + j1["max int8_t"] = (std::numeric_limits::max)(); + j1["max uint8_t"] = (std::numeric_limits::max)(); + j1["min int8_t"] = (std::numeric_limits::lowest)(); + j1["max double"] = (std::numeric_limits::max)(); + j1["min double"] = (std::numeric_limits::lowest)(); + j1["max float"] = (std::numeric_limits::max)(); + j1["zero float"] = 0.0; + j1["min float"] = (std::numeric_limits::lowest)(); + j1["Key too long for small string optimization"] = "String too long for small string optimization"; + + std::vector v; + encode_msgpack(j1, v); + + ojson j2 = decode_msgpack(v); + + std::cout << pretty_print(j2) << std::endl; +} +``` +Output: +```json +{ + "zero": 0, + "one": 1, + "two": 2, + "null": null, + "true": true, + "false": false, + "max int64_t": 9223372036854775807, + "max uint64_t": 18446744073709551615, + "min int64_t": -9223372036854775808, + "max int32_t": 2147483647, + "max uint32_t": 4294967295, + "min int32_t": -2147483648, + "max int16_t": 32767, + "max uint16_t": 65535, + "min int16_t": -32768, + "max int8_t": 127, + "max uint8_t": 255, + "min int8_t": -128, + "max double": 1.79769313486232e+308, + "min double": -1.79769313486232e+308, + "max float": 3.40282346638529e+038, + "zero float": 0.0, + "min float": -3.40282346638529e+038, + "Key too long for small string optimization": "String too long for small string optimization" +} +``` + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/msgpack/msgpack.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/msgpack/msgpack.md new file mode 100644 index 0000000000..7bad78cdc2 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/msgpack/msgpack.md @@ -0,0 +1,94 @@ +### msgpack extension + +The msgpack extension implements encode to and decode from the [MessagePack](http://msgpack.org/index.html) data format. +You can either parse into or serialize from a variant-like structure, [basic_json](../json.md), or your own +data structures, using [json_type_traits](../json_type_traits.md). + + +[decode_msgpack](decode_msgpack.md) + +[encode_msgpack](encode_msgpack.md) + +[msgpack_encoder](msgpack_encoder.md) + +#### jsoncons-MessagePack mappings + +jsoncons data item|jsoncons tag|BSON data item +--------------|------------------|--------------- +null | | nil +bool | | true or false +int64 | | negative fixnum, int 8, int 16, int 32, int 64 +uint64 | | positive fixnum, uint 8, uint 16, uint 32, uint 64 +double | | float32 or float64 +string | | fixstr, str 8, str 16 or str 32 +byte_string | | bin 8, bin 16 or bin 32 +array | | array +object | | map + +### Examples + +Example file (book.json): +```json +[ + { + "category": "reference", + "author": "Nigel Rees", + "title": "Sayings of the Century", + "price": 8.95 + }, + { + "category": "fiction", + "author": "Evelyn Waugh", + "title": "Sword of Honour", + "price": 12.99 + } +] +``` +```c++ +#include +#include + +using namespace jsoncons; + +int main() +{ + std::ifstream is("input/book.json"); + ojson j1; + is >> j1; + + // Encode ojson to MessagePack + std::vector v; + msgpack::encode_msgpack(j1, v); + + // Decode MessagePack to ojson + ojson j2 = msgpack::decode_msgpack(v); + + std::cout << pretty_print(j2) << std::endl; + + // or to json (now alphabetically sorted) + json j3 = msgpack::decode_msgpack(v); + + // or to wjson (converts from utf8 to wide characters) + wjson j4 = msgpack::decode_msgpack(v); +} +``` +Output: +```json +[ + { + "category": "reference", + "author": "Nigel Rees", + "title": "Sayings of the Century", + "price": 8.95 + }, + { + "category": "fiction", + "author": "Evelyn Waugh", + "title": "Sword of Honour", + "price": 12.99 + } +] +``` + + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/msgpack/msgpack_encoder.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/msgpack/msgpack_encoder.md new file mode 100644 index 0000000000..9036b77f2b --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/msgpack/msgpack_encoder.md @@ -0,0 +1,100 @@ +### jsoncons::bson::basic_msgpack_encoder + +```c++ +template< + class Result> +> class basic_msgpack_encoder : public jsoncons::json_content_handler +``` + +`basic_msgpack_encoder` is noncopyable. + +#### Header + + #include + +![msgpack_encoder](./diagrams/msgpack_encoder.png) + +Four specializations for common character types and result types are defined: + +Type |Definition +---------------------------|------------------------------ +msgpack_encoder |basic_msgpack_encoder +bson_bytes_encoder |basic_msgpack_encoder + +#### Member types + +Type |Definition +---------------------------|------------------------------ +char_type |char +result_type |Result +string_view_type | + +#### Constructors + + explicit basic_msgpack_encoder(result_type result) +Constructs a new encoder that writes to the specified result. + +#### Destructor + + virtual ~basic_msgpack_encoder() + +### Inherited from [basic_json_content_handler](../json_content_handler.md) + +#### Member functions + + bool begin_object(semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool begin_object(size_t length, + semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool end_object(const ser_context& context = null_ser_context()) + + bool begin_array(semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool begin_array(semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool end_array(const ser_context& context=null_ser_context()); + + bool name(const string_view_type& name, + const ser_context& context=null_ser_context()); + + bool string_value(const string_view_type& value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool byte_string_value(const byte_string_view& b, + semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool byte_string_value(const uint8_t* p, size_t size, + semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool int64_value(int64_t value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool uint64_value(uint64_t value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool double_value(double value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool bool_value(bool value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool null_value(semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); + + void flush() + +### Examples + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/ojson.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/ojson.md new file mode 100644 index 0000000000..5fd96cf317 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/ojson.md @@ -0,0 +1,87 @@ +### jsoncons::ojson + +```c++ +typedef basic_json> ojson +``` +The `ojson` class is an instantiation of the `basic_json` class template that uses `char` as the character type. The original insertion order of an object's name/value pairs is preserved. + +The `jsoncons` library will always rebind the supplied allocator from the template parameter to internal data structures. + +#### Header + + #include + +#### Interface + +The interface is the same as [json](json.md), with these provisos: + +- `ojson`, like `json`, supports object member `insert_or_assign` methods that take an `object_iterator` as the first parameter. But while with `json` that parameter is just a hint that allows optimization, with `ojson` it is the actual location where to insert the member. + +- In `ojson`, the `insert_or_assign` members that just take a name and a value always insert the member at the end. + +#### See also + +- [json](json.md) constructs a json value that sorts name-value members alphabetically + +- [wjson](wjson.md) constructs a wide character json value that sorts name-value members alphabetically + +- [wojson](wojson.md) constructs a wide character json value that preserves the original insertion order of an object's name/value pairs + +### Examples +```c++ +ojson o = ojson::parse(R"( +{ + "street_number" : "100", + "street_name" : "Queen St W", + "city" : "Toronto", + "country" : "Canada" +} +)"); + +std::cout << pretty_print(o) << std::endl; +``` +Output: +```json +{ + "street_number": "100", + "street_name": "Queen St W", + "city": "Toronto", + "country": "Canada" +} +``` +Insert "postal_code" at end +```c++ +o.insert_or_assign("postal_code", "M5H 2N2"); + +std::cout << pretty_print(o) << std::endl; +``` +Output: +```json +{ + "street_number": "100", + "street_name": "Queen St W", + "city": "Toronto", + "country": "Canada", + "postal_code": "M5H 2N2" +} +``` +Insert "province" before "country" +```c++ +auto it = o.find("country"); +o.insert_or_assign(it,"province","Ontario"); + +std::cout << pretty_print(o) << std::endl; +``` +Output: +```json +{ + "street_number": "100", + "street_name": "Queen St W", + "city": "Toronto", + "province": "Ontario", + "country": "Canada", + "postal_code": "M5H 2N2" +} +``` diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/parse_error_handler.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/parse_error_handler.md new file mode 100644 index 0000000000..fc58ed91e2 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/parse_error_handler.md @@ -0,0 +1,42 @@ +### jsoncons::parse_error_handler + +```c++ +class parse_error_handler; +``` + +When parsing JSON text with [json_reader](json_reader.md), if you need to implement +customized error handling, you must implement this abstract class +and pass it in the constructor of [json_reader](json_reader.md). The `read` method +will then report all warnings and errors through this interface. + +#### Header + + #include + +#### Destructor + + virtual ~json_error_handler() + +#### Public interface methods + + void error(std::error_code ec, + const ser_context& context) throw (ser_error) = 0 +Called for recoverable errors. Calls `do_error`, if `do_error` returns `false`, throws a [ser_error](ser_error.md), otherwise an attempt is made to recover. + + void fatal_error(std::error_code ec, + const ser_context& context) throw (ser_error) = 0 +Called for unrecoverable errors. Calls `do_fatal_error` and throws a [ser_error](ser_error.md). + +#### Private virtual implementation methods + + virtual bool do_error(std::error_code ec, + const ser_context& context) = 0 +Receive an error event, possibly recoverable. An [error_code](json_error_category.md) indicates the type of error. Contextual information including +line and column number is provided in the [context](ser_context.md) parameter. Returns `false` to fail, `true` to attempt recovery. + + virtual void do_fatal_error(std::error_code ec, + const ser_context& context) = 0 +Receives a non recoverable error. An [error_code](json_error_category.md) indicates the type of error. Contextual information including +line and column number is provided in the [context](ser_context.md) parameter. + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/rename_object_member_filter.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/rename_object_member_filter.md new file mode 100644 index 0000000000..b48c6fbe2f --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/rename_object_member_filter.md @@ -0,0 +1,55 @@ +### jsoncons::rename_object_member_filter + +```c++ +typedef basic_rename_object_member_filter rename_object_member_filter; +``` +The `rename_object_member_filter` class is an instantiation of the `basic_rename_object_member_filter` class template that uses `char` as the character type. + +Renames object member names. + +#### Header +```c++ +#include +``` + +![rename_object_member_filter](./diagrams/rename_object_member_filter.png) + +#### Constructors + + rename_object_member_filter(const std::string& name, + const std::string& new_name, + json_content_handler& handler) + + rename_object_member_filter(const std::string& name, + const std::string& new_name, + json_content_handler& handler) + +### See also + +- [json_filter](json_filter.md) + +### Examples + +#### Rename object member names + +```c++ +#include +#include + +using namespace jsoncons; + +int main() +{ + ojson j = ojson::parse(R"({"first":1,"second":2,"fourth":3})"); + + json_encoder encoder(std::cout); + + rename_object_member_filter filter("fourth","third",encoder); + j.dump(filter); +} +``` +Output: +```json +{"first":1,"second":2,"third":3} +``` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/semantic_tag.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/semantic_tag.md new file mode 100644 index 0000000000..a07a465b2c --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/semantic_tag.md @@ -0,0 +1,19 @@ +### jsoncons::semantic_tag + +```c++ +enum class semantic_tag : uint8_t +{ + none = 0, + undefined, + datetime, + timestamp, + bigint, + bigdec, + base16, + base64, + base64url, + uri, + bigfloat +}; +``` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/ser_context.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/ser_context.md new file mode 100644 index 0000000000..57ee058882 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/ser_context.md @@ -0,0 +1,22 @@ +### jsoncons::ser_context + +```c++ +class ser_context; +``` + +Provides contextual information for serializing and deserializing JSON and JSON-like data formats. This information may be used for error reporting. + +#### Header + + #include + + virtual size_t line() const = 0; +Returns the line number for the text being parsed. +Line numbers start at 1. + + virtual size_t column() const = 0; +Returns the column number to the end of the text being parsed. +Column numbers start at 1. + + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/ser_error.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/ser_error.md new file mode 100644 index 0000000000..db0185c748 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/ser_error.md @@ -0,0 +1,68 @@ +### jsoncons::ser_error + +#### Header + + #include + +`jsoncons::ser_error` defines an exception type for reporting serialization and deserialization failures. + +![ser_error](./diagrams/ser_error.png) + +std::exception + +#### Constructors + + ser_error(std::error_code ec); + + ser_error(std::error_code ec, size_t position); + + ser_error(std::error_code ec, + size_t line, + size_t column); + + ser_error(const ser_error& other); + +#### Member functions + + size_t line() const noexcept +Returns the line number to the end of the text where the exception occurred. +Line numbers start at 1. + + size_t column() const noexcept +Returns the column number to the end of the text where the exception occurred. +Column numbers start at 1. + + const char* what() const +Constructs an error message, including line and column position + +#### Inherited from std::system_error + + const std::error_code code() const noexcept +Returns an error code for this exception + +### Example + + #include + + using jsoncons::json; + + int main() + { + string s = "[1,2,3,4,]"; + try + { + jsoncons::json val = jsoncons::json::parse(s); + } + catch(const jsoncons::ser_error& e) + { + std::cout << "Caught ser_error with category " + << e.code().category().name() + << ", code " << e.code().value() + << " and message " << e.what() << std::endl; + } + } + + +Output: + + Caught ser_error with category json_input, code 1 and message Unexpected value separator ',' at line 1 and column 10 diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/spaces_option.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/spaces_option.md new file mode 100644 index 0000000000..9e6fc32a1b --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/spaces_option.md @@ -0,0 +1,12 @@ +### jsoncons::spaces_option + +```c++ +enum class spaces_option : uint8_t +{ + no_spaces=0, + space_after, + space_before, + space_before_and_after +}; +``` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/staj_array_iterator.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/staj_array_iterator.md new file mode 100644 index 0000000000..c81ea586d4 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/staj_array_iterator.md @@ -0,0 +1,192 @@ +### jsoncons::staj_array_iterator + +```c++ +template +using staj_array_iterator = basic_staj_array_iterator>; +``` + +#### Header +```c++ +#include +``` + +A `staj_array_iterator` is an [InputIterator](https://en.cppreference.com/w/cpp/named_req/InputIterator) that +accesses the individual stream events from a [staj_reader](staj_reader.md) and, provided that when it is constructed +the current stream event has type `staj_event_type::begin_array`, it retrieves the elements of the JSON array +as items of type `T`. If when it is constructed the current stream event does not have type `staj_event_type::begin_array`, +it becomes equal to the default-constructed iterator. + +#### Member types + +Member type |Definition +------------------------------------|------------------------------ +`char_type`|char +`value_type`|`T` +`difference_type`|`std::ptrdiff_t` +`pointer`|`value_type*` +`reference`|`value_type&` +`iterator_category`|[std::input_iterator_tag](https://en.cppreference.com/w/cpp/iterator/iterator_tags) + +#### Constructors + + staj_array_iterator() noexcept; // (1) + + staj_array_iterator(basic_staj_reader& reader); // (2) + + staj_array_iterator(basic_staj_reader& reader, + std::error_code& ec); // (3) + +(1) Constructs the end iterator + +(2) Constructs a `staj_array_iterator` that refers to the first element of the array + following the current stream event `begin_array`. If there is no such element, + returns the end iterator. If a parsing error is encountered, throws a + [ser_error](ser_error.md). + +(3) Constructs a `staj_array_iterator` that refers to the first member of the array + following the current stream event `begin_array`. If there is no such element, + returns the end iterator. If a parsing error is encountered, returns the end iterator + and sets `ec`. + +#### Member functions + + const T& operator*() const + + const T* operator->() const + + staj_array_iterator& operator++() + staj_array_iterator& increment(std::error_code& ec) + staj_array_iterator operator++(int) +Advances the iterator to the next array element. + +#### Non-member functions + + template + bool operator==(const staj_array_iterator& a, const staj_array_iterator& b) + + template + bool operator!=(const staj_array_iterator& a, const staj_array_iterator& b) + + template + staj_array_iterator begin(staj_array_iterator iter) noexcept; // (1) + + template + staj_array_iterator end(const staj_array_iterator&) noexcept; // (2) + +(1) Returns iter unchanged + +(2) Returns a default-constructed `stax_array_iterator`, which serves as an end iterator. The argument is ignored. + +The `begin` and `end` non-member functions enable the use of `stax_array_iterators` with range-based for loops. + +### Examples + +#### Iterate over a JSON array, returning json values + +```c++ +const std::string example = R"( +[ + { + "employeeNo" : "101", + "name" : "Tommy Cochrane", + "title" : "Supervisor" + }, + { + "employeeNo" : "102", + "name" : "Bill Skeleton", + "title" : "Line manager" + } +] +)"; + +int main() +{ + std::istringstream is(example); + + json_cursor reader(is); + + staj_array_iterator it(reader); + + for (const auto& j : it) + { + std::cout << pretty_print(j) << "\n"; + } + std::cout << "\n\n"; +} +``` +Output: +``` +{ + "employeeNo": "101", + "name": "Tommy Cochrane", + "title": "Supervisor" +} +{ + "employeeNo": "102", + "name": "Bill Skeleton", + "title": "Line manager" +} +``` + +#### Iterate over the JSON array, returning employee values + +```c++ +struct employee +{ + std::string employeeNo; + std::string name; + std::string title; +}; + +namespace jsoncons +{ + template + struct json_type_traits + { + template + struct json_type_traits + { + static bool is(const Json& j) noexcept + { + return j.is_object() && j.contains("employeeNo") && j.contains("name") && j.contains("title"); + } + static employee as(const Json& j) + { + employee val; + val.employeeNo = j["employeeNo"].template as(); + val.name = j["name"].template as(); + val.title = j["title"].template as(); + return val; + } + static Json to_json(const employee& val) + { + Json j; + j["employeeNo"] = val.employeeNo; + j["name"] = val.name; + j["title"] = val.title; + return j; + } + }; +} + +int main() +{ + std::istringstream is(example); + + json_cursor reader(is); + + staj_array_iterator it(reader); + + for (const auto& val : it) + { + std::cout << val.employeeNo << ", " << val.name << ", " << val.title << "\n"; + } + std::cout << "\n\n"; +} +``` +Output: +``` +101, Tommy Cochrane, Supervisor +102, Bill Skeleton, Line manager +``` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/staj_event.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/staj_event.md new file mode 100644 index 0000000000..ed0bb2c873 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/staj_event.md @@ -0,0 +1,40 @@ +### jsoncons::staj_event + +```c++ +typedef basic_staj_event staj_event; +``` + +#### Header +```c++ +#include + +A JSON-like data event. +``` + +| Event type | Sample data | Valid accessors | +|-------------------|------------------------|-----------------| +| begin_object | | | +| end_object | | | +| begin_array | | | +| end_array | | | +| name | "foo" | `as()`, `as`, `as()` | +| string_value | "1000" | `as()`, `as`, `as()`, `as()`, `as()` | +| byte_string_value | 0x660x6F0x6F | `as()`, `as()` | +| int64_value | -1000 | `as()`, `as()`, `as`, `as()` | +| uint64_value | 1000 | `as()`, `as()`, `as()`, `as()`, `as()` | +| double_value | 125.72 | `as()`, `as()` | +| bool_value | true | `as()`, `as()` | +| null_value | | `as()` | + +#### Member functions + + staj_event_type event_type() const noexcept; +Returns a [staj_event_type](staj_event_type.md) for this event. + + semantic_tag get_semantic_tag() const noexcept; +Returns a [semantic_tag](semantic_tag.md) for this event. + + template + T as(Args&&... args) const; +Attempts to convert the json value to the template value type. + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/staj_event_type.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/staj_event_type.md new file mode 100644 index 0000000000..fc028609ea --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/staj_event_type.md @@ -0,0 +1,27 @@ +### jsoncons::staj_event_type + +#### Header +```c++ +#include +``` + +```c++ +enum class staj_event_type +{ + begin_object, + end_object, + begin_array, + end_array, + name, + string_value, + byte_string_value, + bigint_value, + bigdec_value, + int64_value, + uint64_value, + double_value, + bool_value, + null_value +}; +``` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/staj_filter.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/staj_filter.md new file mode 100644 index 0000000000..b9d623944d --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/staj_filter.md @@ -0,0 +1,20 @@ +### jsoncons::staj_filter + +```c++ +typedef basic_staj_filter staj_filter; +``` + +#### Header +```c++ +#include +``` + +#### Destructor + + virtual ~basic_staj_filter() = default; + +#### Member functions + + virtual bool accept(const staj_event& event, const ser_context& context) = 0; +Tests whether the [current event](staj_event.md) is part of the stream. Returns `true` if the filter accepts the event, `false` otherwise. + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/staj_object_iterator.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/staj_object_iterator.md new file mode 100644 index 0000000000..c9910b1d22 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/staj_object_iterator.md @@ -0,0 +1,131 @@ +### jsoncons::staj_object_iterator + +```c++ +template +using staj_object_iterator = basic_staj_object_iterator>; +``` + +#### Header +```c++ +#include +``` + +A `staj_object_iterator` is an [InputIterator](https://en.cppreference.com/w/cpp/named_req/InputIterator) that +accesses the individual stream events from a [staj_reader](staj_reader.md) and, provided that when it is constructed +the current stream event has type `begin_object`, it returns the elements +of the JSON object as items of type `std::pair`. If when it is constructed the current stream event +does not have type `begin_object`, it becomes equal to the default-constructed iterator. + +#### Member types + +Member type |Definition +------------------------------------|------------------------------ +`char_type`|`char` +`key_type`|`std::basic_string` +`value_type`|`std::pair` +`difference_type`|`std::ptrdiff_t` +`pointer`|`value_type*` +`reference`|`value_type&` +`iterator_category`|[std::input_iterator_tag](https://en.cppreference.com/w/cpp/iterator/iterator_tags) + +#### Constructors + + staj_object_iterator() noexcept; // (1) + + staj_object_iterator(basic_staj_reader& reader); // (2) + + staj_object_iterator(basic_staj_reader& reader, + std::error_code& ec); // (3) + +(1) Constructs the end iterator + +(2) Constructs a `staj_object_iterator` that refers to the first member of the object + following the current stream event `begin_object`. If there is no such member, + returns the end iterator. If a parsing error is encountered, throws a + [ser_error](ser_error.md). + +(3) Constructs a `staj_object_iterator` that refers to the first member of the object + following the current stream event `begin_object`. If there is no such member, + returns the end iterator. If a parsing error is encountered, returns the end iterator + and sets `ec`. + +#### Member functions + + const key_value_type& operator*() const + + const key_value_type* operator->() const + + staj_object_iterator& operator++(); + staj_object_iterator operator++(int); + staj_object_iterator& increment(std::error_code& ec); +Advances the iterator to the next object member. + +#### Non-member functions + + template + bool operator==(const staj_object_iterator& a, const staj_object_iterator& b) + + template + bool operator!=(const staj_object_iterator& a, const staj_object_iterator& b) + + template + staj_object_iterator begin(staj_object_iterator iter) noexcept; // (1) + + template + staj_object_iterator end(const staj_object_iterator&) noexcept; // (2) + +(1) Returns iter unchanged + +(2) Returns a default-constructed `stax_array_iterator`, which serves as an end iterator. The argument is ignored. + +The `begin` and `end` non-member functions enable the use of `stax_array_iterators` with range-based for loops. + +### Examples + +#### Iterate over a JSON object, returning key-json value pairs + +```c++ +const std::string example = R"( +{ + "application": "hiking", + "reputons": [ + { + "rater": "HikingAsylum.array_example.com", + "assertion": "strong-hiker", + "rated": "Marilyn C", + "rating": 0.90 + } + ] +} +)"; + +int main() +{ + std::istringstream is(object_example); + + json_cursor reader(is); + + staj_object_iterator it(reader); + + for (const auto& kv : it) + { + std::cout << kv.first << ":\n" << pretty_print(kv.second) << "\n"; + } + std::cout << "\n\n"; +} +``` +Output: +``` +application: +"hiking" +reputons: +[ + { + "assertion": "strong-hiker", + "rated": "Marilyn C", + "rater": "HikingAsylum.array_example.com", + "rating": 0.90 + } +] +``` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/staj_reader.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/staj_reader.md new file mode 100644 index 0000000000..02a25a2891 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/staj_reader.md @@ -0,0 +1,59 @@ +### jsoncons::staj_reader + +```c++ +typedef basic_staj_reader staj_reader +``` + +#### Header +```c++ +#include +``` + +The `staj_reader` interface supports forward, read-only, access to JSON and JSON-like data formats. + +The `staj_reader` is designed to iterate over stream events until `done()` returns `true`. +The `next()` function causes the reader to advance to the next stream event. The `current()` function +returns the current stream event. The data can be accessed using the [staj_event](staj_event.md) +interface. When `next()` is called, copies of data previously accessed may be invalidated. + +#### Destructor + + virtual ~basic_staj_reader() = default; + +#### Member functions + + virtual bool done() const = 0; +Check if there are no more events. + + virtual const staj_event& current() const = 0; +Returns the current [staj_event](staj_event.md). + + virtual void accept(json_content_handler& handler) = 0; +Sends the parse events from the current event to the +matching completion event to the supplied [handler](json_content_handler.md) +E.g., if the current event is `begin_object`, sends the `begin_object` +event and all inbetween events until the matching `end_object` event. +If a parsing error is encountered, throws a [ser_error](ser_error.md). + + virtual void accept(json_content_handler& handler, + std::error_code& ec) = 0; +Sends the parse events from the current event to the +matching completion event to the supplied [handler](json_content_handler.md) +E.g., if the current event is `begin_object`, sends the `begin_object` +event and all inbetween events until the matching `end_object` event. +If a parsing error is encountered, sets `ec`. + + virtual void next() = 0; +Get the next event. If a parsing error is encountered, throws a [ser_error](ser_error.md). + + virtual void next(std::error_code& ec) = 0; +Get the next event. If a parsing error is encountered, sets `ec`. + + virtual const ser_context& context() const = 0; +Returns the current [context](ser_context.md) + +#### See also + +- [staj_array_iterator](staj_array_iterator.md) +- [staj_object_iterator](staj_object_iterator.md) + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/ubjson/decode_ubjson.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/ubjson/decode_ubjson.md new file mode 100644 index 0000000000..f212cbfcc6 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/ubjson/decode_ubjson.md @@ -0,0 +1,30 @@ +### jsoncons::ubjson::decode_ubjson + +Decodes a [Universal Binary JSON Specification (JSON)](http://ubjson.org/) data format into a C++ data structure. + +#### Header +```c++ +#include + +template +T decode_ubjson(const std::vector& v); // (1) + +template +T decode_ubjson(std::istream>& is); // (2) +``` + +(1) Reads a UBJSON bytes buffer into a type T if T is an instantiation of [basic_json](../json.md) +or if T supports [json_type_traits](../json_type_traits.md). + +(2) Reads a UBJSON binary stream into a type T if T is an instantiation of [basic_json](../json.md) +or if T supports [json_type_traits](../json_type_traits.md). + +#### Exceptions + +Throws [ser_error](../ser_error.md) if parsing fails. + +#### See also + +- [encode_ubjson](encode_ubjson.md) encodes a json value to the [Universal Binary JSON Specification](http://ubjson.org/) data format. + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/ubjson/diagrams/ubjson_encoder.png b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/ubjson/diagrams/ubjson_encoder.png new file mode 100644 index 0000000000..c2dbc8fe89 Binary files /dev/null and b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/ubjson/diagrams/ubjson_encoder.png differ diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/ubjson/diagrams/ubjson_encoder.xml b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/ubjson/diagrams/ubjson_encoder.xml new file mode 100644 index 0000000000..4698371f69 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/ubjson/diagrams/ubjson_encoder.xml @@ -0,0 +1 @@ +vVbfb9owEP5r8tgpiQuljy3QbkNU65gEfUImvibeHJs5BsL++tmJTX6iUqlqHyrfd76z/d13Fzw0TvNHibfJXBBgXuiT3EMTLwxvgpH+b4BjCaChXwKxpKSEggpY0H9gQbdtRwlkjY1KCKbotglGgnOIVAPDUopDc9urYM1TtziGDrCIMOuiS0pUUqKjgV/hX4HGiTs58K0nxW6zBbIEE3GoQWjqobEUQpWrNB8DM9w5Xsq4hzPe08UkcHVJwPTpV85nz4skHP+dqeU8fcm/X9kse8x29sEbnNFo/TsTfK05VTr5OsGcMJBeOGT6pPuNWcVm1YcUT1VHx58UO07AXMHX7kNCFSy2ODLegxaMxhKVMm0Fp+j6k9z9QCrIa5B94iOIFJQ86i3WO7JsW7kFjv1DVbzASTCpFe7aYtjqJT5lrijVC8vqOxi+OcPwblNwDDzSLfMJ3L5SxsaCCVnEIij+NJ4pKf5AzYOG6BaRj6nGReUYfGY5Rp1ydGgFTu7M5NBWxHCmi9VkEnKqVpZ0s34x6y8Da03ymmtydAbXl1+5BMaoRRmzCissF3e2BpnYyQje1p3CMgb19gQA0piD3YrWKtZXMIdJYFjRfXN69lXRnvBDUP2yk2Cum3oJUUsH5bNtUH3YtfLctnQ3auUpaenkKSR1evRFKov38yScPa3wT4ivls8z2M+gp+m/8QQkVZjroumvIcWxxGlHerqtVFNszfbkgkOrly2EGY25UawWih4n6N40KdXfsTvrSCkh5pjeOdGcJB/R+H6rkH5P46MeHYXvb3xtVl/RsoLVTxE0/Q8= \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/ubjson/encode_ubjson.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/ubjson/encode_ubjson.md new file mode 100644 index 0000000000..d49a52b7a8 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/ubjson/encode_ubjson.md @@ -0,0 +1,25 @@ +### jsoncons::ubjson::encode_ubjson + +Encodes a C++ data structure to the [Universal Binary JSON Specification (UBJSON)](http://ubjsonspec.org/) data format. + +#### Header +```c++ +#include + +template +void encode_ubjson(const T& jval, std::vector& v); // (1) + +template +void encode_ubjson(const T& jval, std::ostream& os); // (2) +``` + +(1) Writes a value of type T into a bytes buffer in the UBJSON data format. Type T must be an instantiation of [basic_json](../json.md) +or support [json_type_traits](../json_type_traits.md). + +(2) Writes a value of type T into a binary stream in the UBJSON data format. Type T must be an instantiation of [basic_json](../json.md) +or support [json_type_traits](../json_type_traits.md). + +#### See also + +- [decode_ubjson](decode_ubjson) decodes a [Binary JSON](http://ubjsonspec.org/) data format to a json value. + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/ubjson/ubjson.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/ubjson/ubjson.md new file mode 100644 index 0000000000..82484b5d51 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/ubjson/ubjson.md @@ -0,0 +1,179 @@ +### ubjson extension + +The ubjson extension implements encode to and decode from the [Universal Binary JSON Specification](http://ubjson.org/) data format. +You can either parse into or serialize from a variant-like structure, [basic_json](../json.md), or your own +data structures, using [json_type_traits](../json_type_traits.md). + +[decode_ubjson](decode_ubjson.md) + +[encode_ubjson](encode_ubjson.md) + +[ubjson_encoder](ubjson_encoder.md) + +#### jsoncons-ubjson mappings + +jsoncons data item|jsoncons tag|UBJSON data item +--------------|------------------|--------------- +null | | null +bool | | true or false +int64 | | uint8_t or integer +uint64 | | uint8_t or integer +double | | float 32 or float 64 +string | | string +string | bigint | high precision number type +string | bigdec | high precision number type +byte_string | | array of uint8_t +array | | array +object | | object + +### Examples + +#### encode/decode UBJSON from/to basic_json + +```c++ +#include +#include +#include + +using namespace jsoncons; + +int main() +{ + ojson j1 = ojson::parse(R"( + { + "application": "hiking", + "reputons": [ + { + "rater": "HikingAsylum.example.com", + "assertion": "strong-hiker", + "rated": "Marilyn C", + "rating": 0.90 + } + ] + } + )"); + + // Encode a basic_json value to UBJSON + std::vector data; + ubjson::encode_ubjson(j1, data); + + // Decode UBJSON to a basic_json value + ojson j2 = ubjson::decode_ubjson(data); + std::cout << "(1)\n" << pretty_print(j2) << "\n\n"; + + // Accessing the data items + + const ojson& reputons = j2["reputons"]; + + std::cout << "(2)\n"; + for (auto element : reputons.array_range()) + { + std::cout << element.at("rated").as() << ", "; + std::cout << element.at("rating").as() << "\n"; + } + std::cout << std::endl; + + // Get a UBJSON value for a nested data item with jsonpointer + std::error_code ec; + const auto& rated = jsonpointer::get(j2, "/reputons/0/rated", ec); + if (!ec) + { + std::cout << "(3) " << rated.as_string() << "\n"; + } + + std::cout << std::endl; +} +``` +Output: +``` +(1) +{ + "application": "hiking", + "reputons": [ + { + "rater": "HikingAsylum.example.com", + "assertion": "strong-hiker", + "rated": "Marilyn C", + "rating": 0.9 + } + ] +} + +(2) +Marilyn C, 0.9 + +(3) Marilyn C +``` + +#### encode/decode UBJSON from/to your own data structures + +```c++ +#include +#include +namespace ns { + struct reputon + { + std::string rater; + std::string assertion; + std::string rated; + double rating; + + friend bool operator==(const reputon& lhs, const reputon& rhs) + { + return lhs.rater == rhs.rater && lhs.assertion == rhs.assertion && + lhs.rated == rhs.rated && lhs.rating == rhs.rating; + } + + friend bool operator!=(const reputon& lhs, const reputon& rhs) + { + return !(lhs == rhs); + }; + }; + + class reputation_object + { + std::string application; + std::vector reputons; + + // Make json_type_traits specializations friends to give accesses to private members + JSONCONS_TYPE_TRAITS_FRIEND; + public: + reputation_object() + { + } + reputation_object(const std::string& application, const std::vector& reputons) + : application(application), reputons(reputons) + {} + + friend bool operator==(const reputation_object& lhs, const reputation_object& rhs) + { + return (lhs.application == rhs.application) && (lhs.reputons == rhs.reputons); + } + + friend bool operator!=(const reputation_object& lhs, const reputation_object& rhs) + { + return !(lhs == rhs); + }; + }; + +} // ns + +// Declare the traits. Specify which data members need to be serialized. +JSONCONS_MEMBER_TRAITS_DECL(ns::reputon, rater, assertion, rated, rating) +JSONCONS_MEMBER_TRAITS_DECL(ns::reputation_object, application, reputons) + +int main() +{ + ns::reputation_object val("hiking", { ns::reputon{"HikingAsylum.example.com","strong-hiker","Marilyn C",0.90} }); + + // Encode a ns::reputation_object value to UBJSON + std::vector data; + ubjson::encode_ubjson(val, data); + + // Decode UBJSON to a ns::reputation_object value + ns::reputation_object val2 = ubjson::decode_ubjson(data); + + assert(val2 == val); +} +``` + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/ubjson/ubjson_encoder.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/ubjson/ubjson_encoder.md new file mode 100644 index 0000000000..5cc6f98c9f --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/ubjson/ubjson_encoder.md @@ -0,0 +1,100 @@ +### jsoncons::ubjson::basic_ubjson_encoder + +```c++ +template< + class Result> +> class basic_ubjson_encoder : public jsoncons::json_content_handler +``` + +`basic_ubjson_encoder` is noncopyable and nonmoveable. + +#### Header + + #include + +![ubjson_encoder](./diagrams/ubjson_encoder.png) + +Four specializations for common character types and result types are defined: + +Type |Definition +---------------------------|------------------------------ +ubjson_encoder |basic_ubjson_encoder +ubjson_bytes_encoder |basic_ubjson_encoder + +#### Member types + +Type |Definition +---------------------------|------------------------------ +char_type |char +result_type |Result +string_view_type | + +#### Constructors + + explicit basic_ubjson_encoder(result_type result) +Constructs a new encoder that writes to the specified result. + +#### Destructor + + virtual ~basic_ubjson_encoder() + +### Inherited from [basic_json_content_handler](../json_content_handler.md) + +#### Member functions + + bool begin_object(semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool begin_object(size_t length, + semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool end_object(const ser_context& context = null_ser_context()) + + bool begin_array(semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool begin_array(semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool end_array(const ser_context& context=null_ser_context()); + + bool name(const string_view_type& name, + const ser_context& context=null_ser_context()); + + bool string_value(const string_view_type& value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool byte_string_value(const byte_string_view& b, + semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool byte_string_value(const uint8_t* p, size_t size, + semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool int64_value(int64_t value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool uint64_value(uint64_t value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool double_value(double value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool bool_value(bool value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); + + bool null_value(semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()); + + void flush() + +### Examples + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/wjson.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/wjson.md new file mode 100644 index 0000000000..cadd491d54 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/wjson.md @@ -0,0 +1,27 @@ +### jsoncons::wjson + +```c++ +typedef basic_json> wjson +``` +The `wjson` class is an instantiation of the `basic_json` class template that uses `wchar_t` as the character type. The order of an object's name/value pairs is not preserved, they are sorted alphabetically by name. If you want to preserve the original insertion order, use [wojson](wojson.md) instead. + +The `jsoncons` library will always rebind the supplied allocator from the template parameter to internal data structures. + +#### Header +```c++ +#include +``` +#### Interface + +The interface is the same as [json](json.md), substituting wide character instantiations of classes - `std::wstring`, `std::wistream`, etc. - for utf8 character ones. + +#### See also + +- [wojson](wojson.md) constructs a wide character json value that preserves the original insertion order of an object's name/value pairs + +- [json](json.md) constructs a utf8 character json value that sorts name-value members alphabetically + +- [ojson](ojson.md) constructs a utf8 character json value that preserves the original insertion order of an object's name/value pairs + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/wjson_encoder.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/wjson_encoder.md new file mode 100644 index 0000000000..a21102c873 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/wjson_encoder.md @@ -0,0 +1,15 @@ +### jsoncons::wjson_encoder + +```c++ +typedef basic_json_encoder wjson_encoder +``` + +The `wjson_encoder` class is an instantiation of the `basic_json_encoder` class template that uses `wchar_t` as the character type. It implements [wjson_content_handler](basic_json_content_handler.md) and supports pretty print serialization. + +#### Header + + #include + +#### Interface + +The interface is the same as [json_encoder](json_encoder.md), substituting wide character instantiations of classes - `std::wstring`, etc. - for utf8 character ones. diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/wjson_options.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/wjson_options.md new file mode 100644 index 0000000000..d61ec79c81 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/wjson_options.md @@ -0,0 +1,16 @@ +### jsoncons::wjson_options + +```c++ +typedef basic_json_options wjson_options +``` +The wjson_options class is an instantiation of the basic_json_options class template that uses `wchar_t` as the character type. + +#### Header + +```c++ +#include +``` + +#### Interface + +The interface is the same as [json_options](json_options.md), substituting wide character instantiations of classes - `std::wstring`, etc. - for utf8 character ones. diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/wjson_reader.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/wjson_reader.md new file mode 100644 index 0000000000..78dc37358f --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/wjson_reader.md @@ -0,0 +1,16 @@ +### jsoncons::wjson_reader + +```c++ + typedef basic_json_reader> wjson_reader +``` +The `wjson_reader` class is an instantiation of the `basic_json_reader` class template that uses `wchar_t` as the character type +and `stream_source` as the input source. + +#### Header + + #include + +#### Interface + +The interface is the same as [json_reader](json_reader.md), substituting wide character instantiations of classes - `std::wstring`, `std::wistream`, etc. - for utf8 character ones. + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/wojson.md b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/wojson.md new file mode 100644 index 0000000000..bb7bdd997e --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/doc/ref/wojson.md @@ -0,0 +1,31 @@ +### jsoncons::wojson + +```c++ +typedef basic_json> wojson +``` +The `wojson` class is an instantiation of the `basic_json` class template that uses `wchar_t` as the character type. The original insertion order of an object's name/value pairs is preserved. + +The `jsoncons` library will always rebind the supplied allocator from the template parameter to internal data structures. + +#### Header +```c++ +#include +``` +#### Interface + +The interface is the same as [wjson](wjson.md), substituting wide character instantiations of classes - `std::wstring`, `std::wistream`, etc. - for utf8 character ones. + +- `wojson`, like `wjson`, supports object member `insert_or_assign` methods that take an `object_iterator` as the first parameter. But while with `wjson` that parameter is just a hint that allows optimization, with `wojson` it is the actual location where to insert the member. + +- In `wojson`, the `insert_or_assign` members that just take a name and a value always insert the member at the end. + +#### See also + +- [wjson](wjson.md) constructs a wide character json value that sorts name-value members alphabetically + +- [json](json.md) constructs a utf8 character json value that sorts name-value members alphabetically + +- [ojson](ojson.md) constructs a utf8 character json value that preserves the original insertion order of an object's name/value pairs + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/input/address-book.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/input/address-book.json new file mode 100644 index 0000000000..c3d5d98369 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/input/address-book.json @@ -0,0 +1,13 @@ + { + "address-book" : + [ + { + "name":"Jane Roe", + "email":"jane.roe@example.com" + }, + { + "name":"John", + "email" : "john.doe@example.com" + } + ] + } diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/input/booklist.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/input/booklist.json new file mode 100644 index 0000000000..ec78a4216b --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/input/booklist.json @@ -0,0 +1,28 @@ +{ "store": { + "book": [ + { "category": "reference", + "author": "Nigel Rees", + "title": "Sayings of the Century", + "price": 8.95 + }, + { "category": "fiction", + "author": "Evelyn Waugh", + "title": "Sword of Honour", + "price": 12.99 + }, + { "category": "fiction", + "author": "Herman Melville", + "title": "Moby Dick", + "isbn": "0-553-21311-3", + "price": 8.99 + }, + { "category": "fiction", + "author": "J. R. R. Tolkien", + "title": "The Lord of the Rings", + "isbn": "0-395-19395-8", + "price": 22.99 + } + ] + } +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/input/books.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/input/books.json new file mode 100644 index 0000000000..ae9677c2e3 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/input/books.json @@ -0,0 +1,30 @@ +[ + { + "title" : "Kafka on the Shore", + "author" : "Haruki Murakami", + "price" : 25.17, + "reviews" : + [ + {"rating" : "*****"}, + {"rating" : "*****"} + ] + }, + { + "title" : "Women: A Novel", + "author" : "Charles Bukowski", + "price" : 12.00, + "reviews" : + [ + {"rating" : "*****"}, + {"rating" : "*"} + ] + }, + { + "title" : "Cutter's Way", + "author" : "Ivan Passer", + "reviews" : + [ + {"rating" : "****"} + ] + } +] diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/input/countries.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/input/countries.json new file mode 100644 index 0000000000..29629e4253 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/input/countries.json @@ -0,0 +1,7 @@ +[ + ["country_code","name"], + ["ABW","ARUBA"], + ["ATF","FRENCH SOUTHERN TERRITORIES, D.R. OF"], + ["VUT","VANUATU"], + ["WLF","WALLIS & FUTUNA ISLANDS"] +] diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/input/employees.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/input/employees.json new file mode 100644 index 0000000000..a4837466b4 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/input/employees.json @@ -0,0 +1,30 @@ +[ + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + } +] diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/input/multiple-json-objects.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/input/multiple-json-objects.json new file mode 100644 index 0000000000..c5516582ed --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/input/multiple-json-objects.json @@ -0,0 +1,3 @@ +{"a":1,"b":2,"c":3} +{"a":4,"b":5,"c":6} +{"a":7,"b":8,"c":9} diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/input/sales.csv b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/input/sales.csv new file mode 100644 index 0000000000..b5177e6983 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/input/sales.csv @@ -0,0 +1,6 @@ +customer_name,has_coupon,phone_number,zip_code,sales_tax_rate,total_amount +"John Roe",true,0272561313,01001,0.05,431.65 +"Jane Doe",false,416-272-2561,55416,0.15,480.70 +"Joe Bloggs",false,"4162722561","55416",0.15,300.70 +"John Smith",FALSE,NULL,22313-1450,0.15,300.70 + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/input/tasks.csv b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/input/tasks.csv new file mode 100644 index 0000000000..facd635164 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/input/tasks.csv @@ -0,0 +1,6 @@ +project_id, task_name, task_start, task_finish +4001,task1,01/01/2003,01/31/2003 +4001,task2,02/01/2003,02/28/2003 +4001,task3,03/01/2003,03/31/2003 +4002,task1,04/01/2003,04/30/2003 +4002,task2,05/01/2003, diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/output/booklist.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/output/booklist.json new file mode 100644 index 0000000000..29293a53c7 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/output/booklist.json @@ -0,0 +1,37 @@ +[ + { + "author": "Haruki Murakami", + "category": "Fiction", + "date": "2006-01-03", + "isbn": "1400079276", + "price": 13.45, + "title": "Kafka on the Shore" + }, + { + "author": "Charles Bukowski", + "category": "Fiction", + "date": "2004-07-08", + "isbn": "1852272007", + "price": 22.48, + "ratings": { + "*****": 4 + }, + "title": "Pulp" + }, + { + "author": "Haruki Murakami", + "category": "Fiction", + "date": "2002-04-09", + "isbn": "037571894X", + "price": 9.01, + "title": "A Wild Sheep Chase: A Novel" + }, + { + "author": "George Crile", + "category": "History", + "date": "2007-11-06", + "isbn": "0802143415", + "price": 10.5, + "title": "Charlie Wilson's War" + } +] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/output/booklist2.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/output/booklist2.json new file mode 100644 index 0000000000..29293a53c7 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/output/booklist2.json @@ -0,0 +1,37 @@ +[ + { + "author": "Haruki Murakami", + "category": "Fiction", + "date": "2006-01-03", + "isbn": "1400079276", + "price": 13.45, + "title": "Kafka on the Shore" + }, + { + "author": "Charles Bukowski", + "category": "Fiction", + "date": "2004-07-08", + "isbn": "1852272007", + "price": 22.48, + "ratings": { + "*****": 4 + }, + "title": "Pulp" + }, + { + "author": "Haruki Murakami", + "category": "Fiction", + "date": "2002-04-09", + "isbn": "037571894X", + "price": 9.01, + "title": "A Wild Sheep Chase: A Novel" + }, + { + "author": "George Crile", + "category": "History", + "date": "2007-11-06", + "isbn": "0802143415", + "price": 10.5, + "title": "Charlie Wilson's War" + } +] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/output/export_settings.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/output/export_settings.json new file mode 100644 index 0000000000..8f1ad880ad --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/output/export_settings.json @@ -0,0 +1 @@ +{"File Format Options":{"Color Spaces":["sRGB","AdobeRGB","ProPhoto RGB"],"Image Formats":["JPEG","PSD","TIFF","DNG"]},"File Settings":{"Color Space":"sRGB","Image Format":"JPEG","Limit File Size":true,"Limit File Size To":10000},"Image Sizing":{"Dimension 1":9.84,"Resize To Fit":true,"Resize Unit":"pixels","Resize What":"long_edge"}} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/output/new-address-book1.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/output/new-address-book1.json new file mode 100644 index 0000000000..d390928d82 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/output/new-address-book1.json @@ -0,0 +1,13 @@ +{ + "address-book": [ + { + "first-name": "Jane", + "last-name": "Roe", + "email": "jane.roe@example.com" + }, + { + "first-name": "John", + "email": "john.doe@example.com" + } + ] +} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/output/new-address-book2.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/output/new-address-book2.json new file mode 100644 index 0000000000..628c37a1c8 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/output/new-address-book2.json @@ -0,0 +1,13 @@ +{ + "address-book": [ + { + "email": "jane.roe@example.com", + "first-name": "Jane", + "last-name": "Roe" + }, + { + "email": "john.doe@example.com", + "first-name": "John" + } + ] +} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/output/tasks.csv b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/output/tasks.csv new file mode 100644 index 0000000000..de05a3ee4c --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/output/tasks.csv @@ -0,0 +1,6 @@ +(1) +project_id,task_name,task_start,task_finish +4001,task2,02/01/2003,02/28/2003 +4001,task3,03/01/2003,03/31/2003 +4002,task1,04/01/2003,04/30/2003 +4002,task2,05/01/2003, diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/output/tasks.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/output/tasks.json new file mode 100644 index 0000000000..d61c59d14d --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/output/tasks.json @@ -0,0 +1,33 @@ +(1) +[ + { + "project_id": 4001, + "task_name": "task1", + "task_start": "01/01/2003", + "task_finish": "01/31/2003" + }, + { + "project_id": 4001, + "task_name": "task2", + "task_start": "02/01/2003", + "task_finish": "02/28/2003" + }, + { + "project_id": 4001, + "task_name": "task3", + "task_start": "03/01/2003", + "task_finish": "03/31/2003" + }, + { + "project_id": 4002, + "task_name": "task1", + "task_start": "04/01/2003", + "task_finish": "04/30/2003" + }, + { + "project_id": 4002, + "task_name": "task2", + "task_start": "05/01/2003" + } +] + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/output/xxx.txt b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/output/xxx.txt new file mode 100644 index 0000000000..bed26dd937 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/output/xxx.txt @@ -0,0 +1,3 @@ +[ + "\u007F\u07FF\u0800" +] diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/array_examples.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/array_examples.cpp new file mode 100644 index 0000000000..85be172281 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/array_examples.cpp @@ -0,0 +1,227 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include + +using namespace jsoncons; + +void array_example1() +{ + { + std::vector v = {1,2,3,4}; + json a(v); + std::cout << a << std::endl; + } + { + json j = json::array{1,true,"last"}; + auto d = j.as>(); + for (auto x : d) + { + std::cout << x << std::endl; + } + } + { + std::map m = {{"one",1},{"two",2},{"three",3}}; + json j(m); + std::cout << j << std::endl; + } + { + json j; + j["one"] = 1; + j["two"] = 2; + j["three"] = 3; + + auto um = j.as>(); + for (const auto& x : um) + { + std::cout << x.first << "=" << x.second << std::endl; + } + } +} + +void accessing_a_json_value_as_a_vector() +{ + std::string s = "{\"my-array\" : [1,2,3,4]}"; + json val = json::parse(s); + std::vector v = val["my-array"].as>(); + for (size_t i = 0; i < v.size(); ++i) + { + if (i > 0) + { + std::cout << ","; + } + std::cout << v[i]; + } + std::cout << std::endl; +} + +void construct_json_from_vector() +{ + json root; + + std::vector addresses; + json address1; + address1["city"] = "San Francisco"; + address1["state"] = "CA"; + address1["zip"] = "94107"; + address1["country"] = "USA"; + addresses.push_back(address1); + + json address2; + address2["city"] = "Sunnyvale"; + address2["state"] = "CA"; + address2["zip"] = "94085"; + address2["country"] = "USA"; + addresses.push_back(address2); + + root["addresses"] = addresses; + + std::cout << pretty_print(root) << std::endl; + + std::cout << "size=" << root["addresses"].size() << std::endl; + for (size_t i = 0; i < root["addresses"].size(); ++i) + { + std::cout << root["addresses"][i] << std::endl; + } +} + +void add_element_to_array() +{ + json cities = json::array(); // an empty array + std::cout << cities << std::endl; // output is "[]" + cities.push_back("Toronto"); + cities.push_back("Vancouver"); + cities.insert(cities.array_range().begin(),"Montreal"); // inserts "Montreal" at beginning of array + + std::cout << cities << std::endl; +} + +void reserve_array_capacity() +{ + json cities = json::array(); + cities.reserve(10); // storage is allocated + std::cout << "capacity=" << cities.capacity() << ", size=" << cities.size() << std::endl; + + cities.push_back("Toronto"); + cities.push_back("Vancouver"); + cities.insert(cities.array_range().begin(),"Montreal"); + std::cout << "capacity=" << cities.capacity() << ", size=" << cities.size() << std::endl; + + std::cout << cities << std::endl; +} + +void make_empty_array() +{ + std::cout << "empty array" <() << std::endl; + } +} + +void make_1_dimensional_array_1() +{ + std::cout << "1 dimensional array 1" <(10); + a[1] = 1; + a[2] = 2; + std::cout << pretty_print(a) << std::endl; +} + +void make_1_dimensional_array_2() +{ + std::cout << "1 dimensional array 2" <(10,0); + a[1] = 1; + a[2] = 2; + a[3] = json::array(); + std::cout << pretty_print(a) << std::endl; +} + +void make_2_dimensional_array() +{ + std::cout << "2 dimensional array" <(3,4,0); + a[0][0] = "Tenor"; + a[0][1] = "ATM vol"; + a[0][2] = "25-d-MS"; + a[0][3] = "25-d-RR"; + a[1][0] = "1Y"; + a[1][1] = 0.20; + a[1][2] = 0.009; + a[1][3] = -0.006; + a[2][0] = "2Y"; + a[2][1] = 0.18; + a[2][2] = 0.009; + a[2][3] = -0.005; + + std::cout << pretty_print(a) << std::endl; +} + +void make_3_dimensional_array() +{ + std::cout << "3 dimensional array" <(4,3,2,0); + + double val = 1.0; + for (size_t i = 0; i < a.size(); ++i) + { + for (size_t j = 0; j < a[i].size(); ++j) + { + for (size_t k = 0; k < a[i][j].size(); ++k) + { + a[i][j][k] = val; + val += 1.0; + } + } + } + std::cout << pretty_print(a) << std::endl; +} + +void array_examples() +{ + std::cout << "\nArray examples\n\n"; + array_example1(); + + construct_json_from_vector(); + add_element_to_array(); + reserve_array_capacity(); + accessing_a_json_value_as_a_vector(); + make_empty_array(); + array_range_based_for_loop(); + make_1_dimensional_array_1(); + make_1_dimensional_array_2(); + make_2_dimensional_array(); + make_3_dimensional_array(); + + std::cout << std::endl; +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/basics_examples.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/basics_examples.cpp new file mode 100644 index 0000000000..814861b32a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/basics_examples.cpp @@ -0,0 +1,171 @@ +// jsoncons_test.cpp : Defines the entry point for the console application. +// + +#include +#include +#include + +using namespace jsoncons; +using namespace jsoncons::jsonpath; + +void basics_json_example1() +{ + // Construct a book object + json book1; + + book1["category"] = "Fiction"; + book1["title"] = "A Wild Sheep Chase: A Novel"; + book1["author"] = "Haruki Murakami"; + book1["date"] = "2002-04-09"; + book1["price"] = 9.01; + book1["isbn"] = "037571894X"; + + // Construct another using the member function insert_or_assign + json book2; + + book2.insert_or_assign("category", "History"); + book2.insert_or_assign("title", "Charlie Wilson's War"); + book2.insert_or_assign("author", "George Crile"); + book2.insert_or_assign("date", "2007-11-06"); + book2.insert_or_assign("price", 10.50); + book2.insert_or_assign("isbn", "0802143415"); + + // Use insert_or_assign again, but more efficiently + json book3; + + // Reserve memory, to avoid reallocations + book3.reserve(6); + + // Insert in name alphabetical order + // Give insert_or_assign a hint where to insert the next member + auto hint = book3.insert_or_assign(book3.object_range().begin(),"author", "Haruki Murakami"); + hint = book3.insert_or_assign(hint, "category", "Fiction"); + hint = book3.insert_or_assign(hint, "date", "2006-01-03"); + hint = book3.insert_or_assign(hint, "isbn", "1400079276"); + hint = book3.insert_or_assign(hint, "price", 13.45); + hint = book3.insert_or_assign(hint, "title", "Kafka on the Shore"); + + // Construct a fourth from a string + json book4 = json::parse(R"( + { + "category" : "Fiction", + "title" : "Pulp", + "author" : "Charles Bukowski", + "date" : "2004-07-08", + "price" : 22.48, + "isbn" : "1852272007" + } + )"); + + // Construct a booklist array + json booklist = json::array(); + + // For efficiency, reserve memory, to avoid reallocations + booklist.reserve(4); + + // For efficency, tell jsoncons to move the contents + // of the four book objects into the array + booklist.push_back(std::move(book1)); + booklist.push_back(std::move(book2)); + + // Add the third one to the front + auto where = booklist.insert(booklist.array_range().begin(),std::move(book3)); + + // Add the last one immediately after + booklist.insert(where+1,std::move(book4)); + + // See what's left of book1, 2, 3 and 4 (expect nulls) + std::cout << book1 << "," << book2 << "," << book3 << "," << book4 << std::endl; + + //Loop through the booklist elements using a range-based for loop + for(auto book : booklist.array_range()) + { + std::cout << book["title"].as() + << "," + << book["price"].as() << std::endl; + } + + // The second book + json& book = booklist[1]; + + //Loop through the book members using a range-based for loop + for(auto member : book.object_range()) + { + std::cout << member.key() + << "," + << member.value() << std::endl; + } + + auto it = book.find("author"); + if (it != book.object_range().end()) + { + // member "author" found + } + + if (book.contains("author")) + { + // book has member "author" + } + + std::string s = book.get_with_default("author", "author unknown"); + // Returns author if found, otherwise "author unknown" + + try + { + book["ratings"].as(); + } + catch (const std::out_of_range&) + { + // member "ratings" not found + } + + // Add ratings + book["ratings"]["*****"] = 4; + book["ratings"]["*"] = 1; + + // Delete one-star ratings + book["ratings"].erase("*"); + + // Serialize the booklist to a file + std::ofstream os("./output/booklist.json"); + os << pretty_print(booklist); +} + +void basics_json_example2() +{ + // Deserialize the booklist + std::ifstream is("./output/booklist.json"); + json booklist; + is >> booklist; + + // Use a JSONPath expression to find + + // (1) The authors of books that cost less than $12 + json result = json_query(booklist, "$[*][?(@.price < 12)].author"); + std::cout << "(1) " << result << std::endl; + + // (2) The number of books + result = json_query(booklist, "$.length"); + std::cout << "(2) " << result << std::endl; + + // (3) The third book + result = json_query(booklist, "$[2]"); + std::cout << "(3) " << std::endl << pretty_print(result) << std::endl; + + // (4) The authors of books that were published in 2004 + result = json_query(booklist, "$[*][?(@.date =~ /2004.*?/)].author"); + std::cout << "(4) " << result << std::endl; + + // (5) The titles of all books that have ratings + result = json_query(booklist, "$[*][?(@.ratings)].title"); + std::cout << "(5) " << result << std::endl; +} + +void basics_examples() +{ + std::cout << "\nBasics\n\n"; + basics_json_example1(); + basics_json_example2(); + std::cout << std::endl; +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/basics_wexamples.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/basics_wexamples.cpp new file mode 100644 index 0000000000..4510198f9e --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/basics_wexamples.cpp @@ -0,0 +1,170 @@ +// jsoncons_test.cpp : Defines the entry point for the console application. +// + +#include +#include +#include + +using namespace jsoncons; + +void basics_wjson_example1() +{ + // Construct a book object + wjson book1; + + book1[L"category"] = L"Fiction"; + book1[L"title"] = L"A Wild Sheep Chase: A Novel"; + book1[L"author"] = L"Haruki Murakami"; + book1[L"date"] = L"2002-04-09"; + book1[L"price"] = 9.01; + book1[L"isbn"] = L"037571894X"; + + // Construct another using the member function insert_or_assign + wjson book2; + + book2.insert_or_assign(L"category", L"History"); + book2.insert_or_assign(L"title", L"Charlie Wilson's War"); + book2.insert_or_assign(L"author", L"George Crile"); + book2.insert_or_assign(L"date", L"2007-11-06"); + book2.insert_or_assign(L"price", 10.50); + book2.insert_or_assign(L"isbn", L"0802143415"); + + // Use insert_or_assign again, but more efficiently + wjson book3; + + // Reserve memory, to avoid reallocations + book3.reserve(6); + + // Insert in name alphabetical order + // Give insert_or_assign a hint where to insert the next member + auto hint = book3.insert_or_assign(book3.object_range().begin(), L"author", L"Haruki Murakami"); + hint = book3.insert_or_assign(hint, L"category", L"Fiction"); + hint = book3.insert_or_assign(hint, L"date", L"2006-01-03"); + hint = book3.insert_or_assign(hint, L"isbn", L"1400079276"); + hint = book3.insert_or_assign(hint, L"price", 13.45); + hint = book3.insert_or_assign(hint, L"title", L"Kafka on the Shore"); + + // Construct a fourth from a string + + wjson book4 = wjson::parse(LR"( + { + "category" : "Fiction", + "title" : "Pulp", + "author" : "Charles Bukowski", + "date" : "2004-07-08", + "price" : 22.48, + "isbn" : "1852272007" + } + )"); + // Construct a booklist array + wjson booklist = wjson::array(); + + // For efficiency, reserve memory, to avoid reallocations + booklist.reserve(4); + + // For efficency, tell jsoncons to move the contents + // of the four book objects into the array + booklist.push_back(std::move(book1)); + booklist.push_back(std::move(book2)); + + // Add the third one to the front + auto where = booklist.insert(booklist.array_range().begin(),std::move(book3)); + + // Add the last one immediately after + booklist.insert(where+1,std::move(book4)); + + // See what's left of book1, 2, 3 and 4 (expect nulls) + std::wcout << book1 << L"," << book2 << L"," << book3 << L"," << book4 << std::endl; + + //Loop through the booklist elements using a range-based for loop + for (const auto& book : booklist.array_range()) + { + std::wcout << book[L"title"].as() + << L"," + << book[L"price"].as() << std::endl; + } + + // The second book + wjson& book = booklist[1]; + + //Loop through the book members using a range-based for loop + for(const auto& member : book.object_range()) + { + std::wcout << member.key() + << L"," + << member.value() << std::endl; + } + + auto it = book.find(L"author"); + if (it != book.object_range().end()) + { + // book has member "author" + } + + if (book.contains(L"author")) + { + // book has member "author" + } + + std::wstring s = book.get_with_default(L"author", L"author unknown"); + // Returns author if found, otherwise "author unknown" + + try + { + book[L"ratings"].as(); + } + catch (const std::out_of_range&) + { + // member "ratings" not found + } + + // Add ratings + book[L"ratings"][L"*****"] = 4; + book[L"ratings"][L"*"] = 2; + + // Delete one-star ratings + book[L"ratings"].erase(L"*"); + + // Serialize the booklist to a file + std::wofstream os("./output/booklist2.json"); + os << pretty_print(booklist); +} + +void basics_wjson_example2() +{ + // Deserialize the booklist + std::wifstream is("./output/booklist2.json"); + wjson booklist; + is >> booklist; + + // Use a JSONPath expression to find + // + // (1) The authors of books that cost less than $12 + wjson result = jsonpath::json_query(booklist, L"$[*][?(@.price < 12)].author"); + std::wcout << L"(1) " << result << std::endl; + + // (2) The number of books + result = jsonpath::json_query(booklist, L"$.length"); + std::wcout << L"(2) " << result << std::endl; + + // (3) The third book + result = jsonpath::json_query(booklist, L"$[2]"); + std::wcout << L"(3) " << std::endl << pretty_print(result) << std::endl; + + // (4) The authors of books that were published in 2004 + result = jsonpath::json_query(booklist, L"$[*][?(@.date =~ /2004.*?/)].author"); + std::wcout << L"(4) " << result << std::endl; + + // (5) The titles of all books that have ratings + result = jsonpath::json_query(booklist, L"$[*][?(@.ratings)].title"); + std::wcout << L"(5) " << result << std::endl; +} + +void basics_wexamples() +{ + std::cout << "\nBasics\n\n"; + basics_wjson_example1(); + basics_wjson_example2(); + std::cout << std::endl; +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/bson_examples.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/bson_examples.cpp new file mode 100644 index 0000000000..57f532aa1a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/bson_examples.cpp @@ -0,0 +1,54 @@ +// Copyright 2017 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include + +using namespace jsoncons; + +void serialize_to_bson() +{ + std::vector buffer; + bson::bson_bytes_encoder encoder(buffer); + encoder.begin_array(); // The total number of bytes comprising + // the bson document will be calculated + encoder.string_value("cat"); + encoder.byte_string_value(byte_string({'p','u','r','r'})); + encoder.int64_value(1431027667, semantic_tag::timestamp); + encoder.end_array(); + encoder.flush(); + + for (auto c : buffer) + { + std::cout << std::hex << std::setprecision(2) << std::setw(2) + << std::noshowbase << std::setfill('0') << static_cast(c); + } + std::cout << "\n\n"; + +/* + 22000000 -- Total number of bytes comprising the document (34 bytes) + 02 -- UTF-8 string + 3000 -- "0" + 04000000 -- number bytes in the string (including trailing byte) + 636174 -- "cat" + 00 -- trailing byte + 05 -- binary + 3100 -- "1" + 04000000 -- number of bytes + 70757272 -- 'P''u''r''r' + 09 -- datetime + 3200 -- "2" + d3bf4b55 -- 1431027667 + 00 +*/ +} + +void bson_examples() +{ + std::cout << "\nbson examples\n\n"; + serialize_to_bson(); + std::cout << std::endl; +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/byte_string_examples.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/byte_string_examples.cpp new file mode 100644 index 0000000000..36b3877e9f --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/byte_string_examples.cpp @@ -0,0 +1,93 @@ +// Copyright 2018 Daniel Parker +// Distributed under Boost license + +#include + +using namespace jsoncons; // For brevity + +void construct_json_byte_string() +{ + byte_string bs = {'H','e','l','l','o'}; + + // default suggested encoding (base64url) + json j1(bs); + std::cout << "(1) "<< j1 << "\n\n"; + + // base64 suggested encoding + json j2(bs, semantic_tag::base64); + std::cout << "(2) "<< j2 << "\n\n"; + + // base16 suggested encoding + json j3(bs, semantic_tag::base16); + std::cout << "(3) "<< j3 << "\n\n"; +} + +void retrieve_json_value_as_byte_string() +{ + json j; + j["ByteString"] = byte_string({'H','e','l','l','o'}); + j["EncodedByteString"] = json("SGVsbG8=", semantic_tag::base64); + + std::cout << "(1)\n"; + std::cout << pretty_print(j) << "\n\n"; + + // Retrieve a byte string as a jsoncons::byte_string + byte_string bs1 = j["ByteString"].as(); + std::cout << "(2) " << bs1 << "\n\n"; + + // or alternatively as a std::vector + std::vector v = j["ByteString"].as>(); + + // Retrieve a byte string from a text string containing base64 character values + byte_string bs2 = j["EncodedByteString"].as(); + std::cout << "(3) " << bs2 << "\n\n"; + + // Retrieve a byte string view to access the memory that's holding the byte string + byte_string_view bsv3 = j["ByteString"].as(); + std::cout << "(4) " << bsv3 << "\n\n"; + + // Can't retrieve a byte string view of a text string + try + { + byte_string_view bsv4 = j["EncodedByteString"].as(); + } + catch (const std::exception& e) + { + std::cout << "(5) "<< e.what() << "\n\n"; + } +} + +void serialize_json_byte_string() +{ + byte_string bs = {'H','e','l','l','o'}; + + json j(bs); + + // default + std::cout << "(1) "<< j << "\n\n"; + + // base16 + json_options options2; + options2.byte_string_format(byte_string_chars_format::base16); + std::cout << "(2) "<< print(j, options2) << "\n\n"; + + // base64 + json_options options3; + options3.byte_string_format(byte_string_chars_format::base64); + std::cout << "(3) "<< print(j, options3) << "\n\n"; + + // base64url + json_options options4; + options4.byte_string_format(byte_string_chars_format::base64url); + std::cout << "(4) "<< print(j, options4) << "\n\n"; +} + +void byte_string_examples() +{ + std::cout << "byte_string examples" << "\n\n"; + construct_json_byte_string(); + serialize_json_byte_string(); + retrieve_json_value_as_byte_string(); +} + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/cbor_examples.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/cbor_examples.cpp new file mode 100644 index 0000000000..a45eabf339 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/cbor_examples.cpp @@ -0,0 +1,400 @@ +// Copyright 2017 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +void serialize_to_cbor_buffer() +{ + std::vector buffer; + cbor::cbor_bytes_encoder encoder(buffer); + + encoder.begin_array(); // Indefinite length array + encoder.string_value("cat"); + encoder.byte_string_value(byte_string({'p','u','r','r'})); + encoder.byte_string_value(byte_string({'h','i','s','s'}), + semantic_tag::base64); // suggested conversion to base64 + encoder.int64_value(1431027667, semantic_tag::timestamp); + encoder.end_array(); + encoder.flush(); + + for (auto c : buffer) + { + std::cout << std::hex << std::setprecision(2) << std::setw(2) + << std::noshowbase << std::setfill('0') << static_cast(c); + } + std::cout << "\n\n"; + +/* + 9f -- Start indefinte length array + 63 -- String value of length 3 + 636174 -- "cat" + 44 -- Byte string value of length 4 + 70757272 -- 'p''u''r''r' + d6 - Expected conversion to base64 + 44 + 68697373 -- 'h''i''s''s' + c1 -- Tag value 1 (seconds relative to 1970-01-01T00:00Z in UTC time) + 1a -- 32 bit unsigned integer + 554bbfd3 -- 1431027667 + ff -- "break" +*/ +} + +void serialize_to_cbor_stream() +{ + std::ostringstream os; + cbor::cbor_encoder encoder(os); + + encoder.begin_array(3); // array of length 3 + encoder.string_value("-18446744073709551617", semantic_tag::bigint); + encoder.string_value("184467440737095516.16", semantic_tag::bigdec); + encoder.int64_value(1431027667, semantic_tag::timestamp); + encoder.end_array(); + encoder.flush(); + + for (auto c : os.str()) + { + std::cout << std::hex << std::setprecision(2) << std::setw(2) + << std::noshowbase << std::setfill('0') << (int)unsigned char(c); + } + std::cout << "\n\n"; + +/* + 83 -- array of length 3 + c3 -- Tag 3 (negative bignum) + 49 -- Byte string value of length 9 + 010000000000000000 -- Bytes content + c4 -- Tag 4 (decimal fraction) + 82 -- Array of length 2 + 21 -- -2 (exponent) + c2 Tag 2 (positive bignum) + 49 -- Byte string value of length 9 + 010000000000000000 + c1 -- Tag 1 (seconds relative to 1970-01-01T00:00Z in UTC time) + 1a -- 32 bit unsigned integer + 554bbfd3 -- 1431027667 +*/ +} + +void cbor_reputon_example() +{ + ojson j1 = ojson::parse(R"( + { + "application": "hiking", + "reputons": [ + { + "rater": "HikingAsylum.example.com", + "assertion": "strong-hiker", + "rated": "Marilyn C", + "rating": 0.90 + } + ] + } + )"); + + // Encode a basic_json value to a CBOR value + std::vector data; + cbor::encode_cbor(j1, data); + + // Decode a CBOR value to a basic_json value + ojson j2 = cbor::decode_cbor(data); + std::cout << "(1)\n" << pretty_print(j2) << "\n\n"; + + // Accessing the data items + + const ojson& reputons = j2["reputons"]; + + std::cout << "(2)\n"; + for (auto element : reputons.array_range()) + { + std::cout << element.at("rated").as() << ", "; + std::cout << element.at("rating").as() << "\n"; + } + std::cout << std::endl; + + // Get a CBOR value for a nested data item with jsonpointer + std::error_code ec; + auto const& rated = jsonpointer::get(j2, "/reputons/0/rated", ec); + if (!ec) + { + std::cout << "(3) " << rated.as_string() << "\n"; + } + + std::cout << std::endl; +} + +void decode_cbor_byte_string() +{ + // byte string of length 5 + std::vector buf = {0x45,'H','e','l','l','o'}; + json j = cbor::decode_cbor(buf); + + auto bs = j.as(); + + // byte_string to ostream displays as hex + std::cout << "(1) "<< bs << "\n\n"; + + // byte string value to JSON text becomes base64url + std::cout << "(2) " << j << std::endl; +} + +void decode_byte_string_with_encoding_hint() +{ + // semantic tag indicating expected conversion to base64 + // followed by byte string of length 5 + std::vector buf = {0xd6,0x45,'H','e','l','l','o'}; + json j = cbor::decode_cbor(buf); + + auto bs = j.as(); + + // byte_string to ostream displays as hex + std::cout << "(1) "<< bs << "\n\n"; + + // byte string value to JSON text becomes base64 + std::cout << "(2) " << j << std::endl; +} + +void encode_cbor_byte_string() +{ + // construct byte string value + json j(byte_string("Hello")); + + std::vector buf; + cbor::encode_cbor(j, buf); + + std::cout << std::hex << std::showbase << "(1) "; + for (auto c : buf) + { + std::cout << (int)c; + } + std::cout << std::dec << "\n\n"; + + json j2 = cbor::decode_cbor(buf); + std::cout << "(2) " << j2 << std::endl; +} + +void encode_byte_string_with_encoding_hint() +{ + // construct byte string value + json j1(byte_string("Hello"), semantic_tag::base64); + + std::vector buf; + cbor::encode_cbor(j1, buf); + + std::cout << std::hex << std::showbase << "(1) "; + for (auto c : buf) + { + std::cout << (int)c; + } + std::cout << std::dec << "\n\n"; + + json j2 = cbor::decode_cbor(buf); + std::cout << "(2) " << j2 << std::endl; +} + +void query_cbor() +{ + // Construct a json array of numbers + json j = json::array(); + + j.emplace_back(5.0); + + j.emplace_back(0.000071); + + j.emplace_back("-18446744073709551617",semantic_tag::bigint); + + j.emplace_back("1.23456789012345678901234567890", semantic_tag::bigdec); + + j.emplace_back("0x3p-1", semantic_tag::bigfloat); + + // Encode to JSON + std::cout << "(1)\n"; + std::cout << pretty_print(j); + std::cout << "\n\n"; + + // as() and as() + std::cout << "(2)\n"; + std::cout << std::dec << std::setprecision(15); + for (const auto& item : j.array_range()) + { + std::cout << item.as() << ", " << item.as() << "\n"; + } + std::cout << "\n"; + + // Encode to CBOR + std::vector v; + cbor::encode_cbor(j,v); + + std::cout << "(3)\n"; + for (auto c : v) + { + std::cout << std::hex << std::setprecision(2) << std::setw(2) + << std::setfill('0') << static_cast(c); + } + std::cout << "\n\n"; +/* + 85 -- Array of length 5 + fa -- float + 40a00000 -- 5.0 + fb -- double + 3f129cbab649d389 -- 0.000071 + c3 -- Tag 3 (negative bignum) + 49 -- Byte string value of length 9 + 010000000000000000 + c4 -- Tag 4 (decimal fraction) + 82 -- Array of length 2 + 38 -- Negative integer of length 1 + 1c -- -29 + c2 -- Tag 2 (positive bignum) + 4d -- Byte string value of length 13 + 018ee90ff6c373e0ee4e3f0ad2 + c5 -- Tag 5 (bigfloat) + 82 -- Array of length 2 + 20 -- -1 + 03 -- 3 +*/ + + // Decode back to json + json other = cbor::decode_cbor(v); + assert(other == j); + + // Query with JSONPath + std::cout << "(4)\n"; + json result = jsonpath::json_query(other,"$[?(@ < 1.5)]"); + std::cout << pretty_print(result) << "\n\n"; +} + +void encode_cbor_with_packed_strings() +{ + ojson j = ojson::parse(R"( +[ + { + "name" : "Cocktail", + "count" : 417, + "rank" : 4 + }, + { + "rank" : 4, + "count" : 312, + "name" : "Bath" + }, + { + "count" : 691, + "name" : "Food", + "rank" : 4 + } + ] +)"); + + cbor::cbor_options options; + options.pack_strings(true); + std::vector buf; + + cbor::encode_cbor(j, buf, options); + + for (auto c : buf) + { + std::cout << std::hex << std::setprecision(2) << std::setw(2) + << std::noshowbase << std::setfill('0') << static_cast(c); + } + std::cout << "\n"; + +/* + d90100 -- tag (256) + 83 -- array(3) + a3 -- map(3) + 64 -- text string (4) + 6e616d65 -- "name" + 68 -- text string (8) + 436f636b7461696c -- "Cocktail" + 65 -- text string (5) + 636f756e74 -- "count" + 1901a1 -- unsigned(417) + 64 -- text string (4) + 72616e6b -- "rank" + 04 -- unsigned(4) + a3 -- map(3) + d819 -- tag(25) + 03 -- unsigned(3) + 04 -- unsigned(4) + d819 -- tag(25) + 02 -- unsigned(2) + 190138 -- unsigned(312) + d819 -- tag(25) + 00 -- unsigned(0) + 64 -- text string(4) + 42617468 -- "Bath" + a3 -- map(3) + d819 -- tag(25) + 02 -- unsigned(2) + 1902b3 -- unsigned(691) + d819 -- tag(25) + 00 -- unsigned(0) + 64 - text string(4) + 466f6f64 -- "Food" + d819 -- tag(25) + 03 -- unsigned(3) + 04 -- unsigned(4) +*/ + + ojson j2 = cbor::decode_cbor(buf); + assert(j2 == j); +} + +void decode_cbor_with_packed_strings() +{ + std::vector v = {0xd9,0x01,0x00, // tag(256) + 0x85, // array(5) + 0x63, // text(3) + 0x61,0x61,0x61, // "aaa" + 0xd8, 0x19, // tag(25) + 0x00, // unsigned(0) + 0xd9, 0x01,0x00, // tag(256) + 0x83, // array(3) + 0x63, // text(3) + 0x62,0x62,0x62, // "bbb" + 0x63, // text(3) + 0x61,0x61,0x61, // "aaa" + 0xd8, 0x19, // tag(25) + 0x01, // unsigned(1) + 0xd9, 0x01,0x00, // tag(256) + 0x82, // array(2) + 0x63, // text(3) + 0x63,0x63,0x63, // "ccc" + 0xd8, 0x19, // tag(25) + 0x00, // unsigned(0) + 0xd8, 0x19, // tag(25) + 0x00 // unsigned(0) + }; + + ojson j = cbor::decode_cbor(v); + + std::cout << pretty_print(j) << "\n"; +} + +void cbor_examples() +{ + std::cout << "\ncbor examples\n\n"; + decode_byte_string_with_encoding_hint(); + encode_byte_string_with_encoding_hint(); + decode_cbor_byte_string(); + encode_cbor_byte_string(); + serialize_to_cbor_buffer(); + serialize_to_cbor_stream(); + cbor_reputon_example(); + query_cbor(); + encode_cbor_with_packed_strings(); + + decode_cbor_with_packed_strings(); + + std::cout << std::endl; +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/container_examples.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/container_examples.cpp new file mode 100644 index 0000000000..f3176c0fc6 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/container_examples.cpp @@ -0,0 +1,88 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +void container_example1() +{ + std::cout << "Convert from and to standard library containers\n" << std::endl; + + { + std::vector v{1, 2, 3, 4}; + json j(v); + std::cout << "(1) "<< j << std::endl; + std::deque d = j.as>(); + } + + std::vector vec2{1ul, 2ul, 3ul, 4ul}; + json j_vec2(vec2); + std::cout << j_vec2 << std::endl; + + std::deque deque1{1.123, 2.234, 3.456, 4.567}; + json j_deque1(deque1); + std::cout << j_deque1 << std::endl; + + std::list list1{true, true, false, true}; + json j_list1(list1); + std::cout << j_list1 << std::endl; + + std::forward_listflist1 {12345678909876, 23456789098765, 34567890987654, 45678909876543}; + json j_flist1(flist1); + std::cout << j_flist1 << std::endl; + + std::array array1 {{1, 2, 3, 4}}; + json j_array1(array1); + + std::set set1{"one", "two", "three", "four", "one"}; + json j_set1(set1); // only one entry for "one" is used + std::cout << j_set1 << std::endl; + // ["four", "one", "three", "two"] + + std::unordered_set uset1{"one", "two", "three", "four", "one"}; + json j_uset1(uset1); // only one entry for "one" is used + std::cout << j_uset1 << std::endl; + // maybe ["two", "three", "four", "one"] + + std::multiset mset1{"one", "two", "one", "four"}; + json j_mset1(mset1); // only one entry for "one" is used + std::cout << j_mset1 << std::endl; + // maybe ["one", "two", "four"] + + std::unordered_multiset umset1 {"one", "two", "one", "four"}; + json j_umset1(umset1); // both entries for "one" are used + // maybe ["one", "two", "one", "four"] + + { + std::map m{{"one",1},{"two",2},{"three",3}}; + json j(m); + std::cout << "(1) " << j << std::endl; + std::unordered_map um = j.as>(); + } + + std::unordered_map umap1{ {"one", 1.2}, {"two", 2.3}, {"three", 3.4} }; + json j_umap1(umap1); + std::cout << j_umap1 << std::endl; + + std::cout << std::endl; +} + +void container_examples() +{ + std::cout << "\nContainer examples\n\n"; + container_example1(); + std::cout << std::endl; +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/csv_examples.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/csv_examples.cpp new file mode 100644 index 0000000000..a986d8bd65 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/csv_examples.cpp @@ -0,0 +1,409 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include + +using namespace jsoncons; + +void csv_source_to_json_value() +{ + const std::string s = R"(Date,1Y,2Y,3Y,5Y +2017-01-09,0.0062,0.0075,0.0083,0.011 +2017-01-08,0.0063,0.0076,0.0084,0.0112 +2017-01-08,0.0063,0.0076,0.0084,0.0112 +)"; + + csv::csv_options options; + options.assume_header(true) + .column_types("string,float,float,float,float"); + + // mapping_type::n_objects + options.mapping(csv::mapping_type::n_objects); + ojson j1 = csv::decode_csv(s,options); + std::cout << "\n(1)\n"<< pretty_print(j1) << "\n"; + + // mapping_type::n_rows + options.mapping(csv::mapping_type::n_rows); + ojson j2 = csv::decode_csv(s,options); + std::cout << "\n(2)\n"<< pretty_print(j2) << "\n"; + + // mapping_type::m_columns + options.mapping(csv::mapping_type::m_columns); + ojson j3 = csv::decode_csv(s,options); + std::cout << "\n(3)\n" << pretty_print(j3) << "\n"; +} + +void csv_source_to_cpp_object() +{ + const std::string input = R"(Date,1Y,2Y,3Y,5Y +2017-01-09,0.0062,0.0075,0.0083,0.011 +2017-01-08,0.0063,0.0076,0.0084,0.0112 +2017-01-08,0.0063,0.0076,0.0084,0.0112 +)"; + + csv::csv_options ioptions; + ioptions.header_lines(1) + .mapping(csv::mapping_type::n_rows); + + typedef std::vector> table_type; + + table_type table = csv::decode_csv(input,ioptions); + + std::cout << "(1)\n"; + for (const auto& row : table) + { + std::cout << std::get<0>(row) << "," + << std::get<1>(row) << "," + << std::get<2>(row) << "," + << std::get<3>(row) << "," + << std::get<4>(row) << "\n"; + } + std::cout << "\n"; + + std::string output; + + csv::csv_options ooptions; + ooptions.column_names("Date,1Y,2Y,3Y,5Y"); + csv::encode_csv(table, output, ooptions); + + std::cout << "(2)\n"; + std::cout << output << "\n"; +} + +void csv_decode_without_type_inference() +{ + std::string s = R"(employee-no,employee-name,dept,salary +00000001,"Smith,Matthew",sales,150000.00 +00000002,"Brown,Sarah",sales,89000.00 +)"; + + csv::csv_options options; + options.assume_header(true) + .infer_types(false); + ojson j = csv::decode_csv(s,options); + + std::cout << pretty_print(j) << std::endl; +} + +void read_write_csv_tasks() +{ + std::ifstream is("./input/tasks.csv"); + + json_decoder decoder; + csv::csv_options options; + options.assume_header(true) + .trim(true) + .ignore_empty_values(true) + .column_types("integer,string,string,string"); + csv::csv_reader reader(is,decoder,options); + reader.read(); + ojson tasks = decoder.get_result(); + + std::cout << "(1)\n"; + std::cout << pretty_print(tasks) << "\n\n"; + + std::cout << "(2)\n"; + csv::csv_encoder encoder(std::cout); + tasks.dump(encoder); +} + +void serialize_array_of_arrays_to_comma_delimited() +{ + std::string in_file = "./input/countries.json"; + std::ifstream is(in_file); + + json countries; + is >> countries; + + csv::csv_encoder encoder(std::cout); + countries.dump(encoder); +} + +void serialize_to_tab_delimited_file() +{ + std::string in_file = "./input/employees.json"; + std::ifstream is(in_file); + + json employees; + is >> employees; + + csv::csv_options options; + options.field_delimiter('\t'); + csv::csv_encoder encoder(std::cout,options); + + employees.dump(encoder); +} + +void serialize_books_to_csv_file() +{ + const json books = json::parse(R"( + [ + { + "title" : "Kafka on the Shore", + "author" : "Haruki Murakami", + "price" : 25.17 + }, + { + "title" : "Women: A Novel", + "author" : "Charles Bukowski", + "price" : 12.00 + }, + { + "title" : "Cutter's Way", + "author" : "Ivan Passer" + } + ] + )"); + + csv::csv_encoder encoder(std::cout); + + books.dump(encoder); +} + +void serialize_books_to_csv_file_with_reorder() +{ + const json books = json::parse(R"( + [ + { + "title" : "Kafka on the Shore", + "author" : "Haruki Murakami", + "price" : 25.17 + }, + { + "title" : "Women: A Novel", + "author" : "Charles Bukowski", + "price" : 12.00 + }, + { + "title" : "Cutter's Way", + "author" : "Ivan Passer" + } + ] + )"); + + csv::csv_options options; + options.column_names("author,title,price"); + + csv::csv_encoder encoder(std::cout, options); + + books.dump(encoder); +} + +void last_column_repeats() +{ + const std::string bond_yields = R"(Date,Yield +2017-01-09,0.0062,0.0075,0.0083,0.011,0.012 +2017-01-08,0.0063,0.0076,0.0084,0.0112,0.013 +2017-01-08,0.0063,0.0076,0.0084,0.0112,0.014 +)"; + + json_decoder decoder1; + csv::csv_options options1; + options1.header_lines(1); + options1.column_types("string,float*"); + std::istringstream is1(bond_yields); + csv::csv_reader reader1(is1, decoder1, options1); + reader1.read(); + ojson val1 = decoder1.get_result(); + std::cout << "\n(1)\n" << pretty_print(val1) << "\n"; + + json_decoder decoder2; + csv::csv_options options2; + options2.assume_header(true); + options2.column_types("string,[float*]"); + std::istringstream is2(bond_yields); + csv::csv_reader reader2(is2, decoder2, options2); + reader2.read(); + ojson val2 = decoder2.get_result(); + std::cout << "\n(2)\n" << pretty_print(val2) << "\n"; +} + +void last_two_columns_repeat() +{ + const std::string holidays = R"(1,CAD,2,UK,3,EUR,4,US +38719,2-Jan-2006,40179,1-Jan-2010,38719,2-Jan-2006,39448,1-Jan-2008 +38733,16-Jan-2006,40270,2-Apr-2010,38733,16-Jan-2006,39468,21-Jan-2008 +)"; + + // array of arrays + json_decoder decoder1; + csv::csv_options options1; + options1.column_types("[integer,string]*"); + std::istringstream is1(holidays); + csv::csv_reader reader1(is1, decoder1, options1); + reader1.read(); + ojson val1 = decoder1.get_result(); + std::cout << "(1)\n" << pretty_print(val1) << "\n"; + + // array of objects + json_decoder decoder2; + csv::csv_options options2; + options2.header_lines(1); + options2.column_names("CAD,UK,EUR,US"); + options2.column_types("[integer,string]*"); + std::istringstream is2(holidays); + csv::csv_reader reader2(is2, decoder2, options2); + reader2.read(); + ojson val2 = decoder2.get_result(); + std::cout << "(2)\n" << pretty_print(val2) << "\n"; +} + +void decode_csv_string() +{ + std::string s = R"(employee-no,employee-name,dept,salary +00000001,\"Smith,Matthew\",sales,150000.00 +00000002,\"Brown,Sarah\",sales,89000.00 +)"; + + csv::csv_options options; + options.assume_header(true) + .column_types("string,string,string,float"); + json j = csv::decode_csv(s,options); + + std::cout << pretty_print(j) << std::endl; +} + +void decode_csv_stream() +{ + const std::string bond_yields = R"(Date,1Y,2Y,3Y,5Y +2017-01-09,0.0062,0.0075,0.0083,0.011 +2017-01-08,0.0063,0.0076,0.0084,0.0112 +2017-01-08,0.0063,0.0076,0.0084,0.0112 +)"; + + csv::csv_options options; + options.assume_header(true) + .column_types("string,float,float,float,float"); + + std::istringstream is(bond_yields); + + ojson j = csv::decode_csv(is,options); + + std::cout << pretty_print(j) << std::endl; +} + +void encode_csv_file_from_books() +{ + const json books = json::parse(R"( + [ + { + "title" : "Kafka on the Shore", + "author" : "Haruki Murakami", + "price" : 25.17 + }, + { + "title" : "Women: A Novel", + "author" : "Charles Bukowski", + "price" : 12.00 + }, + { + "title" : "Cutter's Way", + "author" : "Ivan Passer" + } + ] + )"); + + csv::encode_csv(books, std::cout); +} + +void decode_encode_csv_tasks() +{ + std::ifstream is("./input/tasks.csv"); + + csv::csv_options options; + options.assume_header(true) + .trim(true) + .ignore_empty_values(true) + .column_types("integer,string,string,string"); + ojson tasks = csv::decode_csv(is, options); + + std::cout << "(1)\n" << pretty_print(tasks) << "\n\n"; + + std::cout << "(2)\n"; + csv::encode_csv(tasks, std::cout); +} + +void csv_parser_type_inference() +{ + csv::csv_options options; + options.assume_header(true) + .mapping(csv::mapping_type::n_objects); + + std::ifstream is1("input/sales.csv"); + ojson j1 = csv::decode_csv(is1,options); + std::cout << "\n(1)\n"<< pretty_print(j1) << "\n"; + + options.mapping(csv::mapping_type::n_rows); + std::ifstream is2("input/sales.csv"); + ojson j2 = csv::decode_csv(is2,options); + std::cout << "\n(2)\n"<< pretty_print(j2) << "\n"; + + options.mapping(csv::mapping_type::m_columns); + std::ifstream is3("input/sales.csv"); + ojson j3 = csv::decode_csv(is3,options); + std::cout << "\n(3)\n"<< pretty_print(j3) << "\n"; +} + +// Examples with subfields + + +void decode_csv_with_subfields() +{ + const std::string s = R"(calculationPeriodCenters,paymentCenters,resetCenters +NY;LON,TOR,LON +NY,LON,TOR;LON +"NY";"LON","TOR","LON" +"NY","LON","TOR";"LON" +)"; + json_options print_options; + print_options.array_array_line_splits(line_split_kind::same_line); + + csv::csv_options options1; + options1.assume_header(true) + .subfield_delimiter(';'); + + json j1 = csv::decode_csv(s,options1); + std::cout << "(1)\n" << pretty_print(j1,print_options) << "\n\n"; + + csv::csv_options options2; + options2.mapping(csv::mapping_type::n_rows) + .subfield_delimiter(';'); + + json j2 = csv::decode_csv(s,options2); + std::cout << "(2)\n" << pretty_print(j2,print_options) << "\n\n"; + + csv::csv_options options3; + options3.assume_header(true) + .mapping(csv::mapping_type::m_columns) + .subfield_delimiter(';'); + + json j3 = csv::decode_csv(s,options3); + std::cout << "(3)\n" << pretty_print(j3,print_options) << "\n\n"; +} + +void csv_examples() +{ + std::cout << "\nCSV examples\n\n"; + read_write_csv_tasks(); + serialize_to_tab_delimited_file(); + serialize_array_of_arrays_to_comma_delimited(); + serialize_books_to_csv_file(); + serialize_books_to_csv_file_with_reorder(); + last_column_repeats(); + last_two_columns_repeat(); + decode_csv_string(); + decode_csv_stream(); + encode_csv_file_from_books(); + decode_encode_csv_tasks(); + + csv_decode_without_type_inference(); + csv_parser_type_inference(); + + decode_csv_with_subfields(); + csv_source_to_json_value(); + csv_source_to_cpp_object(); + std::cout << std::endl; +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/data_model_examples.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/data_model_examples.cpp new file mode 100644 index 0000000000..42bd2ea1de --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/data_model_examples.cpp @@ -0,0 +1,126 @@ +// Copyright 2017 Daniel Parker +// Distributed under Boost license + +#include +#include +#include + +using namespace jsoncons; + +void data_model_example1() +{ + json j = json::array(); + + j.emplace_back("foo"); + j.emplace_back(byte_string{ 'b','a','r' }); + j.emplace_back("-18446744073709551617", semantic_tag::bigint); + j.emplace_back("273.15", semantic_tag::bigdec); + j.emplace_back("2018-10-19 12:41:07-07:00", semantic_tag::datetime); + j.emplace_back(1431027667, semantic_tag::timestamp); + j.emplace_back(-1431027667, semantic_tag::timestamp); + j.emplace_back(1431027667.5, semantic_tag::timestamp); + + std::cout << "(1)\n" << pretty_print(j) << "\n\n"; + + std::vector bytes; + cbor::encode_cbor(j, bytes); + std::cout << "(2)\n"; + for (auto c : bytes) + { + std::cout << std::hex << std::noshowbase << std::setprecision(2) << std::setw(2) + << std::setfill('0') << static_cast(c); + } + std::cout << "\n\n"; +/* +88 -- Array of length 8 + 63 -- String value of length 3 + 666f6f -- "foo" + 43 -- Byte string value of length 3 + 626172 -- 'b''a''r' + c3 -- Tag 3 (negative bignum) + 49 Byte string value of length 9 + 010000000000000000 -- Bytes content + c4 - Tag 4 (decimal fraction) + 82 -- Array of length 2 + 21 -- -2 + 19 6ab3 -- 27315 + c0 -- Tag 0 (date-time) + 78 19 -- Length (25) + 323031382d31302d31392031323a34313a30372d30373a3030 -- "2018-10-19 12:41:07-07:00" + c1 -- Tag 1 (epoch time) + 1a -- uint32_t + 554bbfd3 -- 1431027667 + c1 + 3a + 554bbfd2 + c1 + fb + 41d552eff4e00000 +*/ +} + +void data_model_example2() +{ + std::vector bytes; + cbor::cbor_bytes_encoder encoder(bytes); + encoder.begin_array(); // indefinite length outer array + encoder.string_value("foo"); + encoder.byte_string_value(byte_string{'b','a','r'}); + encoder.string_value("-18446744073709551617", semantic_tag::bigint); + encoder.string_value("273.15", semantic_tag::bigdec); + encoder.string_value("2018-10-19 12:41:07-07:00", semantic_tag::datetime) ; + encoder.int64_value(1431027667, semantic_tag::timestamp); + encoder.int64_value(-1431027667, semantic_tag::timestamp); + encoder.double_value(1431027667.5, semantic_tag::timestamp); + encoder.end_array(); + encoder.flush(); + + std::cout << "(1)\n"; + for (auto c : bytes) + { + std::cout << std::hex << std::setprecision(2) << std::setw(2) + << std::noshowbase << std::setfill('0') << static_cast(c); + } + std::cout << "\n\n"; + +/* +9f -- Start indefinite length array + 63 -- String value of length 3 + 666f6f -- "foo" + 43 -- Byte string value of length 3 + 626172 -- 'b''a''r' + c3 -- Tag 3 (negative bignum) + 49 Byte string value of length 9 + 010000000000000000 -- Bytes content + c4 - Tag 4 (decimal fraction) + 82 -- Array of length 2 + 21 -- -2 + 19 6ab3 -- 27315 + c0 -- Tag 0 (date-time) + 78 19 -- Length (25) + 323031382d31302d31392031323a34313a30372d30373a3030 -- "2018-10-19 12:41:07-07:00" + c1 -- Tag 1 (epoch time) + 1a -- uint32_t + 554bbfd3 -- 1431027667 + c1 + 3a + 554bbfd2 + c1 + fb + 41d552eff4e00000 + ff -- "break" +*/ + + json j = cbor::decode_cbor(bytes); + + std::cout << "(2)\n" << pretty_print(j) << "\n\n"; +} + +void data_model_examples() +{ + std::cout << "\ndata model examples\n\n"; + data_model_example1(); + data_model_example2(); + std::cout << std::endl; +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/example_types.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/example_types.hpp new file mode 100644 index 0000000000..6899157221 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/example_types.hpp @@ -0,0 +1,105 @@ +#ifndef EXAMPLE_TYPES +#define EXAMPLE_TYPES + +#include +#include +#include + +// book example + +namespace ns { + struct book + { + std::string author; + std::string title; + double price; + }; +} // namespace ns + +namespace jsoncons { + + template + struct json_type_traits + { + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) noexcept + { + return j.is_object() && j.contains("author") && + j.contains("title") && j.contains("price"); + } + static ns::book as(const Json& j) + { + ns::book val; + val.author = j.at("author").template as(); + val.title = j.at("title").template as(); + val.price = j.at("price").template as(); + return val; + } + static Json to_json(const ns::book& val, + allocator_type allocator=allocator_type()) + { + Json j(allocator); + j.try_emplace("author", val.author); + j.try_emplace("title", val.title); + j.try_emplace("price", val.price); + return j; + } + }; +} // namespace jsoncons + +// reputon example + +namespace ns { + struct reputon + { + std::string rater; + std::string assertion; + std::string rated; + double rating; + + friend bool operator==(const reputon& lhs, const reputon& rhs) + { + return lhs.rater == rhs.rater && lhs.assertion == rhs.assertion && + lhs.rated == rhs.rated && lhs.rating == rhs.rating; + } + + friend bool operator!=(const reputon& lhs, const reputon& rhs) + { + return !(lhs == rhs); + }; + }; + + class reputation_object + { + std::string application; + std::vector reputons; + + // Make json_type_traits specializations friends to give accesses to private members + JSONCONS_TYPE_TRAITS_FRIEND; + public: + reputation_object() + { + } + reputation_object(const std::string& application, const std::vector& reputons) + : application(application), reputons(reputons) + {} + + friend bool operator==(const reputation_object& lhs, const reputation_object& rhs) + { + return (lhs.application == rhs.application) && (lhs.reputons == rhs.reputons); + } + + friend bool operator!=(const reputation_object& lhs, const reputation_object& rhs) + { + return !(lhs == rhs); + }; + }; + +} // ns + +// Declare the traits. Specify which data members need to be serialized. +JSONCONS_MEMBER_TRAITS_DECL(ns::reputon, rater, assertion, rated, rating) +JSONCONS_MEMBER_TRAITS_DECL(ns::reputation_object, application, reputons) + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/examples.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/examples.cpp new file mode 100644 index 0000000000..c74b923317 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/examples.cpp @@ -0,0 +1,588 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +void readme_examples(); +void basics_examples(); +void basics_wexamples(); +void json_filter_examples(); +void array_examples(); +void container_examples(); +void wjson_examples(); +void serialization_examples(); +void type_extensibility_examples(); +void type_extensibility_examples2(); +void ojson_examples(); +void unicode_examples(); +void csv_examples(); +void jsonpath_examples(); +void json_accessor_examples(); +void msgpack_examples(); +void jsonpointer_examples(); +void jsonpatch_examples(); +void cbor_examples(); +void ubjson_examples(); +void json_parser_examples(); +void byte_string_examples(); +void pull_parser_examples(); +void data_model_examples(); +void staj_iterator_examples(); +void bson_examples(); +void polymorphic_examples(); + +void comment_example() +{ + std::string s = R"( + { + // Single line comments + /* + Multi line comments + */ + } + )"; + + // Default + json j = json::parse(s); + std::cout << "(1) " << j << std::endl; + + // Strict + try + { + strict_parse_error_handler err_handler; + json j = json::parse(s, err_handler); + } + catch (const ser_error& e) + { + std::cout << "(2) " << e.what() << std::endl; + } +} + +void first_example_a() +{ + std::string path = "./input/books.json"; + std::fstream is(path); + if (!is) + { + std::cout << "Cannot open " << path << std::endl; + return; + } + json books = json::parse(is); + + for (size_t i = 0; i < books.size(); ++i) + { + try + { + json& book = books[i]; + std::string author = book["author"].as(); + std::string title = book["title"].as(); + double price = book["price"].as(); + std::cout << author << ", " << title << ", " << price << std::endl; + } + catch (const std::exception& e) + { + std::cerr << e.what() << std::endl; + } + } +} + +void first_example_b() +{ + std::string path = "./input/books.json"; + std::fstream is(path); + if (!is) + { + std::cout << "Cannot open " << path << std::endl; + return; + } + json books = json::parse(is); + + for (size_t i = 0; i < books.size(); ++i) + { + try + { + json& book = books[i]; + std::string author = book["author"].as(); + std::string title = book["title"].as(); + std::string price = book.get_with_default("price", "N/A"); + std::cout << author << ", " << title << ", " << price << std::endl; + } + catch (const std::exception& e) + { + std::cerr << e.what() << std::endl; + } + } +} + +void first_example_c() +{ + const json books = json::parse(R"( + [ + { + "title" : "Kafka on the Shore", + "author" : "Haruki Murakami", + "price" : 25.17 + }, + { + "title" : "Women: A Novel", + "author" : "Charles Bukowski", + "price" : 12.00 + }, + { + "title" : "Cutter's Way", + "author" : "Ivan Passer" + } + ] + )"); + + json_options options; + + for (const auto& book : books.array_range()) + { + try + { + std::string author = book["author"].as(); + std::string title = book["title"].as(); + std::string price; + book.get_with_default("price", "N/A").dump(price,options); + std::cout << author << ", " << title << ", " << price << std::endl; + } + catch (const ser_error& e) + { + std::cerr << e.what() << std::endl; + } + } +} + +void first_example_d() +{ + std::string path = "./input/books.json"; + std::fstream is(path); + if (!is) + { + std::cout << "Cannot open " << path << std::endl; + return; + } + json books = json::parse(is); + + json_options options; + //options.floatfield(std::ios::fixed); + options.precision(2); + + for (size_t i = 0; i < books.size(); ++i) + { + try + { + json& book = books[i]; + std::string author = book["author"].as(); + std::string title = book["title"].as(); + if (book.contains("price") && book["price"].is_number()) + { + double price = book["price"].as(); + std::cout << author << ", " << title << ", " << price << std::endl; + } + else + { + std::cout << author << ", " << title << ", " << "n/a" << std::endl; + } + } + catch (const std::exception& e) + { + std::cerr << e.what() << std::endl; + } + } + +} + +void second_example_a() +{ + try + { + json books = json::array(); + + { + json book; + book["title"] = "Kafka on the Shore"; + book["author"] = "Haruki Murakami"; + book["price"] = 25.17; + books.push_back(std::move(book)); + } + + { + json book; + book["title"] = "Women: A Novel"; + book["author"] = "Charles Bukowski"; + book["price"] = 12.00; + books.push_back(std::move(book)); + } + + { + json book; + book["title"] = "Cutter's Way"; + book["author"] = "Ivan Passer"; + books.push_back(std::move(book)); + } + + std::cout << pretty_print(books) << std::endl; + } + catch (const std::exception& e) + { + std::cerr << e.what() << std::endl; + } +} + +void json_constructor_examples() +{ + json j1; // An empty object + std::cout << "(1) " << j1 << std::endl; + + json j2 = json::object({{"baz", "qux"}, {"foo", "bar"}}); // An object + std::cout << "(2) " << j2 << std::endl; + + json j3 = json::array({"bar", "baz"}); // An array + std::cout << "(3) " << j3 << std::endl; + + json j4(json::null()); // A null value + std::cout << "(4) " << j4 << std::endl; + + json j5(true); // A boolean value + std::cout << "(5) " << j5 << std::endl; + + double x = 1.0/7.0; + + json j6(x); // A double value + std::cout << "(6) " << j6 << std::endl; + + json j7(x,4); // A double value with specified precision + std::cout << "(7) " << j7 << std::endl; + + json j8("Hello"); // A text string + std::cout << "(8) " << j8 << std::endl; + + byte_string bs = {'H','e','l','l','o'}; + json j9(bs); // A byte string + std::cout << "(9) " << j9 << std::endl; + + std::vector v = {10,20,30}; + json j10 = v; // From a sequence container + std::cout << "(10) " << j10 << std::endl; + + std::map m{ {"one", 1}, {"two", 2}, {"three", 3} }; + json j11 = m; // From an associative container + std::cout << "(11) " << j11 << std::endl; + + // An object value with four members + json obj; + obj["first_name"] = "Jane"; + obj["last_name"] = "Roe"; + obj["events_attended"] = 10; + obj["accept_waiver_of_liability"] = true; + + std::string first_name = obj["first_name"].as(); + std::string last_name = obj.at("last_name").as(); + int events_attended = obj["events_attended"].as(); + bool accept_waiver_of_liability = obj["accept_waiver_of_liability"].as(); + + // An array value with four elements + json arr = json::array(); + arr.push_back(j1); + arr.push_back(j2); + arr.push_back(j3); + arr.push_back(j4); + + json_options options; + std::cout << pretty_print(arr) << std::endl; +} + +void mulitple_json_objects() +{ + std::ifstream is("./input/multiple-json-objects.json"); + if (!is.is_open()) + { + throw std::runtime_error("Cannot open file"); + } + + json_decoder decoder; + json_reader reader(is, decoder); + + while (!reader.eof()) + { + reader.read_next(); + if (!reader.eof()) + { + json val = decoder.get_result(); + std::cout << val << std::endl; + } + } +} + +void object_range_based_for_loop() +{ + json j = json::parse(R"( +{ + "category" : "Fiction", + "title" : "Pulp", + "author" : "Charles Bukowski", + "date" : "2004-07-08", + "price" : 22.48, + "isbn" : "1852272007" +} +)"); + + for (const auto& member : j.object_range()) + { + std::cout << member.key() << " => " << member.value().as() << std::endl; + } +} + +void more_examples() +{ + json file_settings = json::object{ + {"Image Format", "JPEG"}, + {"Color Space", "sRGB"}, + { "Limit File Size", true}, + {"Limit File Size To", 10000} + }; + + json image_sizing; + image_sizing.insert_or_assign("Resize To Fit",true); // a boolean + image_sizing.insert_or_assign("Resize Unit", "pixels"); // a string + image_sizing.insert_or_assign("Resize What", "long_edge"); // a string + image_sizing.insert_or_assign("Dimension 1",9.84); // a double + std::cout << pretty_print(image_sizing) << std::endl; + + json image_formats = json::array{"JPEG","PSD","TIFF","DNG"}; + + json color_spaces = json::array(); + color_spaces.push_back("sRGB"); + color_spaces.push_back("AdobeRGB"); + color_spaces.push_back("ProPhoto RGB"); + + json export_settings; + export_settings["File Format Options"]["Color Spaces"] = std::move(color_spaces); + export_settings["File Format Options"]["Image Formats"] = std::move(image_formats); + export_settings["File Settings"] = std::move(file_settings); + export_settings["Image Sizing"] = std::move(image_sizing); + + // Write to stream + std::ofstream os("./output/export_settings.json"); + os << export_settings; + + // Read from stream + std::ifstream is("./output/export_settings.json"); + json j = json::parse(is); + + // Pretty print + std::cout << "(1)\n" << pretty_print(j) << "\n\n"; + + // Does object member exist? + std::cout << "(2) " << std::boolalpha << j.contains("Image Sizing") << "\n\n"; + + // Get reference to object member + const json& val = j["Image Sizing"]; + + // Access member as double + std::cout << "(3) " << "Dimension 1 = " << val["Dimension 1"].as() << "\n\n"; + + // Try access member with default + std::cout << "(4) " << "Dimension 2 = " << val.get_with_default("Dimension 2",0.0) << "\n\n"; + +} + +void parse_error_example() +{ + std::string s = "[1,2,3,4,]"; + try + { + jsoncons::json val = jsoncons::json::parse(s); + } + catch(const jsoncons::ser_error& e) + { + std::cout << "Caught ser_error with category " << e.code().category().name() + << ", code " << e.code().value() + << " and message " << e.what() << std::endl; + } +} + +void validation_example() +{ + std::string s = R"( +{ + "StartDate" : "2017-03-01", + "MaturityDate" "2020-12-30" +} + )"; + std::stringstream is(s); + + json_reader reader(is); + + std::error_code ec; + reader.read(ec); + if (ec) + { + std::cout << ec.message() + << " on line " << reader.line() + << " and column " << reader.column() + << std::endl; + } +} + +void max_nesting_path_example() +{ + std::string s = "[[[[[[[[[[[[[[[[[[[[[\"Too deep\"]]]]]]]]]]]]]]]]]]]]]"; + try + { + json_options options; + options.max_nesting_depth(20); + json::parse(s, options); + } + catch (const ser_error& e) + { + std::cout << e.what() << std::endl; + } +} + +void get_example() +{ + json j = json::parse(R"( + { + "application": "hiking", + "reputons": [ + { + "rater": "HikingAsylum.example.com", + "assertion": "strong-hiker", + "rated": "Marilyn C", + "rating": 0.90 + } + ] + } + )"); + + // Using index or `at` accessors + std::string result1 = j["reputons"][0]["rated"].as(); + std::cout << "(1) " << result1 << std::endl; + std::string result2 = j.at("reputons").at(0).at("rated").as(); + std::cout << "(2) " << result2 << std::endl; + + // Using JSON Pointer + std::string result3 = jsonpointer::get(j, "/reputons/0/rated").as(); + std::cout << "(3) " << result3 << std::endl; + + // Using JSONPath + json result4 = jsonpath::json_query(j, "$.reputons.0.rated"); + if (result4.size() > 0) + { + std::cout << "(4) " << result4[0].as() << std::endl; + } + json result5 = jsonpath::json_query(j, "$..0.rated"); + if (result5.size() > 0) + { + std::cout << "(5) " << result5[0].as() << std::endl; + } +} + +int main() +{ + try + { + + std::cout << "jsoncons version: " << version() << std::endl; + + object_range_based_for_loop(); + + basics_examples(); + basics_wexamples(); + ojson_examples(); + + first_example_a(); + first_example_b(); + first_example_c(); + first_example_d(); + + second_example_a(); + + array_examples(); + container_examples(); + + csv_examples(); + + mulitple_json_objects(); + + wjson_examples(); + + unicode_examples(); + + parse_error_example(); + + type_extensibility_examples2(); + + json_filter_examples(); + + msgpack_examples(); + + validation_example(); + + comment_example(); + + json_constructor_examples(); + + json_accessor_examples(); + + json_accessor_examples(); + + jsonpatch_examples(); + + max_nesting_path_example(); + + get_example(); + + json_parser_examples(); + + more_examples(); + + data_model_examples(); + + pull_parser_examples(); + + staj_iterator_examples(); + + bson_examples(); + + serialization_examples(); + + jsonpointer_examples(); + + cbor_examples(); + + byte_string_examples(); + + readme_examples(); + + type_extensibility_examples(); + + cbor_examples(); + + csv_examples(); + + ubjson_examples(); + + jsonpath_examples(); + + polymorphic_examples(); + } + catch (const std::exception& e) + { + std::cout << e.what() << std::endl; + } + + return 0; +} diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/json_accessor_examples.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/json_accessor_examples.cpp new file mode 100644 index 0000000000..cc14474351 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/json_accessor_examples.cpp @@ -0,0 +1,122 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include + +using namespace jsoncons; + +void is_as_examples() +{ + json j = json::parse(R"( + { + "k1" : 2147483647, + "k2" : 2147483648, + "k3" : -10, + "k4" : 10.5, + "k5" : true, + "k6" : "10.5" + } + )"); + + std::cout << std::boolalpha << "(1) " << j["k1"].is() << '\n'; + std::cout << std::boolalpha << "(2) " << j["k2"].is() << '\n'; + std::cout << std::boolalpha << "(3) " << j["k2"].is() << '\n'; + std::cout << std::boolalpha << "(4) " << j["k3"].is() << '\n'; + std::cout << std::boolalpha << "(5) " << j["k3"].is() << '\n'; + std::cout << std::boolalpha << "(6) " << j["k4"].is() << '\n'; + std::cout << std::boolalpha << "(7) " << j["k4"].is() << '\n'; + std::cout << std::boolalpha << "(8) " << j["k5"].is() << '\n'; + std::cout << std::boolalpha << "(9) " << j["k5"].is() << '\n'; + std::cout << std::boolalpha << "(10) " << j["k6"].is() << '\n'; + std::cout << '\n'; + std::cout << "(1) " << j["k1"].as() << '\n'; + std::cout << "(2) " << j["k2"].as() << '\n'; + std::cout << "(3) " << j["k2"].as() << '\n'; + std::cout << "(4) " << j["k3"].as() << '\n'; + std::cout << "(5) " << j["k3"].as() << '\n'; + std::cout << "(6) " << j["k4"].as() << '\n'; + std::cout << "(7) " << j["k4"].as() << '\n'; + std::cout << std::boolalpha << "(8) " << j["k5"].as() << '\n'; + std::cout << std::boolalpha << "(9) " << j["k5"].as() << '\n'; + std::cout << "(10) " << j["k6"].as() << '\n'; +} + +void byte_string_from_initializer_list() +{ + json j(byte_string({'H','e','l','l','o'})); + byte_string bs = j.as(); + + std::cout << "(1) "<< bs << "\n\n"; + + std::cout << "(2) "; + for (auto b : bs) + { + std::cout << (char)b; + } + std::cout << "\n\n"; + + std::cout << "(3) " << j << std::endl; +} + +void byte_string_from_char_array() +{ + json j(byte_string("Hello")); + byte_string bs = j.as(); + + std::cout << "(1) "<< bs << "\n\n"; + + std::cout << "(2) "; + for (auto b : bs) + { + std::cout << (char)b; + } + std::cout << "\n\n"; + + std::cout << "(3) " << j << std::endl; +} + +void introspection_example() +{ + std::string path = "./input/books.json"; + std::fstream is(path); + if (!is) + { + std::cout << "Cannot open " << path << std::endl; + return; + } + json val = json::parse(is); + std::cout << std::boolalpha; + std::cout << "Is this an object? " << val.is() << ", or an array? " << val.is() << std::endl; + + if (val.is()) + { + for (size_t i = 0; i < val.size(); ++i) + { + json& elem = val[i]; + std::cout << "Is element " << i << " an object? " << elem.is() << std::endl; + if (elem.is()) + { + for (auto it = elem.object_range().begin(); it != elem.object_range().end(); ++it){ + std::cout << "Is member " << it->key() << " a string? " << it->value().is() << ", or a double? " << it->value().is() << ", or perhaps an int? " << it->value().is() << std::endl; + + } + } + } + } +} + +void json_accessor_examples() +{ + is_as_examples(); + + introspection_example(); + + byte_string_from_initializer_list(); + + byte_string_from_char_array(); +} + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/json_cursor_examples.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/json_cursor_examples.cpp new file mode 100644 index 0000000000..7494f7132a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/json_cursor_examples.cpp @@ -0,0 +1,143 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include + +using namespace jsoncons; + +// Example JSON text +const std::string example = R"( +[ + { + "author" : "Haruki Murakami", + "title" : "Hard-Boiled Wonderland and the End of the World", + "isbn" : "0679743464", + "publisher" : "Vintage", + "date" : "1993-03-02", + "price": 18.90 + }, + { + "author" : "Graham Greene", + "title" : "The Comedians", + "isbn" : "0099478374", + "publisher" : "Vintage Classics", + "date" : "2005-09-21", + "price": 15.74 + } +] +)"; + +// In the example, the application pulls the next event in the +// JSON input stream by calling next(). + +void reading_a_json_stream() +{ + std::istringstream is(example); + + json_cursor reader(is); + + for (; !reader.done(); reader.next()) + { + const auto& event = reader.current(); + switch (event.event_type()) + { + case staj_event_type::begin_array: + std::cout << "begin_array\n"; + break; + case staj_event_type::end_array: + std::cout << "end_array\n"; + break; + case staj_event_type::begin_object: + std::cout << "begin_object\n"; + break; + case staj_event_type::end_object: + std::cout << "end_object\n"; + break; + case staj_event_type::name: + // If underlying type is string, can return as string_view + std::cout << "name: " << event.as() << "\n"; + break; + case staj_event_type::string_value: + std::cout << "string_value: " << event.as() << "\n"; + break; + case staj_event_type::null_value: + std::cout << "null_value: " << event.as() << "\n"; + break; + case staj_event_type::bool_value: + std::cout << "bool_value: " << event.as() << "\n"; + break; + case staj_event_type::int64_value: + std::cout << "int64_value: " << event.as() << "\n"; + break; + case staj_event_type::uint64_value: + std::cout << "uint64_value: " << event.as() << "\n"; + break; + case staj_event_type::double_value: + // Return as string, could also use event.as() + std::cout << "double_value: " << event.as() << "\n"; + break; + default: + std::cout << "Unhandled event type\n"; + break; + } + } +} + +class author_filter : public staj_filter +{ + bool accept_next_ = false; +public: + bool accept(const staj_event& event, const ser_context& context) override + { + if (event.event_type() == staj_event_type::name && + event.as() == "author") + { + accept_next_ = true; + return false; + } + else if (accept_next_) + { + accept_next_ = false; + return true; + } + else + { + accept_next_ = false; + return false; + } + } +}; + +// Filtering the stream +void filtering_a_json_stream() +{ + std::istringstream is(example); + + author_filter filter; + json_cursor reader(is, filter); + + for (; !reader.done(); reader.next()) + { + const auto& event = reader.current(); + switch (event.event_type()) + { + case staj_event_type::string_value: + std::cout << event.as() << "\n"; + break; + } + } +} + +void pull_parser_examples() +{ + std::cout << "\nPull parser examples\n\n"; + + reading_a_json_stream(); + std::cout << "\n"; + filtering_a_json_stream(); + + std::cout << "\n"; +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/json_filter_examples.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/json_filter_examples.cpp new file mode 100644 index 0000000000..6224fda910 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/json_filter_examples.cpp @@ -0,0 +1,128 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include + +using namespace jsoncons; + +class name_fix_up_filter : public json_filter +{ +public: + name_fix_up_filter(json_content_handler& handler) + : json_filter(handler) + { + } + +private: + bool do_name(const string_view_type& name, + const ser_context& context) override + { + member_name_ = std::string(name); + if (member_name_ != "name") + { + this->to_handler().name(name, context); + } + return true; + } + + bool do_string_value(const string_view_type& s, + semantic_tag tag, + const ser_context& context) override + { + if (member_name_ == "name") + { + size_t end_first = s.find_first_of(" \t"); + size_t start_last = s.find_first_not_of(" \t", end_first); + this->to_handler().name("first-name", context); + string_view_type first = s.substr(0, end_first); + this->to_handler().string_value(first, tag, context); + if (start_last != string_view_type::npos) + { + this->to_handler().name("last-name", context); + string_view_type last = s.substr(start_last); + this->to_handler().string_value(last, tag, context); + } + else + { + std::cerr << "Incomplete name \"" << s + << "\" at line " << context.line() + << " and column " << context.column() << std::endl; + } + } + else + { + this->to_handler().string_value(s, tag, context); + } + return true; + } + + std::string member_name_; +}; + +void name_fix_up_example1() +{ + std::string in_file = "./input/address-book.json"; + std::string out_file = "./output/new-address-book1.json"; + std::ifstream is(in_file); + std::ofstream os(out_file); + + json_encoder encoder(os); + name_fix_up_filter filter(encoder); + json_reader reader(is, filter); + reader.read_next(); +} + +void name_fix_up_example2() +{ + std::string in_file = "./input/address-book.json"; + std::string out_file = "./output/new-address-book2.json"; + std::ifstream is(in_file); + std::ofstream os(out_file); + + json j; + is >> j; + + json_encoder encoder(os); + name_fix_up_filter filter(encoder); + j.dump(filter); +} + +void change_member_name_example() +{ + std::string s = R"({"first":1,"second":2,"fourth":3,"fifth":4})"; + + json_encoder encoder(std::cout); + + // Filters can be chained + rename_object_member_filter filter2("fifth", "fourth", encoder); + rename_object_member_filter filter1("fourth", "third", filter2); + + // A filter can be passed to any function that takes + // a json_content_handler ... + std::cout << "(1) "; + std::istringstream is(s); + json_reader reader(is, filter1); + reader.read(); + std::cout << std::endl; + + // or a json_content_handler + std::cout << "(2) "; + ojson j = ojson::parse(s); + j.dump(filter1); + std::cout << std::endl; +} + +void json_filter_examples() +{ + std::cout << "\njson_filter examples\n\n"; + name_fix_up_example1(); + name_fix_up_example2(); + change_member_name_example(); + + std::cout << std::endl; +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/json_parser_examples.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/json_parser_examples.cpp new file mode 100644 index 0000000000..dfa3337cdd --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/json_parser_examples.cpp @@ -0,0 +1,152 @@ +// Copyright 2018 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include + +using namespace jsoncons; + +void incremental_parsing_example1() +{ + jsoncons::json_decoder decoder; + json_parser parser; + try + { + parser.update("[fal"); + parser.parse_some(decoder); + std::cout << "(1) done: " << std::boolalpha << parser.done() << ", source_exhausted: " << parser.source_exhausted() << "\n\n"; + + parser.update("se]"); + parser.parse_some(decoder); + std::cout << "(2) done: " << std::boolalpha << parser.done() << ", source_exhausted: " << parser.source_exhausted() << "\n\n"; + + parser.finish_parse(decoder); + std::cout << "(3) done: " << std::boolalpha << parser.done() << ", source_exhausted: " << parser.source_exhausted() << "\n\n"; + + parser.check_done(); + std::cout << "(4) done: " << std::boolalpha << parser.done() << ", source_exhausted: " << parser.source_exhausted() << "\n\n"; + + json j = decoder.get_result(); + std::cout << "(5) " << j << "\n\n"; + } + catch (const ser_error& e) + { + std::cout << e.what() << std::endl; + } +} + +void incremental_parsing_example2() +{ + jsoncons::json_decoder decoder; + json_parser parser; + try + { + parser.update("10"); + parser.parse_some(decoder); + std::cout << "(1) done: " << std::boolalpha << parser.done() << ", source_exhausted: " << parser.source_exhausted() << "\n\n"; + + parser.update(".5"); + parser.parse_some(decoder); // This is the end, but the parser can't tell + std::cout << "(2) done: " << std::boolalpha << parser.done() << ", source_exhausted: " << parser.source_exhausted() << "\n\n"; + + parser.finish_parse(decoder); // Indicates that this is the end + std::cout << "(3) done: " << std::boolalpha << parser.done() << ", source_exhausted: " << parser.source_exhausted() << "\n\n"; + + parser.check_done(); // Checks if there are any unconsumed + // non-whitespace characters in the input + std::cout << "(4) done: " << std::boolalpha << parser.done() << ", source_exhausted: " << parser.source_exhausted() << "\n\n"; + + json j = decoder.get_result(); + std::cout << "(5) " << j << "\n"; + } + catch (const ser_error& e) + { + std::cout << e.what() << std::endl; + } +} + +void incremental_parsing_example3() +{ + jsoncons::json_decoder decoder; + json_parser parser; + try + { + parser.update("[10"); + parser.parse_some(decoder); + std::cout << "(1) done: " << std::boolalpha << parser.done() << ", source_exhausted: " << parser.source_exhausted() << "\n\n"; + + parser.update(".5]{}"); + parser.parse_some(decoder); // The parser reaches the end at ']' + std::cout << "(2) done: " << std::boolalpha << parser.done() << ", source_exhausted: " << parser.source_exhausted() << "\n\n"; + + parser.finish_parse(decoder); // Indicates that this is the end + std::cout << "(3) done: " << std::boolalpha << parser.done() << ", source_exhausted: " << parser.source_exhausted() << "\n\n"; + + parser.check_done(); // Checks if there are any unconsumed + // non-whitespace characters in the input + // (there are) + } + catch (const ser_error& e) + { + std::cout << "(4) " << e.what() << std::endl; + } +} + +void parse_nan_replacement_example() +{ + std::string s = R"( + { + "A" : "NaN", + "B" : "Infinity", + "C" : "-Infinity" + } + )"; + + json_options options; + options.nan_to_str("NaN") + .inf_to_str("Infinity"); + + jsoncons::json_decoder decoder; + json_parser parser(options); + try + { + parser.update(s); + parser.parse_some(decoder); + parser.finish_parse(decoder); + parser.check_done(); + } + catch (const ser_error& e) + { + std::cout << e.what() << std::endl; + } + + json j = decoder.get_result(); // performs move + if (j["A"].is()) + { + std::cout << "A: " << j["A"].as() << std::endl; + } + if (j["B"].is()) + { + std::cout << "B: " << j["B"].as() << std::endl; + } + if (j["C"].is()) + { + std::cout << "C: " << j["C"].as() << std::endl; + } +} + +void json_parser_examples() +{ + std::cout << "\njson_parser examples\n\n"; + incremental_parsing_example1(); + incremental_parsing_example2(); + incremental_parsing_example3(); + parse_nan_replacement_example(); + + std::cout << std::endl; +} + + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/jsonpatch_examples.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/jsonpatch_examples.cpp new file mode 100644 index 0000000000..1846f9f7b2 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/jsonpatch_examples.cpp @@ -0,0 +1,116 @@ +// Copyright 2017 Daniel Parker +// Distributed under Boost license + +#include +#include + +using namespace jsoncons; + +void jsonpatch_add_add() +{ + // Apply a JSON Patch + + json doc = R"( + { "foo": "bar"} + )"_json; + + json doc2 = doc; + + json patch = R"( + [ + { "op": "add", "path": "/baz", "value": "qux" }, + { "op": "add", "path": "/foo", "value": [ "bar", "baz" ] } + ] + )"_json; + + std::error_code ec; + jsonpatch::apply_patch(doc, patch, ec); + + std::cout << "(1)\n" << pretty_print(doc) << std::endl; + + // Create a JSON Patch + + auto patch2 = jsonpatch::from_diff(doc2,doc); + + std::cout << "(2)\n" << pretty_print(patch2) << std::endl; + + jsonpatch::apply_patch(doc2,patch2,ec); + + std::cout << "(3)\n" << pretty_print(doc2) << std::endl; +} + +void jsonpatch_add_add_add_failed1() +{ + json target = R"( + { "foo": "bar"} + )"_json; + + json patch = R"( + [ + { "op": "add", "path": "/baz", "value": "qux" }, + { "op": "add", "path": "/foo", "value": [ "bar", "baz" ] }, + { "op": "add", "path": "/baz/bat", "value": "qux" } // nonexistent target + ] + )"_json; + + try + { + jsonpatch::apply_patch(target, patch); + } + catch (const jsonpatch::jsonpatch_error& e) + { + std::cout << "(1) " << e.what() << std::endl; + std::cout << "(2) " << target << std::endl; + } +} + +void jsonpatch_add_add_add_failed2() +{ + json target = R"( + { "foo": "bar"} + )"_json; + + json patch = R"( + [ + { "op": "add", "path": "/baz", "value": "qux" }, + { "op": "add", "path": "/foo", "value": [ "bar", "baz" ] }, + { "op": "add", "path": "/baz/bat", "value": "qux" } // nonexistent target + ] + )"_json; + + std::error_code ec; + jsonpatch::apply_patch(target, patch, ec); + + std::cout << "(1) " << std::error_code(ec).message() << std::endl; + std::cout << "(2) " << target << std::endl; +} + +void create_a_json_patch() +{ + json source = R"( + {"/": 9, "foo": "bar"} + )"_json; + + json target = R"( + { "baz":"qux", "foo": [ "bar", "baz" ]} + )"_json; + + auto patch = jsonpatch::from_diff(source, target); + + std::error_code ec; + jsonpatch::apply_patch(source, patch, ec); + + std::cout << "(1)\n" << pretty_print(patch) << std::endl; + std::cout << "(2)\n" << pretty_print(source) << std::endl; +} + +void jsonpatch_examples() +{ + std::cout << "\njsonpatch examples\n\n"; + create_a_json_patch(); + jsonpatch_add_add(); + jsonpatch_add_add_add_failed2(); + jsonpatch_add_add_add_failed1(); + std::cout << std::endl; +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/jsonpath_examples.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/jsonpath_examples.cpp new file mode 100644 index 0000000000..113787791a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/jsonpath_examples.cpp @@ -0,0 +1,248 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include + +using namespace jsoncons; + +void json_query_examples() +{ + std::ifstream is("./input/booklist.json"); + json booklist = json::parse(is); + + // The authors of books that are cheaper than $10 + json result1 = jsonpath::json_query(booklist, "$.store.book[?(@.price < 10)].author"); + std::cout << "(1) " << result1 << "\n"; + + // The number of books + json result2 = jsonpath::json_query(booklist, "$..book.length"); + std::cout << "(2) " << result2 << "\n"; + + // The third book + json result3 = jsonpath::json_query(booklist, "$..book[2]"); + std::cout << "(3)\n" << pretty_print(result3) << "\n"; + + // All books whose author's name starts with Evelyn + json result4 = jsonpath::json_query(booklist, "$.store.book[?(@.author =~ /Evelyn.*?/)]"); + std::cout << "(4)\n" << pretty_print(result4) << "\n"; + + // The titles of all books that have isbn number + json result5 = jsonpath::json_query(booklist, "$..book[?(@.isbn)].title"); + std::cout << "(5) " << result5 << "\n"; + + // All authors and titles of books + json result6 = jsonpath::json_query(booklist, "$['store']['book']..['author','title']"); + std::cout << "(6)\n" << pretty_print(result6) << "\n"; + + // Union of two ranges of book titles + json result7 = jsonpath::json_query(booklist, "$..book[1:2,2:4].title"); + std::cout << "(7)\n" << pretty_print(result7) << "\n"; + + // Union of a subset of book titles identified by index + json result8 = jsonpath::json_query(booklist, "$.store[book[0].title,book[1].title,book[3].title]"); + std::cout << "(8)\n" << pretty_print(result8) << "\n"; + + // Union of third book title and all book titles with price > 10 + json result9 = jsonpath::json_query(booklist, "$.store[book[3].title,book[?(@.price > 10)].title]"); + std::cout << "(9)\n" << pretty_print(result9) << "\n"; + + // Intersection of book titles with category fiction and price < 15 + json result10 = jsonpath::json_query(booklist, "$.store.book[?(@.category == 'fiction')][?(@.price < 15)].title"); + std::cout << "(10)\n" << pretty_print(result10) << "\n"; + + // Normalized path expressions + json result11 = jsonpath::json_query(booklist, "$.store.book[?(@.author =~ /Evelyn.*?/)]", jsonpath::result_type::path); + std::cout << "(11)\n" << pretty_print(result11) << "\n"; + + // All titles whose author's second name is 'Waugh' + json result12 = jsonpath::json_query(booklist,"$.store.book[?(tokenize(@.author,'\\\\s+')[1] == 'Waugh')].title"); + std::cout << "(12)\n" << result12 << "\n"; + + // All keys in the second book + json result13 = jsonpath::json_query(booklist,"keys($.store.book[1])[*]"); + std::cout << "(13)\n" << result13 << "\n"; +} + +void json_replace_example1() +{ + std::ifstream is("./input/booklist.json"); + json booklist = json::parse(is); + + jsonpath::json_replace(booklist,"$.store.book[?(@.isbn == '0-553-21311-3')].price",10.0); + std::cout << pretty_print(booklist) << "\n"; +} + +void json_replace_example2() +{ + json j; + try + { + j = json::parse(R"( +{"store": +{"book": [ +{"category": "reference", +"author": "Margaret Weis", +"title": "Dragonlance Series", +"price": 31.96}, +{"category": "reference", +"author": "Brent Weeks", +"title": "Night Angel Trilogy", +"price": 14.70 +}]}} +)"); + } + catch (const std::exception& e) + { + std::cout << e.what() << "\n"; + } + + std::cout << ("1\n") << pretty_print(j) << "\n"; + + jsonpath::json_replace(j,"$..book[?(@.price==31.96)].price", 30.9); + + std::cout << ("2\n") << pretty_print(j) << "\n"; +} + +void jsonpath_complex_examples() +{ + const json j = json::parse(R"( + [ + { + "root": { + "id" : 10, + "second": [ + { + "names": [ + 2 + ], + "complex": [ + { + "names": [ + 1 + ], + "panels": [ + { + "result": [ + 1 + ] + }, + { + "result": [ + 1, + 2, + 3, + 4 + ] + }, + { + "result": [ + 1 + ] + } + ] + } + ] + } + ] + } + }, + { + "root": { + "id" : 20, + "second": [ + { + "names": [ + 2 + ], + "complex": [ + { + "names": [ + 1 + ], + "panels": [ + { + "result": [ + 1 + ] + }, + { + "result": [ + 3, + 4, + 5, + 6 + ] + }, + { + "result": [ + 1 + ] + } + ] + } + ] + } + ] + } + } + ] + )"); + + // Find all arrays of elements where result.length is 4 + json result1 = jsonpath::json_query(j,"$..[?(@.result.length == 4)].result"); + std::cout << "(1) " << result1 << "\n"; + + // Find array of elements that has id 10 and result.length is 4 + json result2 = jsonpath::json_query(j,"$..[?(@.id == 10)]..[?(@.result.length == 4)].result"); + std::cout << "(2) " << result2 << "\n"; + + // Find all arrays of elements where result.length is 4 and that have value 3 + json result3 = jsonpath::json_query(j,"$..[?(@.result.length == 4 && (@.result[0] == 3 || @.result[1] == 3 || @.result[2] == 3 || @.result[3] == 3))].result"); + std::cout << "(3) " << result3 << "\n"; +} + +void jsonpath_union() +{ + const json root = json::parse(R"( +{ + "firstName": "John", + "lastName" : "doe", + "age" : 26, + "address" : { + "streetAddress": "naist street", + "city" : "Nara", + "postalCode" : "630-0192" + }, + "phoneNumbers": [ + { + "type" : "iPhone", + "number": "0123-4567-8888" + }, + { + "type" : "home", + "number": "0123-4567-8910" + } + ] +} )"); + + std::string path = "$..[firstName,address.city]"; + json result = jsonpath::json_query(root,path); + + std::cout << result << "\n"; +} + +void jsonpath_examples() +{ + std::cout << "\nJsonPath examples\n\n"; + std::cout << "Here\n"; + json_replace_example1(); + json_replace_example2(); + jsonpath_complex_examples(); + jsonpath_union(); + json_query_examples(); + std::cout << "\n"; +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/jsonpointer_examples.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/jsonpointer_examples.cpp new file mode 100644 index 0000000000..2e6045bddd --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/jsonpointer_examples.cpp @@ -0,0 +1,474 @@ +// Copyright 2017 Daniel Parker +// Distributed under Boost license + +#include +#include + +using namespace jsoncons; + +void jsonpointer_select_RFC6901() +{ + // Example from RFC 6901 + auto j = json::parse(R"( + { + "foo": ["bar", "baz"], + "": 0, + "a/b": 1, + "c%d": 2, + "e^f": 3, + "g|h": 4, + "i\\j": 5, + "k\"l": 6, + " ": 7, + "m~n": 8 + } + )"); + + try + { + const json& result1 = jsonpointer::get(j, ""); + std::cout << "(1) " << result1 << std::endl; + const json& result2 = jsonpointer::get(j, "/foo"); + std::cout << "(2) " << result2 << std::endl; + const json& result3 = jsonpointer::get(j, "/foo/0"); + std::cout << "(3) " << result3 << std::endl; + const json& result4 = jsonpointer::get(j, "/"); + std::cout << "(4) " << result4 << std::endl; + const json& result5 = jsonpointer::get(j, "/a~1b"); + std::cout << "(5) " << result5 << std::endl; + const json& result6 = jsonpointer::get(j, "/c%d"); + std::cout << "(6) " << result6 << std::endl; + const json& result7 = jsonpointer::get(j, "/e^f"); + std::cout << "(7) " << result7 << std::endl; + const json& result8 = jsonpointer::get(j, "/g|h"); + std::cout << "(8) " << result8 << std::endl; + const json& result9 = jsonpointer::get(j, "/i\\j"); + std::cout << "(9) " << result9 << std::endl; + const json& result10 = jsonpointer::get(j, "/k\"l"); + std::cout << "(10) " << result10 << std::endl; + const json& result11 = jsonpointer::get(j, "/ "); + std::cout << "(11) " << result11 << std::endl; + const json& result12 = jsonpointer::get(j, "/m~0n"); + std::cout << "(12) " << result12 << std::endl; + } + catch (const jsonpointer::jsonpointer_error& e) + { + std::cerr << e.what() << std::endl; + } +} + +void jsonpointer_contains() +{ + // Example from RFC 6901 + auto j = json::parse(R"( + { + "foo": ["bar", "baz"], + "": 0, + "a/b": 1, + "c%d": 2, + "e^f": 3, + "g|h": 4, + "i\\j": 5, + "k\"l": 6, + " ": 7, + "m~n": 8 + } + )"); + + std::cout << "(1) " << jsonpointer::contains(j, "/foo/0") << std::endl; + std::cout << "(2) " << jsonpointer::contains(j, "e^g") << std::endl; +} + +void jsonpointer_select_author() +{ + auto j = json::parse(R"( + [ + { "category": "reference", + "author": "Nigel Rees", + "title": "Sayings of the Century", + "price": 8.95 + }, + { "category": "fiction", + "author": "Evelyn Waugh", + "title": "Sword of Honour", + "price": 12.99 + } + ] + )"); + + // Using exceptions to report errors + try + { + json result = jsonpointer::get(j, "/1/author"); + std::cout << "(1) " << result << std::endl; + } + catch (const jsonpointer::jsonpointer_error& e) + { + std::cout << e.what() << std::endl; + } + + // Using error codes to report errors + std::error_code ec; + const json& result = jsonpointer::get(j, "/0/title", ec); + + if (ec) + { + std::cout << ec.message() << std::endl; + } + else + { + std::cout << "(2) " << result << std::endl; + } +} + +void jsonpointer_add_member_to_object() +{ + auto target = json::parse(R"( + { "foo": "bar"} + )"); + + std::error_code ec; + jsonpointer::insert(target, "/baz", json("qux"), ec); + if (ec) + { + std::cout << ec.message() << std::endl; + } + else + { + std::cout << target << std::endl; + } +} + +void jsonpointer_add_element_to_array() +{ + auto target = json::parse(R"( + { "foo": [ "bar", "baz" ] } + )"); + + std::error_code ec; + jsonpointer::insert(target, "/foo/1", json("qux"), ec); + if (ec) + { + std::cout << ec.message() << std::endl; + } + else + { + std::cout << target << std::endl; + } +} + +void jsonpointer_add_element_to_end_array() +{ + auto target = json::parse(R"( + { "foo": [ "bar", "baz" ] } + )"); + + std::error_code ec; + jsonpointer::insert(target, "/foo/-", json("qux"), ec); + if (ec) + { + std::cout << ec.message() << std::endl; + } + else + { + std::cout << target << std::endl; + } +} + +void jsonpointer_insert_name_exists() +{ + auto target = json::parse(R"( + { "foo": "bar", "baz" : "abc"} + )"); + + std::error_code ec; + jsonpointer::insert(target, "/baz", json("qux"), ec); + if (ec) + { + std::cout << ec.message() << std::endl; + } + else + { + std::cout << target << std::endl; + } +} + +void jsonpointer_add_element_outside_range() +{ + auto target = json::parse(R"( + { "foo": [ "bar", "baz" ] } + )"); + + std::error_code ec; + jsonpointer::insert_or_assign(target, "/foo/3", json("qux"), ec); + if (ec) + { + std::cout << ec.message() << std::endl; + } + else + { + std::cout << target << std::endl; + } +} + +void jsonpointer_insert_or_assign_name_exists() +{ + auto target = json::parse(R"( + { "foo": "bar", "baz" : "abc"} + )"); + + std::error_code ec; + jsonpointer::insert_or_assign(target, "/baz", json("qux"), ec); + if (ec) + { + std::cout << ec.message() << std::endl; + } + else + { + std::cout << target << std::endl; + } +} + +void jsonpointer_remove_object_member() +{ + auto target = json::parse(R"( + { "foo": "bar", "baz" : "qux"} + )"); + + std::error_code ec; + jsonpointer::remove(target, "/baz", ec); + if (ec) + { + std::cout << ec.message() << std::endl; + } + else + { + std::cout << target << std::endl; + } +} + +void jsonpointer_remove_array_element() +{ + auto target = json::parse(R"( + { "foo": [ "bar", "qux", "baz" ] } + )"); + + std::error_code ec; + jsonpointer::remove(target, "/foo/1", ec); + if (ec) + { + std::cout << ec.message() << std::endl; + } + else + { + std::cout << target << std::endl; + } +} + +void jsonpointer_replace_object_value() +{ + auto target = json::parse(R"( + { + "baz": "qux", + "foo": "bar" + } + )"); + + std::error_code ec; + jsonpointer::replace(target, "/baz", json("boo"), ec); + if (ec) + { + std::cout << ec.message() << std::endl; + } + else + { + std::cout << target << std::endl; + } +} + +void jsonpointer_replace_array_value() +{ + auto target = json::parse(R"( + { "foo": [ "bar", "baz" ] } + )"); + + std::error_code ec; + jsonpointer::replace(target, "/foo/1", json("qux"), ec); + if (ec) + { + std::cout << ec.message() << std::endl; + } + else + { + std::cout << pretty_print(target) << std::endl; + } +} + +void jsonpointer_error_example() +{ + auto j = json::parse(R"( + [ + { "category": "reference", + "author": "Nigel Rees", + "title": "Sayings of the Century", + "price": 8.95 + }, + { "category": "fiction", + "author": "Evelyn Waugh", + "title": "Sword of Honour", + "price": 12.99 + } + ] + )"); + + try + { + json result = jsonpointer::get(j, "/1/isbn"); + std::cout << "succeeded?" << std::endl; + std::cout << result << std::endl; + } + catch (const jsonpointer::jsonpointer_error& e) + { + std::cout << "Caught jsonpointer_error with category " << e.code().category().name() + << ", code " << e.code().value() + << " and message \"" << e.what() << "\"" << std::endl; + } +} + +void jsonpointer_get_examples() +{ + { + json j = json::array{"baz","foo"}; + json& item = jsonpointer::get(j,"/0"); + std::cout << "(1) " << item << std::endl; + + //std::vector u; + //cbor::encode_cbor(j,u); + //for (auto c : u) + //{ + // std::cout << "0x" << std::hex << (int)c << ","; + //} + //std::cout << std::endl; + } + { + const json j = json::array{"baz","foo"}; + const json& item = jsonpointer::get(j,"/1"); + std::cout << "(2) " << item << std::endl; + } + { + json j = json::array{"baz","foo"}; + + std::error_code ec; + json& item = jsonpointer::get(j,"/1",ec); + std::cout << "(4) " << item << std::endl; + } + { + const json j = json::array{"baz","foo"}; + + std::error_code ec; + const json& item = jsonpointer::get(j,"/0",ec); + std::cout << "(5) " << item << std::endl; + } +} + +void jsonpointer_address_example() +{ + auto j = json::parse(R"( + { + "a/b": ["bar", "baz"], + "m~n": ["foo", "qux"] + } + )"); + + jsonpointer::address addr; + addr /= "m~n"; + addr /= "1"; + + std::cout << "(1) " << addr << "\n\n"; + + std::cout << "(2)\n"; + for (const auto& item : addr) + { + std::cout << item << "\n"; + } + std::cout << "\n"; + + json item = jsonpointer::get(j, addr); + std::cout << "(3) " << item << "\n"; +} + +void jsonpointer_address_iterator_example() +{ + jsonpointer::address addr("/store/book/1/author"); + + std::cout << "(1) " << addr << "\n\n"; + + std::cout << "(2)\n"; + for (const auto& token : addr) + { + std::cout << token << "\n"; + } + + std::cout << "\n"; +} + +void jsonpointer_address_append_tokens() +{ + jsonpointer::address addr; + + addr /= "a/b"; + addr /= ""; + addr /= "m~n"; + + std::cout << "(1) " << addr << "\n\n"; + + std::cout << "(2)\n"; + for (const auto& token : addr) + { + std::cout << token << "\n"; + } + + std::cout << "\n"; +} + +void jsonpointer_address_concatentae() +{ + jsonpointer::address addr("/a~1b"); + + addr += jsonpointer::address("//m~0n"); + + std::cout << "(1) " << addr << "\n\n"; + + std::cout << "(2)\n"; + for (const auto& token : addr) + { + std::cout << token << "\n"; + } + + std::cout << "\n"; +} + +void jsonpointer_examples() +{ + std::cout << "\njsonpointer examples\n\n"; + jsonpointer_select_author(); + jsonpointer_address_example(); + jsonpointer_select_RFC6901(); + jsonpointer_add_member_to_object(); + jsonpointer_add_element_to_array(); + jsonpointer_add_element_to_end_array(); + jsonpointer_add_element_outside_range(); + jsonpointer_remove_object_member(); + jsonpointer_remove_array_element(); + jsonpointer_replace_object_value(); + jsonpointer_replace_array_value(); + jsonpointer_contains(); + jsonpointer_error_example(); + jsonpointer_insert_name_exists(); + jsonpointer_insert_or_assign_name_exists(); + jsonpointer_get_examples(); + jsonpointer_address_iterator_example(); + jsonpointer_address_append_tokens(); + jsonpointer_address_concatentae(); +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/jsonpointer_examples.cpp.orig b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/jsonpointer_examples.cpp.orig new file mode 100644 index 0000000000..e0c0c579a8 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/jsonpointer_examples.cpp.orig @@ -0,0 +1,494 @@ +// Copyright 2017 Daniel Parker +// Distributed under Boost license + +#include +#include + +namespace jp = jsoncons::jsonpointer; + +void jsonpointer_select_RFC6901() +{ + // Example from RFC 6901 + auto j = jsoncons::json::parse(R"( + { + "foo": ["bar", "baz"], + "": 0, + "a/b": 1, + "c%d": 2, + "e^f": 3, + "g|h": 4, + "i\\j": 5, + "k\"l": 6, + " ": 7, + "m~n": 8 + } + )"); + + try + { + const jsoncons::json& result1 = jp::get(j, ""); + std::cout << "(1) " << result1 << std::endl; + const jsoncons::json& result2 = jp::get(j, "/foo"); + std::cout << "(2) " << result2 << std::endl; + const jsoncons::json& result3 = jp::get(j, "/foo/0"); + std::cout << "(3) " << result3 << std::endl; + const jsoncons::json& result4 = jp::get(j, "/"); + std::cout << "(4) " << result4 << std::endl; + const jsoncons::json& result5 = jp::get(j, "/a~1b"); + std::cout << "(5) " << result5 << std::endl; + const jsoncons::json& result6 = jp::get(j, "/c%d"); + std::cout << "(6) " << result6 << std::endl; + const jsoncons::json& result7 = jp::get(j, "/e^f"); + std::cout << "(7) " << result7 << std::endl; + const jsoncons::json& result8 = jp::get(j, "/g|h"); + std::cout << "(8) " << result8 << std::endl; + const jsoncons::json& result9 = jp::get(j, "/i\\j"); + std::cout << "(9) " << result9 << std::endl; + const jsoncons::json& result10 = jp::get(j, "/k\"l"); + std::cout << "(10) " << result10 << std::endl; + const jsoncons::json& result11 = jp::get(j, "/ "); + std::cout << "(11) " << result11 << std::endl; + const jsoncons::json& result12 = jp::get(j, "/m~0n"); + std::cout << "(12) " << result12 << std::endl; + } + catch (const jp::jsonpointer_error& e) + { + std::cerr << e.what() << std::endl; + } +} + +void jsonpointer_contains() +{ + // Example from RFC 6901 + auto j = jsoncons::json::parse(R"( + { + "foo": ["bar", "baz"], + "": 0, + "a/b": 1, + "c%d": 2, + "e^f": 3, + "g|h": 4, + "i\\j": 5, + "k\"l": 6, + " ": 7, + "m~n": 8 + } + )"); + + std::cout << "(1) " << jp::contains(j, "/foo/0") << std::endl; + std::cout << "(2) " << jp::contains(j, "e^g") << std::endl; +} + +void jsonpointer_select_author() +{ + auto j = jsoncons::json::parse(R"( + [ + { "category": "reference", + "author": "Nigel Rees", + "title": "Sayings of the Century", + "price": 8.95 + }, + { "category": "fiction", + "author": "Evelyn Waugh", + "title": "Sword of Honour", + "price": 12.99 + } + ] + )"); + + // Using exceptions to report errors + try + { + jsoncons::json result = jp::get(j, "/1/author"); + std::cout << "(1) " << result << std::endl; + } + catch (const jp::jsonpointer_error& e) + { + std::cout << e.what() << std::endl; + } + + // Using error codes to report errors + std::error_code ec; + const jsoncons::json& result = jp::get(j, "/0/title", ec); + + if (ec) + { + std::cout << ec.message() << std::endl; + } + else + { + std::cout << "(2) " << result << std::endl; + } +} + +void jsonpointer_add_member_to_object() +{ + auto target = jsoncons::json::parse(R"( + { "foo": "bar"} + )"); + + std::error_code ec; + jp::insert(target, "/baz", jsoncons::json("qux"), ec); + if (ec) + { + std::cout << ec.message() << std::endl; + } + else + { + std::cout << target << std::endl; + } +} + +void jsonpointer_add_element_to_array() +{ + auto target = jsoncons::json::parse(R"( + { "foo": [ "bar", "baz" ] } + )"); + + std::error_code ec; + jp::insert(target, "/foo/1", jsoncons::json("qux"), ec); + if (ec) + { + std::cout << ec.message() << std::endl; + } + else + { + std::cout << target << std::endl; + } +} + +void jsonpointer_add_element_to_end_array() +{ + auto target = jsoncons::json::parse(R"( + { "foo": [ "bar", "baz" ] } + )"); + + std::error_code ec; + jp::insert(target, "/foo/-", jsoncons::json("qux"), ec); + if (ec) + { + std::cout << ec.message() << std::endl; + } + else + { + std::cout << target << std::endl; + } +} + +void jsonpointer_insert_name_exists() +{ + auto target = jsoncons::json::parse(R"( + { "foo": "bar", "baz" : "abc"} + )"); + + std::error_code ec; + jp::insert(target, "/baz", jsoncons::json("qux"), ec); + if (ec) + { + std::cout << ec.message() << std::endl; + } + else + { + std::cout << target << std::endl; + } +} + +void jsonpointer_add_element_outside_range() +{ + auto target = jsoncons::json::parse(R"( + { "foo": [ "bar", "baz" ] } + )"); + + std::error_code ec; + jp::insert_or_assign(target, "/foo/3", jsoncons::json("qux"), ec); + if (ec) + { + std::cout << ec.message() << std::endl; + } + else + { + std::cout << target << std::endl; + } +} + +void jsonpointer_insert_or_assign_name_exists() +{ + auto target = jsoncons::json::parse(R"( + { "foo": "bar", "baz" : "abc"} + )"); + + std::error_code ec; + jp::insert_or_assign(target, "/baz", jsoncons::json("qux"), ec); + if (ec) + { + std::cout << ec.message() << std::endl; + } + else + { + std::cout << target << std::endl; + } +} + +void jsonpointer_remove_object_member() +{ + auto target = jsoncons::json::parse(R"( + { "foo": "bar", "baz" : "qux"} + )"); + + std::error_code ec; + jp::remove(target, "/baz", ec); + if (ec) + { + std::cout << ec.message() << std::endl; + } + else + { + std::cout << target << std::endl; + } +} + +void jsonpointer_remove_array_element() +{ + auto target = jsoncons::json::parse(R"( + { "foo": [ "bar", "qux", "baz" ] } + )"); + + std::error_code ec; + jp::remove(target, "/foo/1", ec); + if (ec) + { + std::cout << ec.message() << std::endl; + } + else + { + std::cout << target << std::endl; + } +} + +void jsonpointer_replace_object_value() +{ + auto target = jsoncons::json::parse(R"( + { + "baz": "qux", + "foo": "bar" + } + )"); + + std::error_code ec; + jp::replace(target, "/baz", jsoncons::json("boo"), ec); + if (ec) + { + std::cout << ec.message() << std::endl; + } + else + { + std::cout << target << std::endl; + } +} + +void jsonpointer_replace_array_value() +{ + auto target = jsoncons::json::parse(R"( + { "foo": [ "bar", "baz" ] } + )"); + + std::error_code ec; + jp::replace(target, "/foo/1", jsoncons::json("qux"), ec); + if (ec) + { + std::cout << ec.message() << std::endl; + } + else + { + std::cout << pretty_print(target) << std::endl; + } +} + +void jsonpointer_error_example() +{ + auto j = jsoncons::json::parse(R"( + [ + { "category": "reference", + "author": "Nigel Rees", + "title": "Sayings of the Century", + "price": 8.95 + }, + { "category": "fiction", + "author": "Evelyn Waugh", + "title": "Sword of Honour", + "price": 12.99 + } + ] + )"); + + try + { + jsoncons::json result = jp::get(j, "/1/isbn"); + std::cout << "succeeded?" << std::endl; + std::cout << result << std::endl; + } + catch (const jp::jsonpointer_error& e) + { + std::cout << "Caught jsonpointer_error with category " << e.code().category().name() + << ", code " << e.code().value() + << " and message \"" << e.what() << "\"" << std::endl; + } +} + +void jsonpointer_get_examples() +{ + { + jsoncons::json j = jsoncons::json::array{"baz","foo"}; + jsoncons::json& item = jp::get(j,"/0"); + std::cout << "(1) " << item << std::endl; + + //std::vector u; + //cbor::encode_cbor(j,u); + //for (auto c : u) + //{ + // std::cout << "0x" << std::hex << (int)c << ","; + //} + //std::cout << std::endl; + } + { + const jsoncons::json j = jsoncons::json::array{"baz","foo"}; + const jsoncons::json& item = jp::get(j,"/1"); + std::cout << "(2) " << item << std::endl; + } + { + jsoncons::json j = jsoncons::json::array{"baz","foo"}; + + std::error_code ec; + jsoncons::json& item = jp::get(j,"/1",ec); + std::cout << "(4) " << item << std::endl; + } + { + const jsoncons::json j = jsoncons::json::array{"baz","foo"}; + + std::error_code ec; + const jsoncons::json& item = jp::get(j,"/0",ec); + std::cout << "(5) " << item << std::endl; + } +} + +void jsonpointer_address_example() +{ + auto j = jsoncons::json::parse(R"( + { + "a/b": ["bar", "baz"], + "m~n": ["foo", "qux"] + } + )"); + +<<<<<<< HEAD + jp::address addr; + addr /= "m~n"; + addr /= "1"; +======= + jsonpointer::address p; + p /= "m~n"; + p /= "1"; +>>>>>>> efc18942efb17086d3de2d1d853d56a11666ebb0 + + std::cout << "(1) " << addr << "\n\n"; + + std::cout << "(2)\n"; + for (const auto& item : addr) + { + std::cout << item << "\n"; + } + std::cout << "\n"; + + jsoncons::json item = jp::get(j, addr); + std::cout << "(3) " << item << "\n"; +} + +void jsonpointer_address_iterator_example() +{ +<<<<<<< HEAD + jp::address addr("/store/book/1/author"); +======= + jp::address p("/store/book/1/author"); +>>>>>>> efc18942efb17086d3de2d1d853d56a11666ebb0 + + std::cout << "(1) " << addr << "\n\n"; + + std::cout << "(2)\n"; + for (const auto& token : addr) + { + std::cout << token << "\n"; + } + + std::cout << "\n"; +} + +void jsonpointer_address_append_tokens() +{ +<<<<<<< HEAD + jp::address addr; +======= + jp::address p; +>>>>>>> efc18942efb17086d3de2d1d853d56a11666ebb0 + + addr /= "a/b"; + addr /= ""; + addr /= "m~n"; + + std::cout << "(1) " << addr << "\n\n"; + + std::cout << "(2)\n"; + for (const auto& token : addr) + { + std::cout << token << "\n"; + } + + std::cout << "\n"; +} + +void jsonpointer_address_concatentae() +{ +<<<<<<< HEAD + jp::address addr("/a~1b"); + + addr += jp::address("//m~0n"); +======= + jp::address p("/a~1b"); + + p += jp::address("//m~0n"); +>>>>>>> efc18942efb17086d3de2d1d853d56a11666ebb0 + + std::cout << "(1) " << addr << "\n\n"; + + std::cout << "(2)\n"; + for (const auto& token : addr) + { + std::cout << token << "\n"; + } + + std::cout << "\n"; +} + +void jsonpointer_examples() +{ + std::cout << "\njsonpointer examples\n\n"; + jsonpointer_select_author(); + jsonpointer_address_example(); + jsonpointer_select_RFC6901(); + jsonpointer_add_member_to_object(); + jsonpointer_add_element_to_array(); + jsonpointer_add_element_to_end_array(); + jsonpointer_add_element_outside_range(); + jsonpointer_remove_object_member(); + jsonpointer_remove_array_element(); + jsonpointer_replace_object_value(); + jsonpointer_replace_array_value(); + jsonpointer_contains(); + jsonpointer_error_example(); + jsonpointer_insert_name_exists(); + jsonpointer_insert_or_assign_name_exists(); + jsonpointer_get_examples(); + jsonpointer_address_iterator_example(); + jsonpointer_address_append_tokens(); + jsonpointer_address_concatentae(); +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/msgpack_examples.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/msgpack_examples.cpp new file mode 100644 index 0000000000..4dcef22ee9 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/msgpack_examples.cpp @@ -0,0 +1,92 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include + +using namespace jsoncons; + +void message_pack_example1() +{ +ojson j1 = ojson::parse(R"( +[ + { "category": "reference", + "author": "Nigel Rees", + "title": "Sayings of the Century", + "price": 8.95 + }, + { "category": "fiction", + "author": "Evelyn Waugh", + "title": "Sword of Honour", + "price": 12.99 + } +] +)"); + + std::vector v; + msgpack::encode_msgpack(j1, v); + + ojson j2 = msgpack::decode_msgpack(v); + + std::cout << pretty_print(j2) << std::endl; + + json j3 = msgpack::decode_msgpack(v); + + std::cout << pretty_print(j3) << std::endl; + + std::cout << std::endl; + + //wjson j4 = msgpack::decode_msgpack(v); + + //std::wcout << pretty_print(j4) << std::endl; + + //std::cout << std::endl; +} + +void message_pack_example2() +{ + ojson j1; + j1["zero"] = 0; + j1["one"] = 1; + j1["two"] = 2; + j1["null"] = null_type(); + j1["true"] = true; + j1["false"] = false; + j1["max int64_t"] = (std::numeric_limits::max)(); + j1["max uint64_t"] = (std::numeric_limits::max)(); + j1["min int64_t"] = (std::numeric_limits::lowest)(); + j1["max int32_t"] = (std::numeric_limits::max)(); + j1["max uint32_t"] = (std::numeric_limits::max)(); + j1["min int32_t"] = (std::numeric_limits::lowest)(); + j1["max int16_t"] = (std::numeric_limits::max)(); + j1["max uint16_t"] = (std::numeric_limits::max)(); + j1["min int16_t"] = (std::numeric_limits::lowest)(); + j1["max int8_t"] = (std::numeric_limits::max)(); + j1["max uint8_t"] = (std::numeric_limits::max)(); + j1["min int8_t"] = (std::numeric_limits::lowest)(); + j1["max double"] = (std::numeric_limits::max)(); + j1["min double"] = (std::numeric_limits::lowest)(); + j1["max float"] = (std::numeric_limits::max)(); + j1["zero float"] = 0.0; + j1["min float"] = (std::numeric_limits::lowest)(); + j1["Key too long for small string optimization"] = "String too long for small string optimization"; + + std::vector v; + msgpack::encode_msgpack(j1, v); + + ojson j2 = msgpack::decode_msgpack(v); + + std::cout << pretty_print(j2) << std::endl; + + std::cout << std::endl; +} + +void msgpack_examples() +{ + std::cout << "\nmsgpack examples\n\n"; + message_pack_example1(); + message_pack_example2(); + std::cout << std::endl; +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/ojson_examples.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/ojson_examples.cpp new file mode 100644 index 0000000000..41650ce788 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/ojson_examples.cpp @@ -0,0 +1,45 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include + +using namespace jsoncons; + +void ojson_examples() +{ + std::cout << "\nojson examples\n\n"; + + ojson o = ojson::parse(R"( + { + "street_number" : "100", + "street_name" : "Queen St W", + "city" : "Toronto", + "country" : "Canada" + } + )"); + + std::cout << pretty_print(o) << std::endl; + + o.insert_or_assign("postal_code", "M5H 2N2"); + std::cout << pretty_print(o) << std::endl; + + ojson o2 = o; + + ojson o3 = o; + o3["street_name"] = "Queen St W"; + + auto it = o.find("country"); + o.insert_or_assign(it,"province","Ontario"); + + o.insert_or_assign("unit_type","O"); + + std::cout << pretty_print(o) << std::endl; + + o.erase("unit_type"); + + std::cout << pretty_print(o) << std::endl; + + std::cout << std::endl; +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/polymorphic_examples.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/polymorphic_examples.cpp new file mode 100644 index 0000000000..bdacfebb1a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/polymorphic_examples.cpp @@ -0,0 +1,181 @@ +// Copyright 2016 Daniel Parker +// Distributed under Boost license + +#include "example_types.hpp" +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +namespace ns { + +class Employee +{ + std::string firstName_; + std::string lastName_; +public: + Employee(const std::string& firstName, const std::string& lastName) + : firstName_(firstName), lastName_(lastName) + { + } + virtual ~Employee() = default; + + virtual double calculatePay() const = 0; + + const std::string& firstName() const {return firstName_;} + const std::string& lastName() const {return lastName_;} +}; + +class HourlyEmployee : public Employee +{ + double wage_; + unsigned hours_; +public: + HourlyEmployee(const std::string& firstName, const std::string& lastName, + double wage, unsigned hours) + : Employee(firstName, lastName), + wage_(wage), hours_(hours) + { + } + HourlyEmployee(const HourlyEmployee&) = default; + HourlyEmployee(HourlyEmployee&&) = default; + HourlyEmployee& operator=(const HourlyEmployee&) = default; + HourlyEmployee& operator=(HourlyEmployee&&) = default; + + double wage() const {return wage_;} + + unsigned hours() const {return hours_;} + + double calculatePay() const override + { + return wage_*hours_; + } +}; + +class CommissionedEmployee : public Employee +{ + double baseSalary_; + double commission_; + unsigned sales_; +public: + CommissionedEmployee(const std::string& firstName, const std::string& lastName, + double baseSalary, double commission, unsigned sales) + : Employee(firstName, lastName), + baseSalary_(baseSalary), commission_(commission), sales_(sales) + { + } + CommissionedEmployee(const CommissionedEmployee&) = default; + CommissionedEmployee(CommissionedEmployee&&) = default; + CommissionedEmployee& operator=(const CommissionedEmployee&) = default; + CommissionedEmployee& operator=(CommissionedEmployee&&) = default; + + double baseSalary() const + { + return baseSalary_; + } + + double commission() const + { + return commission_; + } + + unsigned sales() const + { + return sales_; + } + + double calculatePay() const override + { + return baseSalary_ + commission_*sales_; + } +}; +} // ns + +JSONCONS_GETTER_CTOR_TRAITS_DECL(ns::HourlyEmployee, firstName, lastName, wage, hours) +JSONCONS_GETTER_CTOR_TRAITS_DECL(ns::CommissionedEmployee, firstName, lastName, baseSalary, commission, sales) + +namespace jsoncons { + +template +struct json_type_traits> +{ + static bool is(const Json& j) noexcept + { + return j.is() || j.is(); + } + static std::shared_ptr as(const Json& j) + { + if (j.at("type").as() == "Hourly") + { + return std::make_shared(j.as()); + } + else if (j.at("type").as() == "Commissioned") + { + return std::make_shared(j.as()); + } + else + { + throw std::runtime_error("Not an employee"); + } + } + static Json to_json(const std::shared_ptr& ptr) + { + if (ns::HourlyEmployee* p = dynamic_cast(ptr.get())) + { + Json j(*p); + j.try_emplace("type","Hourly"); + return j; + } + else if (ns::CommissionedEmployee* p = dynamic_cast(ptr.get())) + { + Json j(*p); + j.try_emplace("type","Commissioned"); + return j; + } + else + { + throw std::runtime_error("Not an employee"); + } + } +}; + +} // jsoncons + +void employee_polymorphic_example() +{ + std::vector> v; + + v.push_back(std::make_shared("John", "Smith", 40.0, 1000)); + v.push_back(std::make_shared("Jane", "Doe", 30000, 0.25, 1000)); + + json j(v); + std::cout << pretty_print(j) << "\n\n"; + + assert(j[0].is()); + assert(!j[0].is()); + assert(!j[1].is()); + assert(j[1].is()); + + + for (size_t i = 0; i < j.size(); ++i) + { + auto p = j[i].as>(); + assert(p->firstName() == v[i]->firstName()); + assert(p->lastName() == v[i]->lastName()); + assert(p->calculatePay() == v[i]->calculatePay()); + } +} + +void polymorphic_examples() +{ + std::cout << "\nType extensibility examples\n\n"; + + employee_polymorphic_example(); + + std::cout << std::endl; +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/readme_examples.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/readme_examples.cpp new file mode 100644 index 0000000000..3725d6d757 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/readme_examples.cpp @@ -0,0 +1,154 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include + +namespace readme +{ + using namespace jsoncons; + + void playing_around() + { + // Construct some CBOR using the streaming API + std::vector b; + cbor::cbor_bytes_encoder encoder(b); + encoder.begin_array(); // indefinite length outer array + encoder.begin_array(3); // a fixed length array + encoder.string_value("foo"); + encoder.byte_string_value(byte_string{'P','u','s','s'}); // no suggested conversion + encoder.string_value("-18446744073709551617", semantic_tag::bigint); + encoder.end_array(); + encoder.end_array(); + encoder.flush(); + + // Print bytes + std::cout << "(1) "; + for (auto c : b) + { + std::cout << std::hex << std::setprecision(2) << std::setw(2) + << std::setfill('0') << static_cast(c); + } + std::cout << "\n\n"; +/* + 9f -- Start indefinte length array + 83 -- Array of length 3 + 63 -- String value of length 3 + 666f6f -- "foo" + 44 -- Byte string value of length 4 + 50757373 -- 'P''u''s''s' + c3 -- Tag 3 (negative bignum) + 49 -- Byte string value of length 9 + 010000000000000000 -- Bytes content + ff -- "break" +*/ + // Unpack bytes into a json variant value, and add some more elements + json j = cbor::decode_cbor(b); + + // Loop over the rows + std::cout << "(2)\n"; + for (const json& row : j.array_range()) + { + std::cout << row << "\n"; + } + std::cout << "\n"; + + // Get bignum value at position 0/2 using jsonpointer + json& v = jsonpointer::get(j, "/0/2"); + std::cout << "(3) " << v.as() << "\n\n"; + + // Print JSON representation with default options + std::cout << "(4)\n"; + std::cout << pretty_print(j) << "\n\n"; + + // Print JSON representation with different options + json_options options; + options.byte_string_format(byte_string_chars_format::base64) + .bigint_format(bigint_chars_format::base64url); + std::cout << "(5)\n"; + std::cout << pretty_print(j, options) << "\n\n"; + + // Add some more elements + + json another_array = json::array(); + another_array.emplace_back(byte_string({'P','u','s','s'}), + semantic_tag::base64); // suggested conversion to base64 + another_array.emplace_back("273.15", semantic_tag::bigdec); + another_array.emplace(another_array.array_range().begin(),"bar"); // place at front + + j.push_back(std::move(another_array)); + std::cout << "(6)\n"; + std::cout << pretty_print(j) << "\n\n"; + + // Get big decimal value at position /1/2 using jsonpointer + json& ref = jsonpointer::get(j, "/1/2"); + std::cout << "(7) " << ref.as() << "\n\n"; + +#if (defined(__GNUC__) || defined(__clang__)) && (!defined(__STRICT_ANSI__) && defined(_GLIBCXX_USE_INT128)) + // e.g. if code compiled with GCC and std=gnu++11 (rather than std=c++11) + __int128 i = j[1][2].as<__int128>(); +#endif + + // Get byte string value at position /1/1 as a byte_string + byte_string bs = j[1][1].as(); + std::cout << "(8) " << bs << "\n\n"; + + // or alternatively as a std::vector + std::vector u = j[1][1].as>(); + + // Repack bytes + std::vector b2; + cbor::encode_cbor(j, b2); + + // Print the repacked bytes + std::cout << "(9) "; + for (auto c : b2) + { + std::cout << std::hex << std::setprecision(2) << std::setw(2) + << std::setfill('0') << static_cast(c); + } + std::cout << "\n\n"; +/* + 82 -- Array of length 2 + 83 -- Array of length 3 + 63 -- String value of length 3 + 666f6f -- "foo" + 44 -- Byte string value of length 4 + 50757373 -- 'P''u''s''s' + c3 -- Tag 3 (negative bignum) + 49 -- Byte string value of length 9 + 010000000000000000 -- Bytes content + 83 -- Another array of length 3 + 63 -- String value of length 3 + 626172 -- "bar" + d6 - Expected conversion to base64 + 44 -- Byte string value of length 4 + 50757373 -- 'P''u''s''s' + c4 -- Tag 4 (decimal fraction) + 82 -- Array of length 2 + 21 -- -2 + 19 6ab3 -- 27315 +*/ + // Encode to CSV + csv::csv_options csv_options; + csv_options.column_names("Column 1,Column 2,Column 3"); + + std::cout << "(10)\n"; + csv::encode_csv(j, std::cout, csv_options); + } +} + +void readme_examples() +{ + std::cout << "\nReadme examples\n\n"; + + readme::playing_around(); + + std::cout << std::endl; +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/serialization_examples.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/serialization_examples.cpp new file mode 100644 index 0000000000..b7704a16c8 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/serialization_examples.cpp @@ -0,0 +1,461 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include + +using namespace jsoncons; + +void serialization_example1() +{ + json val = json::parse(R"( +{ + "sfm_data_version": "0.2", + "root_path": "D:\\Lagring\\Plugg\\Examensarbete\\Data\\images", + "views": [], + "intrinsics": [], + "extrinsics": [ + { + "key": 0, + "value": { + "rotation": [ + [ + 0.89280214808572156, + 0.35067276062587932, + -0.28272413998197254 + ], + [ + -0.090429686592667424, + 0.75440463553446824, + 0.65015084224113584 + ], + [ + 0.44127859245183554, + -0.5548894131618759, + 0.70524530697098287 + ] + ], + "center": [ + -0.60959634064871249, + 0.24123645392011658, + 0.57783384588917808 + ] + } + } + ] +} + +)"); + + std::cout << "Default pretty print" << std::endl; + std::cout << pretty_print(val) << std::endl; + + + std::cout << "array_array_line_splits(line_split_kind::new_line)" << std::endl; + std::cout << "array_object_line_splits(line_split_kind::new_line)" << std::endl; + + json_options options; + + options.array_array_line_splits(line_split_kind::new_line) + .array_object_line_splits(line_split_kind::new_line); + std::cout << pretty_print(val,options) << std::endl; +} + +void serialization_example2() +{ + + json val; + + val["verts"] = json::array{1, 2, 3}; + val["normals"] = json::array{1, 0, 1}; + val["uvs"] = json::array{0, 0, 1, 1}; + + std::cout << "Default object-array same line options" << std::endl; + std::cout << pretty_print(val) << std::endl; + + std::cout << "object_array_line_splits(line_split_kind::same_line)" << std::endl; + json_options options1; + options1.object_array_line_splits(line_split_kind::same_line); + std::cout << pretty_print(val,options1) << std::endl; + + std::cout << "object_array_line_splits(line_split_kind::new_line)" << std::endl; + json_options options2; + options2 .object_array_line_splits(line_split_kind::new_line); + std::cout << pretty_print(val,options2 ) << std::endl; + + std::cout << "object_array_line_splits(line_split_kind::multi_line)" << std::endl; + json_options options3; + options3.object_array_line_splits(line_split_kind::multi_line); + std::cout << pretty_print(val,options3) << std::endl; +} + +void serialization_example3() +{ + { + json val = json::parse(R"( + [ + {"first-name" : "John", + "last-name" : "Doe"}, + {"first-name" : "Jane", + "last-name" : "Doe"} + ] + )"); + + json_options options; + options.array_object_line_splits(line_split_kind::same_line); + std::cout << "array_object_line_splits(line_split_kind::same_line)" << std::endl; + std::cout << pretty_print(val,options) << std::endl; + } + + { + json val = json::parse(R"({ + "verts" : [1, 2, 3], + + "normals" : [1, 0, 1], + + "uvs" : [ 0, 0, 1, 1 ] + } + )"); + std::cout << "Default print" << std::endl; + std::cout << print(val) << std::endl; + + std::cout << "Default pretty print" << std::endl; + std::cout << pretty_print(val) << std::endl; + + json_options options1; + options1.array_array_line_splits(line_split_kind::same_line); + std::cout << pretty_print(val,options1) << std::endl; + + json_options options; + options.object_object_line_splits(line_split_kind::new_line); + std::cout << pretty_print(val,options) << std::endl; + } + + { + json val2 = json::parse(R"( + { + "data": + { + "item": [[2],[4,5,2,3],[4],[4,5,2,3],[2],[4,5,3],[2],[4,3]], //A two-dimensional array + //blank line + "id": [0,1,2,3,4,5,6,7] //A one-dimensional array + } + } + )"); + + std::cout << "Default" << std::endl; + std::cout << pretty_print(val2) << std::endl; + + std::cout << "array_array_line_splits(line_split_kind::new_line)" << std::endl; + json_options options2; + options2 .array_array_line_splits(line_split_kind::new_line); + std::cout << pretty_print(val2,options2 ) << std::endl; + + std::cout << "array_array_line_splits(line_split_kind::same_line)" << std::endl; + json_options options4; + options4.array_array_line_splits(line_split_kind::same_line); + std::cout << pretty_print(val2, options4) << std::endl; + + std::cout << "array_array_line_splits(line_split_kind::same_line)" << std::endl; + json_options options5; + options5.array_array_line_splits(line_split_kind::same_line); + std::cout << pretty_print(val2, options5) << std::endl; + } + + json val3 = json::parse(R"( + { + "data": + { + "item": [[2]] //A two-dimensional array + } + } +)"); + std::cout << "array_array_line_splits(line_split_kind::new_line)" << std::endl; + json_options options6; + options6.array_array_line_splits(line_split_kind::new_line); + std::cout << pretty_print(val3,options6) << std::endl; +} + +void serialization_example4() +{ + json val; + val["data"]["id"] = json::array{0,1,2,3,4,5,6,7}; + val["data"]["item"] = json::array{json::array{2}, + json::array{4,5,2,3}, + json::array{4}, + json::array{4,5,2,3}, + json::array{2}, + json::array{4,5,3}, + json::array{2}, + json::array{4,3}}; + + std::cout << "Default array-array split line options" << std::endl; + std::cout << pretty_print(val) << std::endl; + + std::cout << "Array-array same line options" << std::endl; + json_options options1; + options1.array_array_line_splits(line_split_kind::same_line); + std::cout << pretty_print(val, options1) << std::endl; + + std::cout << "object_array_line_splits(line_split_kind::new_line)" << std::endl; + std::cout << "array_array_line_splits(line_split_kind::same_line)" << std::endl; + json_options options2; + options2 .object_array_line_splits(line_split_kind::new_line) + .array_array_line_splits(line_split_kind::same_line); + std::cout << pretty_print(val, options2 ) << std::endl; + + std::cout << "object_array_line_splits(line_split_kind::new_line)" << std::endl; + std::cout << "array_array_line_splits(line_split_kind::multi_line)" << std::endl; + json_options options3; + options3.object_array_line_splits(line_split_kind::new_line) + .array_array_line_splits(line_split_kind::multi_line); + std::cout << pretty_print(val, options3) << std::endl; + + { + json val = json::parse(R"( + { + "header" : {"properties": {}}, + "data": + { + "tags" : [], + "id" : [1,2,3], + "item": [[1,2,3]] + } + } + )"); + std::cout << "Default" << std::endl; + std::cout << pretty_print(val) << std::endl; + + std::string style1 = "array_array_line_splits(line_split_kind:same_line)"; + std::cout << style1 << std::endl; + json_options options1; + options1.array_array_line_splits(line_split_kind::same_line); + std::cout << pretty_print(val,options1) << std::endl; + + std::string style2 = "array_array_line_splits(line_split_kind::new_line)"; + std::cout << style2 << std::endl; + json_options options2; + options2 .array_array_line_splits(line_split_kind::new_line); + std::cout << pretty_print(val,options2 ) << std::endl; + + std::string style3 = "array_array_line_splits(line_split_kind::multi_line)"; + std::cout << style3 << std::endl; + json_options options3; + options3.array_array_line_splits(line_split_kind::multi_line); + std::cout << pretty_print(val,options3) << std::endl; + + std::string style4 = "object_array_line_splits(line_split_kind:same_line)"; + std::cout << style4 << std::endl; + json_options options4; + options4.object_array_line_splits(line_split_kind::same_line); + std::cout << pretty_print(val,options4) << std::endl; + + std::string style5 = "object_array_line_splits(line_split_kind::new_line)"; + std::cout << style5 << std::endl; + json_options options5; + options5.object_array_line_splits(line_split_kind::new_line); + std::cout << pretty_print(val,options5) << std::endl; + + std::string style6 = "object_array_line_splits(line_split_kind::multi_line)"; + std::cout << style6 << std::endl; + json_options options6; + options6.object_array_line_splits(line_split_kind::multi_line); + std::cout << pretty_print(val,options6) << std::endl; + } +} + +void dump_json_fragments() +{ + const json some_books = json::parse(R"( + [ + { + "title" : "Kafka on the Shore", + "author" : "Haruki Murakami", + "price" : 25.17 + }, + { + "title" : "Women: A Novel", + "author" : "Charles Bukowski", + "price" : 12.00 + } + ] + )"); + + const json more_books = json::parse(R"( + [ + { + "title" : "A Wild Sheep Chase: A Novel", + "author" : "Haruki Murakami", + "price" : 9.01 + }, + { + "title" : "Cutter's Way", + "author" : "Ivan Passer", + "price" : 8.00 + } + ] + )"); + + json_encoder encoder(std::cout); // pretty print + encoder.begin_array(); + for (const auto& book : some_books.array_range()) + { + book.dump(encoder); + } + for (const auto& book : more_books.array_range()) + { + book.dump(encoder); + } + encoder.end_array(); + encoder.flush(); +} + +void nan_inf_replacement() +{ + json j; + j["field1"] = std::sqrt(-1.0); + j["field2"] = 1.79e308 * 1000; + j["field3"] = -1.79e308 * 1000; + + json_options options; + options.nan_to_str("NaN") + .inf_to_str("Inf"); + + std::ostringstream os; + os << pretty_print(j, options); + + std::cout << "(1)\n" << os.str() << std::endl; + + json j2 = json::parse(os.str(),options); + + std::cout << "\n(2) " << j2["field1"].as() << std::endl; + std::cout << "(3) " << j2["field2"].as() << std::endl; + std::cout << "(4) " << j2["field3"].as() << std::endl; + + std::cout << "\n(5)\n" << pretty_print(j2,options) << std::endl; +} + +void bignum_serialization_examples1() +{ + std::string s = "-18446744073709551617"; + + json j(bignum(s.c_str())); + + std::cout << "(default) "; + j.dump(std::cout); + std::cout << "\n\n"; + + std::cout << "(integer) "; + json_options options1; + options1.bigint_format(bigint_chars_format::number); + j.dump(std::cout, options1); + std::cout << "\n\n"; + + std::cout << "(base64) "; + json_options options3; + options3.bigint_format(bigint_chars_format::base64); + j.dump(std::cout, options3); + std::cout << "\n\n"; + + std::cout << "(base64url) "; + json_options options4; + options4.bigint_format(bigint_chars_format::base64url); + j.dump(std::cout, options4); + std::cout << "\n\n"; +} + +void bignum_serialization_examples2() +{ + std::string s = "-18446744073709551617"; + + json j = json::parse(s); + + std::cout << "(1) "; + j.dump(std::cout); + std::cout << "\n\n"; + + std::cout << "(2) "; + json_options options1; + options1.bigint_format(bigint_chars_format::number); + j.dump(std::cout, options1); + std::cout << "\n\n"; + + std::cout << "(3) "; + json_options options2; + options2.bigint_format(bigint_chars_format::base64url); + j.dump(std::cout, options2); + std::cout << "\n\n"; +} + +void bignum_access_examples() +{ + std::string input = "-18446744073709551617"; + + json j = json::parse(input); + + // Access as string + std::string s = j.as(); + std::cout << "(1) " << s << "\n\n"; + + // Access as double + double d = j.as(); + std::cout << "(2) " << std::setprecision(17) << d << "\n\n"; + + // Access as jsoncons::bignum + jsoncons::bignum bn = j.as(); + std::cout << "(3) " << bn << "\n\n"; + + // If your compiler supports extended integral types for which std::numeric_limits is specialized +#if (defined(__GNUC__) || defined(__clang__)) && (!defined(__STRICT_ANSI__) && defined(_GLIBCXX_USE_INT128)) + __int128 i = j.as<__int128>(); + std::cout << "(4) " << i << "\n\n"; +#endif +} + +void decimal_precision_examples() +{ + std::string s = R"( + { + "a" : 12.00, + "b" : 1.23456789012345678901234567890 + } + )"; + + // Default + json j = json::parse(s); + + std::cout.precision(15); + + // Access as string + std::cout << "(1) a: " << j["a"].as() << ", b: " << j["b"].as() << "\n"; + // Access as double + std::cout << "(2) a: " << j["a"].as() << ", b: " << j["b"].as() << "\n\n"; + + // Using lossless_number option + json_options options; + options.lossless_number(true); + + json j2 = json::parse(s, options); + // Access as string + std::cout << "(3) a: " << j2["a"].as() << ", b: " << j2["b"].as() << "\n"; + // Access as double + std::cout << "(4) a: " << j2["a"].as() << ", b: " << j2["b"].as() << "\n\n"; +} + +void serialization_examples() +{ + std::cout << "\nSerialization examples\n\n"; + serialization_example1(); + serialization_example2(); + serialization_example3(); + serialization_example4(); + dump_json_fragments(); + nan_inf_replacement(); + bignum_serialization_examples2(); + bignum_serialization_examples1(); + decimal_precision_examples(); + bignum_access_examples(); + std::cout << std::endl; +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/staj_iterator_examples.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/staj_iterator_examples.cpp new file mode 100644 index 0000000000..23fcd6f995 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/staj_iterator_examples.cpp @@ -0,0 +1,135 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include + +using namespace jsoncons; + +// Example JSON text +const std::string array_example = R"( +[ + { + "employeeNo" : "101", + "name" : "Tommy Cochrane", + "title" : "Supervisor" + }, + { + "employeeNo" : "102", + "name" : "Bill Skeleton", + "title" : "Line manager" + } +] +)"; + +const std::string object_example = R"( +{ + "application": "hiking", + "reputons": [ + { + "rater": "HikingAsylum.array_example.com", + "assertion": "strong-hiker", + "rated": "Marilyn C", + "rating": 0.90 + } + ] +} +)"; + +void staj_array_iterator_example() +{ + std::istringstream is(array_example); + + json_cursor reader(is); + + staj_array_iterator it(reader); + + for (const auto& j : it) + { + std::cout << pretty_print(j) << "\n"; + } + std::cout << "\n\n"; +} + +struct employee +{ + std::string employeeNo; + std::string name; + std::string title; +}; + +namespace jsoncons +{ + template + struct json_type_traits + { + static bool is(const Json& j) noexcept + { + return j.is_object() && j.contains("employeeNo") && j.contains("name") && j.contains("title"); + } + static employee as(const Json& j) + { + employee val; + val.employeeNo = j["employeeNo"].template as(); + val.name = j["name"].template as(); + val.title = j["title"].template as(); + return val; + } + static Json to_json(const employee& val) + { + Json j; + j["employeeNo"] = val.employeeNo; + j["name"] = val.name; + j["title"] = val.title; + return j; + } + }; +} + +void staj_array_iterator_example2() +{ + std::istringstream is(array_example); + + json_cursor reader(is); + + staj_array_iterator it(reader); + + for (const auto& val : it) + { + std::cout << val.employeeNo << ", " << val.name << ", " << val.title << "\n"; + } + std::cout << "\n\n"; +} + +void staj_object_iterator_example() +{ + + std::istringstream is(object_example); + + json_cursor reader(is); + + staj_object_iterator it(reader); + + for (const auto& kv : it) + { + std::cout << kv.first << ":\n" << pretty_print(kv.second) << "\n"; + } + std::cout << "\n\n"; +} + +void staj_iterator_examples() +{ + std::cout << "\nstaj_iterator examples\n\n"; + + staj_array_iterator_example(); + + staj_array_iterator_example2(); + + staj_object_iterator_example(); + + std::cout << "\n"; +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/type_extensibility_examples.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/type_extensibility_examples.cpp new file mode 100644 index 0000000000..35fa87eb10 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/type_extensibility_examples.cpp @@ -0,0 +1,162 @@ +// Copyright 2016 Daniel Parker +// Distributed under Boost license + +#include "example_types.hpp" +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +void book_extensibility_example() +{ + using jsoncons::json; + + ns::book book1{"Haruki Murakami", "Kafka on the Shore", 25.17}; + + json j = book1; + + std::cout << "(1) " << std::boolalpha << j.is() << "\n\n"; + + std::cout << "(2) " << pretty_print(j) << "\n\n"; + + ns::book temp = j.as(); + std::cout << "(3) " << temp.author << "," + << temp.title << "," + << temp.price << "\n\n"; + + ns::book book2{"Charles Bukowski", "Women: A Novel", 12.0}; + + std::vector book_array{book1, book2}; + + json ja = book_array; + + std::cout << "(4) " << std::boolalpha + << ja.is>() << "\n\n"; + + std::cout << "(5)\n" << pretty_print(ja) << "\n\n"; + + auto book_list = ja.as>(); + + std::cout << "(6)" << std::endl; + for (auto b : book_list) + { + std::cout << b.author << ", " + << b.title << ", " + << b.price << std::endl; + } +} + +void book_extensibility_example2() +{ + const std::string s = R"( + [ + { + "author" : "Haruki Murakami", + "title" : "Kafka on the Shore", + "price" : 25.17 + }, + { + "author" : "Charles Bukowski", + "title" : "Pulp", + "price" : 22.48 + } + ] + )"; + + std::vector book_list = decode_json>(s); + + std::cout << "(1)\n"; + for (const auto& item : book_list) + { + std::cout << item.author << ", " + << item.title << ", " + << item.price << "\n"; + } + + std::cout << "\n(2)\n"; + encode_json(book_list, std::cout, indenting::indent); + std::cout << "\n\n"; +} + +void reputons_extensibility_example() +{ + ns::reputation_object val("hiking", { ns::reputon{"HikingAsylum.example.com","strong-hiker","Marilyn C",0.90} }); + + std::string s; + encode_json(val, s, indenting::indent); + std::cout << s << "\n"; + + auto val2 = decode_json(s); + + assert(val2 == val); +} + +//own vector will always be of an even length +struct own_vector : std::vector { using std::vector::vector; }; + +namespace jsoncons { + +template +struct json_type_traits +{ + static bool is(const Json& j) noexcept + { + return j.is_object() && j.size() % 2 == 0; + } + static own_vector as(const Json& j) + { + own_vector v; + for (auto& item : j.object_range()) + { + std::string s(item.key()); + v.push_back(std::strtol(s.c_str(),nullptr,10)); + v.push_back(item.value().template as()); + } + return v; + } + static Json to_json(const own_vector& val){ + Json j; + for(size_t i=0;i +struct is_json_type_traits_declared : public std::true_type +{}; +} // jsoncons + +void own_vector_extensibility_example() +{ + using jsoncons::json; + + json j = json::object{ {"1",2},{"3",4} }; + assert(j.is()); + auto v = j.as(); + json j2 = v; + + std::cout << j2 << "\n"; +} + +void type_extensibility_examples() +{ + std::cout << std::setprecision(6); + + std::cout << "\nType extensibility examples\n\n"; + + book_extensibility_example(); + + own_vector_extensibility_example(); + + book_extensibility_example2(); + + reputons_extensibility_example(); + + std::cout << std::endl; +} diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/type_extensibility_examples2.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/type_extensibility_examples2.cpp new file mode 100644 index 0000000000..c77fa236c3 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/type_extensibility_examples2.cpp @@ -0,0 +1,134 @@ +// Copyright 2017 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include + +using namespace jsoncons; +using namespace jsoncons::literals; + +class Employee +{ + std::string name_; +public: + Employee(const std::string& name) + : name_(name) + { + } + virtual ~Employee() = default; + const std::string& name() const + { + return name_; + } + virtual double calculatePay() const = 0; +}; + +class HourlyEmployee : public Employee +{ +public: + HourlyEmployee(const std::string& name) + : Employee(name) + { + } + double calculatePay() const override + { + return 10000; + } +}; + +class CommissionedEmployee : public Employee +{ +public: + CommissionedEmployee(const std::string& name) + : Employee(name) + { + } + double calculatePay() const override + { + return 20000; + } +}; + +class EmployeeRegistry +{ + typedef std::unordered_map> employee_map; + employee_map employees_; +public: + EmployeeRegistry() + { + employees_.try_emplace("John Smith",std::make_shared("John Smith")); + employees_.try_emplace("Jane Doe",std::make_shared("Jane Doe")); + } + + bool contains(const std::string& name) const + { + return employees_.count(name) > 0; + } + + std::shared_ptr get(const std::string& name) const + { + auto it = employees_.find(name); + if (it == employees_.end()) + { + throw std::runtime_error("Employee not found"); + } + return it->second; + } +}; + +namespace jsoncons +{ + template + struct json_type_traits> + { + static bool is(const Json& j, const EmployeeRegistry& registry) noexcept + { + return j.is_string() && registry.contains(j.as()); + } + static std::shared_ptr as(const Json& j, + const EmployeeRegistry& registry) + { + return registry.get(j.as()); + } + static Json to_json(std::shared_ptr val) + { + Json j(val->name()); + return j; + } + }; +}; + +void type_extensibility_examples2() +{ + std::cout << "\nType extensibility examples 2\n\n"; + + json j = R"( + { + "EmployeeName" : "John Smith" + } + )"_json; + + EmployeeRegistry registry; + + std::shared_ptr employee = j["EmployeeName"].as>(registry); + + std::cout << "(1) " << employee->name() << " => " + << employee->calculatePay() << std::endl; + + // j does not have a key "SalesRep", so get_with_default returns "Jane Doe" + // The template parameter is explicitly specified as json, to return a json string + // json::as is then applied to the returned json string + std::shared_ptr salesRep = j.get_with_default("SalesRep","Jane Doe") + .as>(registry); + + std::cout << "(2) " << salesRep->name() << " => " + << salesRep->calculatePay() << std::endl; + + json j2; + j2["EmployeeName"] = employee; + j2["SalesRep"] = salesRep; + + std::cout << "(3)\n" << pretty_print(j2) << std::endl; +} diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/ubjson_examples.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/ubjson_examples.cpp new file mode 100644 index 0000000000..fbbbc5081d --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/ubjson_examples.cpp @@ -0,0 +1,84 @@ +// Copyright 2017 Daniel Parker +// Distributed under Boost license + +#include "example_types.hpp" +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +void to_from_ubjson_using_basic_json() +{ + ojson j1 = ojson::parse(R"( + { + "application": "hiking", + "reputons": [ + { + "rater": "HikingAsylum.example.com", + "assertion": "strong-hiker", + "rated": "Marilyn C", + "rating": 0.90 + } + ] + } + )"); + + // Encode a basic_json value to UBJSON + std::vector data; + ubjson::encode_ubjson(j1, data); + + // Decode UBJSON to a basic_json value + ojson j2 = ubjson::decode_ubjson(data); + std::cout << "(1)\n" << pretty_print(j2) << "\n\n"; + + // Accessing the data items + + const ojson& reputons = j2["reputons"]; + + std::cout << "(2)\n"; + for (auto element : reputons.array_range()) + { + std::cout << element.at("rated").as() << ", "; + std::cout << element.at("rating").as() << "\n"; + } + std::cout << std::endl; + + // Get a UBJSON value for a nested data item with jsonpointer + std::error_code ec; + auto const& rated = jsonpointer::get(j2, "/reputons/0/rated", ec); + if (!ec) + { + std::cout << "(3) " << rated.as_string() << "\n"; + } + + std::cout << std::endl; +} + +void to_from_ubjson_using_example_type() +{ + ns::reputation_object val("hiking", { ns::reputon{"HikingAsylum.example.com","strong-hiker","Marilyn C",0.90} }); + + // Encode a ns::reputation_object value to UBJSON + std::vector data; + ubjson::encode_ubjson(val, data); + + // Decode UBJSON to a ns::reputation_object value + ns::reputation_object val2 = ubjson::decode_ubjson(data); + + assert(val2 == val); +} + +void ubjson_examples() +{ + std::cout << "\nubjson examples\n\n"; + to_from_ubjson_using_basic_json(); + to_from_ubjson_using_example_type(); + + std::cout << std::endl; +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/unicode_examples.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/unicode_examples.cpp new file mode 100644 index 0000000000..f3000ffb25 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/unicode_examples.cpp @@ -0,0 +1,32 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include + +using namespace jsoncons; + +void read_and_write_escaped_unicode() +{ + std::string input = "[\"\\u8A73\\u7D30\\u95B2\\u89A7\\uD800\\uDC01\\u4E00\"]"; + json value = json::parse(input); + json_options options; + options.escape_all_non_ascii(true); + std::string output; + value.dump(output,options); + + std::cout << "Input:" << std::endl; + std::cout << input << std::endl; + std::cout << std::endl; + std::cout << "Output:" << std::endl; + std::cout << output << std::endl; +} + +void unicode_examples() +{ + std::cout << "\nUnicode examples\n\n"; + read_and_write_escaped_unicode(); + std::cout << std::endl; +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/wjson_examples.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/wjson_examples.cpp new file mode 100644 index 0000000000..8c75577cfb --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples/src/wjson_examples.cpp @@ -0,0 +1,85 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#ifdef _MSC_VER +#include +#endif +#include +#include +#include + +using namespace jsoncons; + +void wjson_object() +{ + wjson root; + root[L"field1"] = L"test"; + root[L"field2"] = 3.9; + root[L"field3"] = true; + std::wcout << root << L"\n"; +} + +void wjson_escape_u2() +{ +#ifdef _MSC_VER + std::wstring input = L"[\"\\u007F\\u07FF\\u0800\"]"; + std::wistringstream is(input); + + wjson val = wjson::parse(is); + + std::wstring s = val[0].as(); + std::cout << "length=" << s.length() << std::endl; + std::cout << "Hex dump: ["; + for (size_t i = 0; i < s.size(); ++i) + { + if (i != 0) + std::cout << " "; + uint32_t u(s[i] >= 0 ? s[i] : 256 + s[i] ); + std::cout << "0x" << std::hex<< std::setfill('0') << std::setw(2) << u; + } + std::cout << "]" << std::endl; + + std::wofstream os("./output/xxx.txt"); + os.imbue(std::locale(os.getloc(), new std::codecvt_utf8_utf16)); + + wjson_options options; + options.escape_all_non_ascii(true); + + os << pretty_print(val,options) << L"\n"; +#endif +} + +void wjson_surrogate_pair() +{ +#ifdef _MSC_VER + std::wstring input = L"[\"\\uD950\\uDF21\"]"; + std::wistringstream is(input); + + wjson val = wjson::parse(is); + + std::wstring s = val[0].as(); + std::cout << "length=" << s.length() << std::endl; + std::cout << "Hex dump: ["; + for (size_t i = 0; i < s.size(); ++i) + { + if (i != 0) + std::cout << " "; + uint32_t u(s[i] >= 0 ? s[i] : 256 + s[i] ); + std::cout << "0x" << std::hex<< std::setfill('0') << std::setw(2) << u; + } + std::cout << "]" << std::endl; +#endif +} + +void wjson_examples() +{ + std::cout << "\nwjson examples\n\n"; + wjson_object(); + wjson_escape_u2(); + wjson_surrogate_pair(); + std::cout << std::endl; +} + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples_boost/interprocess_allocator/shared_memory.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples_boost/interprocess_allocator/shared_memory.cpp new file mode 100644 index 0000000000..d053d6854d --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples_boost/interprocess_allocator/shared_memory.cpp @@ -0,0 +1,107 @@ +#include +#include +#include +#include +#include //std::system +#include + +using namespace jsoncons; + +typedef boost::interprocess::allocator shmem_allocator; + +struct boost_sorted_policy : public sorted_policy +{ + template + using sequence_container_type = boost::interprocess::vector; + + template + using key_storage = boost::interprocess::basic_string; + + template + using string_storage = boost::interprocess::basic_string; +}; + +typedef basic_json shm_json; + +int main(int argc, char *argv[]) +{ + typedef std::pair MyType; + + if(argc == 1){ //Parent process + //Remove shared memory on construction and destruction + struct shm_remove + { + shm_remove() { boost::interprocess::shared_memory_object::remove("MySharedMemory"); } + ~shm_remove(){ boost::interprocess::shared_memory_object::remove("MySharedMemory"); } + } remover; + + //Construct managed shared memory + boost::interprocess::managed_shared_memory segment(boost::interprocess::create_only, + "MySharedMemory", 65536); + + //Initialize shared memory STL-compatible allocator + const shmem_allocator allocator(segment.get_segment_manager()); + + // Create json value with all dynamic allocations in shared memory + + shm_json* j = segment.construct("my json")(shm_json::array(allocator)); + j->push_back(10); + + shm_json o(allocator); + //o.try_emplace("category", "reference",allocator); + //o.try_emplace("author", "Nigel Rees",allocator); + //o.try_emplace("title", "Sayings of the Century",allocator); + //o.try_emplace("price", 8.95, allocator); + o.insert_or_assign("category", "reference"); + o.insert_or_assign("author", "Nigel Rees"); + o.insert_or_assign("title", "Sayings of the Century"); + o.insert_or_assign("price", 8.95); + + j->push_back(o); + + shm_json a = shm_json::array(2,shm_json::object(allocator),allocator); + a[0]["first"] = 1; + + j->push_back(a); + + std::pair res; + res = segment.find("my json"); + + std::cout << "Parent:" << std::endl; + std::cout << pretty_print(*(res.first)) << std::endl; + + //Launch child process + std::string s(argv[0]); s += " child "; + if(0 != std::system(s.c_str())) + return 1; + + + //Check child has destroyed all objects + if(segment.find("my json").first) + return 1; + } + else{ + //Open managed shared memory + boost::interprocess::managed_shared_memory segment(boost::interprocess::open_only, + "MySharedMemory"); + + std::pair res; + res = segment.find("my json"); + + if (res.first != nullptr) + { + std::cout << "Child:" << std::endl; + std::cout << pretty_print(*(res.first)) << std::endl; + } + else + { + std::cout << "Result is null" << std::endl; + } + + //We're done, delete all the objects + segment.destroy("my json"); + } + return 0; +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples_boost/more_examples/src/extensibility.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples_boost/more_examples/src/extensibility.cpp new file mode 100644 index 0000000000..1275c350bf --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples_boost/more_examples/src/extensibility.cpp @@ -0,0 +1,240 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace jsoncons +{ + template + struct json_type_traits + { + static bool is(const Json& val) noexcept + { + if (!val.is_string()) + { + return false; + } + std::string s = val.template as(); + try + { + boost::gregorian::from_simple_string(s); + return true; + } + catch (...) + { + return false; + } + } + + static boost::gregorian::date as(const Json& val) + { + std::string s = val.template as(); + return boost::gregorian::from_simple_string(s); + } + + static Json to_json(boost::gregorian::date val) + { + return Json(to_iso_extended_string(val)); + } + }; + + template + struct json_type_traits> + { + typedef boost::multiprecision::number multiprecision_type; + + static bool is(const Json& val) noexcept + { + if (!(val.is_string() && val.get_semantic_tag() == semantic_tag::bigdec)) + { + return false; + } + else + { + return true; + } + } + + static multiprecision_type as(const Json& val) + { + return multiprecision_type(val.template as()); + } + + static Json to_json(multiprecision_type val) + { + return Json(val.str(), semantic_tag::bigdec); + } + }; + + template + struct json_type_traits> + { + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& val) noexcept + { + if (!val.is_array()) + { + return false; + } + if (val.size() > 0) + { + size_t n = val[0].size(); + for (const auto& a: val.array_range()) + { + if (!(a.is_array() && a.size() == n)) + { + return false; + } + for (auto x: a.array_range()) + { + if (!x.template is()) + { + return false; + } + } + } + } + return true; + } + + static boost::numeric::ublas::matrix as(const Json& val) + { + if (val.is_array() && val.size() > 0) + { + size_t m = val.size(); + size_t n = 0; + for (const auto& a : val.array_range()) + { + if (a.size() > n) + { + n = a.size(); + } + } + + boost::numeric::ublas::matrix A(m,n,T()); + for (size_t i = 0; i < m; ++i) + { + const auto& a = val[i]; + for (size_t j = 0; j < a.size(); ++j) + { + A(i,j) = a[j].template as(); + } + } + return A; + } + else + { + boost::numeric::ublas::matrix A; + return A; + } + } + + static Json to_json(const boost::numeric::ublas::matrix& val, + allocator_type allocator = allocator_type()) + { + Json a = Json::template make_array<2>(val.size1(), val.size2(), T()); + for (size_t i = 0; i < val.size1(); ++i) + { + for (size_t j = 0; j < val.size1(); ++j) + { + a[i][j] = val(i,j); + } + } + return a; + } + }; +} + +using namespace jsoncons; +using boost::numeric::ublas::matrix; + +void boost_date_conversions() +{ + using boost::gregorian::date; + + json deal; + deal["maturity"] = date(2014,10,14); + + json observation_dates = json::array(); + observation_dates.push_back(date(2014,2,14)); + observation_dates.push_back(date(2014,2,21)); + + deal["observationDates"] = std::move(observation_dates); + + date maturity = deal["maturity"].as(); + + assert(deal["maturity"].as() == date(2014,10,14)); + assert(deal["observationDates"].is_array()); + assert(deal["observationDates"].size() == 2); + assert(deal["observationDates"][0].as() == date(2014,2,14)); + assert(deal["observationDates"][1].as() == date(2014,2,21)); + + std::cout << pretty_print(deal) << std::endl; +} + +void boost_matrix_conversions() +{ + matrix A(2, 2); + A(0, 0) = 1.1; + A(0, 1) = 2.1; + A(1, 0) = 3.1; + A(1, 1) = 4.1; + + json a = A; + + assert(a.is>()); + assert(!a.is>()); + + assert(a[0][0].as()==A(0,0)); + assert(a[0][1].as()==A(0,1)); + assert(a[1][0].as()==A(1,0)); + assert(a[1][1].as()==A(1,1)); + + matrix B = a.as>(); + + assert(B.size1() ==a.size()); + assert(B.size2() ==a[0].size()); + + assert(a[0][0].as()==B(0,0)); + assert(a[0][1].as()==B(0,1)); + assert(a[1][0].as()==B(1,0)); + assert(a[1][1].as()==B(1,1)); +} + + +void boost_multiprecison_conversions() +{ + typedef boost::multiprecision::number multiprecision_type; + + std::string s = "[100000000000000000000000000000000.1234]"; + json_options options; + options.lossless_number(true); + json j = json::parse(s, options); + + multiprecision_type x = j[0].as(); + + std::cout << "(1) " << std::setprecision(std::numeric_limits::max_digits10) + << x << "\n"; + + json j2 = json::array{x}; + std::cout << "(2) " << j2[0].as() << "\n"; +} + +void extensibility_examples() +{ + std::cout << "extensibility examples\n\n"; + + boost_date_conversions(); + boost_matrix_conversions(); + boost_multiprecison_conversions(); +} diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples_boost/more_examples/src/more_examples.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples_boost/more_examples/src/more_examples.cpp new file mode 100644 index 0000000000..247a2c9446 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples_boost/more_examples/src/more_examples.cpp @@ -0,0 +1,22 @@ +// Copyright 2018 Daniel Parker +// Distributed under Boost license + +#include + +void extensibility_examples(); +void pool_allocator_examples(); + +int main() +{ + try + { + extensibility_examples(); + pool_allocator_examples(); + } + catch (const std::exception& e) + { + std::cout << e.what() << std::endl; + } + + return 0; +} diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/examples_boost/more_examples/src/pool_allocator.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples_boost/more_examples/src/pool_allocator.cpp new file mode 100644 index 0000000000..460640b201 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/examples_boost/more_examples/src/pool_allocator.cpp @@ -0,0 +1,33 @@ +// Copyright 2018 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +typedef basic_json> my_json; + +void pool_allocator_examples() +{ + std::cout << "pool_allocator examples\n\n"; + + jsoncons::json_decoder> decoder; + + static std::string s("[1,2,3,4,5,6]"); + std::istringstream is(s); + + basic_json_reader,boost::pool_allocator> reader(is,decoder); + reader.read(); + + my_json j = decoder.get_result(); + + std::cout << j << std::endl; +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/basic_json.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/basic_json.hpp new file mode 100644 index 0000000000..76e58e278f --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/basic_json.hpp @@ -0,0 +1,4984 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_BASIC_JSON_HPP +#define JSONCONS_BASIC_JSON_HPP + +#include // std::numeric_limits +#include +#include +#include +#include +#include +#include // std::allocator +#include +#include // std::memcpy +#include // std::swap +#include // std::initializer_list +#include // std::move +#include // std::enable_if +#include // std::basic_istream +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace jsoncons { + +struct sorted_policy +{ + static constexpr bool preserve_order = false; + + template + using sequence_container_type = std::vector; + + template + using key_storage = std::basic_string; + + template + using string_storage = std::basic_string; + + typedef default_parse_error_handler parse_error_handler_type; +}; + +struct preserve_order_policy : public sorted_policy +{ + static constexpr bool preserve_order = true; +}; + +template +class range +{ + IteratorT first_; + IteratorT last_; +public: + range(const IteratorT& first, const IteratorT& last) + : first_(first), last_(last) + { + } + +public: + IteratorT begin() + { + return first_; + } + IteratorT end() + { + return last_; + } +}; + +enum class storage_type : uint8_t +{ + null_val = 0x00, + bool_val = 0x01, + int64_val = 0x02, + uint64_val = 0x03, + double_val = 0x04, + short_string_val = 0x05, + long_string_val = 0x06, + byte_string_val = 0x07, + array_val = 0x08, + empty_object_val = 0x09, + object_val = 0x0a, + tag_val = 0x0b +}; + +template +class basic_json +{ +public: + + typedef Allocator allocator_type; + + typedef ImplementationPolicy implementation_policy; + + typedef typename ImplementationPolicy::parse_error_handler_type parse_error_handler_type; + + typedef CharT char_type; + typedef typename std::char_traits char_traits_type; + typedef basic_string_view string_view_type; + + typedef typename std::allocator_traits:: template rebind_alloc char_allocator_type; + + typedef std::basic_string string_type; + + typedef basic_json json_type; + + typedef json_type& reference; + typedef const json_type& const_reference; + typedef json_type* pointer; + typedef const json_type* const_pointer; + + typedef key_value key_value_type; + +#if !defined(JSONCONS_NO_DEPRECATED) + typedef json_type value_type; + typedef string_type key_type; + typedef key_value_type kvp_type; + typedef key_value_type member_type; + typedef jsoncons::null_type null_type; +#endif + + typedef typename std::allocator_traits:: template rebind_alloc byte_allocator_type; + using byte_string_storage_type = typename implementation_policy::template sequence_container_type; + + typedef json_array array; + + typedef typename std::allocator_traits:: template rebind_alloc key_value_allocator_type; + + typedef json_object object; + + typedef typename std::allocator_traits:: template rebind_alloc array_allocator; + typedef typename std::allocator_traits:: template rebind_alloc object_allocator; + + typedef typename object::iterator object_iterator; + typedef typename object::const_iterator const_object_iterator; + typedef typename array::iterator array_iterator; + typedef typename array::const_iterator const_array_iterator; + + struct variant + { + class data_base + { + static const uint8_t major_type_shift = 0x04; + static const uint8_t additional_information_mask = (1U << 4) - 1; + + uint8_t type_; + public: + data_base(uint8_t type) + : type_(type) + {} + + data_base(storage_type data_type, semantic_tag semantic_type) + : type_((static_cast(data_type) << major_type_shift) | static_cast(semantic_type)) + {} + + uint8_t type() const + { + return type_; + } + + storage_type get_storage_type() const + { + + uint8_t value = type_ >> major_type_shift; + return static_cast(value); + } + + semantic_tag get_semantic_tag() const + { + uint8_t value = type_ & additional_information_mask; + return static_cast(value); + } + }; + + class null_data final : public data_base + { + public: + null_data() + : data_base(storage_type::null_val, semantic_tag::none) + { + } + null_data(semantic_tag tag) + : data_base(storage_type::null_val, tag) + { + } + }; + + class empty_object_data final : public data_base + { + public: + empty_object_data(semantic_tag tag) + : data_base(storage_type::empty_object_val, tag) + { + } + }; + + class bool_data final : public data_base + { + bool val_; + public: + bool_data(bool val, semantic_tag tag) + : data_base(storage_type::bool_val, tag),val_(val) + { + } + + bool_data(const bool_data& val) + : data_base(val.type()),val_(val.val_) + { + } + + bool value() const + { + return val_; + } + + }; + + class int64_data final : public data_base + { + int64_t val_; + public: + int64_data(int64_t val, + semantic_tag tag = semantic_tag::none) + : data_base(storage_type::int64_val, tag),val_(val) + { + } + + int64_data(const int64_data& val) + : data_base(val.type()),val_(val.val_) + { + } + + int64_t value() const + { + return val_; + } + }; + + class uint64_data final : public data_base + { + uint64_t val_; + public: + uint64_data(uint64_t val, + semantic_tag tag = semantic_tag::none) + : data_base(storage_type::uint64_val, tag),val_(val) + { + } + + uint64_data(const uint64_data& val) + : data_base(val.type()),val_(val.val_) + { + } + + uint64_t value() const + { + return val_; + } + }; + + class double_data final : public data_base + { + double val_; + public: + double_data(double val, + semantic_tag tag = semantic_tag::none) + : data_base(storage_type::double_val, tag), + val_(val) + { + } + + double_data(const double_data& val) + : data_base(val.type()), + val_(val.val_) + { + } + + double value() const + { + return val_; + } + }; + + class short_string_data final : public data_base + { + static const size_t capacity = 14/sizeof(char_type); + uint8_t length_; + char_type data_[capacity]; + public: + static const size_t max_length = (14 / sizeof(char_type)) - 1; + + short_string_data(semantic_tag tag, const char_type* p, uint8_t length) + : data_base(storage_type::short_string_val, tag), length_(length) + { + JSONCONS_ASSERT(length <= max_length); + std::memcpy(data_,p,length*sizeof(char_type)); + data_[length] = 0; + } + + short_string_data(const short_string_data& val) + : data_base(val.type()), length_(val.length_) + { + std::memcpy(data_,val.data_,val.length_*sizeof(char_type)); + data_[length_] = 0; + } + + uint8_t length() const + { + return length_; + } + + const char_type* data() const + { + return data_; + } + + const char_type* c_str() const + { + return data_; + } + }; + + // long_string_data + class long_string_data final : public data_base + { + typedef typename jsoncons::detail::heap_only_string_factory::string_pointer pointer; + + pointer ptr_; + public: + + long_string_data(semantic_tag tag, const char_type* data, size_t length, const Allocator& a) + : data_base(storage_type::long_string_val, tag) + { + ptr_ = jsoncons::detail::heap_only_string_factory::create(data,length,a); + } + + long_string_data(const long_string_data& val) + : data_base(val.type()) + { + ptr_ = jsoncons::detail::heap_only_string_factory::create(val.data(),val.length(),val.get_allocator()); + } + + long_string_data(long_string_data&& val) + : data_base(val.type()), ptr_(nullptr) + { + std::swap(val.ptr_,ptr_); + } + + long_string_data(const long_string_data& val, const Allocator& a) + : data_base(val.type()) + { + ptr_ = jsoncons::detail::heap_only_string_factory::create(val.data(),val.length(),a); + } + + ~long_string_data() + { + if (ptr_ != nullptr) + { + jsoncons::detail::heap_only_string_factory::destroy(ptr_); + } + } + + void swap(long_string_data& val) + { + std::swap(val.ptr_,ptr_); + } + + const char_type* data() const + { + return ptr_->data(); + } + + const char_type* c_str() const + { + return ptr_->c_str(); + } + + size_t length() const + { + return ptr_->length(); + } + + allocator_type get_allocator() const + { + return ptr_->get_allocator(); + } + }; + + // byte_string_data + class byte_string_data final : public data_base + { + typedef typename std::allocator_traits:: template rebind_alloc string_holder_allocator_type; + typedef typename std::allocator_traits::pointer pointer; + + pointer ptr_; + + template + void create(string_holder_allocator_type allocator, Args&& ... args) + { + typename std::allocator_traits:: template rebind_alloc alloc(allocator); + ptr_ = alloc.allocate(1); + try + { + std::allocator_traits:: template rebind_traits::construct(alloc, jsoncons::detail::to_plain_pointer(ptr_), std::forward(args)...); + } + catch (...) + { + alloc.deallocate(ptr_,1); + throw; + } + } + public: + + byte_string_data(semantic_tag semantic_type, + const uint8_t* data, size_t length, + const Allocator& a) + : data_base(storage_type::byte_string_val, semantic_type) + { + create(string_holder_allocator_type(a), data, data+length, a); + } + + byte_string_data(const byte_string_data& val) + : data_base(val.type()) + { + create(val.ptr_->get_allocator(), *(val.ptr_)); + } + + byte_string_data(byte_string_data&& val) + : data_base(val.type()), ptr_(nullptr) + { + std::swap(val.ptr_,ptr_); + } + + byte_string_data(const byte_string_data& val, const Allocator& a) + : data_base(val.type()) + { + create(string_holder_allocator_type(a), *(val.ptr_), a); + } + + ~byte_string_data() + { + if (ptr_ != nullptr) + { + typename std::allocator_traits:: template rebind_alloc alloc(ptr_->get_allocator()); + std::allocator_traits:: template rebind_traits::destroy(alloc, jsoncons::detail::to_plain_pointer(ptr_)); + alloc.deallocate(ptr_,1); + } + } + + void swap(byte_string_data& val) + { + std::swap(val.ptr_,ptr_); + } + + const uint8_t* data() const + { + return ptr_->data(); + } + + size_t length() const + { + return ptr_->size(); + } + + const uint8_t* begin() const + { + return ptr_->data(); + } + + const uint8_t* end() const + { + return ptr_->data() + ptr_->size(); + } + + allocator_type get_allocator() const + { + return ptr_->get_allocator(); + } + }; + + // array_data + class array_data final : public data_base + { + typedef typename std::allocator_traits::pointer pointer; + pointer ptr_; + + template + void create(array_allocator allocator, Args&& ... args) + { + typename std::allocator_traits:: template rebind_alloc alloc(allocator); + ptr_ = alloc.allocate(1); + try + { + std::allocator_traits:: template rebind_traits::construct(alloc, jsoncons::detail::to_plain_pointer(ptr_), std::forward(args)...); + } + catch (...) + { + alloc.deallocate(ptr_,1); + throw; + } + } + public: + array_data(const array& val, semantic_tag tag) + : data_base(storage_type::array_val, tag) + { + create(val.get_allocator(), val); + } + + array_data(const array& val, semantic_tag tag, const Allocator& a) + : data_base(storage_type::array_val, tag) + { + create(array_allocator(a), val, a); + } + + array_data(const array_data& val) + : data_base(val.type()) + { + create(val.ptr_->get_allocator(), *(val.ptr_)); + } + + array_data(array_data&& val) + : data_base(val.type()), ptr_(nullptr) + { + std::swap(val.ptr_, ptr_); + } + + array_data(const array_data& val, const Allocator& a) + : data_base(val.type()) + { + create(array_allocator(a), *(val.ptr_), a); + } + ~array_data() + { + if (ptr_ != nullptr) + { + typename std::allocator_traits:: template rebind_alloc alloc(ptr_->get_allocator()); + std::allocator_traits:: template rebind_traits::destroy(alloc, jsoncons::detail::to_plain_pointer(ptr_)); + alloc.deallocate(ptr_,1); + } + } + + allocator_type get_allocator() const + { + return ptr_->get_allocator(); + } + + void swap(array_data& val) + { + std::swap(val.ptr_,ptr_); + } + + array& value() + { + return *ptr_; + } + + const array& value() const + { + return *ptr_; + } + }; + + // object_data + class object_data final : public data_base + { + typedef typename std::allocator_traits::pointer pointer; + pointer ptr_; + + template + void create(Allocator allocator, Args&& ... args) + { + typename std::allocator_traits:: template rebind_alloc alloc(allocator); + ptr_ = alloc.allocate(1); + try + { + std::allocator_traits:: template rebind_traits::construct(alloc, jsoncons::detail::to_plain_pointer(ptr_), std::forward(args)...); + } + catch (...) + { + alloc.deallocate(ptr_,1); + throw; + } + } + public: + explicit object_data(const object& val, semantic_tag tag) + : data_base(storage_type::object_val, tag) + { + create(val.get_allocator(), val); + } + + explicit object_data(const object& val, semantic_tag tag, const Allocator& a) + : data_base(storage_type::object_val, tag) + { + create(object_allocator(a), val, a); + } + + explicit object_data(const object_data& val) + : data_base(val.type()) + { + create(val.ptr_->get_allocator(), *(val.ptr_)); + } + + explicit object_data(object_data&& val) + : data_base(val.type()), ptr_(nullptr) + { + std::swap(val.ptr_,ptr_); + } + + explicit object_data(const object_data& val, const Allocator& a) + : data_base(val.type()) + { + create(object_allocator(a), *(val.ptr_), a); + } + + ~object_data() + { + if (ptr_ != nullptr) + { + typename std::allocator_traits:: template rebind_alloc alloc(ptr_->get_allocator()); + std::allocator_traits:: template rebind_traits::destroy(alloc, jsoncons::detail::to_plain_pointer(ptr_)); + alloc.deallocate(ptr_,1); + } + } + + void swap(object_data& val) + { + std::swap(val.ptr_,ptr_); + } + + object& value() + { + return *ptr_; + } + + const object& value() const + { + return *ptr_; + } + + allocator_type get_allocator() const + { + return ptr_->get_allocator(); + } + }; + + private: + static const size_t data_size = static_max::value; + static const size_t data_align = static_max::value; + + typedef typename std::aligned_storage::type data_t; + + data_t data_; + public: + variant(semantic_tag tag) + { + new(reinterpret_cast(&data_))empty_object_data(tag); + } + + explicit variant(null_type, semantic_tag tag) + { + new(reinterpret_cast(&data_))null_data(tag); + } + + explicit variant(bool val, semantic_tag tag) + { + new(reinterpret_cast(&data_))bool_data(val,tag); + } + explicit variant(int64_t val, semantic_tag tag) + { + new(reinterpret_cast(&data_))int64_data(val, tag); + } + explicit variant(uint64_t val, semantic_tag tag) + { + new(reinterpret_cast(&data_))uint64_data(val, tag); + } + + variant(double val, semantic_tag tag) + { + new(reinterpret_cast(&data_))double_data(val, tag); + } + + variant(const char_type* s, size_t length, semantic_tag tag) + { + if (length <= short_string_data::max_length) + { + new(reinterpret_cast(&data_))short_string_data(tag, s, static_cast(length)); + } + else + { + new(reinterpret_cast(&data_))long_string_data(tag, s, length, char_allocator_type()); + } + } + + variant(const char_type* s, size_t length, semantic_tag tag, const Allocator& alloc) + { + if (length <= short_string_data::max_length) + { + new(reinterpret_cast(&data_))short_string_data(tag, s, static_cast(length)); + } + else + { + new(reinterpret_cast(&data_))long_string_data(tag, s, length, char_allocator_type(alloc)); + } + } + + variant(const byte_string_view& bs, semantic_tag tag) + { + new(reinterpret_cast(&data_))byte_string_data(tag, bs.data(), bs.length(), byte_allocator_type()); + } + + variant(const byte_string_view& bs, semantic_tag tag, const Allocator& allocator) + { + new(reinterpret_cast(&data_))byte_string_data(tag, bs.data(), bs.length(), allocator); + } + + variant(const basic_bignum& n) + { + std::basic_string s; + n.dump(s); + + if (s.length() <= short_string_data::max_length) + { + new(reinterpret_cast(&data_))short_string_data(semantic_tag::bigint, s.data(), static_cast(s.length())); + } + else + { + new(reinterpret_cast(&data_))long_string_data(semantic_tag::bigint, s.data(), s.length(), char_allocator_type()); + } + } + + variant(const basic_bignum& n, const Allocator& allocator) + { + std::basic_string s; + n.dump(s); + + if (s.length() <= short_string_data::max_length) + { + new(reinterpret_cast(&data_))short_string_data(semantic_tag::bigint, s.data(), static_cast(s.length())); + } + else + { + new(reinterpret_cast(&data_))long_string_data(semantic_tag::bigint, s.data(), s.length(), char_allocator_type(allocator)); + } + } + variant(const object& val, semantic_tag tag) + { + new(reinterpret_cast(&data_))object_data(val, tag); + } + variant(const object& val, semantic_tag tag, const Allocator& alloc) + { + new(reinterpret_cast(&data_))object_data(val, tag, alloc); + } + variant(const array& val, semantic_tag tag) + { + new(reinterpret_cast(&data_))array_data(val, tag); + } + variant(const array& val, semantic_tag tag, const Allocator& alloc) + { + new(reinterpret_cast(&data_))array_data(val, tag, alloc); + } + + variant(const variant& val) + { + Init_(val); + } + + variant(const variant& val, const Allocator& allocator) + { + Init_(val,allocator); + } + + variant(variant&& val) noexcept + { + Init_rv_(std::forward(val)); + } + + variant(variant&& val, const Allocator& allocator) noexcept + { + Init_rv_(std::forward(val), allocator, + typename std::allocator_traits::propagate_on_container_move_assignment()); + } + + ~variant() + { + Destroy_(); + } + + void Destroy_() + { + switch (get_storage_type()) + { + case storage_type::long_string_val: + reinterpret_cast(&data_)->~long_string_data(); + break; + case storage_type::byte_string_val: + reinterpret_cast(&data_)->~byte_string_data(); + break; + case storage_type::array_val: + reinterpret_cast(&data_)->~array_data(); + break; + case storage_type::object_val: + reinterpret_cast(&data_)->~object_data(); + break; + default: + break; + } + } + + variant& operator=(const variant& val) + { + if (this !=&val) + { + Destroy_(); + switch (val.get_storage_type()) + { + case storage_type::null_val: + new(reinterpret_cast(&data_))null_data(*(val.null_data_cast())); + break; + case storage_type::empty_object_val: + new(reinterpret_cast(&data_))empty_object_data(*(val.empty_object_data_cast())); + break; + case storage_type::bool_val: + new(reinterpret_cast(&data_))bool_data(*(val.bool_data_cast())); + break; + case storage_type::int64_val: + new(reinterpret_cast(&data_))int64_data(*(val.int64_data_cast())); + break; + case storage_type::uint64_val: + new(reinterpret_cast(&data_))uint64_data(*(val.uint64_data_cast())); + break; + case storage_type::double_val: + new(reinterpret_cast(&data_))double_data(*(val.double_data_cast())); + break; + case storage_type::short_string_val: + new(reinterpret_cast(&data_))short_string_data(*(val.short_string_data_cast())); + break; + case storage_type::long_string_val: + new(reinterpret_cast(&data_))long_string_data(*(val.string_data_cast())); + break; + case storage_type::byte_string_val: + new(reinterpret_cast(&data_))byte_string_data(*(val.byte_string_data_cast())); + break; + case storage_type::array_val: + new(reinterpret_cast(&data_))array_data(*(val.array_data_cast())); + break; + case storage_type::object_val: + new(reinterpret_cast(&data_))object_data(*(val.object_data_cast())); + break; + default: + JSONCONS_UNREACHABLE(); + break; + } + } + return *this; + } + + variant& operator=(variant&& val) noexcept + { + if (this !=&val) + { + swap(val); + } + return *this; + } + + storage_type get_storage_type() const + { + return reinterpret_cast(&data_)->get_storage_type(); + } + + semantic_tag get_semantic_tag() const + { + return reinterpret_cast(&data_)->get_semantic_tag(); + } + + const null_data* null_data_cast() const + { + return reinterpret_cast(&data_); + } + + const empty_object_data* empty_object_data_cast() const + { + return reinterpret_cast(&data_); + } + + const bool_data* bool_data_cast() const + { + return reinterpret_cast(&data_); + } + + const int64_data* int64_data_cast() const + { + return reinterpret_cast(&data_); + } + + const uint64_data* uint64_data_cast() const + { + return reinterpret_cast(&data_); + } + + const double_data* double_data_cast() const + { + return reinterpret_cast(&data_); + } + + const short_string_data* short_string_data_cast() const + { + return reinterpret_cast(&data_); + } + + long_string_data* string_data_cast() + { + return reinterpret_cast(&data_); + } + + const long_string_data* string_data_cast() const + { + return reinterpret_cast(&data_); + } + + byte_string_data* byte_string_data_cast() + { + return reinterpret_cast(&data_); + } + + const byte_string_data* byte_string_data_cast() const + { + return reinterpret_cast(&data_); + } + + object_data* object_data_cast() + { + return reinterpret_cast(&data_); + } + + const object_data* object_data_cast() const + { + return reinterpret_cast(&data_); + } + + array_data* array_data_cast() + { + return reinterpret_cast(&data_); + } + + const array_data* array_data_cast() const + { + return reinterpret_cast(&data_); + } + + size_t size() const + { + switch (get_storage_type()) + { + case storage_type::array_val: + return array_data_cast()->value().size(); + case storage_type::object_val: + return object_data_cast()->value().size(); + default: + return 0; + } + } + + string_view_type as_string_view() const + { + switch (get_storage_type()) + { + case storage_type::short_string_val: + return string_view_type(short_string_data_cast()->data(),short_string_data_cast()->length()); + case storage_type::long_string_val: + return string_view_type(string_data_cast()->data(),string_data_cast()->length()); + default: + JSONCONS_THROW(json_runtime_error("Not a string")); + } + } + + template > + basic_byte_string as_byte_string() const + { + switch (get_storage_type()) + { + case storage_type::short_string_val: + case storage_type::long_string_val: + { + switch (get_semantic_tag()) + { + case semantic_tag::base16: + { + basic_byte_string bs; + auto s = as_string_view(); + decode_base16(s.begin(), s.end(), bs); + return bs; + } + case semantic_tag::base64: + { + basic_byte_string bs; + auto s = as_string_view(); + decode_base64(s.begin(), s.end(), bs); + return bs; + } + case semantic_tag::base64url: + { + basic_byte_string bs; + auto s = as_string_view(); + decode_base64url(s.begin(), s.end(), bs); + return bs; + } + default: + JSONCONS_THROW(json_runtime_error("Not a byte string")); + } + break; + } + case storage_type::byte_string_val: + return basic_byte_string(byte_string_data_cast()->data(),byte_string_data_cast()->length()); + default: + JSONCONS_THROW(json_runtime_error("Not a byte string")); + } + } + + byte_string_view as_byte_string_view() const + { + switch (get_storage_type()) + { + case storage_type::byte_string_val: + return byte_string_view(byte_string_data_cast()->data(),byte_string_data_cast()->length()); + default: + JSONCONS_THROW(json_runtime_error("Not a byte string")); + } + } + + template > + basic_bignum as_bignum() const + { + switch (get_storage_type()) + { + case storage_type::short_string_val: + case storage_type::long_string_val: + if (!jsoncons::detail::is_integer(as_string_view().data(), as_string_view().length())) + { + JSONCONS_THROW(json_runtime_error("Not an integer")); + } + return basic_bignum(as_string_view().data(), as_string_view().length()); + case storage_type::double_val: + return basic_bignum(double_data_cast()->value()); + case storage_type::int64_val: + return basic_bignum(int64_data_cast()->value()); + case storage_type::uint64_val: + return basic_bignum(uint64_data_cast()->value()); + case storage_type::bool_val: + return basic_bignum(bool_data_cast()->value() ? 1 : 0); + default: + JSONCONS_THROW(json_runtime_error("Not a bignum")); + } + } + + bool operator==(const variant& rhs) const + { + if (this ==&rhs) + { + return true; + } + switch (get_storage_type()) + { + case storage_type::null_val: + switch (rhs.get_storage_type()) + { + case storage_type::null_val: + return true; + default: + return false; + } + break; + case storage_type::empty_object_val: + switch (rhs.get_storage_type()) + { + case storage_type::empty_object_val: + return true; + case storage_type::object_val: + return rhs.size() == 0; + default: + return false; + } + break; + case storage_type::bool_val: + switch (rhs.get_storage_type()) + { + case storage_type::bool_val: + return bool_data_cast()->value() == rhs.bool_data_cast()->value(); + default: + return false; + } + break; + case storage_type::int64_val: + switch (rhs.get_storage_type()) + { + case storage_type::int64_val: + return int64_data_cast()->value() == rhs.int64_data_cast()->value(); + case storage_type::uint64_val: + return int64_data_cast()->value() >= 0 ? static_cast(int64_data_cast()->value()) == rhs.uint64_data_cast()->value() : false; + case storage_type::double_val: + return static_cast(int64_data_cast()->value()) == rhs.double_data_cast()->value(); + default: + return false; + } + break; + case storage_type::uint64_val: + switch (rhs.get_storage_type()) + { + case storage_type::int64_val: + return rhs.int64_data_cast()->value() >= 0 ? uint64_data_cast()->value() == static_cast(rhs.int64_data_cast()->value()) : false; + case storage_type::uint64_val: + return uint64_data_cast()->value() == rhs.uint64_data_cast()->value(); + case storage_type::double_val: + return static_cast(uint64_data_cast()->value()) == rhs.double_data_cast()->value(); + default: + return false; + } + break; + case storage_type::double_val: + switch (rhs.get_storage_type()) + { + case storage_type::int64_val: + return double_data_cast()->value() == static_cast(rhs.int64_data_cast()->value()); + case storage_type::uint64_val: + return double_data_cast()->value() == static_cast(rhs.uint64_data_cast()->value()); + case storage_type::double_val: + return double_data_cast()->value() == rhs.double_data_cast()->value(); + default: + return false; + } + break; + case storage_type::short_string_val: + switch (rhs.get_storage_type()) + { + case storage_type::short_string_val: + return as_string_view() == rhs.as_string_view(); + case storage_type::long_string_val: + return as_string_view() == rhs.as_string_view(); + default: + return false; + } + break; + case storage_type::long_string_val: + switch (rhs.get_storage_type()) + { + case storage_type::short_string_val: + return as_string_view() == rhs.as_string_view(); + case storage_type::long_string_val: + return as_string_view() == rhs.as_string_view(); + default: + return false; + } + break; + case storage_type::byte_string_val: + switch (rhs.get_storage_type()) + { + case storage_type::byte_string_val: + { + return as_byte_string_view() == rhs.as_byte_string_view(); + } + default: + return false; + } + break; + case storage_type::array_val: + switch (rhs.get_storage_type()) + { + case storage_type::array_val: + return array_data_cast()->value() == rhs.array_data_cast()->value(); + default: + return false; + } + break; + case storage_type::object_val: + switch (rhs.get_storage_type()) + { + case storage_type::empty_object_val: + return size() == 0; + case storage_type::object_val: + return object_data_cast()->value() == rhs.object_data_cast()->value(); + default: + return false; + } + break; + default: + JSONCONS_UNREACHABLE(); + break; + } + } + + bool operator!=(const variant& rhs) const + { + return !(*this == rhs); + } + + bool operator<(const variant& rhs) const + { + if (this == &rhs) + { + return false; + } + switch (get_storage_type()) + { + case storage_type::null_val: + return (int)get_storage_type() < (int)rhs.get_storage_type(); + case storage_type::empty_object_val: + switch (rhs.get_storage_type()) + { + case storage_type::empty_object_val: + return false; + case storage_type::object_val: + return rhs.size() != 0; + default: + return (int)get_storage_type() < (int)rhs.get_storage_type(); + } + break; + case storage_type::bool_val: + switch (rhs.get_storage_type()) + { + case storage_type::bool_val: + return bool_data_cast()->value() < rhs.bool_data_cast()->value(); + default: + return (int)get_storage_type() < (int)rhs.get_storage_type(); + } + break; + case storage_type::int64_val: + switch (rhs.get_storage_type()) + { + case storage_type::int64_val: + return int64_data_cast()->value() < rhs.int64_data_cast()->value(); + case storage_type::uint64_val: + return int64_data_cast()->value() >= 0 ? static_cast(int64_data_cast()->value()) < rhs.uint64_data_cast()->value() : true; + case storage_type::double_val: + return static_cast(int64_data_cast()->value()) < rhs.double_data_cast()->value(); + default: + return (int)get_storage_type() < (int)rhs.get_storage_type(); + } + break; + case storage_type::uint64_val: + switch (rhs.get_storage_type()) + { + case storage_type::int64_val: + return rhs.int64_data_cast()->value() >= 0 ? uint64_data_cast()->value() < static_cast(rhs.int64_data_cast()->value()) : true; + case storage_type::uint64_val: + return uint64_data_cast()->value() < rhs.uint64_data_cast()->value(); + case storage_type::double_val: + return static_cast(uint64_data_cast()->value()) < rhs.double_data_cast()->value(); + default: + return (int)get_storage_type() < (int)rhs.get_storage_type(); + } + break; + case storage_type::double_val: + switch (rhs.get_storage_type()) + { + case storage_type::int64_val: + return double_data_cast()->value() < static_cast(rhs.int64_data_cast()->value()); + case storage_type::uint64_val: + return double_data_cast()->value() < static_cast(rhs.uint64_data_cast()->value()); + case storage_type::double_val: + return double_data_cast()->value() < rhs.double_data_cast()->value(); + default: + return (int)get_storage_type() < (int)rhs.get_storage_type(); + } + break; + case storage_type::short_string_val: + switch (rhs.get_storage_type()) + { + case storage_type::short_string_val: + return as_string_view() < rhs.as_string_view(); + case storage_type::long_string_val: + return as_string_view() < rhs.as_string_view(); + default: + return (int)get_storage_type() < (int)rhs.get_storage_type(); + } + break; + case storage_type::long_string_val: + switch (rhs.get_storage_type()) + { + case storage_type::short_string_val: + return as_string_view() < rhs.as_string_view(); + case storage_type::long_string_val: + return as_string_view() < rhs.as_string_view(); + default: + return (int)get_storage_type() < (int)rhs.get_storage_type(); + } + break; + case storage_type::byte_string_val: + switch (rhs.get_storage_type()) + { + case storage_type::byte_string_val: + { + return as_byte_string_view() < rhs.as_byte_string_view(); + } + default: + return (int)get_storage_type() < (int)rhs.get_storage_type(); + } + break; + case storage_type::array_val: + switch (rhs.get_storage_type()) + { + case storage_type::array_val: + return array_data_cast()->value() < rhs.array_data_cast()->value(); + default: + return (int)get_storage_type() < (int)rhs.get_storage_type(); + } + break; + case storage_type::object_val: + switch (rhs.get_storage_type()) + { + case storage_type::empty_object_val: + return false; + case storage_type::object_val: + return object_data_cast()->value() < rhs.object_data_cast()->value(); + default: + return (int)get_storage_type() < (int)rhs.get_storage_type(); + } + break; + default: + JSONCONS_UNREACHABLE(); + break; + } + } + + template + typename std::enable_if::pointer>::value,void>::type + swap(variant& other) noexcept + { + if (this ==&other) + { + return; + } + + std::swap(data_,other.data_); + } + + template + typename std::enable_if::pointer>::value, void>::type + swap(variant& other) noexcept + { + if (this ==&other) + { + return; + } + + variant temp(other); + switch (get_storage_type()) + { + case storage_type::null_val: + new(reinterpret_cast(&(other.data_)))null_data(*null_data_cast()); + break; + case storage_type::empty_object_val: + new(reinterpret_cast(&(other.data_)))empty_object_data(*empty_object_data_cast()); + break; + case storage_type::bool_val: + new(reinterpret_cast(&(other.data_)))bool_data(*bool_data_cast()); + break; + case storage_type::int64_val: + new(reinterpret_cast(&(other.data_)))int64_data(*int64_data_cast()); + break; + case storage_type::uint64_val: + new(reinterpret_cast(&(other.data_)))uint64_data(*uint64_data_cast()); + break; + case storage_type::double_val: + new(reinterpret_cast(&(other.data_)))double_data(*double_data_cast()); + break; + case storage_type::short_string_val: + new(reinterpret_cast(&(other.data_)))short_string_data(*short_string_data_cast()); + break; + case storage_type::long_string_val: + new(reinterpret_cast(&other.data_))long_string_data(std::move(*string_data_cast())); + break; + case storage_type::byte_string_val: + new(reinterpret_cast(&other.data_))byte_string_data(std::move(*byte_string_data_cast())); + break; + case storage_type::array_val: + new(reinterpret_cast(&(other.data_)))array_data(std::move(*array_data_cast())); + break; + case storage_type::object_val: + new(reinterpret_cast(&(other.data_)))object_data(std::move(*object_data_cast())); + break; + default: + JSONCONS_UNREACHABLE(); + break; + } + switch (temp.get_storage_type()) + { + case storage_type::long_string_val: + new(reinterpret_cast(&data_))long_string_data(std::move(*temp.string_data_cast())); + break; + case storage_type::byte_string_val: + new(reinterpret_cast(&data_))byte_string_data(std::move(*temp.byte_string_data_cast())); + break; + case storage_type::array_val: + new(reinterpret_cast(&(data_)))array_data(std::move(*temp.array_data_cast())); + break; + case storage_type::object_val: + new(reinterpret_cast(&(data_)))object_data(std::move(*temp.object_data_cast())); + break; + default: + std::swap(data_,temp.data_); + break; + } + } + private: + + void Init_(const variant& val) + { + switch (val.get_storage_type()) + { + case storage_type::null_val: + new(reinterpret_cast(&data_))null_data(*(val.null_data_cast())); + break; + case storage_type::empty_object_val: + new(reinterpret_cast(&data_))empty_object_data(*(val.empty_object_data_cast())); + break; + case storage_type::bool_val: + new(reinterpret_cast(&data_))bool_data(*(val.bool_data_cast())); + break; + case storage_type::int64_val: + new(reinterpret_cast(&data_))int64_data(*(val.int64_data_cast())); + break; + case storage_type::uint64_val: + new(reinterpret_cast(&data_))uint64_data(*(val.uint64_data_cast())); + break; + case storage_type::double_val: + new(reinterpret_cast(&data_))double_data(*(val.double_data_cast())); + break; + case storage_type::short_string_val: + new(reinterpret_cast(&data_))short_string_data(*(val.short_string_data_cast())); + break; + case storage_type::long_string_val: + new(reinterpret_cast(&data_))long_string_data(*(val.string_data_cast())); + break; + case storage_type::byte_string_val: + new(reinterpret_cast(&data_))byte_string_data(*(val.byte_string_data_cast())); + break; + case storage_type::object_val: + new(reinterpret_cast(&data_))object_data(*(val.object_data_cast())); + break; + case storage_type::array_val: + new(reinterpret_cast(&data_))array_data(*(val.array_data_cast())); + break; + default: + break; + } + } + + void Init_(const variant& val, const Allocator& a) + { + switch (val.get_storage_type()) + { + case storage_type::null_val: + case storage_type::empty_object_val: + case storage_type::bool_val: + case storage_type::int64_val: + case storage_type::uint64_val: + case storage_type::double_val: + case storage_type::short_string_val: + Init_(val); + break; + case storage_type::long_string_val: + new(reinterpret_cast(&data_))long_string_data(*(val.string_data_cast()),a); + break; + case storage_type::byte_string_val: + new(reinterpret_cast(&data_))byte_string_data(*(val.byte_string_data_cast()),a); + break; + case storage_type::array_val: + new(reinterpret_cast(&data_))array_data(*(val.array_data_cast()),a); + break; + case storage_type::object_val: + new(reinterpret_cast(&data_))object_data(*(val.object_data_cast()),a); + break; + default: + break; + } + } + + void Init_rv_(variant&& val) noexcept + { + switch (val.get_storage_type()) + { + case storage_type::null_val: + case storage_type::empty_object_val: + case storage_type::double_val: + case storage_type::int64_val: + case storage_type::uint64_val: + case storage_type::bool_val: + case storage_type::short_string_val: + Init_(val); + break; + case storage_type::long_string_val: + { + new(reinterpret_cast(&data_))long_string_data(std::move(*val.string_data_cast())); + new(reinterpret_cast(&val.data_))null_data(); + } + break; + case storage_type::byte_string_val: + { + new(reinterpret_cast(&data_))byte_string_data(std::move(*val.byte_string_data_cast())); + new(reinterpret_cast(&val.data_))null_data(); + } + break; + case storage_type::array_val: + { + new(reinterpret_cast(&data_))array_data(std::move(*val.array_data_cast())); + new(reinterpret_cast(&val.data_))null_data(); + } + break; + case storage_type::object_val: + { + new(reinterpret_cast(&data_))object_data(std::move(*val.object_data_cast())); + new(reinterpret_cast(&val.data_))null_data(); + } + break; + default: + JSONCONS_UNREACHABLE(); + break; + } + } + + void Init_rv_(variant&& val, const Allocator&, std::true_type) noexcept + { + Init_rv_(std::forward(val)); + } + + void Init_rv_(variant&& val, const Allocator& a, std::false_type) noexcept + { + switch (val.get_storage_type()) + { + case storage_type::null_val: + case storage_type::empty_object_val: + case storage_type::double_val: + case storage_type::int64_val: + case storage_type::uint64_val: + case storage_type::bool_val: + case storage_type::short_string_val: + Init_(std::forward(val)); + break; + case storage_type::long_string_val: + { + if (a == val.string_data_cast()->get_allocator()) + { + Init_rv_(std::forward(val), a, std::true_type()); + } + else + { + Init_(val,a); + } + } + break; + case storage_type::byte_string_val: + { + if (a == val.byte_string_data_cast()->get_allocator()) + { + Init_rv_(std::forward(val), a, std::true_type()); + } + else + { + Init_(val,a); + } + } + break; + case storage_type::object_val: + { + if (a == val.object_data_cast()->get_allocator()) + { + Init_rv_(std::forward(val), a, std::true_type()); + } + else + { + Init_(val,a); + } + } + break; + case storage_type::array_val: + { + if (a == val.array_data_cast()->get_allocator()) + { + Init_rv_(std::forward(val), a, std::true_type()); + } + else + { + Init_(val,a); + } + } + break; + default: + break; + } + } + }; + + template + class json_proxy + { + private: + + ParentT& parent_; + const char_type* data_; + size_t length_; + + json_proxy() = delete; + json_proxy& operator = (const json_proxy& other) = delete; + + json_proxy(ParentT& parent, const char_type* data, size_t length) + : parent_(parent), data_(data), length_(length) + { + } + + basic_json& evaluate() + { + return parent_.evaluate(string_view_type(data_,length_)); + } + + const basic_json& evaluate() const + { + return parent_.evaluate(string_view_type(data_,length_)); + } + + basic_json& evaluate_with_default() + { + basic_json& val = parent_.evaluate_with_default(); + auto it = val.find(string_view_type(data_,length_)); + if (it == val.object_range().end()) + { + it = val.insert_or_assign(val.object_range().begin(),string_view_type(data_,length_),object(val.object_value().get_allocator())); + } + return it->value(); + } + + basic_json& evaluate(size_t index) + { + return evaluate().at(index); + } + + const basic_json& evaluate(size_t index) const + { + return evaluate().at(index); + } + + basic_json& evaluate(const string_view_type& index) + { + return evaluate().at(index); + } + + const basic_json& evaluate(const string_view_type& index) const + { + return evaluate().at(index); + } + public: + + friend class basic_json; + typedef json_proxy proxy_type; + + range object_range() + { + return evaluate().object_range(); + } + + range object_range() const + { + return evaluate().object_range(); + } + + range array_range() + { + return evaluate().array_range(); + } + + range array_range() const + { + return evaluate().array_range(); + } + + size_t size() const noexcept + { + return evaluate().size(); + } + + storage_type get_storage_type() const + { + return evaluate().get_storage_type(); + } + + semantic_tag get_semantic_tag() const + { + return evaluate().get_semantic_tag(); + } + + size_t count(const string_view_type& name) const + { + return evaluate().count(name); + } + + allocator_type get_allocator() const + { + return evaluate().get_allocator(); + } + + bool contains(const string_view_type& name) const + { + return evaluate().contains(name); + } + + bool is_null() const noexcept + { + return evaluate().is_null(); + } + + bool empty() const + { + return evaluate().empty(); + } + + size_t capacity() const + { + return evaluate().capacity(); + } + + void reserve(size_t n) + { + evaluate().reserve(n); + } + + void resize(size_t n) + { + evaluate().resize(n); + } + + template + void resize(size_t n, T val) + { + evaluate().resize(n,val); + } + + template + bool is(Args&&... args) const + { + return evaluate().template is(std::forward(args)...); + } + + bool is_string() const noexcept + { + return evaluate().is_string(); + } + + bool is_string_view() const noexcept + { + return evaluate().is_string_view(); + } + + bool is_byte_string() const noexcept + { + return evaluate().is_byte_string(); + } + + bool is_byte_string_view() const noexcept + { + return evaluate().is_byte_string_view(); + } + + bool is_bignum() const noexcept + { + return evaluate().is_bignum(); + } + + bool is_number() const noexcept + { + return evaluate().is_number(); + } + bool is_bool() const noexcept + { + return evaluate().is_bool(); + } + + bool is_object() const noexcept + { + return evaluate().is_object(); + } + + bool is_array() const noexcept + { + return evaluate().is_array(); + } + + bool is_int64() const noexcept + { + return evaluate().is_int64(); + } + + bool is_uint64() const noexcept + { + return evaluate().is_uint64(); + } + + bool is_double() const noexcept + { + return evaluate().is_double(); + } + + string_view_type as_string_view() const + { + return evaluate().as_string_view(); + } + + byte_string_view as_byte_string_view() const + { + return evaluate().as_byte_string_view(); + } + + basic_bignum as_bignum() const + { + return evaluate().as_bignum(); + } + + template > + string_type as_string() const + { + return evaluate().as_string(); + } + + template > + string_type as_string(const SAllocator& allocator) const + { + return evaluate().as_string(allocator); + } + + template > + basic_byte_string as_byte_string() const + { + return evaluate().template as_byte_string(); + } + + template > + string_type as_string(const basic_json_options& options) const + { + return evaluate().as_string(options); + } + + template > + string_type as_string(const basic_json_options& options, + const SAllocator& allocator) const + { + return evaluate().as_string(options,allocator); + } + + template + T as(Args&&... args) const + { + return evaluate().template as(std::forward(args)...); + } + + template + typename std::enable_if::value,T>::type + as(const char_allocator_type& allocator) const + { + return evaluate().template as(allocator); + } + bool as_bool() const + { + return evaluate().as_bool(); + } + + double as_double() const + { + return evaluate().as_double(); + } + + template + T as_integer() const + { + return evaluate().template as_integer(); + } + + template + json_proxy& operator=(T&& val) + { + parent_.evaluate_with_default().insert_or_assign(string_view_type(data_,length_), std::forward(val)); + return *this; + } + + bool operator==(const basic_json& rhs) const + { + return evaluate() == rhs; + } + + bool operator!=(const basic_json& rhs) const + { + return evaluate() != rhs; + } + + bool operator<(const basic_json& rhs) const + { + return evaluate() < rhs; + } + + bool operator<=(const basic_json& rhs) const + { + return !(rhs < evaluate()); + } + + bool operator>(const basic_json& rhs) const + { + return !(evaluate() <= rhs); + } + + bool operator>=(const basic_json& rhs) const + { + return !(evaluate() < rhs); + } + + basic_json& operator[](size_t i) + { + return evaluate_with_default().at(i); + } + + const basic_json& operator[](size_t i) const + { + return evaluate().at(i); + } + + json_proxy operator[](const string_view_type& key) + { + return json_proxy(*this,key.data(),key.length()); + } + + const basic_json& operator[](const string_view_type& name) const + { + return at(name); + } + + basic_json& at(const string_view_type& name) + { + return evaluate().at(name); + } + + const basic_json& at(const string_view_type& name) const + { + return evaluate().at(name); + } + + const basic_json& at(size_t index) + { + return evaluate().at(index); + } + + const basic_json& at(size_t index) const + { + return evaluate().at(index); + } + + object_iterator find(const string_view_type& name) + { + return evaluate().find(name); + } + + const_object_iterator find(const string_view_type& name) const + { + return evaluate().find(name); + } + + template + T get_with_default(const string_view_type& name, const T& default_val) const + { + return evaluate().template get_with_default(name,default_val); + } + + template > + T get_with_default(const string_view_type& name, const CharT* default_val) const + { + return evaluate().template get_with_default(name,default_val); + } + + void shrink_to_fit() + { + evaluate_with_default().shrink_to_fit(); + } + + void clear() + { + evaluate().clear(); + } + // Remove all elements from an array or object + + void erase(const_object_iterator pos) + { + evaluate().erase(pos); + } + // Remove a range of elements from an object + + void erase(const_object_iterator first, const_object_iterator last) + { + evaluate().erase(first, last); + } + // Remove a range of elements from an object + + void erase(const string_view_type& name) + { + evaluate().erase(name); + } + + void erase(const_array_iterator pos) + { + evaluate().erase(pos); + } + // Removes the element at pos + + void erase(const_array_iterator first, const_array_iterator last) + { + evaluate().erase(first, last); + } + // Remove a range of elements from an array + + // merge + + void merge(const basic_json& source) + { + return evaluate().merge(source); + } + + void merge(basic_json&& source) + { + return evaluate().merge(std::forward(source)); + } + + void merge(object_iterator hint, const basic_json& source) + { + return evaluate().merge(hint, source); + } + + void merge(object_iterator hint, basic_json&& source) + { + return evaluate().merge(hint, std::forward(source)); + } + + // merge_or_update + + void merge_or_update(const basic_json& source) + { + return evaluate().merge_or_update(source); + } + + void merge_or_update(basic_json&& source) + { + return evaluate().merge_or_update(std::forward(source)); + } + + void merge_or_update(object_iterator hint, const basic_json& source) + { + return evaluate().merge_or_update(hint, source); + } + + void merge_or_update(object_iterator hint, basic_json&& source) + { + return evaluate().merge_or_update(hint, std::forward(source)); + } + + template + std::pair insert_or_assign(const string_view_type& name, T&& val) + { + return evaluate().insert_or_assign(name,std::forward(val)); + } + + // emplace + + template + std::pair try_emplace(const string_view_type& name, Args&&... args) + { + return evaluate().try_emplace(name,std::forward(args)...); + } + + template + object_iterator insert_or_assign(object_iterator hint, const string_view_type& name, T&& val) + { + return evaluate().insert_or_assign(hint, name, std::forward(val)); + } + + template + object_iterator try_emplace(object_iterator hint, const string_view_type& name, Args&&... args) + { + return evaluate().try_emplace(hint, name, std::forward(args)...); + } + + template + array_iterator emplace(const_array_iterator pos, Args&&... args) + { + evaluate_with_default().emplace(pos, std::forward(args)...); + } + + template + basic_json& emplace_back(Args&&... args) + { + return evaluate_with_default().emplace_back(std::forward(args)...); + } + + template + void push_back(T&& val) + { + evaluate_with_default().push_back(std::forward(val)); + } + + template + array_iterator insert(const_array_iterator pos, T&& val) + { + return evaluate_with_default().insert(pos, std::forward(val)); + } + + template + array_iterator insert(const_array_iterator pos, InputIt first, InputIt last) + { + return evaluate_with_default().insert(pos, first, last); + } + + template + void insert(InputIt first, InputIt last) + { + evaluate_with_default().insert(first, last); + } + + template + void insert(sorted_unique_range_tag tag, InputIt first, InputIt last) + { + evaluate_with_default().insert(tag, first, last); + } + + template + void dump(std::basic_string& s) const + { + evaluate().dump(s); + } + + template + void dump(std::basic_string& s, + indenting line_indent) const + { + evaluate().dump(s, line_indent); + } + + template + void dump(std::basic_string& s, + const basic_json_options& options) const + { + evaluate().dump(s,options); + } + + template + void dump(std::basic_string& s, + const basic_json_options& options, + indenting line_indent) const + { + evaluate().dump(s,options,line_indent); + } + + void dump(basic_json_content_handler& handler) const + { + evaluate().dump(handler); + } + + void dump(std::basic_ostream& os) const + { + evaluate().dump(os); + } + + void dump(std::basic_ostream& os, indenting line_indent) const + { + evaluate().dump(os, line_indent); + } + + void dump(std::basic_ostream& os, const basic_json_options& options) const + { + evaluate().dump(os,options); + } + + void dump(std::basic_ostream& os, const basic_json_options& options, indenting line_indent) const + { + evaluate().dump(os,options,line_indent); + } +#if !defined(JSONCONS_NO_DEPRECATED) + + bool is_datetime() const noexcept + { + return evaluate().is_datetime(); + } + + bool is_epoch_time() const noexcept + { + return evaluate().is_epoch_time(); + } + + template + void add(T&& val) + { + evaluate_with_default().add(std::forward(val)); + } + + template + array_iterator add(const_array_iterator pos, T&& val) + { + return evaluate_with_default().add(pos, std::forward(val)); + } + + // set + + template + std::pair set(const string_view_type& name, T&& val) + { + return evaluate().set(name,std::forward(val)); + } + + template + object_iterator set(object_iterator hint, const string_view_type& name, T&& val) + { + return evaluate().set(hint, name, std::forward(val)); + } + + bool has_key(const string_view_type& name) const + { + return evaluate().has_key(name); + } + + bool is_integer() const noexcept + { + return evaluate().is_int64(); + } + + bool is_uinteger() const noexcept + { + return evaluate().is_uint64(); + } + + unsigned long long as_ulonglong() const + { + return evaluate().as_ulonglong(); + } + + uint64_t as_uinteger() const + { + return evaluate().as_uinteger(); + } + + void dump(std::basic_ostream& os, const basic_json_options& options, bool pprint) const + { + evaluate().dump(os,options,pprint); + } + + void dump(std::basic_ostream& os, bool pprint) const + { + evaluate().dump(os, pprint); + } + + string_type to_string(const char_allocator_type& allocator = char_allocator_type()) const noexcept + { + return evaluate().to_string(allocator); + } + void write(basic_json_content_handler& handler) const + { + evaluate().write(handler); + } + + void write(std::basic_ostream& os) const + { + evaluate().write(os); + } + + void write(std::basic_ostream& os, const basic_json_options& options) const + { + evaluate().write(os,options); + } + + void write(std::basic_ostream& os, const basic_json_options& options, bool pprint) const + { + evaluate().write(os,options,pprint); + } + + string_type to_string(const basic_json_options& options, char_allocator_type& allocator = char_allocator_type()) const + { + return evaluate().to_string(options,allocator); + } + + range members() + { + return evaluate().members(); + } + + range members() const + { + return evaluate().members(); + } + + range elements() + { + return evaluate().elements(); + } + + range elements() const + { + return evaluate().elements(); + } + void to_stream(basic_json_content_handler& handler) const + { + evaluate().to_stream(handler); + } + + void to_stream(std::basic_ostream& os) const + { + evaluate().to_stream(os); + } + + void to_stream(std::basic_ostream& os, const basic_json_options& options) const + { + evaluate().to_stream(os,options); + } + + void to_stream(std::basic_ostream& os, const basic_json_options& options, bool pprint) const + { + evaluate().to_stream(os,options,pprint); + } +#endif + void swap(basic_json& val) + { + evaluate_with_default().swap(val); + } + + friend std::basic_ostream& operator<<(std::basic_ostream& os, const json_proxy& o) + { + o.dump(os); + return os; + } + +#if !defined(JSONCONS_NO_DEPRECATED) + + void resize_array(size_t n) + { + evaluate().resize_array(n); + } + + template + void resize_array(size_t n, T val) + { + evaluate().resize_array(n,val); + } + + object_iterator begin_members() + { + return evaluate().begin_members(); + } + + const_object_iterator begin_members() const + { + return evaluate().begin_members(); + } + + object_iterator end_members() + { + return evaluate().end_members(); + } + + const_object_iterator end_members() const + { + return evaluate().end_members(); + } + + array_iterator begin_elements() + { + return evaluate().begin_elements(); + } + + const_array_iterator begin_elements() const + { + return evaluate().begin_elements(); + } + + array_iterator end_elements() + { + return evaluate().end_elements(); + } + + const_array_iterator end_elements() const + { + return evaluate().end_elements(); + } + + template + basic_json get(const string_view_type& name, T&& default_val) const + { + return evaluate().get(name,std::forward(default_val)); + } + + const basic_json& get(const string_view_type& name) const + { + return evaluate().get(name); + } + + bool is_ulonglong() const noexcept + { + return evaluate().is_ulonglong(); + } + + bool is_longlong() const noexcept + { + return evaluate().is_longlong(); + } + + int as_int() const + { + return evaluate().as_int(); + } + + unsigned int as_uint() const + { + return evaluate().as_uint(); + } + + long as_long() const + { + return evaluate().as_long(); + } + + unsigned long as_ulong() const + { + return evaluate().as_ulong(); + } + + long long as_longlong() const + { + return evaluate().as_longlong(); + } + + bool has_member(const string_type& name) const + { + return evaluate().has_member(name); + } + + // Remove a range of elements from an array + void remove_range(size_t from_index, size_t to_index) + { + evaluate().remove_range(from_index, to_index); + } + // Remove a range of elements from an array + void remove(const string_view_type& name) + { + evaluate().remove(name); + } + void remove_member(const string_view_type& name) + { + evaluate().remove(name); + } + bool is_empty() const noexcept + { + return empty(); + } + bool is_numeric() const noexcept + { + return is_number(); + } +#endif + }; + + static basic_json parse(std::basic_istream& is) + { + parse_error_handler_type err_handler; + return parse(is,err_handler); + } + + static basic_json parse(std::basic_istream& is, parse_error_handler& err_handler) + { + json_decoder> handler; + basic_json_reader> reader(is, handler, err_handler); + reader.read_next(); + reader.check_done(); + if (!handler.is_valid()) + { + JSONCONS_THROW(json_runtime_error("Failed to parse json stream")); + } + return handler.get_result(); + } + + static basic_json parse(const string_view_type& s) + { + parse_error_handler_type err_handler; + return parse(s,err_handler); + } + +#if !defined(JSONCONS_NO_DEPRECATED) + + void add(size_t index, const basic_json& value) + { + evaluate_with_default().add(index, value); + } + + void add(size_t index, basic_json&& value) + { + evaluate_with_default().add(index, std::forward(value)); + } + + static basic_json parse(const char_type* s, size_t length) + { + parse_error_handler_type err_handler; + return parse(s,length,err_handler); + } + + static basic_json parse(const char_type* s, size_t length, parse_error_handler& err_handler) + { + return parse(string_view_type(s,length),err_handler); + } +#endif + + static basic_json parse(const string_view_type& s, parse_error_handler& err_handler) + { + json_decoder decoder; + basic_json_parser parser(err_handler); + + auto result = unicons::skip_bom(s.begin(), s.end()); + if (result.ec != unicons::encoding_errc()) + { + throw ser_error(result.ec); + } + size_t offset = result.it - s.begin(); + parser.update(s.data()+offset,s.size()-offset); + parser.parse_some(decoder); + parser.finish_parse(decoder); + parser.check_done(); + if (!decoder.is_valid()) + { + JSONCONS_THROW(json_runtime_error("Failed to parse json string")); + } + return decoder.get_result(); + } + + static basic_json parse(std::basic_istream& is, const basic_json_options& options) + { + parse_error_handler_type err_handler; + return parse(is,options,err_handler); + } + + static basic_json parse(std::basic_istream& is, const basic_json_options& options, parse_error_handler& err_handler) + { + json_decoder> handler; + basic_json_reader> reader(is, handler, options, err_handler); + reader.read_next(); + reader.check_done(); + if (!handler.is_valid()) + { + JSONCONS_THROW(json_runtime_error("Failed to parse json stream")); + } + return handler.get_result(); + } + + static basic_json parse(const string_view_type& s, const basic_json_options& options) + { + parse_error_handler_type err_handler; + return parse(s,options,err_handler); + } + + static basic_json parse(const string_view_type& s, const basic_json_options& options, parse_error_handler& err_handler) + { + json_decoder decoder; + basic_json_parser parser(options,err_handler); + + auto result = unicons::skip_bom(s.begin(), s.end()); + if (result.ec != unicons::encoding_errc()) + { + throw ser_error(result.ec); + } + size_t offset = result.it - s.begin(); + parser.update(s.data()+offset,s.size()-offset); + parser.parse_some(decoder); + parser.finish_parse(decoder); + parser.check_done(); + if (!decoder.is_valid()) + { + JSONCONS_THROW(json_runtime_error("Failed to parse json string")); + } + return decoder.get_result(); + } + + static basic_json make_array() + { + return basic_json(array()); + } + + static basic_json make_array(const array& a) + { + return basic_json(a); + } + + static basic_json make_array(const array& a, allocator_type allocator) + { + return basic_json(variant(a, semantic_tag::none, allocator)); + } + + static basic_json make_array(std::initializer_list init, const Allocator& allocator = Allocator()) + { + return array(std::move(init),allocator); + } + + static basic_json make_array(size_t n, const Allocator& allocator = Allocator()) + { + return array(n,allocator); + } + + template + static basic_json make_array(size_t n, const T& val, const Allocator& allocator = Allocator()) + { + return basic_json::array(n, val,allocator); + } + + template + static typename std::enable_if::type make_array(size_t n) + { + return array(n); + } + + template + static typename std::enable_if::type make_array(size_t n, const T& val, const Allocator& allocator = Allocator()) + { + return array(n,val,allocator); + } + + template + static typename std::enable_if<(dim>1),basic_json>::type make_array(size_t n, Args... args) + { + const size_t dim1 = dim - 1; + + basic_json val = make_array(std::forward(args)...); + val.resize(n); + for (size_t i = 0; i < n; ++i) + { + val[i] = make_array(std::forward(args)...); + } + return val; + } + + static const basic_json& null() + { + static basic_json a_null = basic_json(null_type(), semantic_tag::none); + return a_null; + } + + variant var_; + + basic_json(semantic_tag tag = semantic_tag::none) + : var_(tag) + { + } + + explicit basic_json(const Allocator& allocator, semantic_tag tag = semantic_tag::none) + : var_(object(allocator),tag) + { + } + + basic_json(const basic_json& val) + : var_(val.var_) + { + } + + basic_json(const basic_json& val, const Allocator& allocator) + : var_(val.var_,allocator) + { + } + + basic_json(basic_json&& other) noexcept + : var_(std::move(other.var_)) + { + } + + basic_json(basic_json&& other, const Allocator&) noexcept + : var_(std::move(other.var_) /*,allocator*/ ) + { + } + + basic_json(const variant& val) + : var_(val) + { + } + + basic_json(variant&& other) + : var_(std::forward(other)) + { + } + + basic_json(const array& val, semantic_tag tag = semantic_tag::none) + : var_(val, tag) + { + } + + basic_json(array&& other, semantic_tag tag = semantic_tag::none) + : var_(std::forward(other), tag) + { + } + + basic_json(const object& other, semantic_tag tag = semantic_tag::none) + : var_(other, tag) + { + } + + basic_json(object&& other, semantic_tag tag = semantic_tag::none) + : var_(std::forward(other), tag) + { + } + + template + basic_json(const json_proxy& proxy) + : var_(proxy.evaluate().var_) + { + } + + template + basic_json(const json_proxy& proxy, const Allocator& allocator) + : var_(proxy.evaluate().var_,allocator) + { + } + + template + basic_json(const T& val) + : var_(json_type_traits::to_json(val).var_) + { + } + + template + basic_json(const T& val, const Allocator& allocator) + : var_(json_type_traits::to_json(val,allocator).var_) + { + } + + basic_json(const char_type* s, semantic_tag tag = semantic_tag::none) + : var_(s, char_traits_type::length(s), tag) + { + } + + basic_json(const char_type* s, const Allocator& allocator) + : var_(s, char_traits_type::length(s), semantic_tag::none, allocator) + { + } + +#if !defined(JSONCONS_NO_DEPRECATED) + basic_json(double val, uint8_t) + : var_(val, semantic_tag::none) + { + } + basic_json(double val, + const floating_point_options&, + semantic_tag tag = semantic_tag::none) + : var_(val, tag) + { + } +#endif + + basic_json(double val, semantic_tag tag) + : var_(val, tag) + { + } + + template + basic_json(T val, semantic_tag tag, typename std::enable_if::value && std::is_signed::value>::type* = 0) + : var_(static_cast(val), tag) + { + } + + template + basic_json(T val, semantic_tag tag, typename std::enable_if::value && !std::is_signed::value>::type* = 0) + : var_(static_cast(val), tag) + { + } + + basic_json(const char_type *s, size_t length, semantic_tag tag = semantic_tag::none) + : var_(s, length, tag) + { + } + + basic_json(const string_view_type& sv, semantic_tag tag) + : var_(sv.data(), sv.length(), tag) + { + } + + basic_json(null_type val, semantic_tag tag) + : var_(val, tag) + { + } + + basic_json(bool val, semantic_tag tag) + : var_(val, tag) + { + } + + basic_json(const string_view_type& sv, semantic_tag tag, const Allocator& allocator) + : var_(sv.data(), sv.length(), tag, allocator) + { + } + + basic_json(const char_type *s, size_t length, + semantic_tag tag, const Allocator& allocator) + : var_(s, length, tag, allocator) + { + } + +#if !defined(JSONCONS_NO_DEPRECATED) + + basic_json(const byte_string_view& bs, + byte_string_chars_format encoding_hint, + semantic_tag tag = semantic_tag::none) + : var_(bs, tag) + { + switch (encoding_hint) + { + { + case byte_string_chars_format::base16: + var_ = variant(bs, semantic_tag::base16); + break; + case byte_string_chars_format::base64: + var_ = variant(bs, semantic_tag::base64); + break; + case byte_string_chars_format::base64url: + var_ = variant(bs, semantic_tag::base64url); + break; + default: + break; + } + } + } +#endif + + explicit basic_json(const byte_string_view& bs, + semantic_tag tag = semantic_tag::none) + : var_(bs, tag) + { + } + + basic_json(const byte_string_view& bs, + semantic_tag tag, + const Allocator& allocator) + : var_(bs, tag, allocator) + { + } + + explicit basic_json(const basic_bignum& bs) + : var_(bs) + { + } + + explicit basic_json(const basic_bignum& bs, const Allocator& allocator) + : var_(bs, byte_allocator_type(allocator)) + { + } + +#if !defined(JSONCONS_NO_DEPRECATED) + + template + basic_json(InputIterator first, InputIterator last, const Allocator& allocator = Allocator()) + : var_(first,last,allocator) + { + } +#endif + + ~basic_json() + { + } + + basic_json& operator=(const basic_json& rhs) + { + if (this != &rhs) + { + var_ = rhs.var_; + } + return *this; + } + + basic_json& operator=(basic_json&& rhs) noexcept + { + if (this !=&rhs) + { + var_ = std::move(rhs.var_); + } + return *this; + } + + template + basic_json& operator=(const T& val) + { + var_ = json_type_traits::to_json(val).var_; + return *this; + } + + basic_json& operator=(const char_type* s) + { + var_ = variant(s, char_traits_type::length(s), semantic_tag::none); + return *this; + } + + friend bool operator==(const basic_json& lhs, const basic_json& rhs) + { + return lhs.var_ == rhs.var_; + } + + friend bool operator!=(const basic_json& lhs, const basic_json& rhs) + { + return !(lhs == rhs); + } + + friend bool operator<(const basic_json& lhs, const basic_json& rhs) + { + return lhs.var_ < rhs.var_; + } + + friend bool operator<=(const basic_json& lhs, const basic_json& rhs) + { + return !(rhs < lhs); + } + + friend bool operator>(const basic_json& lhs, const basic_json& rhs) + { + return !(lhs <= rhs); + } + + friend bool operator>=(const basic_json& lhs, const basic_json& rhs) + { + return !(lhs < rhs); + } + + size_t size() const noexcept + { + switch (var_.get_storage_type()) + { + case storage_type::empty_object_val: + return 0; + case storage_type::object_val: + return object_value().size(); + case storage_type::array_val: + return array_value().size(); + default: + return 0; + } + } + + basic_json& operator[](size_t i) + { + return at(i); + } + + const basic_json& operator[](size_t i) const + { + return at(i); + } + + json_proxy operator[](const string_view_type& name) + { + switch (var_.get_storage_type()) + { + case storage_type::empty_object_val: + create_object_implicitly(); + JSONCONS_FALLTHROUGH; + case storage_type::object_val: + return json_proxy(*this, name.data(),name.length()); + break; + default: + JSONCONS_THROW(not_an_object(name.data(),name.length())); + break; + } + } + + const basic_json& operator[](const string_view_type& name) const + { + return at(name); + } + + template + void dump(std::basic_string& s) const + { + typedef std::basic_string string_type; + basic_json_compressed_encoder> encoder(s); + dump(encoder); + } + + template + void dump(std::basic_string& s, indenting line_indent) const + { + typedef std::basic_string string_type; + if (line_indent == indenting::indent) + { + basic_json_encoder> encoder(s); + dump(encoder); + } + else + { + basic_json_compressed_encoder> encoder(s); + dump(encoder); + } + } + + template + void dump(std::basic_string& s, + const basic_json_options& options) const + { + typedef std::basic_string string_type; + basic_json_compressed_encoder> encoder(s, options); + dump(encoder); + } + + template + void dump(std::basic_string& s, + const basic_json_options& options, + indenting line_indent) const + { + typedef std::basic_string string_type; + if (line_indent == indenting::indent) + { + basic_json_encoder> encoder(s, options); + dump(encoder); + } + else + { + basic_json_compressed_encoder> encoder(s, options); + dump(encoder); + } + } + + void dump(basic_json_content_handler& handler) const + { + dump_noflush(handler); + handler.flush(); + } + + void dump(std::basic_ostream& os) const + { + basic_json_compressed_encoder encoder(os); + dump(encoder); + } + + void dump(std::basic_ostream& os, indenting line_indent) const + { + if (line_indent == indenting::indent) + { + basic_json_encoder encoder(os); + dump(encoder); + } + else + { + basic_json_compressed_encoder encoder(os); + dump(encoder); + } + } + + void dump(std::basic_ostream& os, const basic_json_options& options) const + { + basic_json_compressed_encoder encoder(os, options); + dump(encoder); + } + + void dump(std::basic_ostream& os, const basic_json_options& options, indenting line_indent) const + { + if (line_indent == indenting::indent) + { + basic_json_encoder encoder(os, options); + dump(encoder); + } + else + { + basic_json_compressed_encoder encoder(os, options); + dump(encoder); + } + } + + string_type to_string(const char_allocator_type& allocator=char_allocator_type()) const noexcept + { + string_type s(allocator); + basic_json_compressed_encoder> encoder(s); + dump(encoder); + return s; + } + + string_type to_string(const basic_json_options& options, + const char_allocator_type& allocator=char_allocator_type()) const + { + string_type s(allocator); + basic_json_compressed_encoder> encoder(s,options); + dump(encoder); + return s; + } + +#if !defined(JSONCONS_NO_DEPRECATED) + void dump_fragment(basic_json_content_handler& handler) const + { + dump(handler); + } + + void dump_body(basic_json_content_handler& handler) const + { + dump(handler); + } + + void dump(std::basic_ostream& os, bool pprint) const + { + if (pprint) + { + basic_json_encoder encoder(os); + dump(encoder); + } + else + { + basic_json_compressed_encoder encoder(os); + dump(encoder); + } + } + + void dump(std::basic_ostream& os, const basic_json_options& options, bool pprint) const + { + if (pprint) + { + basic_json_encoder encoder(os, options); + dump(encoder); + } + else + { + basic_json_compressed_encoder encoder(os, options); + dump(encoder); + } + } + + void write_body(basic_json_content_handler& handler) const + { + dump(handler); + } + void write(basic_json_content_handler& handler) const + { + dump(handler); + } + + void write(std::basic_ostream& os) const + { + dump(os); + } + + void write(std::basic_ostream& os, const basic_json_options& options) const + { + dump(os,options); + } + + void write(std::basic_ostream& os, const basic_json_options& options, bool pprint) const + { + dump(os,options,pprint); + } + + void to_stream(basic_json_content_handler& handler) const + { + dump(handler); + } + + void to_stream(std::basic_ostream& os) const + { + dump(os); + } + + void to_stream(std::basic_ostream& os, const basic_json_options& options) const + { + dump(os,options); + } + + void to_stream(std::basic_ostream& os, const basic_json_options& options, bool pprint) const + { + dump(os,options,pprint ? indenting::indent : indenting::no_indent); + } +#endif + bool is_null() const noexcept + { + return var_.get_storage_type() == storage_type::null_val; + } + + allocator_type get_allocator() const + { + switch (var_.get_storage_type()) + { + case storage_type::long_string_val: + { + return var_.string_data_cast()->get_allocator(); + } + case storage_type::byte_string_val: + { + return var_.byte_string_data_cast()->get_allocator(); + } + case storage_type::array_val: + { + return var_.array_data_cast()->get_allocator(); + } + case storage_type::object_val: + { + return var_.object_data_cast()->get_allocator(); + } + default: + return allocator_type(); + } + } + + bool contains(const string_view_type& name) const + { + switch (var_.get_storage_type()) + { + case storage_type::object_val: + { + const_object_iterator it = object_value().find(name); + return it != object_range().end(); + } + break; + default: + return false; + } + } + + size_t count(const string_view_type& name) const + { + switch (var_.get_storage_type()) + { + case storage_type::object_val: + { + auto it = object_value().find(name); + if (it == object_range().end()) + { + return 0; + } + size_t count = 0; + while (it != object_range().end()&& it->key() == name) + { + ++count; + ++it; + } + return count; + } + break; + default: + return 0; + } + } + + template + bool is(Args&&... args) const + { + return json_type_traits::is(*this,std::forward(args)...); + } + + bool is_string() const noexcept + { + return (var_.get_storage_type() == storage_type::long_string_val) || (var_.get_storage_type() == storage_type::short_string_val); + } + + bool is_string_view() const noexcept + { + return is_string(); + } + + bool is_byte_string() const noexcept + { + return var_.get_storage_type() == storage_type::byte_string_val; + } + + bool is_byte_string_view() const noexcept + { + return is_byte_string(); + } + + bool is_bignum() const + { + switch (get_storage_type()) + { + case storage_type::short_string_val: + case storage_type::long_string_val: + return jsoncons::detail::is_integer(as_string_view().data(), as_string_view().length()); + case storage_type::int64_val: + case storage_type::uint64_val: + return true; + default: + return false; + } + } + + bool is_bool() const noexcept + { + return var_.get_storage_type() == storage_type::bool_val; + } + + bool is_object() const noexcept + { + return var_.get_storage_type() == storage_type::object_val || var_.get_storage_type() == storage_type::empty_object_val; + } + + bool is_array() const noexcept + { + return var_.get_storage_type() == storage_type::array_val; + } + + bool is_int64() const noexcept + { + return var_.get_storage_type() == storage_type::int64_val || (var_.get_storage_type() == storage_type::uint64_val&& (as_integer() <= static_cast((std::numeric_limits::max)()))); + } + + bool is_uint64() const noexcept + { + return var_.get_storage_type() == storage_type::uint64_val || (var_.get_storage_type() == storage_type::int64_val&& as_integer() >= 0); + } + + bool is_double() const noexcept + { + return var_.get_storage_type() == storage_type::double_val; + } + + bool is_number() const noexcept + { + switch (var_.get_storage_type()) + { + case storage_type::int64_val: + case storage_type::uint64_val: + case storage_type::double_val: + return true; + case storage_type::short_string_val: + case storage_type::long_string_val: + return var_.get_semantic_tag() == semantic_tag::bigint || + var_.get_semantic_tag() == semantic_tag::bigdec || + var_.get_semantic_tag() == semantic_tag::bigfloat; +#if !defined(JSONCONS_NO_DEPRECATED) + case storage_type::array_val: + return var_.get_semantic_tag() == semantic_tag::bigfloat; +#endif + default: + return false; + } + } + + bool empty() const noexcept + { + switch (var_.get_storage_type()) + { + case storage_type::byte_string_val: + return var_.byte_string_data_cast()->length() == 0; + break; + case storage_type::short_string_val: + return var_.short_string_data_cast()->length() == 0; + case storage_type::long_string_val: + return var_.string_data_cast()->length() == 0; + case storage_type::array_val: + return array_value().size() == 0; + case storage_type::empty_object_val: + return true; + case storage_type::object_val: + return object_value().size() == 0; + default: + return false; + } + } + + size_t capacity() const + { + switch (var_.get_storage_type()) + { + case storage_type::array_val: + return array_value().capacity(); + case storage_type::object_val: + return object_value().capacity(); + default: + return 0; + } + } + + template + void create_object_implicitly() + { + static_assert(is_stateless::value, "Cannot create object implicitly - allocator is stateful."); + var_ = variant(object(Allocator()), semantic_tag::none); + } + + void reserve(size_t n) + { + switch (var_.get_storage_type()) + { + case storage_type::array_val: + array_value().reserve(n); + break; + case storage_type::empty_object_val: + { + create_object_implicitly(); + object_value().reserve(n); + } + break; + case storage_type::object_val: + { + object_value().reserve(n); + } + break; + default: + break; + } + } + + void resize(size_t n) + { + switch (var_.get_storage_type()) + { + case storage_type::array_val: + array_value().resize(n); + break; + default: + break; + } + } + + template + void resize(size_t n, T val) + { + switch (var_.get_storage_type()) + { + case storage_type::array_val: + array_value().resize(n, val); + break; + default: + break; + } + } + + template + T as(Args&&... args) const + { + return json_type_traits::as(*this,std::forward(args)...); + } + + template + typename std::enable_if::value,T>::type + as(const char_allocator_type& allocator) const + { + return json_type_traits::as(*this,allocator); + } + + bool as_bool() const + { + switch (var_.get_storage_type()) + { + case storage_type::short_string_val: + case storage_type::long_string_val: + if (var_.get_semantic_tag() == semantic_tag::bigint) + { + return static_cast(var_.as_bignum()); + } + + try + { + basic_json j = basic_json::parse(as_string_view()); + return j.as_bool(); + } + catch (...) + { + JSONCONS_THROW(json_runtime_error("Not a bool")); + } + break; + case storage_type::bool_val: + return var_.bool_data_cast()->value(); + case storage_type::double_val: + return var_.double_data_cast()->value() != 0.0; + case storage_type::int64_val: + return var_.int64_data_cast()->value() != 0; + case storage_type::uint64_val: + return var_.uint64_data_cast()->value() != 0; + default: + JSONCONS_THROW(json_runtime_error("Not a bool")); + } + } + + template + T as_integer() const + { + switch (var_.get_storage_type()) + { + case storage_type::short_string_val: + case storage_type::long_string_val: + { + auto result = jsoncons::detail::to_integer(as_string_view().data(), as_string_view().length()); + if (result.ec != jsoncons::detail::to_integer_errc()) + { + JSONCONS_THROW(json_runtime_error(make_error_code(result.ec).message())); + } + return result.value; + } + case storage_type::double_val: + return static_cast(var_.double_data_cast()->value()); + case storage_type::int64_val: + return static_cast(var_.int64_data_cast()->value()); + case storage_type::uint64_val: + return static_cast(var_.uint64_data_cast()->value()); + case storage_type::bool_val: + return static_cast(var_.bool_data_cast()->value() ? 1 : 0); + default: + JSONCONS_THROW(json_runtime_error("Not an integer")); + } + } + +#if !defined(JSONCONS_NO_DEPRECATED) + size_t precision() const + { + switch (var_.get_storage_type()) + { + case storage_type::double_val: + return 0; + default: + JSONCONS_THROW(json_runtime_error("Not a double")); + } + } + + size_t decimal_places() const + { + switch (var_.get_storage_type()) + { + case storage_type::double_val: + return 0; + default: + JSONCONS_THROW(json_runtime_error("Not a double")); + } + } +#endif + + double as_double() const + { + switch (var_.get_storage_type()) + { + case storage_type::short_string_val: + case storage_type::long_string_val: + { + jsoncons::detail::string_to_double to_double; + // to_double() throws std::invalid_argument if conversion fails + return to_double(as_cstring(), as_string_view().length()); + } + case storage_type::double_val: + return var_.double_data_cast()->value(); + case storage_type::int64_val: + return static_cast(var_.int64_data_cast()->value()); + case storage_type::uint64_val: + return static_cast(var_.uint64_data_cast()->value()); +#if !defined(JSONCONS_NO_DEPRECATED) + case storage_type::array_val: + if (get_semantic_tag() == semantic_tag::bigfloat) + { + jsoncons::detail::string_to_double to_double; + string_type s = as_string(); + return to_double(s.c_str(), s.length()); + } + else + { + JSONCONS_THROW(json_runtime_error("Not a double")); + } +#endif + default: + JSONCONS_THROW(json_runtime_error("Not a double")); + } + } + + string_view_type as_string_view() const + { + return var_.as_string_view(); + } + + byte_string_view as_byte_string_view() const + { + return var_.as_byte_string_view(); + } + + template > + basic_byte_string as_byte_string() const + { + return var_.template as_byte_string(); + } + + basic_bignum as_bignum() const + { + return var_.as_bignum(); + } + + template > + string_type as_string() const + { + return as_string(basic_json_options(),SAllocator()); + } + + template > + string_type as_string(const SAllocator& allocator) const + { + return as_string(basic_json_options(),allocator); + } + + template > + string_type as_string(const basic_json_options& options) const + { + return as_string(options,SAllocator()); + } + + template > + string_type as_string(const basic_json_options& options, + const SAllocator& allocator) const + { + switch (var_.get_storage_type()) + { + case storage_type::short_string_val: + case storage_type::long_string_val: + { + return string_type(as_string_view().data(),as_string_view().length(),allocator); + } + case storage_type::byte_string_val: + { + string_type s(allocator); + byte_string_chars_format format = jsoncons::detail::resolve_byte_string_chars_format(options.byte_string_format(), + byte_string_chars_format::none, + byte_string_chars_format::base64url); + switch (format) + { + case byte_string_chars_format::base64: + encode_base64(var_.byte_string_data_cast()->begin(), + var_.byte_string_data_cast()->end(), + s); + break; + case byte_string_chars_format::base16: + encode_base16(var_.byte_string_data_cast()->begin(), + var_.byte_string_data_cast()->end(), + s); + break; + default: + encode_base64url(var_.byte_string_data_cast()->begin(), + var_.byte_string_data_cast()->end(), + s); + break; + } + return s; + } + case storage_type::array_val: + { + string_type s(allocator); +#if !defined(JSONCONS_NO_DEPRECATED) + if (get_semantic_tag() == semantic_tag::bigfloat) + { + JSONCONS_ASSERT(size() == 2); + int64_t exp = at(0).template as_integer(); + string_type mantissa = at(1).as_string(); + bignum n(mantissa); + int64_t new_exp = 0; + bignum five(5); + if (exp > 0) + { + new_exp = static_cast(std::floor(exp*std::log(2)/std::log(10))); + bignum five_power = power(five,(unsigned)new_exp); + uint64_t binShift = exp - new_exp; + n = ((n) << (unsigned)binShift)/five_power; + } + else + { + new_exp = static_cast(std::ceil(-exp*std::log(2)/std::log(10))); + bignum five_power = power(five,(unsigned)new_exp); + uint64_t binShift = -exp - new_exp; + n = (n*five_power) >> (unsigned)binShift; + } + + std::string str; + n.dump(str); + if (str[0] == '-') + { + s.push_back('-'); + jsoncons::detail::prettify_string(str.c_str()+1, str.size()-1, -(int)new_exp, -4, 17, s); + } + else + { + jsoncons::detail::prettify_string(str.c_str(), str.size(), -(int)new_exp, -4, 17, s); + } + } + else +#endif + { + basic_json_compressed_encoder> encoder(s,options); + dump(encoder); + } + return s; + } + default: + { + string_type s(allocator); + basic_json_compressed_encoder> encoder(s,options); + dump(encoder); + return s; + } + } + } + + const char_type* as_cstring() const + { + switch (var_.get_storage_type()) + { + case storage_type::short_string_val: + return var_.short_string_data_cast()->c_str(); + case storage_type::long_string_val: + return var_.string_data_cast()->c_str(); + default: + JSONCONS_THROW(json_runtime_error("Not a cstring")); + } + } + +#if !defined(JSONCONS_NO_DEPRECATED) + + bool is_datetime() const noexcept + { + return var_.get_semantic_tag() == semantic_tag::datetime; + } + + bool is_epoch_time() const noexcept + { + return var_.get_semantic_tag() == semantic_tag::timestamp; + } + + bool has_key(const string_view_type& name) const + { + return contains(name); + } + + bool is_integer() const noexcept + { + return var_.get_storage_type() == storage_type::int64_val || (var_.get_storage_type() == storage_type::uint64_val&& (as_integer() <= static_cast((std::numeric_limits::max)()))); + } + + bool is_uinteger() const noexcept + { + return var_.get_storage_type() == storage_type::uint64_val || (var_.get_storage_type() == storage_type::int64_val&& as_integer() >= 0); + } + + int64_t as_uinteger() const + { + return as_integer(); + } + + size_t double_precision() const + { + switch (var_.get_storage_type()) + { + case storage_type::double_val: + return 0; + default: + JSONCONS_THROW(json_runtime_error("Not a double")); + } + } +#endif + + basic_json& at(const string_view_type& name) + { + switch (var_.get_storage_type()) + { + case storage_type::empty_object_val: + JSONCONS_THROW(key_not_found(name.data(),name.length())); + case storage_type::object_val: + { + auto it = object_value().find(name); + if (it == object_range().end()) + { + JSONCONS_THROW(key_not_found(name.data(),name.length())); + } + return it->value(); + } + break; + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + basic_json& evaluate() + { + return *this; + } + + basic_json& evaluate_with_default() + { + return *this; + } + + const basic_json& evaluate() const + { + return *this; + } + basic_json& evaluate(const string_view_type& name) + { + return at(name); + } + + const basic_json& evaluate(const string_view_type& name) const + { + return at(name); + } + + const basic_json& at(const string_view_type& name) const + { + switch (var_.get_storage_type()) + { + case storage_type::empty_object_val: + JSONCONS_THROW(key_not_found(name.data(),name.length())); + case storage_type::object_val: + { + auto it = object_value().find(name); + if (it == object_range().end()) + { + JSONCONS_THROW(key_not_found(name.data(),name.length())); + } + return it->value(); + } + break; + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + basic_json& at(size_t i) + { + switch (var_.get_storage_type()) + { + case storage_type::array_val: + if (i >= array_value().size()) + { + JSONCONS_THROW(json_runtime_error("Invalid array subscript")); + } + return array_value().operator[](i); + case storage_type::object_val: + return object_value().at(i); + default: + JSONCONS_THROW(json_runtime_error("Index on non-array value not supported")); + } + } + + const basic_json& at(size_t i) const + { + switch (var_.get_storage_type()) + { + case storage_type::array_val: + if (i >= array_value().size()) + { + JSONCONS_THROW(json_runtime_error("Invalid array subscript")); + } + return array_value().operator[](i); + case storage_type::object_val: + return object_value().at(i); + default: + JSONCONS_THROW(json_runtime_error("Index on non-array value not supported")); + } + } + + object_iterator find(const string_view_type& name) + { + switch (var_.get_storage_type()) + { + case storage_type::empty_object_val: + return object_range().end(); + case storage_type::object_val: + return object_value().find(name); + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + const_object_iterator find(const string_view_type& name) const + { + switch (var_.get_storage_type()) + { + case storage_type::empty_object_val: + return object_range().end(); + case storage_type::object_val: + return object_value().find(name); + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + template + T get_with_default(const string_view_type& name, const T& default_val) const + { + switch (var_.get_storage_type()) + { + case storage_type::empty_object_val: + { + return default_val; + } + case storage_type::object_val: + { + const_object_iterator it = object_value().find(name); + if (it != object_range().end()) + { + return it->value().template as(); + } + else + { + return default_val; + } + } + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + template> + T get_with_default(const string_view_type& name, const CharT* default_val) const + { + switch (var_.get_storage_type()) + { + case storage_type::empty_object_val: + { + return T(default_val); + } + case storage_type::object_val: + { + const_object_iterator it = object_value().find(name); + if (it != object_range().end()) + { + return it->value().template as(); + } + else + { + return T(default_val); + } + } + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + // Modifiers + + void shrink_to_fit() + { + switch (var_.get_storage_type()) + { + case storage_type::array_val: + array_value().shrink_to_fit(); + break; + case storage_type::object_val: + object_value().shrink_to_fit(); + break; + default: + break; + } + } + + void clear() + { + switch (var_.get_storage_type()) + { + case storage_type::array_val: + array_value().clear(); + break; + case storage_type::object_val: + object_value().clear(); + break; + default: + break; + } + } + + void erase(const_object_iterator pos) + { + switch (var_.get_storage_type()) + { + case storage_type::empty_object_val: + break; + case storage_type::object_val: + object_value().erase(pos); + break; + default: + JSONCONS_THROW(json_runtime_error("Not an object")); + break; + } + } + + void erase(const_object_iterator first, const_object_iterator last) + { + switch (var_.get_storage_type()) + { + case storage_type::empty_object_val: + break; + case storage_type::object_val: + object_value().erase(first, last); + break; + default: + JSONCONS_THROW(json_runtime_error("Not an object")); + break; + } + } + + void erase(const_array_iterator pos) + { + switch (var_.get_storage_type()) + { + case storage_type::array_val: + array_value().erase(pos); + break; + default: + JSONCONS_THROW(json_runtime_error("Not an array")); + break; + } + } + + void erase(const_array_iterator first, const_array_iterator last) + { + switch (var_.get_storage_type()) + { + case storage_type::array_val: + array_value().erase(first, last); + break; + default: + JSONCONS_THROW(json_runtime_error("Not an array")); + break; + } + } + + // Removes all elements from an array value whose index is between from_index, inclusive, and to_index, exclusive. + + void erase(const string_view_type& name) + { + switch (var_.get_storage_type()) + { + case storage_type::empty_object_val: + break; + case storage_type::object_val: + object_value().erase(name); + break; + default: + JSONCONS_THROW(not_an_object(name.data(),name.length())); + break; + } + } + + template + std::pair insert_or_assign(const string_view_type& name, T&& val) + { + switch (var_.get_storage_type()) + { + case storage_type::empty_object_val: + create_object_implicitly(); + JSONCONS_FALLTHROUGH; + case storage_type::object_val: + return object_value().insert_or_assign(name, std::forward(val)); + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + template + std::pair try_emplace(const string_view_type& name, Args&&... args) + { + switch (var_.get_storage_type()) + { + case storage_type::empty_object_val: + create_object_implicitly(); + JSONCONS_FALLTHROUGH; + case storage_type::object_val: + return object_value().try_emplace(name, std::forward(args)...); + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + // merge + + void merge(const basic_json& source) + { + switch (var_.get_storage_type()) + { + case storage_type::empty_object_val: + create_object_implicitly(); + JSONCONS_FALLTHROUGH; + case storage_type::object_val: + return object_value().merge(source.object_value()); + default: + { + JSONCONS_THROW(json_runtime_error("Attempting to merge a value that is not an object")); + } + } + } + + void merge(basic_json&& source) + { + switch (var_.get_storage_type()) + { + case storage_type::empty_object_val: + create_object_implicitly(); + JSONCONS_FALLTHROUGH; + case storage_type::object_val: + return object_value().merge(std::move(source.object_value())); + default: + { + JSONCONS_THROW(json_runtime_error("Attempting to merge a value that is not an object")); + } + } + } + + void merge(object_iterator hint, const basic_json& source) + { + switch (var_.get_storage_type()) + { + case storage_type::empty_object_val: + create_object_implicitly(); + JSONCONS_FALLTHROUGH; + case storage_type::object_val: + return object_value().merge(hint, source.object_value()); + default: + { + JSONCONS_THROW(json_runtime_error("Attempting to merge a value that is not an object")); + } + } + } + + void merge(object_iterator hint, basic_json&& source) + { + switch (var_.get_storage_type()) + { + case storage_type::empty_object_val: + create_object_implicitly(); + JSONCONS_FALLTHROUGH; + case storage_type::object_val: + return object_value().merge(hint, std::move(source.object_value())); + default: + { + JSONCONS_THROW(json_runtime_error("Attempting to merge a value that is not an object")); + } + } + } + + // merge_or_update + + void merge_or_update(const basic_json& source) + { + switch (var_.get_storage_type()) + { + case storage_type::empty_object_val: + create_object_implicitly(); + JSONCONS_FALLTHROUGH; + case storage_type::object_val: + return object_value().merge_or_update(source.object_value()); + default: + { + JSONCONS_THROW(json_runtime_error("Attempting to merge or update a value that is not an object")); + } + } + } + + void merge_or_update(basic_json&& source) + { + switch (var_.get_storage_type()) + { + case storage_type::empty_object_val: + create_object_implicitly(); + JSONCONS_FALLTHROUGH; + case storage_type::object_val: + return object_value().merge_or_update(std::move(source.object_value())); + default: + { + JSONCONS_THROW(json_runtime_error("Attempting to merge or update a value that is not an object")); + } + } + } + + void merge_or_update(object_iterator hint, const basic_json& source) + { + switch (var_.get_storage_type()) + { + case storage_type::empty_object_val: + create_object_implicitly(); + JSONCONS_FALLTHROUGH; + case storage_type::object_val: + return object_value().merge_or_update(hint, source.object_value()); + default: + { + JSONCONS_THROW(json_runtime_error("Attempting to merge or update a value that is not an object")); + } + } + } + + void merge_or_update(object_iterator hint, basic_json&& source) + { + switch (var_.get_storage_type()) + { + case storage_type::empty_object_val: + create_object_implicitly(); + JSONCONS_FALLTHROUGH; + case storage_type::object_val: + return object_value().merge_or_update(hint, std::move(source.object_value())); + default: + { + JSONCONS_THROW(json_runtime_error("Attempting to merge or update a value that is not an object")); + } + } + } + + template + object_iterator insert_or_assign(object_iterator hint, const string_view_type& name, T&& val) + { + switch (var_.get_storage_type()) + { + case storage_type::empty_object_val: + create_object_implicitly(); + JSONCONS_FALLTHROUGH; + case storage_type::object_val: + return object_value().insert_or_assign(hint, name, std::forward(val)); + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + template + object_iterator try_emplace(object_iterator hint, const string_view_type& name, Args&&... args) + { + switch (var_.get_storage_type()) + { + case storage_type::empty_object_val: + create_object_implicitly(); + JSONCONS_FALLTHROUGH; + case storage_type::object_val: + return object_value().try_emplace(hint, name, std::forward(args)...); + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + template + array_iterator insert(const_array_iterator pos, T&& val) + { + switch (var_.get_storage_type()) + { + case storage_type::array_val: + return array_value().insert(pos, std::forward(val)); + break; + default: + { + JSONCONS_THROW(json_runtime_error("Attempting to insert into a value that is not an array")); + } + } + } + + template + array_iterator insert(const_array_iterator pos, InputIt first, InputIt last) + { + switch (var_.get_storage_type()) + { + case storage_type::array_val: + return array_value().insert(pos, first, last); + break; + default: + { + JSONCONS_THROW(json_runtime_error("Attempting to insert into a value that is not an array")); + } + } + } + + template + void insert(InputIt first, InputIt last) + { + switch (var_.get_storage_type()) + { + case storage_type::empty_object_val: + case storage_type::object_val: + return object_value().insert(first, last, get_key_value()); + break; + default: + { + JSONCONS_THROW(json_runtime_error("Attempting to insert into a value that is not an object")); + } + } + } + + template + void insert(sorted_unique_range_tag tag, InputIt first, InputIt last) + { + switch (var_.get_storage_type()) + { + case storage_type::empty_object_val: + case storage_type::object_val: + return object_value().insert(tag, first, last, get_key_value()); + break; + default: + { + JSONCONS_THROW(json_runtime_error("Attempting to insert into a value that is not an object")); + } + } + } + + template + array_iterator emplace(const_array_iterator pos, Args&&... args) + { + switch (var_.get_storage_type()) + { + case storage_type::array_val: + return array_value().emplace(pos, std::forward(args)...); + break; + default: + { + JSONCONS_THROW(json_runtime_error("Attempting to insert into a value that is not an array")); + } + } + } + + template + basic_json& emplace_back(Args&&... args) + { + switch (var_.get_storage_type()) + { + case storage_type::array_val: + return array_value().emplace_back(std::forward(args)...); + default: + { + JSONCONS_THROW(json_runtime_error("Attempting to insert into a value that is not an array")); + } + } + } + + storage_type get_storage_type() const + { + return var_.get_storage_type(); + } + + semantic_tag get_semantic_tag() const + { + return var_.get_semantic_tag(); + } + + void swap(basic_json& b) + { + var_.swap(b.var_); + } + + friend void swap(basic_json& a, basic_json& b) + { + a.swap(b); + } + + template + void push_back(T&& val) + { + switch (var_.get_storage_type()) + { + case storage_type::array_val: + array_value().push_back(std::forward(val)); + break; + default: + { + JSONCONS_THROW(json_runtime_error("Attempting to insert into a value that is not an array")); + } + } + } + +#if !defined(JSONCONS_NO_DEPRECATED) + + template + void add(T&& val) + { + push_back(std::forward(val)); + } + + template + array_iterator add(const_array_iterator pos, T&& val) + { + return insert(pos, std::forward(val)); + } + + template + std::pair set(const string_view_type& name, T&& val) + { + return insert_or_assign(name, std::forward(val)); + } + + // set + + template + object_iterator set(object_iterator hint, const string_view_type& name, T&& val) + { + return insert_or_assign(hint, name, std::forward(val)); + } + + static basic_json parse_file(const std::basic_string& filename) + { + parse_error_handler_type err_handler; + return parse_file(filename,err_handler); + } + + static basic_json parse_file(const std::basic_string& filename, + parse_error_handler& err_handler) + { + std::basic_ifstream is(filename); + return parse(is,err_handler); + } + + static basic_json parse_stream(std::basic_istream& is) + { + return parse(is); + } + static basic_json parse_stream(std::basic_istream& is, parse_error_handler& err_handler) + { + return parse(is,err_handler); + } + + static basic_json parse_string(const string_type& s) + { + return parse(s); + } + + static basic_json parse_string(const string_type& s, parse_error_handler& err_handler) + { + return parse(s,err_handler); + } + + void resize_array(size_t n) + { + resize(n); + } + + template + void resize_array(size_t n, T val) + { + resize(n,val); + } + + object_iterator begin_members() + { + return object_range().begin(); + } + + const_object_iterator begin_members() const + { + return object_range().begin(); + } + + object_iterator end_members() + { + return object_range().end(); + } + + const_object_iterator end_members() const + { + return object_range().end(); + } + + array_iterator begin_elements() + { + return array_range().begin(); + } + + const_array_iterator begin_elements() const + { + return array_range().begin(); + } + + array_iterator end_elements() + { + return array_range().end(); + } + + const_array_iterator end_elements() const + { + return array_range().end(); + } + + template + basic_json get(const string_view_type& name, T&& default_val) const + { + switch (var_.get_storage_type()) + { + case storage_type::empty_object_val: + { + return basic_json(std::forward(default_val)); + } + case storage_type::object_val: + { + const_object_iterator it = object_value().find(name); + if (it != object_range().end()) + { + return it->value(); + } + else + { + return basic_json(std::forward(default_val)); + } + } + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + const basic_json& get(const string_view_type& name) const + { + static const basic_json a_null = null_type(); + + switch (var_.get_storage_type()) + { + case storage_type::empty_object_val: + return a_null; + case storage_type::object_val: + { + const_object_iterator it = object_value().find(name); + return it != object_range().end() ? it->value() : a_null; + } + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + bool is_longlong() const noexcept + { + return var_.get_storage_type() == storage_type::int64_val; + } + + bool is_ulonglong() const noexcept + { + return var_.get_storage_type() == storage_type::uint64_val; + } + + long long as_longlong() const + { + return as_integer(); + } + + unsigned long long as_ulonglong() const + { + return as_integer(); + } + + int as_int() const + { + switch (var_.get_storage_type()) + { + case storage_type::double_val: + return static_cast(var_.double_data_cast()->value()); + case storage_type::int64_val: + return static_cast(var_.int64_data_cast()->value()); + case storage_type::uint64_val: + return static_cast(var_.uint64_data_cast()->value()); + case storage_type::bool_val: + return var_.bool_data_cast()->value() ? 1 : 0; + default: + JSONCONS_THROW(json_runtime_error("Not an int")); + } + } + + unsigned int as_uint() const + { + switch (var_.get_storage_type()) + { + case storage_type::double_val: + return static_cast(var_.double_data_cast()->value()); + case storage_type::int64_val: + return static_cast(var_.int64_data_cast()->value()); + case storage_type::uint64_val: + return static_cast(var_.uint64_data_cast()->value()); + case storage_type::bool_val: + return var_.bool_data_cast()->value() ? 1 : 0; + default: + JSONCONS_THROW(json_runtime_error("Not an unsigned int")); + } + } + + long as_long() const + { + switch (var_.get_storage_type()) + { + case storage_type::double_val: + return static_cast(var_.double_data_cast()->value()); + case storage_type::int64_val: + return static_cast(var_.int64_data_cast()->value()); + case storage_type::uint64_val: + return static_cast(var_.uint64_data_cast()->value()); + case storage_type::bool_val: + return var_.bool_data_cast()->value() ? 1 : 0; + default: + JSONCONS_THROW(json_runtime_error("Not a long")); + } + } + + unsigned long as_ulong() const + { + switch (var_.get_storage_type()) + { + case storage_type::double_val: + return static_cast(var_.double_data_cast()->value()); + case storage_type::int64_val: + return static_cast(var_.int64_data_cast()->value()); + case storage_type::uint64_val: + return static_cast(var_.uint64_data_cast()->value()); + case storage_type::bool_val: + return var_.bool_data_cast()->value() ? 1 : 0; + default: + JSONCONS_THROW(json_runtime_error("Not an unsigned long")); + } + } + + bool has_member(const string_type& name) const + { + switch (var_.get_storage_type()) + { + case storage_type::object_val: + { + const_object_iterator it = object_value().find(name); + return it != object_range().end(); + } + break; + default: + return false; + } + } + + void remove_range(size_t from_index, size_t to_index) + { + switch (var_.get_storage_type()) + { + case storage_type::array_val: + array_value().remove_range(from_index, to_index); + break; + default: + break; + } + } + // Removes all elements from an array value whose index is between from_index, inclusive, and to_index, exclusive. + + void remove(const string_view_type& name) + { + erase(name); + } + void remove_member(const string_view_type& name) + { + erase(name); + } + // Removes a member from an object value + + bool is_empty() const noexcept + { + return empty(); + } + bool is_numeric() const noexcept + { + return is_number(); + } + + template + static typename std::enable_if::type make_multi_array() + { + return make_array(); + } + template + static typename std::enable_if::type make_multi_array(size_t n) + { + return make_array(n); + } + template + static typename std::enable_if::type make_multi_array(size_t n, T val) + { + return make_array(n,val); + } + template + static typename std::enable_if::type make_multi_array(size_t m, size_t n) + { + return make_array<2>(m, n); + } + template + static typename std::enable_if::type make_multi_array(size_t m, size_t n, T val) + { + return make_array<2>(m, n, val); + } + template + static typename std::enable_if::type make_multi_array(size_t m, size_t n, size_t k) + { + return make_array<3>(m, n, k); + } + template + static typename std::enable_if::type make_multi_array(size_t m, size_t n, size_t k, T val) + { + return make_array<3>(m, n, k, val); + } + range members() + { + return object_range(); + } + + range members() const + { + return object_range(); + } + + range elements() + { + return array_range(); + } + + range elements() const + { + return array_range(); + } +#endif + + range object_range() + { + static basic_json empty_object = object(); + switch (var_.get_storage_type()) + { + case storage_type::empty_object_val: + return range(empty_object.object_range().begin(), empty_object.object_range().end()); + case storage_type::object_val: + return range(object_value().begin(),object_value().end()); + default: + JSONCONS_THROW(json_runtime_error("Not an object")); + } + } + + range object_range() const + { + static const basic_json empty_object = object(); + switch (var_.get_storage_type()) + { + case storage_type::empty_object_val: + return range(empty_object.object_range().begin(), empty_object.object_range().end()); + case storage_type::object_val: + return range(object_value().begin(),object_value().end()); + default: + JSONCONS_THROW(json_runtime_error("Not an object")); + } + } + + range array_range() + { + switch (var_.get_storage_type()) + { + case storage_type::array_val: + return range(array_value().begin(),array_value().end()); + default: + JSONCONS_THROW(json_runtime_error("Not an array")); + } + } + + range array_range() const + { + switch (var_.get_storage_type()) + { + case storage_type::array_val: + return range(array_value().begin(),array_value().end()); + default: + JSONCONS_THROW(json_runtime_error("Not an array")); + } + } + + array& array_value() + { + switch (var_.get_storage_type()) + { + case storage_type::array_val: + return var_.array_data_cast()->value(); + default: + JSONCONS_THROW(json_runtime_error("Bad array cast")); + break; + } + } + + const array& array_value() const + { + switch (var_.get_storage_type()) + { + case storage_type::array_val: + return var_.array_data_cast()->value(); + default: + JSONCONS_THROW(json_runtime_error("Bad array cast")); + break; + } + } + + object& object_value() + { + switch (var_.get_storage_type()) + { + case storage_type::empty_object_val: + create_object_implicitly(); + JSONCONS_FALLTHROUGH; + case storage_type::object_val: + return var_.object_data_cast()->value(); + default: + JSONCONS_THROW(json_runtime_error("Bad object cast")); + break; + } + } + + const object& object_value() const + { + switch (var_.get_storage_type()) + { + case storage_type::empty_object_val: + const_cast(this)->create_object_implicitly(); // HERE + JSONCONS_FALLTHROUGH; + case storage_type::object_val: + return var_.object_data_cast()->value(); + default: + JSONCONS_THROW(json_runtime_error("Bad object cast")); + break; + } + } + +private: + + void dump_noflush(basic_json_content_handler& handler) const + { + switch (var_.get_storage_type()) + { + case storage_type::short_string_val: + case storage_type::long_string_val: + handler.string_value(as_string_view(), var_.get_semantic_tag()); + break; + case storage_type::byte_string_val: + handler.byte_string_value(var_.byte_string_data_cast()->data(), var_.byte_string_data_cast()->length(), + var_.get_semantic_tag()); + break; + case storage_type::double_val: + handler.double_value(var_.double_data_cast()->value(), + var_.get_semantic_tag()); + break; + case storage_type::int64_val: + handler.int64_value(var_.int64_data_cast()->value(), var_.get_semantic_tag()); + break; + case storage_type::uint64_val: + handler.uint64_value(var_.uint64_data_cast()->value(), var_.get_semantic_tag()); + break; + case storage_type::bool_val: + handler.bool_value(var_.bool_data_cast()->value(), var_.get_semantic_tag()); + break; + case storage_type::null_val: + handler.null_value(var_.get_semantic_tag()); + break; + case storage_type::empty_object_val: + handler.begin_object(0, var_.get_semantic_tag()); + handler.end_object(); + break; + case storage_type::object_val: + { + handler.begin_object(size(), var_.get_semantic_tag()); + const object& o = object_value(); + for (const_object_iterator it = o.begin(); it != o.end(); ++it) + { + handler.name(string_view_type((it->key()).data(),it->key().length())); + it->value().dump_noflush(handler); + } + handler.end_object(); + } + break; + case storage_type::array_val: + { + handler.begin_array(size(), var_.get_semantic_tag()); + const array& o = array_value(); + for (const_array_iterator it = o.begin(); it != o.end(); ++it) + { + it->dump_noflush(handler); + } + handler.end_array(); + } + break; + default: + break; + } + } + + friend std::basic_ostream& operator<<(std::basic_ostream& os, const basic_json& o) + { + o.dump(os); + return os; + } + + friend std::basic_istream& operator<<(std::basic_istream& is, basic_json& o) + { + json_decoder handler; + basic_json_reader> reader(is, handler); + reader.read_next(); + reader.check_done(); + if (!handler.is_valid()) + { + JSONCONS_THROW(json_runtime_error("Failed to parse json stream")); + } + o = handler.get_result(); + return is; + } +}; + +template +void swap(typename Json::key_value_type& a, typename Json::key_value_type& b) +{ + a.swap(b); +} + +template +std::basic_istream& operator>>(std::basic_istream& is, Json& o) +{ + typedef typename Json::char_type char_type; + + json_decoder handler; + basic_json_reader> reader(is, handler); + reader.read_next(); + reader.check_done(); + if (!handler.is_valid()) + { + JSONCONS_THROW(json_runtime_error("Failed to parse json stream")); + } + o = handler.get_result(); + return is; +} + +typedef basic_json> json; +typedef basic_json> wjson; +typedef basic_json> ojson; +typedef basic_json> wojson; + +#if !defined(JSONCONS_NO_DEPRECATED) +typedef basic_json> owjson; +typedef json_decoder json_deserializer; +typedef json_decoder wjson_deserializer; +typedef json_decoder ojson_deserializer; +typedef json_decoder wojson_deserializer; +#endif + +inline namespace literals { + +inline +jsoncons::json operator "" _json(const char* s, std::size_t n) +{ + return jsoncons::json::parse(jsoncons::json::string_view_type(s, n)); +} + +inline +jsoncons::wjson operator "" _json(const wchar_t* s, std::size_t n) +{ + return jsoncons::wjson::parse(jsoncons::wjson::string_view_type(s, n)); +} + +inline +jsoncons::ojson operator "" _ojson(const char* s, std::size_t n) +{ + return jsoncons::ojson::parse(jsoncons::ojson::string_view_type(s, n)); +} + +inline +jsoncons::wojson operator "" _ojson(const wchar_t* s, std::size_t n) +{ + return jsoncons::wojson::parse(jsoncons::wojson::string_view_type(s, n)); +} + +} + +} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/bignum.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/bignum.hpp new file mode 100644 index 0000000000..f0a650ff94 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/bignum.hpp @@ -0,0 +1,1604 @@ +// Copyright 2018 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_BIGNUM_HPP +#define JSONCONS_BIGNUM_HPP + +#include +#include // std::vector +#include +#include +#include // assert +#include // std::numeric_limits +#include // std::max, std::min, std::reverse +#include // std::string +#include // std::memcpy +#include // std::fmod +#include // std::allocator +#include // std::initializer_list +#include // std::enable_if + +namespace jsoncons { + +/* +This implementation is based on Chapter 2 and Appendix A of +Ammeraal, L. (1996) Algorithms and Data Structures in C++, +Chichester: John Wiley. + +*/ + +template +class basic_bignum_base +{ +public: + typedef Allocator allocator_type; + typedef typename std::allocator_traits:: template rebind_alloc basic_type_allocator_type; + +private: + basic_type_allocator_type allocator_; + +public: + basic_bignum_base() + : allocator_() + { + } + explicit basic_bignum_base(const allocator_type& allocator) + : allocator_(basic_type_allocator_type(allocator)) + { + } + + basic_type_allocator_type allocator() const + { + return allocator_; + } +}; + +template > +class basic_bignum : protected basic_bignum_base +{ +private: + using basic_bignum_base::allocator; + + static constexpr uint64_t max_basic_type = (std::numeric_limits::max)(); + static constexpr uint64_t basic_type_bits = sizeof(uint64_t) * 8; // Number of bits + static constexpr uint64_t basic_type_halfBits = basic_type_bits/2; + + static constexpr uint16_t word_length = 4; // Use multiples of word_length words + static constexpr uint64_t r_mask = (uint64_t(1) << basic_type_halfBits) - 1; + static constexpr uint64_t l_mask = max_basic_type - r_mask; + static constexpr uint64_t l_bit = max_basic_type - (max_basic_type >> 1); + + union + { + size_t capacity_; + uint64_t values_[2]; + }; + uint64_t* data_; + bool neg_; + bool dynamic_; + size_t length_; +public: +// Constructors and Destructor + basic_bignum() + : values_{0,0}, data_(values_), neg_(false), dynamic_(false), length_(0) + { + } + + explicit basic_bignum(const Allocator& allocator) + : basic_bignum_base(allocator), values_{0,0}, data_(values_), neg_(false), dynamic_(false), length_(0) + { + } + + basic_bignum(const basic_bignum& n) + : basic_bignum_base(n.allocator()), neg_(n.neg_), length_(n.length_) + { + if (!n.dynamic_) + { + values_[0] = n.values_[0]; + values_[1] = n.values_[1]; + data_ = values_; + dynamic_ = false; + } + else + { + capacity_ = n.capacity_; + data_ = allocator().allocate(capacity_); + dynamic_ = true; + std::memcpy( data_, n.data_, n.length_*sizeof(uint64_t) ); + } + } + + basic_bignum(basic_bignum&& other) + : basic_bignum_base(other.allocator()), neg_(other.neg_), dynamic_(false), length_(other.length_) + { + initialize(std::move(other)); + } + + template + explicit basic_bignum(const CharT* str) + : values_{0,0} + { + initialize(str, strlen(str)); + } + + template + basic_bignum(const std::basic_string& s) + : values_{0,0} + { + initialize(s.data(), s.length()); + } + + template + basic_bignum(const CharT* data, size_t length) + : values_{0,0} + { + initialize(data, length); + } + + template + basic_bignum(const std::basic_string& s, uint8_t base) + : values_{0,0} + { + initialize(s.data(), s.length(), base); + } + + template + basic_bignum(const CharT* data, size_t length, uint8_t base) + : values_{0,0} + { + initialize(data, length, base); + } + + basic_bignum(int signum, std::initializer_list l) + : values_{0,0} + { + if (l.size() > 0) + { + basic_bignum v = 0; + for (auto c: l) + { + v = (v * 256) + (uint64_t)(c); + } + + if (signum == -1) + { + v = -1 - v; + } + + initialize(v); + } + else + { + neg_ = false; + initialize_from_integer(0u); + } + } + + basic_bignum(int signum, const uint8_t* str, size_t n) + : values_{0,0} + { + if (n > 0) + { + basic_bignum v = 0; + for (size_t i = 0; i < n; i++) + { + v = (v * 256) + (uint64_t)(str[i]); + } + + if (signum == -1) + { + v = -1 - v; + } + + initialize(v); + } + else + { + neg_ = false; + initialize_from_integer(0u); + } + } + + basic_bignum(short i) + : values_{0,0} + { + neg_ = i < 0; + uint64_t u = neg_ ? -i : i; + initialize_from_integer( u ); + } + + basic_bignum(unsigned short u) + : values_{0,0} + { + neg_ = false; + initialize_from_integer( u ); + } + + basic_bignum(int i) + : values_{0,0} + { + neg_ = i < 0; + uint64_t u = neg_ ? -i : i; + initialize_from_integer( u ); + } + + basic_bignum(unsigned int u) + : values_{0,0} + { + neg_ = false; + initialize_from_integer( u ); + } + + basic_bignum(long i) + : values_{0,0} + { + neg_ = i < 0; + uint64_t u = neg_ ? -i : i; + initialize_from_integer( u ); + } + + basic_bignum(unsigned long u) + : values_{0,0} + { + neg_ = false; + initialize_from_integer( u ); + } + + basic_bignum(long long i) + : values_{0,0} + { + neg_ = i < 0; + uint64_t u = neg_ ? -i : i; + initialize_from_integer( u ); + } + + basic_bignum(unsigned long long u) + : values_{0,0} + { + neg_ = false; + initialize_from_integer( u ); + } + + explicit basic_bignum( double x ) + : values_{0,0} + { + bool neg = false; + + if ( x < 0 ) + { + neg = true; + x = -x; + } + basic_bignum v = 0; + + double values = (double)max_basic_type + 1.0; + basic_bignum factor = 1; + + while ( x >= 1 ) + { + uint64_t u = (uint64_t) std::fmod( x, values ); + v = v + factor* basic_bignum(u); + x /= values; + factor = factor*(basic_bignum( max_basic_type ) + basic_bignum(1)); + } + + if ( neg ) + { + v.neg_ = true; + } + initialize( v ); + } + + explicit basic_bignum(long double x) + : values_{0,0} + { + bool neg = false; + + if ( x < 0 ) + { + neg = true; + x = -x; + } + + basic_bignum v = 0; + + long double values = (long double)max_basic_type + 1.0; + basic_bignum factor = 1; + + while ( x >= 1.0 ) + { + uint64_t u = (uint64_t) std::fmod( x, values ); + v = v + factor* basic_bignum(u); + x /= values; + factor = factor*(basic_bignum( max_basic_type ) + basic_bignum(1)); + } + + if ( neg ) + { + v.neg_ = true; + } + initialize( v ); + } + + ~basic_bignum() + { + if ( dynamic_ ) + { + allocator().deallocate(data_, capacity_); + } + } + + size_t capacity() const { return dynamic_ ? capacity_ : 2; } + +// Operators + bool operator!() const + { + return length() == 0 ? true : false; + } + + basic_bignum operator-() const + { + basic_bignum v = *this; + v.neg_ = !v.neg_; + return v; + } + + basic_bignum& operator=( const basic_bignum& y ) + { + if ( this != &y ) + { + set_length( y.length() ); + neg_ = y.neg_; + if ( y.length() > 0 ) + { + std::memcpy( data_, y.data_, y.length()*sizeof(uint64_t) ); + } + } + return *this; + } + + basic_bignum& operator+=( const basic_bignum& y ) + { + if ( neg_ != y.neg_ ) + return *this -= -y; + uint64_t d; + uint64_t carry = 0; + + incr_length( (std::max)(y.length(), length()) + 1 ); + + for (size_t i = 0; i < length(); i++ ) + { + if ( i >= y.length() && carry == 0 ) + break; + d = data_[i] + carry; + carry = d < carry; + if ( i < y.length() ) + { + data_[i] = d + y.data_[i]; + if ( data_[i] < d ) + carry = 1; + } + else + data_[i] = d; + } + reduce(); + return *this; + } + + basic_bignum& operator-=( const basic_bignum& y ) + { + if ( neg_ != y.neg_ ) + return *this += -y; + if ( (!neg_ && y > *this) || (neg_ && y < *this) ) + return *this = -(y - *this); + uint64_t borrow = 0; + uint64_t d; + for (size_t i = 0; i < length(); i++ ) + { + if ( i >= y.length() && borrow == 0 ) + break; + d = data_[i] - borrow; + borrow = d > data_[i]; + if ( i < y.length()) + { + data_[i] = d - y.data_[i]; + if ( data_[i] > d ) + borrow = 1; + } + else + data_[i] = d; + } + reduce(); + return *this; + } + + basic_bignum& operator*=( int64_t y ) + { + *this *= uint64_t(y < 0 ? -y : y); + if ( y < 0 ) + neg_ = !neg_; + return *this; + } + + basic_bignum& operator*=( uint64_t y ) + { + size_t len0 = length(); + uint64_t hi; + uint64_t lo; + uint64_t dig = data_[0]; + uint64_t carry = 0; + + incr_length( length() + 1 ); + + size_t i = 0; + for (i = 0; i < len0; i++ ) + { + DDproduct( dig, y, hi, lo ); + data_[i] = lo + carry; + dig = data_[i+1]; + carry = hi + (data_[i] < lo); + } + data_[i] = carry; + reduce(); + return *this; + } + + basic_bignum& operator*=( basic_bignum y ) + { + if ( length() == 0 || y.length() == 0 ) + return *this = 0; + bool difSigns = neg_ != y.neg_; + if ( length() + y.length() == 2 ) // length() = y.length() = 1 + { + uint64_t a = data_[0], b = y.data_[0]; + data_[0] = a * b; + if ( data_[0] / a != b ) + { + set_length( 2 ); + DDproduct( a, b, data_[1], data_[0] ); + } + neg_ = difSigns; + return *this; + } + if ( length() == 1 ) // && y.length() > 1 + { + uint64_t digit = data_[0]; + *this = y; + *this *= digit; + } + else + { + if ( y.length() == 1 ) + *this *= y.data_[0]; + else + { + size_t lenProd = length() + y.length(), jA, jB; + uint64_t sumHi = 0, sumLo, hi, lo, + sumLo_old, sumHi_old, carry=0; + basic_bignum x = *this; + set_length( lenProd ); // Give *this length lenProd + + for (size_t i = 0; i < lenProd; i++ ) + { + sumLo = sumHi; + sumHi = carry; + carry = 0; + for ( jA=0; jA < x.length(); jA++ ) + { + jB = i - jA; + if ( jB >= 0 && jB < y.length() ) + { + DDproduct( x.data_[jA], y.data_[jB], hi, lo ); + sumLo_old = sumLo; + sumHi_old = sumHi; + sumLo += lo; + if ( sumLo < sumLo_old ) + sumHi++; + sumHi += hi; + carry += (sumHi < sumHi_old); + } + } + data_[i] = sumLo; + } + } + } + reduce(); + neg_ = difSigns; + return *this; + } + + basic_bignum& operator/=( const basic_bignum& divisor ) + { + basic_bignum r; + divide( divisor, *this, r, false ); + return *this; + } + + basic_bignum& operator%=( const basic_bignum& divisor ) + { + basic_bignum q; + divide( divisor, q, *this, true ); + return *this; + } + + basic_bignum& operator<<=( uint64_t k ) + { + size_t q = (size_t)(k / basic_type_bits); + if ( q ) // Increase length_ by q: + { + incr_length(length() + q); + for (size_t i = length(); i-- > 0; ) + data_[i] = ( i < q ? 0 : data_[i - q]); + k %= basic_type_bits; + } + if ( k ) // 0 < k < basic_type_bits: + { + uint64_t k1 = basic_type_bits - k; + uint64_t mask = (1 << k) - 1; + incr_length( length() + 1 ); + for (size_t i = length(); i-- > 0; ) + { + data_[i] <<= k; + if ( i > 0 ) + data_[i] |= (data_[i-1] >> k1) & mask; + } + } + reduce(); + return *this; + } + + basic_bignum& operator>>=(uint64_t k) + { + size_t q = (size_t)(k / basic_type_bits); + if ( q >= length() ) + { + set_length( 0 ); + return *this; + } + if (q > 0) + { + memmove( data_, data_+q, (size_t)((length() - q)*sizeof(uint64_t)) ); + set_length( length() - q ); + k %= basic_type_bits; + if ( k == 0 ) + { + reduce(); + return *this; + } + } + + size_t n = (size_t)(length() - 1); + int64_t k1 = basic_type_bits - k; + uint64_t mask = (1 << k) - 1; + for (size_t i = 0; i <= n; i++) + { + data_[i] >>= k; + if ( i < n ) + data_[i] |= ((data_[i+1] & mask) << k1); + } + reduce(); + return *this; + } + + basic_bignum& operator++() + { + *this += 1; + return *this; + } + + basic_bignum operator++(int) + { + basic_bignum old = *this; + ++(*this); + return old; + } + + basic_bignum& operator--() + { + *this -= 1; + return *this; + } + + basic_bignum operator--(int) + { + basic_bignum old = *this; + --(*this); + return old; + } + + basic_bignum& operator|=( const basic_bignum& a ) + { + if ( length() < a.length() ) + { + incr_length( a.length() ); + } + + const uint64_t* qBegin = a.begin(); + const uint64_t* q = a.end() - 1; + uint64_t* p = begin() + a.length() - 1; + + while ( q >= qBegin ) + { + *p-- |= *q--; + } + + reduce(); + + return *this; + } + + basic_bignum& operator^=( const basic_bignum& a ) + { + if ( length() < a.length() ) + { + incr_length( a.length() ); + } + + const uint64_t* qBegin = a.begin(); + const uint64_t* q = a.end() - 1; + uint64_t* p = begin() + a.length() - 1; + + while ( q >= qBegin ) + { + *p-- ^= *q--; + } + + reduce(); + + return *this; + } + + basic_bignum& operator&=( const basic_bignum& a ) + { + size_t old_length = length(); + + set_length( (std::min)( length(), a.length() ) ); + + const uint64_t* pBegin = begin(); + uint64_t* p = end() - 1; + const uint64_t* q = a.begin() + length() - 1; + + while ( p >= pBegin ) + { + *p-- &= *q--; + } + + if ( old_length > length() ) + { + memset( data_ + length(), 0, old_length - length() ); + } + + reduce(); + + return *this; + } + + explicit operator bool() const + { + return length() != 0 ? true : false; + } + + explicit operator int64_t() const + { + int64_t x = 0; + if ( length() > 0 ) + { + x = data_ [0]; + } + + return neg_ ? -x : x; + } + + explicit operator uint64_t() const + { + uint64_t u = 0; + if ( length() > 0 ) + { + u = data_ [0]; + } + + return u; + } + + explicit operator double() const + { + double x = 0.0; + double factor = 1.0; + double values = (double)max_basic_type + 1.0; + + const uint64_t* p = begin(); + const uint64_t* pEnd = end(); + while ( p < pEnd ) + { + x += *p*factor; + factor *= values; + ++p; + } + + return neg_ ? -x : x; + } + + explicit operator long double() const + { + long double x = 0.0; + long double factor = 1.0; + long double values = (long double)max_basic_type + 1.0; + + const uint64_t* p = begin(); + const uint64_t* pEnd = end(); + while ( p < pEnd ) + { + x += *p*factor; + factor *= values; + ++p; + } + + return neg_ ? -x : x; + } + + template + void dump(int& signum, std::vector& data) const + { + basic_bignum n(*this); + if (neg_) + { + signum = -1; + n = - n -1; + } + else + { + signum = 1; + } + basic_bignum divisor(256); + + while (n >= 256) + { + basic_bignum q; + basic_bignum r; + n.divide(divisor, q, r, true); + n = q; + data.push_back((uint8_t)(uint64_t)r); + } + if (n >= 0) + { + data.push_back((uint8_t)(uint64_t)n); + } + std::reverse(data.begin(),data.end()); + } + + template + void dump(std::basic_string& data) const + { + basic_bignum v(*this); + + int len = int(uint32_t(v.length()) * basic_bignum::basic_type_bits / 3) + 2; + data.resize(len); + + int n = len; + int i = 0; + // 1/3 > ln(2)/ln(10) + static uint64_t p10 = 1; + static uint64_t ip10 = 0; + + if ( v.length() == 0 ) + { + data[0] = '0'; + i = 1; + } + else + { + uint64_t r; + if ( p10 == 1 ) + { + while ( p10 <= (std::numeric_limits::max)()/10 ) + { + p10 *= 10; + ip10++; + } + } // p10 is max unsigned power of 10 + basic_bignum R; + basic_bignum LP10 = p10; // LP10 = p10 = ::pow(10, ip10) + if ( v.neg_ ) + { + data[0] = '-'; + i = 1; + } + do + { + v.divide( LP10, v, R, true ); + r = (R.length() ? R.data_[0] : 0); + for ( size_t j=0; j < ip10; j++ ) + { + data[--n] = char(r % 10 + '0'); + r /= 10; + if ( r + v.length() == 0 ) + break; + } + } while ( v.length() ); + while ( n < len ) + data[i++] = data[n++]; + } + data.resize(i); + } + + template + void dump_hex_string(std::basic_string& data) const + { + basic_bignum v(*this); + + int len = int(uint32_t(v.length()) * basic_bignum::basic_type_bits / 3) + 2; + data.resize(len); + + int n = len; + int i = 0; + // 1/3 > ln(2)/ln(10) + static uint64_t p10 = 1; + static uint64_t ip10 = 0; + + if ( v.length() == 0 ) + { + data[0] = '0'; + i = 1; + } + else + { + uint64_t r; + if ( p10 == 1 ) + { + while ( p10 <= (std::numeric_limits::max)()/16 ) + { + p10 *= 16; + ip10++; + } + } // p10 is max unsigned power of 16 + basic_bignum R; + basic_bignum LP10 = p10; // LP10 = p10 = ::pow(16, ip10) + if ( v.neg_ ) + { + data[0] = '-'; + i = 1; + } + do + { + v.divide( LP10, v, R, true ); + r = (R.length() ? R.data_[0] : 0); + for ( size_t j=0; j < ip10; j++ ) + { + uint8_t c = r % 16; + data[--n] = (c < 10) ? ('0' + c) : ('A' - 10 + c); + r /= 16; + if ( r + v.length() == 0 ) + break; + } + } while ( v.length() ); + while ( n < len ) + data[i++] = data[n++]; + } + data.resize(i); + } + +// Global Operators + + friend bool operator==( const basic_bignum& x, const basic_bignum& y ) + { + return x.compare(y) == 0 ? true : false; + } + + friend bool operator==( const basic_bignum& x, int y ) + { + return x.compare(y) == 0 ? true : false; + } + + friend bool operator!=( const basic_bignum& x, const basic_bignum& y ) + { + return x.compare(y) != 0 ? true : false; + } + + friend bool operator!=( const basic_bignum& x, int y ) + { + return x.compare(basic_bignum(y)) != 0 ? true : false; + } + + friend bool operator<( const basic_bignum& x, const basic_bignum& y ) + { + return x.compare(y) < 0 ? true : false; + } + + friend bool operator<( const basic_bignum& x, int64_t y ) + { + return x.compare(y) < 0 ? true : false; + } + + friend bool operator>( const basic_bignum& x, const basic_bignum& y ) + { + return x.compare(y) > 0 ? true : false; + } + + friend bool operator>( const basic_bignum& x, int y ) + { + return x.compare(basic_bignum(y)) > 0 ? true : false; + } + + friend bool operator<=( const basic_bignum& x, const basic_bignum& y ) + { + return x.compare(y) <= 0 ? true : false; + } + + friend bool operator<=( const basic_bignum& x, int y ) + { + return x.compare(y) <= 0 ? true : false; + } + + friend bool operator>=( const basic_bignum& x, const basic_bignum& y ) + { + return x.compare(y) >= 0 ? true : false; + } + + friend bool operator>=( const basic_bignum& x, int y ) + { + return x.compare(y) >= 0 ? true : false; + } + + friend basic_bignum operator+( basic_bignum x, const basic_bignum& y ) + { + return x += y; + } + + friend basic_bignum operator+( basic_bignum x, int64_t y ) + { + return x += y; + } + + friend basic_bignum operator-( basic_bignum x, const basic_bignum& y ) + { + return x -= y; + } + + friend basic_bignum operator-( basic_bignum x, int64_t y ) + { + return x -= y; + } + + friend basic_bignum operator*( int64_t x, const basic_bignum& y ) + { + return basic_bignum(y) *= x; + } + + friend basic_bignum operator*( basic_bignum x, const basic_bignum& y ) + { + return x *= y; + } + + friend basic_bignum operator*( basic_bignum x, int64_t y ) + { + return x *= y; + } + + friend basic_bignum operator/( basic_bignum x, const basic_bignum& y ) + { + return x /= y; + } + + friend basic_bignum operator/( basic_bignum x, int y ) + { + return x /= y; + } + + friend basic_bignum operator%( basic_bignum x, const basic_bignum& y ) + { + return x %= y; + } + + friend basic_bignum operator<<( basic_bignum u, unsigned k ) + { + return u <<= k; + } + + friend basic_bignum operator<<( basic_bignum u, int k ) + { + return u <<= k; + } + + friend basic_bignum operator>>( basic_bignum u, unsigned k ) + { + return u >>= k; + } + + friend basic_bignum operator>>( basic_bignum u, int k ) + { + return u >>= k; + } + + friend basic_bignum operator|( basic_bignum x, const basic_bignum& y ) + { + return x |= y; + } + + friend basic_bignum operator|( basic_bignum x, int y ) + { + return x |= y; + } + + friend basic_bignum operator|( basic_bignum x, unsigned y ) + { + return x |= y; + } + + friend basic_bignum operator^( basic_bignum x, const basic_bignum& y ) + { + return x ^= y; + } + + friend basic_bignum operator^( basic_bignum x, int y ) + { + return x ^= y; + } + + friend basic_bignum operator^( basic_bignum x, unsigned y ) + { + return x ^= y; + } + + friend basic_bignum operator&( basic_bignum x, const basic_bignum& y ) + { + return x &= y; + } + + friend basic_bignum operator&( basic_bignum x, int y ) + { + return x &= y; + } + + friend basic_bignum operator&( basic_bignum x, unsigned y ) + { + return x &= y; + } + + friend basic_bignum abs( const basic_bignum& a ) + { + if ( a.neg_ ) + { + return -a; + } + return a; + } + + friend basic_bignum power( basic_bignum x, unsigned n ) + { + basic_bignum y = 1; + + while ( n ) + { + if ( n & 1 ) + { + y *= x; + } + x *= x; + n >>= 1; + } + + return y; + } + + friend basic_bignum sqrt( const basic_bignum& a ) + { + basic_bignum x = a; + basic_bignum b = a; + basic_bignum q; + + b <<= 1; + while ( b >>= 2, b > 0 ) + { + x >>= 1; + } + while ( x > (q = a/x) + 1 || x < q - 1 ) + { + x += q; + x >>= 1; + } + return x < q ? x : q; + } + + template + friend std::basic_ostream& operator<<(std::basic_ostream& os, const basic_bignum& v) + { + std::basic_string s; + v.dump(s); + os << s; + + return os; + } + + int compare( const basic_bignum& y ) const + { + if ( neg_ != y.neg_ ) + return y.neg_ - neg_; + int code = 0; + if ( length() == 0 && y.length() == 0 ) + code = 0; + else if ( length() < y.length() ) + code = -1; + else if ( length() > y.length() ) + code = +1; + else + { + for (size_t i = length(); i-- > 0; ) + { + if (data_[i] > y.data_[i]) + { + code = 1; + break; + } + else if (data_[i] < y.data_[i]) + { + code = -1; + break; + } + } + } + return neg_ ? -code : code; + } + +private: + void DDproduct( uint64_t A, uint64_t B, + uint64_t& hi, uint64_t& lo ) const + // Multiplying two digits: (hi, lo) = A * B + { + uint64_t hiA = A >> basic_type_halfBits, loA = A & r_mask, + hiB = B >> basic_type_halfBits, loB = B & r_mask, + mid1, mid2, old; + + lo = loA * loB; + hi = hiA * hiB; + mid1 = loA * hiB; + mid2 = hiA * loB; + old = lo; + lo += mid1 << basic_type_halfBits; + hi += (lo < old) + (mid1 >> basic_type_halfBits); + old = lo; + lo += mid2 << basic_type_halfBits; + hi += (lo < old) + (mid2 >> basic_type_halfBits); + } + + uint64_t DDquotient( uint64_t A, uint64_t B, uint64_t d ) const + // Divide double word (A, B) by d. Quotient = (qHi, qLo) + { + uint64_t left, middle, right, qHi, qLo, x, dLo1, + dHi = d >> basic_type_halfBits, dLo = d & r_mask; + qHi = A/(dHi + 1); + // This initial guess of qHi may be too small. + middle = qHi * dLo; + left = qHi * dHi; + x = B - (middle << basic_type_halfBits); + A -= (middle >> basic_type_halfBits) + left + (x > B); + B = x; + dLo1 = dLo << basic_type_halfBits; + // Increase qHi if necessary: + while ( A > dHi || (A == dHi && B >= dLo1) ) + { + x = B - dLo1; + A -= dHi + (x > B); + B = x; + qHi++; + } + qLo = ((A << basic_type_halfBits) | (B >> basic_type_halfBits))/(dHi + 1); + // This initial guess of qLo may be too small. + right = qLo * dLo; + middle = qLo * dHi; + x = B - right; + A -= (x > B); + B = x; + x = B - (middle << basic_type_halfBits); + A -= (middle >> basic_type_halfBits) + (x > B); + B = x; + // Increase qLo if necessary: + while ( A || B >= d ) + { + x = B - d; + A -= (x > B); + B = x; + qLo++; + } + return (qHi << basic_type_halfBits) + qLo; + } + + void subtractmul( uint64_t* a, uint64_t* b, size_t n, uint64_t& q ) const + // a -= q * b: b in n positions; correct q if necessary + { + uint64_t hi, lo, d, carry = 0; + size_t i; + for ( i = 0; i < n; i++ ) + { + DDproduct( b[i], q, hi, lo ); + d = a[i]; + a[i] -= lo; + if ( a[i] > d ) + carry++; + d = a[i + 1]; + a[i + 1] -= hi + carry; + carry = a[i + 1] > d; + } + if ( carry ) // q was too large + { + q--; + carry = 0; + for ( i = 0; i < n; i++ ) + { + d = a[i] + carry; + carry = d < carry; + a[i] = d + b[i]; + if ( a[i] < d ) + carry = 1; + } + a[n] = 0; + } + } + + int normalize( basic_bignum& denom, basic_bignum& num, int& x ) const + { + size_t r = denom.length() - 1; + uint64_t y = denom.data_[r]; + + x = 0; + while ( (y & l_bit) == 0 ) + { + y <<= 1; + x++; + } + denom <<= x; + num <<= x; + if ( r > 0 && denom.data_[r] < denom.data_[r-1] ) + { + denom *= max_basic_type; + num *= max_basic_type; + return 1; + } + return 0; + } + + void unnormalize( basic_bignum& rem, int x, int secondDone ) const + { + if ( secondDone ) + { + rem /= max_basic_type; + } + if ( x > 0 ) + { + rem >>= x; + } + else + { + rem.reduce(); + } + } + + void divide( basic_bignum denom, basic_bignum& quot, basic_bignum& rem, bool remDesired ) const + { + if ( denom.length() == 0 ) + { + throw std::runtime_error( "Zero divide." ); + } + bool quot_neg = neg_ ^ denom.neg_; + bool rem_neg = neg_; + int x = 0; + basic_bignum num = *this; + num.neg_ = denom.neg_ = false; + if ( num < denom ) + { + quot = uint64_t(0); + rem = num; + rem.neg_ = rem_neg; + return; + } + if ( denom.length() == 1 && num.length() == 1 ) + { + quot = uint64_t( num.data_[0]/denom.data_[0] ); + rem = uint64_t( num.data_[0]%denom.data_[0] ); + quot.neg_ = quot_neg; + rem.neg_ = rem_neg; + return; + } + else if (denom.length() == 1 && (denom.data_[0] & l_mask) == 0 ) + { + // Denominator fits into a half word + uint64_t divisor = denom.data_[0], dHi = 0, + q1, r, q2, dividend; + quot.set_length(length()); + for (size_t i=length(); i-- > 0; ) + { + dividend = (dHi << basic_type_halfBits) | (data_[i] >> basic_type_halfBits); + q1 = dividend/divisor; + r = dividend % divisor; + dividend = (r << basic_type_halfBits) | (data_[i] & r_mask); + q2 = dividend/divisor; + dHi = dividend % divisor; + quot.data_[i] = (q1 << basic_type_halfBits) | q2; + } + quot.reduce(); + rem = dHi; + quot.neg_ = quot_neg; + rem.neg_ = rem_neg; + return; + } + basic_bignum num0 = num, denom0 = denom; + int second_done = normalize(denom, num, x); + size_t l = denom.length() - 1; + size_t n = num.length() - 1; + quot.set_length(n - l); + for (size_t i=quot.length(); i-- > 0; ) + quot.data_[i] = 0; + rem = num; + if ( rem.data_[n] >= denom.data_[l] ) + { + rem.incr_length(rem.length() + 1); + n++; + quot.incr_length(quot.length() + 1); + } + uint64_t d = denom.data_[l]; + for ( size_t k = n; k > l; k-- ) + { + uint64_t q = DDquotient(rem.data_[k], rem.data_[k-1], d); + subtractmul( rem.data_ + k - l - 1, denom.data_, l + 1, q ); + quot.data_[k - l - 1] = q; + } + quot.reduce(); + quot.neg_ = quot_neg; + if ( remDesired ) + { + unnormalize(rem, x, second_done); + rem.neg_ = rem_neg; + } + } + + size_t length() const { return length_; } + uint64_t* begin() { return data_; } + const uint64_t* begin() const { return data_; } + uint64_t* end() { return data_ + length_; } + const uint64_t* end() const { return data_ + length_; } + + void set_length(size_t n) + { + length_ = n; + if ( length_ > capacity() ) + { + if ( dynamic_ ) + { + delete[] data_; + } + capacity_ = round_up(length_); + data_ = allocator().allocate(capacity_); + dynamic_ = true; + } + } + + size_t round_up(size_t i) const // Find suitable new block size + { + return (i/word_length + 1) * word_length; + } + + template + typename std::enable_if::value && + !std::is_signed::value && + sizeof(T) <= sizeof(int64_t),void>::type + initialize_from_integer(T u) + { + data_ = values_; + dynamic_ = false; + length_ = u != 0 ? 1 : 0; + + data_ [0] = u; + } + + template + typename std::enable_if::value && + !std::is_signed::value && + sizeof(int64_t) < sizeof(T) && + sizeof(T) <= sizeof(int64_t)*2, void>::type + initialize_from_integer(T u) + { + data_ = values_; + dynamic_ = false; + length_ = u != 0 ? 2 : 0; + + data_[0] = uint64_t(u & max_basic_type); + u >>= basic_type_bits; + data_[1] = uint64_t(u & max_basic_type); + } + + void initialize( const basic_bignum& n ) + { + neg_ = n.neg_; + length_ = n.length_; + + if ( length_ <= 2 ) + { + data_ = values_; + dynamic_ = false; + values_ [0] = n.data_ [0]; + values_ [1] = n.data_ [1]; + } + else + { + capacity_ = round_up( length_ ); + data_ = allocator().allocate(capacity_); + dynamic_ = true; + if ( length_ > 0 ) + { + std::memcpy( data_, n.data_, length_*sizeof(uint64_t) ); + } + reduce(); + } + } + + void initialize(basic_bignum&& other) + { + neg_ = other.neg_; + length_ = other.length_; + dynamic_ = other.dynamic_; + + if (other.dynamic_) + { + capacity_ = other.capacity_; + data_ = other.data_; + + other.data_ = other.values_; + other.dynamic_ = false; + other.length_ = 0; + other.neg_ = false; + } + else + { + values_[0] = other.data_[0]; + values_[1] = other.data_[1]; + data_ = values_; + } + } + + void reduce() + { + uint64_t* p = end() - 1; + uint64_t* pBegin = begin(); + while ( p >= pBegin ) + { + if ( *p ) + { + break; + } + --length_; + --p; + } + if ( length_ == 0 ) + { + neg_ = false; + } + } + + void incr_length( size_t len_new ) + { + size_t len_old = length_; + length_ = len_new; // length_ > len_old + + if ( length_ > capacity() ) + { + size_t capacity_new = round_up( length_ ); + + uint64_t* data_old = data_; + + data_ = allocator().allocate(capacity_new); + + if ( len_old > 0 ) + { + std::memcpy( data_, data_old, len_old*sizeof(uint64_t) ); + } + if ( dynamic_ ) + { + allocator().deallocate(data_old,capacity_); + } + capacity_ = capacity_new; + dynamic_ = true; + } + + if ( length_ > len_old ) + { + memset( data_+len_old, 0, (length_ - len_old)*sizeof(uint64_t) ); + } + } + + template + void initialize(const CharT* data, size_t length) + { + bool neg; + if (*data == '-') + { + neg = true; + data++; + --length; + } + else + { + neg = false; + } + + basic_bignum v = 0; + for (size_t i = 0; i < length; i++) + { + CharT c = data[i]; + switch (c) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + v = (v * 10) + (uint64_t)(c - '0'); + break; + default: + throw std::runtime_error(std::string("Invalid digit ") + "\'" + (char)c + "\'"); + } + } + + if ( neg ) + { + v.neg_ = true; + } + initialize(std::move(v)); + } + + template + void initialize(const CharT* data, size_t length, uint8_t base) + { + if (!(base >= 2 && base <= 16)) + { + throw std::runtime_error("Unsupported base"); + } + + bool neg; + if (*data == '-') + { + neg = true; + data++; + --length; + } + else + { + neg = false; + } + + basic_bignum v = 0; + for (size_t i = 0; i < length; i++) + { + CharT c = data[i]; + uint64_t d; + switch (c) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + d = (uint64_t)(c - '0'); + break; + case 'a':case 'b':case 'c':case 'd':case 'e':case 'f': + d = (uint64_t)(c - ('a' - 10)); + break; + case 'A':case 'B':case 'C':case 'D':case 'E':case 'F': + d = (uint64_t)(c - ('A' - 10)); + break; + default: + throw std::runtime_error(std::string("Invalid digit in base ") + std::to_string(base) + ": \'" + (char)c + "\'"); + } + if (d >= base) + { + throw std::runtime_error(std::string("Invalid digit in base ") + std::to_string(base) + ": \'" + (char)c + "\'"); + } + v = (v * base) + d; + } + + if ( neg ) + { + v.neg_ = true; + } + initialize(std::move(v)); + } +}; + +typedef basic_bignum> bignum; + +} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/byte_string.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/byte_string.hpp new file mode 100644 index 0000000000..8d638e813a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/byte_string.hpp @@ -0,0 +1,710 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_BYTE_STRING_HPP +#define JSONCONS_BYTE_STRING_HPP + +#include +#include +#include +#include +#include // std::memcmp +#include // std::allocator +#include +#include +#include +#include // std::move +#include +#include + +namespace jsoncons { + +// Algorithms + +namespace detail { +template +typename std::enable_if::value_type,uint8_t>::value,size_t>::type +encode_base64_generic(InputIt first, InputIt last, const char alphabet[65], Container& result) +{ + size_t count = 0; + unsigned char a3[3]; + unsigned char a4[4]; + unsigned char fill = alphabet[64]; + int i = 0; + int j = 0; + + while (first != last) + { + a3[i++] = *first++; + if (i == 3) + { + a4[0] = (a3[0] & 0xfc) >> 2; + a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4); + a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6); + a4[3] = a3[2] & 0x3f; + + for (i = 0; i < 4; i++) + { + result.push_back(alphabet[a4[i]]); + ++count; + } + i = 0; + } + } + + if (i > 0) + { + for (j = i; j < 3; ++j) + { + a3[j] = 0; + } + + a4[0] = (a3[0] & 0xfc) >> 2; + a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4); + a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6); + + for (j = 0; j < i + 1; ++j) + { + result.push_back(alphabet[a4[j]]); + ++count; + } + + if (fill != 0) + { + while (i++ < 3) + { + result.push_back(fill); + ++count; + } + } + } + + return count; +} + +// Hack to support vs2015 +template +typename std::enable_if::type +decode_base64_generic(InputIt first, InputIt last, + const uint8_t reverse_alphabet[256], + F f, + Container& result) +{ + uint8_t a4[4], a3[3]; + uint8_t i = 0; + uint8_t j = 0; + + while (first != last && *first != '=') + { + if (!f(*first)) + { + JSONCONS_THROW(json_runtime_error("Cannot decode encoded byte string")); + } + + a4[i++] = *first++; + if (i == 4) + { + for (i = 0; i < 4; ++i) + { + a4[i] = reverse_alphabet[a4[i]]; + } + + a3[0] = (a4[0] << 2) + ((a4[1] & 0x30) >> 4); + a3[1] = ((a4[1] & 0xf) << 4) + ((a4[2] & 0x3c) >> 2); + a3[2] = ((a4[2] & 0x3) << 6) + a4[3]; + + for (i = 0; i < 3; i++) + { + result.push_back(a3[i]); + } + i = 0; + } + } + + if (i > 0) + { + for (j = 0; j < i; ++j) + { + a4[j] = reverse_alphabet[a4[j]]; + } + + a3[0] = (a4[0] << 2) + ((a4[1] & 0x30) >> 4); + a3[1] = ((a4[1] & 0xf) << 4) + ((a4[2] & 0x3c) >> 2); + + for (j = 0; j < i - 1; ++j) + { + result.push_back(a3[j]); + } + } +} + +} + +template +typename std::enable_if::value_type,uint8_t>::value,size_t>::type +encode_base16(InputIt first, InputIt last, Container& result) +{ + static constexpr char characters[] = "0123456789ABCDEF"; + + for (auto it = first; it != last; ++it) + { + uint8_t c = *it; + result.push_back(characters[c >> 4]); + result.push_back(characters[c & 0xf]); + } + return (last-first)*2; +} + +template +typename std::enable_if::value_type,uint8_t>::value,size_t>::type +encode_base64url(InputIt first, InputIt last, Container& result) +{ + static constexpr char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789-_" + "\0"; + return detail::encode_base64_generic(first, last, alphabet, result); +} + +template +typename std::enable_if::value_type,uint8_t>::value,size_t>::type +encode_base64(InputIt first, InputIt last, Container& result) +{ + static constexpr char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/" + "="; + return detail::encode_base64_generic(first, last, alphabet, result); +} + +template +bool is_base64(Char c) +{ + return (c >= 0 && c < 128) && (isalnum((int)c) || c == '+' || c == '/'); +} + +template +bool is_base64url(Char c) +{ + return (c >= 0 && c < 128) && (isalnum((int)c) || c == '-' || c == '_'); +} + +inline +static bool is_base64url(int c) +{ + return isalnum(c) || c == '-' || c == '_'; +} + +// decode + +// Hack to support vs2015 +template +typename std::enable_if::type +decode_base64url(InputIt first, InputIt last, Container& result) +{ + static constexpr uint8_t reverse_alphabet[256] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 62, 0xff, 0xff, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0xff, 0xff, 0xff, 0xff, 63, + 0xff, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }; + + + jsoncons::detail::decode_base64_generic(first, last, reverse_alphabet, + is_base64url::value_type>, + result); +} + +// Hack to support vs2015 +template +typename std::enable_if::type +decode_base64(InputIt first, InputIt last, Container& result) +{ + static constexpr uint8_t reverse_alphabet[256] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 62, 0xff, 0xff, 0xff, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }; + jsoncons::detail::decode_base64_generic(first, last, reverse_alphabet, + is_base64::value_type>, + result); +} + +// Hack to support vs2015 +template +typename std::enable_if::type +decode_base16(InputIt first, InputIt last, Container& result) +{ + size_t len = std::distance(first,last); + if (len & 1) + { + JSONCONS_THROW(json_runtime_error("Cannot decode encoded base16 string - odd length")); + } + + InputIt it = first; + while (it != last) + { + uint8_t val; + auto a = *it++; + if (a >= '0' && a <= '9') + { + val = (a - '0') << 4; + } + else if ((a | 0x20) >= 'a' && (a | 0x20) <= 'f') + { + val = ((a | 0x20) - 'a' + 10) << 4; + } + else + { + JSONCONS_THROW(json_runtime_error("Not a hex digit. Cannot decode encoded base16 string")); + } + + auto b = *it++; + if (b >= '0' && b <= '9') + { + val |= (b - '0'); + } + else if ((b | 0x20) >= 'a' && (b | 0x20) <= 'f') + { + val |= ((b | 0x20) - 'a' + 10); + } + else + { + JSONCONS_THROW(json_runtime_error("Not a hex digit. Cannot decode encoded base16 string")); + } + + result.push_back(val); + } +} + +struct byte_traits +{ + typedef uint8_t char_type; + + static constexpr int eof() + { + return std::char_traits::eof(); + } + + static int compare(const char_type* s1, const char_type* s2, std::size_t count) + { + return std::memcmp(s1,s2,count); + } +}; + +// basic_byte_string + +template +class basic_byte_string; + +// byte_string_view +class byte_string_view +{ + const uint8_t* data_; + size_t length_; +public: + typedef byte_traits traits_type; + + typedef const uint8_t* const_iterator; + typedef const uint8_t* iterator; + typedef std::size_t size_type; + typedef uint8_t value_type; + + byte_string_view() + : data_(nullptr), length_(0) + { + } + + byte_string_view(const uint8_t* data, size_t length) + : data_(data), length_(length) + { + } + + byte_string_view(const byte_string_view&) = default; + + byte_string_view(byte_string_view&&) = default; + + byte_string_view& operator=(const byte_string_view&) = default; + + byte_string_view& operator=(byte_string_view&&) = default; + + const uint8_t* data() const + { + return data_; + } + + size_t length() const + { + return length_; + } + + size_t size() const + { + return length_; + } + + // iterator support + const_iterator begin() const noexcept + { + return data_; + } + const_iterator end() const noexcept + { + return data_ + length_; + } + + uint8_t operator[](size_type pos) const + { + return data_[pos]; + } + + int compare(const byte_string_view& s) const + { + const int rc = traits_type::compare(data_, s.data(), (std::min)(length_, s.length())); + return rc != 0 ? rc : (length_ == s.length() ? 0 : length_ < s.length() ? -1 : 1); + } + + template + int compare(const basic_byte_string& s) const + { + const int rc = traits_type::compare(data_, s.data(), (std::min)(length_, s.length())); + return rc != 0 ? rc : (length_ == s.length() ? 0 : length_ < s.length() ? -1 : 1); + } + + template + friend std::basic_ostream& operator<<(std::basic_ostream& os, const byte_string_view& o) + { + std::basic_ostringstream ss; + ss.flags(std::ios::hex); + ss.precision(2); + ss.width(2); + ss.fill('0'); + + for (auto b : o) + { + ss << (int)b; + } + os << ss.str(); + return os; + } +}; + +// basic_byte_string +template > +class basic_byte_string +{ + std::vector data_; +public: + typedef byte_traits traits_type; + + typedef typename std::vector::const_iterator const_iterator; + typedef typename std::vector::const_iterator iterator; + typedef std::size_t size_type; + typedef uint8_t value_type; + + basic_byte_string() = default; + + explicit basic_byte_string(const Allocator& alloc) + : data_(alloc) + { + } + + basic_byte_string(std::initializer_list init) + : data_(std::move(init)) + { + } + + basic_byte_string(std::initializer_list init, const Allocator& alloc) + : data_(std::move(init), alloc) + { + } + + explicit basic_byte_string(const byte_string_view& v) + : data_(v.begin(),v.end()) + { + } + + basic_byte_string(const basic_byte_string& v) + : data_(v.data_) + { + } + + basic_byte_string(basic_byte_string&& v) + { + data_.swap(v.data_); + } + + basic_byte_string(const byte_string_view& v, const Allocator& alloc) + : data_(v.begin(),v.end(),alloc) + { + } + + basic_byte_string(const char* s) + { + while (*s) + { + data_.push_back(*s++); + } + } + + basic_byte_string(const uint8_t* data, size_t length) + : data_(data, data+length) + { + } + + basic_byte_string& operator=(const basic_byte_string& s) = default; + + basic_byte_string& operator=(basic_byte_string&& s) = default; + + operator byte_string_view() const noexcept + { + return byte_string_view(data(),length()); + } + + void reserve(size_t new_cap) + { + data_.reserve(new_cap); + } + + void push_back(uint8_t b) + { + data_.push_back(b); + } + + void assign(const uint8_t* s, size_t count) + { + data_.clear(); + data_.insert(s, s+count); + } + + void append(const uint8_t* s, size_t count) + { + data_.insert(s, s+count); + } + + void clear() + { + data_.clear(); + } + + uint8_t operator[](size_type pos) const + { + return data_[pos]; + } + + // iterator support + const_iterator begin() const noexcept + { + return data_.begin(); + } + const_iterator end() const noexcept + { + return data_.end(); + } + + const uint8_t* data() const + { + return data_.data(); + } + + size_t size() const + { + return data_.size(); + } + + size_t length() const + { + return data_.size(); + } + + int compare(const byte_string_view& s) const + { + const int rc = traits_type::compare(data(), s.data(), (std::min)(length(), s.length())); + return rc != 0 ? rc : (length() == s.length() ? 0 : length() < s.length() ? -1 : 1); + } + + int compare(const basic_byte_string& s) const + { + const int rc = traits_type::compare(data(), s.data(), (std::min)(length(), s.length())); + return rc != 0 ? rc : (length() == s.length() ? 0 : length() < s.length() ? -1 : 1); + } + + template + friend std::basic_ostream& operator<<(std::basic_ostream& os, const basic_byte_string& o) + { + os << byte_string_view(o); + return os; + } +}; + +// == +inline +bool operator==(const byte_string_view& lhs, const byte_string_view& rhs) +{ + return lhs.compare(rhs) == 0; +} +template +bool operator==(const byte_string_view& lhs, const basic_byte_string& rhs) +{ + return lhs.compare(rhs) == 0; +} +template +bool operator==(const basic_byte_string& lhs, const byte_string_view& rhs) +{ + return rhs.compare(lhs) == 0; +} +template +bool operator==(const basic_byte_string& lhs, const basic_byte_string& rhs) +{ + return rhs.compare(lhs) == 0; +} + +// != + +inline +bool operator!=(const byte_string_view& lhs, const byte_string_view& rhs) +{ + return lhs.compare(rhs) != 0; +} +template +bool operator!=(const byte_string_view& lhs, const basic_byte_string& rhs) +{ + return lhs.compare(rhs) != 0; +} +template +bool operator!=(const basic_byte_string& lhs, const byte_string_view& rhs) +{ + return rhs.compare(lhs) != 0; +} +template +bool operator!=(const basic_byte_string& lhs, const basic_byte_string& rhs) +{ + return rhs.compare(lhs) != 0; +} + +// <= + +inline +bool operator<=(const byte_string_view& lhs, const byte_string_view& rhs) +{ + return lhs.compare(rhs) <= 0; +} +template +bool operator<=(const byte_string_view& lhs, const basic_byte_string& rhs) +{ + return lhs.compare(rhs) <= 0; +} +template +bool operator<=(const basic_byte_string& lhs, const byte_string_view& rhs) +{ + return rhs.compare(lhs) >= 0; +} +template +bool operator<=(const basic_byte_string& lhs, const basic_byte_string& rhs) +{ + return rhs.compare(lhs) >= 0; +} + +// < + +inline +bool operator<(const byte_string_view& lhs, const byte_string_view& rhs) +{ + return lhs.compare(rhs) < 0; +} +template +bool operator<(const byte_string_view& lhs, const basic_byte_string& rhs) +{ + return lhs.compare(rhs) < 0; +} +template +bool operator<(const basic_byte_string& lhs, const byte_string_view& rhs) +{ + return rhs.compare(lhs) > 0; +} +template +bool operator<(const basic_byte_string& lhs, const basic_byte_string& rhs) +{ + return rhs.compare(lhs) > 0; +} + +// >= + +inline +bool operator>=(const byte_string_view& lhs, const byte_string_view& rhs) +{ + return lhs.compare(rhs) >= 0; +} +template +bool operator>=(const byte_string_view& lhs, const basic_byte_string& rhs) +{ + return lhs.compare(rhs) >= 0; +} +template +bool operator>=(const basic_byte_string& lhs, const byte_string_view& rhs) +{ + return rhs.compare(lhs) <= 0; +} +template +bool operator>=(const basic_byte_string& lhs, const basic_byte_string& rhs) +{ + return rhs.compare(lhs) <= 0; +} + +// > + +inline +bool operator>(const byte_string_view& lhs, const byte_string_view& rhs) +{ + return lhs.compare(rhs) > 0; +} +template +bool operator>(const byte_string_view& lhs, const basic_byte_string& rhs) +{ + return lhs.compare(rhs) > 0; +} +template +bool operator>(const basic_byte_string& lhs, const byte_string_view& rhs) +{ + return rhs.compare(lhs) < 0; +} +template +bool operator>(const basic_byte_string& lhs, const basic_byte_string& rhs) +{ + return rhs.compare(lhs) < 0; +} + +typedef basic_byte_string> byte_string; + + +} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/config/binary_detail.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/config/binary_detail.hpp new file mode 100644 index 0000000000..9b94906982 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/config/binary_detail.hpp @@ -0,0 +1,547 @@ +// Copyright 2017 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_CONFIG_BINARY_DETAIL_HPP +#define JSONCONS_CONFIG_BINARY_DETAIL_HPP + +#include +#include +#include +#include // std::memcpy +#include +#include // std::enable_if + +#if defined(__apple_build_version__) && ((__clang_major__ < 8) || ((__clang_major__ == 8) && (__clang_minor__ < 1))) +#define APPLE_MISSING_INTRINSICS 1 +#endif + +// The definitions below follow the definitions in compiler_support_p.h, https://github.com/01org/tinycbor +// MIT license + +#ifdef __F16C__ +# include +#endif + +#ifndef __has_builtin +# define __has_builtin(x) 0 +#endif + +#if (defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)) || \ + (__has_builtin(__builtin_bswap64) && __has_builtin(__builtin_bswap32)) +# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +# define JSONCONS_BE64_TO_H __builtin_bswap64 +# define JSONCONS_H_TO_BE64 __builtin_bswap64 +# define JSONCONS_BE32_TO_H __builtin_bswap32 +# define JSONCONS_H_TO_BE32 __builtin_bswap32 +# ifdef __INTEL_COMPILER +# define JSONCONS_BE16_TO_H _bswap16 +# define JSONCONS_H_TO_BE16 _bswap16 +# elif (__GNUC__ * 100 + __GNUC_MINOR__ >= 608) || __has_builtin(__builtin_bswap16) +# define JSONCONS_BE16_TO_H __builtin_bswap16 +# define JSONCONS_H_TO_BE16 __builtin_bswap16 +# else +# define JSONCONS_BE16_TO_H(x) (((uint16_t)x >> 8) | ((uint16_t)x << 8)) +# define JSONCONS_H_TO_BE16 JSONCONS_BE16_TO_H +# endif +# define JSONCONS_LE64_TO_H +# define JSONCONS_H_TO_LE64 +# define JSONCONS_LE32_TO_H +# define JSONCONS_H_TO_LE32 +# define JSONCONS_LE16_TO_H +# define JSONCONS_H_TO_LE16 +# else +# define JSONCONS_LE64_TO_H __builtin_bswap64 +# define JSONCONS_H_TO_LE64 __builtin_bswap64 +# define JSONCONS_LE32_TO_H __builtin_bswap32 +# define JSONCONS_H_TO_LE32 __builtin_bswap32 +# ifdef __INTEL_COMPILER +# define JSONCONS_LE16_TO_H _bswap16 +# define JSONCONS_H_TO_LE16 _bswap16 +# elif (__GNUC__ * 100 + __GNUC_MINOR__ >= 608) || __has_builtin(__builtin_bswap16) +# define JSONCONS_LE16_TO_H __builtin_bswap16 +# define JSONCONS_H_TO_LE16 __builtin_bswap16 +# else +# define JSONCONS_LE16_TO_H(x) (((uint16_t)x >> 8) | ((uint16_t)x << 8)) +# define JSONCONS_H_TO_LE16 JSONCONS_LE16_TO_H +# endif +# define JSONCONS_BE64_TO_H +# define JSONCONS_H_TO_BE64 +# define JSONCONS_BE32_TO_H +# define JSONCONS_H_TO_BE32 +# define JSONCONS_BE16_TO_H +# define JSONCONS_H_TO_BE16 +# endif +#elif defined(__sun) +# include +#elif defined(_MSC_VER) +/* MSVC, which implies Windows, which implies little-endian and sizeof(long) == 4 */ +# define JSONCONS_BE64_TO_H _byteswap_uint64 +# define JSONCONS_H_TO_BE64 _byteswap_uint64 +# define JSONCONS_BE32_TO_H _byteswap_ulong +# define JSONCONS_H_TO_BE32 _byteswap_ulong +# define JSONCONS_BE16_TO_H _byteswap_ushort +# define JSONCONS_H_TO_BE16 _byteswap_ushort +# define JSONCONS_LE64_TO_H +# define JSONCONS_H_TO_LE64 +# define JSONCONS_LE32_TO_H +# define JSONCONS_H_TO_LE32 +# define JSONCONS_LE16_TO_H +# define JSONCONS_H_TO_LE16 +#endif +#ifndef JSONCONS_BE16_TO_H +# include +# define JSONCONS_BE16_TO_H ntohs +# define JSONCONS_H_TO_BE16 htons +#endif +#ifndef JSONCONS_BE32_TO_H +# include +# define JSONCONS_BE32_TO_H ntohl +# define JSONCONS_H_TO_BE32 htonl +#endif +#ifndef JSONCONS_BE64_TO_H +# define JSONCONS_BE64_TO_H ntohll +# define JSONCONS_H_TO_BE64 htonll +/* ntohll isn't usually defined */ +# ifndef ntohll +# if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +# define ntohll +# define htonll +# elif defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +# define ntohll(x) ((ntohl((uint32_t)(x)) * UINT64_C(0x100000000)) + (ntohl((x) >> 32))) +# define htonll ntohll +# else +# error "Unable to determine byte order!" +# endif +# endif +#endif + +namespace jsoncons { namespace detail { + +class read_nbytes_failed : public std::invalid_argument, public virtual json_exception +{ +public: + explicit read_nbytes_failed(size_t count) noexcept + : std::invalid_argument("") + { + buffer_.append("Failed attempting to read "); + buffer_.append(std::to_string(count)); + buffer_.append(" bytes from vector"); + } + ~read_nbytes_failed() noexcept + { + } + const char* what() const noexcept override + { + return buffer_.c_str(); + } +private: + std::string buffer_; +}; + +namespace detail { + +static inline bool add_check_overflow(size_t v1, size_t v2, size_t *r) +{ +#if ((defined(__GNUC__) && (__GNUC__ >= 5)) && !defined(__INTEL_COMPILER)) || __has_builtin(__builtin_add_overflow) + return __builtin_add_overflow(v1, v2, r); +#else + // unsigned additions are well-defined + *r = v1 + v2; + return v1 > v1 + v2; +#endif +} + +} + +inline +uint16_t encode_half(double val) +{ +#if defined(__F16C__) && !defined(APPLE_MISSING_INTRINSICS) + return _cvtss_sh((float)val, 3); +#else + uint64_t v; + std::memcpy(&v, &val, sizeof(v)); + int sign = v >> 63 << 15; + int exp = (v >> 52) & 0x7ff; + int mant = v << 12 >> 12 >> (53-11); /* keep only the 11 most significant bits of the mantissa */ + exp -= 1023; + if (exp == 1024) { + /* infinity or NaN */ + exp = 16; + mant >>= 1; + } else if (exp >= 16) { + /* overflow, as largest number */ + exp = 15; + mant = 1023; + } else if (exp >= -14) { + /* regular normal */ + } else if (exp >= -24) { + /* subnormal */ + mant |= 1024; + mant >>= -(exp + 14); + exp = -15; + } else { + /* underflow, make zero */ + return 0; + } + + /* safe cast here as bit operations above guarantee not to overflow */ + return (uint16_t)(sign | ((exp + 15) << 10) | mant); +#endif +} + +/* this function was copied & adapted from RFC 7049 Appendix D */ +inline +double decode_half(uint16_t half) +{ +#if defined(__F16C__) && !defined(APPLE_MISSING_INTRINSICS) + return _cvtsh_ss(half); +#else + int exp = (half >> 10) & 0x1f; + int mant = half & 0x3ff; + double val; + if (exp == 0) + { + val = ldexp((double)mant, -24); + } + else if (exp != 31) + { + val = ldexp(mant + 1024.0, exp - 25); + } + else + { + val = mant == 0 ? INFINITY : NAN; + } + return half & 0x8000 ? -val : val; +#endif +} + +// to_big_endian + + +template +typename std::enable_if::value && sizeof(T) == sizeof(uint8_t),void>::type +to_big_endian(T val, OutputIt d_first) +{ + *d_first = static_cast(val); +} + + +template +typename std::enable_if::value && +sizeof(T) == sizeof(uint16_t),void>::type +to_big_endian(T val, OutputIt d_first) +{ + T x = JSONCONS_H_TO_BE16(val); + + uint8_t where[sizeof(T)]; + std::memcpy(where, &x, sizeof(T)); + + *d_first++ = where[0]; + *d_first++ = where[1]; +} + +template +typename std::enable_if::value && +sizeof(T) == sizeof(uint32_t),void>::type +to_big_endian(T val, OutputIt d_first) +{ + T x = JSONCONS_H_TO_BE32(val); + + uint8_t where[sizeof(T)]; + std::memcpy(where, &x, sizeof(T)); + + *d_first++ = where[0]; + *d_first++ = where[1]; + *d_first++ = where[2]; + *d_first++ = where[3]; +} + +template +typename std::enable_if::value && +sizeof(T) == sizeof(uint64_t),void>::type +to_big_endian(T val, OutputIt d_first) +{ + T x = JSONCONS_H_TO_BE64(val); + + uint8_t where[sizeof(T)]; + std::memcpy(where, &x, sizeof(T)); + + *d_first++ = where[0]; + *d_first++ = where[1]; + *d_first++ = where[2]; + *d_first++ = where[3]; + *d_first++ = where[4]; + *d_first++ = where[5]; + *d_first++ = where[6]; + *d_first++ = where[7]; +} + +template +void to_big_endian(float val, OutputIt d_first) +{ + uint32_t where; + std::memcpy(&where,&val,sizeof(val)); + to_big_endian(where, d_first); +} + +template +void to_big_endian(double val, OutputIt d_first) +{ + uint64_t where; + std::memcpy(&where,&val,sizeof(val)); + to_big_endian(where, d_first); +} + +// to_little_endian + +template +typename std::enable_if::value && +sizeof(T) == sizeof(uint32_t),void>::type +to_little_endian(T val, OutputIt d_first) +{ + T x = JSONCONS_H_TO_LE32(val); + + uint8_t where[sizeof(T)]; + std::memcpy(where, &x, sizeof(T)); + + *d_first++ = where[0]; + *d_first++ = where[1]; + *d_first++ = where[2]; + *d_first++ = where[3]; +} + +template +typename std::enable_if::value && +sizeof(T) == sizeof(uint64_t),void>::type +to_little_endian(T val, OutputIt d_first) +{ + T x = JSONCONS_H_TO_LE64(val); + + uint8_t where[sizeof(T)]; + std::memcpy(where, &x, sizeof(T)); + + *d_first++ = where[0]; + *d_first++ = where[1]; + *d_first++ = where[2]; + *d_first++ = where[3]; + *d_first++ = where[4]; + *d_first++ = where[5]; + *d_first++ = where[6]; + *d_first++ = where[7]; +} + +template +void to_little_endian(float val, OutputIt d_first) +{ + uint32_t where; + std::memcpy(&where,&val,sizeof(val)); + to_little_endian(where, d_first); +} + +template +void to_little_endian(double val, OutputIt d_first) +{ + uint64_t where; + std::memcpy(&where,&val,sizeof(val)); + to_little_endian(where, d_first); +} + +// from_big_endian + +template +typename std::enable_if::value && +sizeof(T) == sizeof(uint8_t),T>::type +from_big_endian(const uint8_t* first, const uint8_t* last, const uint8_t** endp) +{ + if (first + sizeof(T) > last) + { + *endp = first; + return 0; + } + else + { + *endp = first + sizeof(T); + return static_cast(*(first)); + } +} + +template +typename std::enable_if::value && +sizeof(T) == sizeof(uint16_t),T>::type +from_big_endian(const uint8_t* first, const uint8_t* last, const uint8_t** endp) +{ + if (first + sizeof(T) > last) + { + *endp = first; + return 0; + } + else + { + *endp = first + sizeof(T); + T val; + std::memcpy(&val,first,sizeof(T)); + return JSONCONS_BE16_TO_H(val); + } +} + +template +typename std::enable_if::value && sizeof(T) == sizeof(uint32_t),T>::type +from_big_endian(const uint8_t* first, const uint8_t* last, const uint8_t** endp) +{ + if (first + sizeof(T) > last) + { + *endp = first; + return 0; + } + else + { + *endp = first + sizeof(T); + T val; + std::memcpy(&val,first,sizeof(T)); + return JSONCONS_BE32_TO_H(val); + } +} + +template +typename std::enable_if::value && sizeof(T) == sizeof(uint64_t),T>::type +from_big_endian(const uint8_t* first, const uint8_t* last, const uint8_t** endp) +{ + if (first + sizeof(T) > last) + { + *endp = first; + return 0; + } + else + { + *endp = first + sizeof(T); + T val; + std::memcpy(&val,first,sizeof(T)); + return JSONCONS_BE64_TO_H(val); + } +} + +template +typename std::enable_if::value && +sizeof(T) == sizeof(uint32_t),T>::type +from_big_endian(const uint8_t* first, const uint8_t* last, const uint8_t** endp) +{ + uint32_t data = from_big_endian(first,last,endp); + T val; + std::memcpy(&val,&data,sizeof(T)); + return val; +} + +template +typename std::enable_if::value && +sizeof(T) == sizeof(uint64_t),T>::type +from_big_endian(const uint8_t* first, const uint8_t* last, const uint8_t** endp) +{ + uint64_t data = from_big_endian(first,last,endp); + T val; + std::memcpy(&val,&data,sizeof(T)); + return val; +} + +// from_little_endian + +template +typename std::enable_if::value && +sizeof(T) == sizeof(uint8_t),T>::type +from_little_endian(const uint8_t* first, const uint8_t* last, const uint8_t** endp) +{ + if (first + sizeof(T) > last) + { + *endp = first; + return 0; + } + else + { + *endp = first + sizeof(T); + return static_cast(*(first)); + } +} + +template +typename std::enable_if::value && +sizeof(T) == sizeof(uint16_t),T>::type +from_little_endian(const uint8_t* first, const uint8_t* last, const uint8_t** endp) +{ + if (first + sizeof(T) > last) + { + *endp = first; + return 0; + } + else + { + *endp = first + sizeof(T); + T val; + std::memcpy(&val,first,sizeof(T)); + return JSONCONS_LE16_TO_H(val); + } +} + +template +typename std::enable_if::value && sizeof(T) == sizeof(uint32_t),T>::type +from_little_endian(const uint8_t* first, const uint8_t* last, const uint8_t** endp) +{ + if (first + sizeof(T) > last) + { + *endp = first; + return 0; + } + else + { + *endp = first + sizeof(T); + T val; + std::memcpy(&val,first,sizeof(T)); + return JSONCONS_LE32_TO_H(val); + } +} + +template +typename std::enable_if::value && sizeof(T) == sizeof(uint64_t),T>::type +from_little_endian(const uint8_t* first, const uint8_t* last, const uint8_t** endp) +{ + if (first + sizeof(T) > last) + { + *endp = first; + return 0; + } + else + { + *endp = first + sizeof(T); + T val; + std::memcpy(&val,first,sizeof(T)); + return JSONCONS_LE64_TO_H(val); + } +} + +template +typename std::enable_if::value && +sizeof(T) == sizeof(uint32_t),T>::type +from_little_endian(const uint8_t* first, const uint8_t* last, const uint8_t** endp) +{ + uint32_t data = from_little_endian(first,last,endp); + T val; + std::memcpy(&val,&data,sizeof(T)); + return val; +} + +template +typename std::enable_if::value && +sizeof(T) == sizeof(uint64_t),T>::type +from_little_endian(const uint8_t* first, const uint8_t* last, const uint8_t** endp) +{ + uint64_t data = from_little_endian(first,last,endp); + T val; + std::memcpy(&val,&data,sizeof(T)); + return val; +} + +}} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/config/jsoncons_config.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/config/jsoncons_config.hpp new file mode 100644 index 0000000000..f61c18b14c --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/config/jsoncons_config.hpp @@ -0,0 +1,114 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSONCONS_CONFIG_HPP +#define JSONCONS_JSONCONS_CONFIG_HPP + +#include +#include +#include +#include + +// Uncomment the following line to suppress deprecated names (recommended for new code) +//#define JSONCONS_NO_DEPRECATED + +// The definitions below follow the definitions in compiler_support_p.h, https://github.com/01org/tinycbor +// MIT license + +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54577 +#if defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ < 9 +#define JSONCONS_NO_ERASE_TAKING_CONST_ITERATOR 1 +#endif + +#if defined(__clang__) +# define JSONCONS_FALLTHROUGH [[clang::fallthrough]] +#elif defined(__GNUC__) && ((__GNUC__ >= 7)) +# define JSONCONS_FALLTHROUGH __attribute__((fallthrough)) +#elif defined (__GNUC__) +# define JSONCONS_FALLTHROUGH // FALLTHRU +#else +# define JSONCONS_FALLTHROUGH +#endif + +#if defined(__GNUC__) || defined(__clang__) +#define JSONCONS_LIKELY(x) __builtin_expect(!!(x), 1) +#define JSONCONS_UNLIKELY(x) __builtin_expect(!!(x), 0) +#define JSONCONS_UNREACHABLE() __builtin_unreachable() +#elif defined(_MSC_VER) +#define JSONCONS_LIKELY(x) x +#define JSONCONS_UNLIKELY(x) x +#define JSONCONS_UNREACHABLE() __assume(0) +#else +#define JSONCONS_LIKELY(x) x +#define JSONCONS_UNLIKELY(x) x +#define JSONCONS_UNREACHABLE() do {} while (0) +#endif + +// Follows boost 1_68 +#if !defined(JSONCONS_HAS_STRING_VIEW) +# if defined(__clang__) +# if (__cplusplus >= 201703) +# if __has_include() +# define JSONCONS_HAS_STRING_VIEW 1 +# endif // __has_include() +# endif // (__cplusplus >= 201703) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if (__GNUC__ >= 7) +# if (__cplusplus >= 201703) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) +# define JSONCONS_HAS_STRING_VIEW 1 +# endif // (__cplusplus >= 201703) +# endif // (__GNUC__ >= 7) +# endif // defined(__GNUC__) +# if defined(_MSC_VER) +# if (_MSC_VER >= 1910 && _HAS_CXX17) +# define JSONCONS_HAS_STRING_VIEW +# endif // (_MSC_VER >= 1910 && _HAS_CXX17) +# endif // defined(_MSC_VER) +#endif // !defined(JSONCONS_HAS_STRING_VIEW) + +#define JSONCONS_NO_TO_CHARS + +#if defined(ANDROID) || defined(__ANDROID__) +#define JSONCONS_HAS_STRTOLD_L +#if __ANDROID_API__ >= 21 +#else +#define JSONCONS_NO_LOCALECONV +#endif +#endif + +#if defined(_MSC_VER) +#define JSONCONS_HAS_MSC__STRTOD_L +#define JSONCONS_HAS_FOPEN_S +#endif + +#if !defined(JSONCONS_HAS_STRING_VIEW) +#include +namespace jsoncons { +template > +using basic_string_view = jsoncons::detail::basic_string_view; +using string_view = basic_string_view>; +using wstring_view = basic_string_view>; +} +#else +#include +namespace jsoncons { +template > +using basic_string_view = std::basic_string_view; +using string_view = std::string_view; +using wstring_view = std::wstring_view; +} +#endif + +#define JSONCONS_STRING_LITERAL(name, ...) \ + template \ + const std::basic_string& name##_literal() {\ + static const CharT s[] = { __VA_ARGS__};\ + static const std::basic_string sv(s, sizeof(s) / sizeof(CharT));\ + return sv;\ + } + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/config/version.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/config/version.hpp new file mode 100644 index 0000000000..7c012b5536 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/config/version.hpp @@ -0,0 +1,40 @@ +// Copyright 2017 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_VERSION_HPP +#define JSONCONS_VERSION_HPP + +#include + +#define JSONCONS_VERSION_MAJOR 0 +#define JSONCONS_VERSION_MINOR 125 +#define JSONCONS_VERSION_PATCH 0 + +namespace jsoncons { + +struct versioning_info +{ + unsigned int const major; + unsigned int const minor; + unsigned int const patch; + + friend std::ostream& operator<<(std::ostream& os, const versioning_info& ver) + { + os << ver.major << '.' + << ver.minor << '.' + << ver.patch; + return os; + } +}; + +constexpr versioning_info version() +{ + return versioning_info{JSONCONS_VERSION_MAJOR, JSONCONS_VERSION_MINOR, JSONCONS_VERSION_PATCH}; +} + +} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/detail/grisu3.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/detail/grisu3.hpp new file mode 100644 index 0000000000..d8bd81107f --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/detail/grisu3.hpp @@ -0,0 +1,405 @@ +/* +Implements the Grisu3 algorithm for printing floating-point numbers. + +Follows Florian Loitsch's grisu3_59_56 implementation, available at +http://florian.loitsch.com/publications, in bench.tar.gz, with +minor modifications. +*/ + +/* + Copyright (c) 2009 Florian Loitsch + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, + copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following + conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef JSONCONS_GRISU3_HPP +#define JSONCONS_GRISU3_HPP + +#pragma once +#include +#include +#include +#include +#include +#include // std::memmove + +namespace jsoncons { namespace detail { + +// diy_fp + +typedef struct diy_fp_t { + uint64_t f; + int e; +} diy_fp_t; + +inline +diy_fp_t minus(diy_fp_t x, diy_fp_t y) +{ + assert(x.e == y.e); + assert(x.f >= y.f); + diy_fp_t r = { x.f = x.f - y.f, x.e = x.e }; + return r; +} + +inline +diy_fp_t multiply(diy_fp_t x, diy_fp_t y) +{ + uint64_t a, b, c, d, ac, bc, ad, bd, tmp; + diy_fp_t r; uint64_t M32 = 0xFFFFFFFF; + a = x.f >> 32; b = x.f & M32; + c = y.f >> 32; d = y.f & M32; + ac = a * c; bc = b * c; ad = a * d; bd = b * d; + tmp = (bd >> 32) + (ad & M32) + (bc & M32); + tmp += 1U << 31; /// mult_round + r.f = ac + (ad >> 32) + (bc >> 32) + (tmp >> 32); + r.e = x.e + y.e + 64; + return r; +} + +// k_comp + +inline +int k_comp(int e, int alpha, int /*gamma*/) +{ + constexpr double d_1_log2_10 = 0.30102999566398114; // 1 / lg(10) + return static_cast(std::ceil((alpha - e + 63) * d_1_log2_10)); +} + +// powers_ten_round64 + +constexpr int diy_significand_size = 64; + +static const uint64_t powers_ten[] = { 0xbf29dcaba82fdeae, 0xeef453d6923bd65a, 0x9558b4661b6565f8, 0xbaaee17fa23ebf76, 0xe95a99df8ace6f54, 0x91d8a02bb6c10594, 0xb64ec836a47146fa, 0xe3e27a444d8d98b8, 0x8e6d8c6ab0787f73, 0xb208ef855c969f50, 0xde8b2b66b3bc4724, 0x8b16fb203055ac76, 0xaddcb9e83c6b1794, 0xd953e8624b85dd79, 0x87d4713d6f33aa6c, 0xa9c98d8ccb009506, 0xd43bf0effdc0ba48, 0x84a57695fe98746d, 0xa5ced43b7e3e9188, 0xcf42894a5dce35ea, 0x818995ce7aa0e1b2, 0xa1ebfb4219491a1f, 0xca66fa129f9b60a7, 0xfd00b897478238d1, 0x9e20735e8cb16382, 0xc5a890362fddbc63, 0xf712b443bbd52b7c, 0x9a6bb0aa55653b2d, 0xc1069cd4eabe89f9, 0xf148440a256e2c77, 0x96cd2a865764dbca, 0xbc807527ed3e12bd, 0xeba09271e88d976c, 0x93445b8731587ea3, 0xb8157268fdae9e4c, 0xe61acf033d1a45df, 0x8fd0c16206306bac, 0xb3c4f1ba87bc8697, 0xe0b62e2929aba83c, 0x8c71dcd9ba0b4926, 0xaf8e5410288e1b6f, 0xdb71e91432b1a24b, 0x892731ac9faf056f, 0xab70fe17c79ac6ca, 0xd64d3d9db981787d, 0x85f0468293f0eb4e, 0xa76c582338ed2622, 0xd1476e2c07286faa, 0x82cca4db847945ca, 0xa37fce126597973d, 0xcc5fc196fefd7d0c, 0xff77b1fcbebcdc4f, 0x9faacf3df73609b1, 0xc795830d75038c1e, 0xf97ae3d0d2446f25, 0x9becce62836ac577, 0xc2e801fb244576d5, 0xf3a20279ed56d48a, 0x9845418c345644d7, 0xbe5691ef416bd60c, 0xedec366b11c6cb8f, 0x94b3a202eb1c3f39, 0xb9e08a83a5e34f08, 0xe858ad248f5c22ca, 0x91376c36d99995be, 0xb58547448ffffb2e, 0xe2e69915b3fff9f9, 0x8dd01fad907ffc3c, 0xb1442798f49ffb4b, 0xdd95317f31c7fa1d, 0x8a7d3eef7f1cfc52, 0xad1c8eab5ee43b67, 0xd863b256369d4a41, 0x873e4f75e2224e68, 0xa90de3535aaae202, 0xd3515c2831559a83, 0x8412d9991ed58092, 0xa5178fff668ae0b6, 0xce5d73ff402d98e4, 0x80fa687f881c7f8e, 0xa139029f6a239f72, 0xc987434744ac874f, 0xfbe9141915d7a922, 0x9d71ac8fada6c9b5, 0xc4ce17b399107c23, 0xf6019da07f549b2b, 0x99c102844f94e0fb, 0xc0314325637a193a, 0xf03d93eebc589f88, 0x96267c7535b763b5, 0xbbb01b9283253ca3, 0xea9c227723ee8bcb, 0x92a1958a7675175f, 0xb749faed14125d37, 0xe51c79a85916f485, 0x8f31cc0937ae58d3, 0xb2fe3f0b8599ef08, 0xdfbdcece67006ac9, 0x8bd6a141006042be, 0xaecc49914078536d, 0xda7f5bf590966849, 0x888f99797a5e012d, 0xaab37fd7d8f58179, 0xd5605fcdcf32e1d7, 0x855c3be0a17fcd26, 0xa6b34ad8c9dfc070, 0xd0601d8efc57b08c, 0x823c12795db6ce57, 0xa2cb1717b52481ed, 0xcb7ddcdda26da269, 0xfe5d54150b090b03, 0x9efa548d26e5a6e2, 0xc6b8e9b0709f109a, 0xf867241c8cc6d4c1, 0x9b407691d7fc44f8, 0xc21094364dfb5637, 0xf294b943e17a2bc4, 0x979cf3ca6cec5b5b, 0xbd8430bd08277231, 0xece53cec4a314ebe, 0x940f4613ae5ed137, 0xb913179899f68584, 0xe757dd7ec07426e5, 0x9096ea6f3848984f, 0xb4bca50b065abe63, 0xe1ebce4dc7f16dfc, 0x8d3360f09cf6e4bd, 0xb080392cc4349ded, 0xdca04777f541c568, 0x89e42caaf9491b61, 0xac5d37d5b79b6239, 0xd77485cb25823ac7, 0x86a8d39ef77164bd, 0xa8530886b54dbdec, 0xd267caa862a12d67, 0x8380dea93da4bc60, 0xa46116538d0deb78, 0xcd795be870516656, 0x806bd9714632dff6, 0xa086cfcd97bf97f4, 0xc8a883c0fdaf7df0, 0xfad2a4b13d1b5d6c, 0x9cc3a6eec6311a64, 0xc3f490aa77bd60fd, 0xf4f1b4d515acb93c, 0x991711052d8bf3c5, 0xbf5cd54678eef0b7, 0xef340a98172aace5, 0x9580869f0e7aac0f, 0xbae0a846d2195713, 0xe998d258869facd7, 0x91ff83775423cc06, 0xb67f6455292cbf08, 0xe41f3d6a7377eeca, 0x8e938662882af53e, 0xb23867fb2a35b28e, 0xdec681f9f4c31f31, 0x8b3c113c38f9f37f, 0xae0b158b4738705f, 0xd98ddaee19068c76, 0x87f8a8d4cfa417ca, 0xa9f6d30a038d1dbc, 0xd47487cc8470652b, 0x84c8d4dfd2c63f3b, 0xa5fb0a17c777cf0a, 0xcf79cc9db955c2cc, 0x81ac1fe293d599c0, 0xa21727db38cb0030, 0xca9cf1d206fdc03c, 0xfd442e4688bd304b, 0x9e4a9cec15763e2f, 0xc5dd44271ad3cdba, 0xf7549530e188c129, 0x9a94dd3e8cf578ba, 0xc13a148e3032d6e8, 0xf18899b1bc3f8ca2, 0x96f5600f15a7b7e5, 0xbcb2b812db11a5de, 0xebdf661791d60f56, 0x936b9fcebb25c996, 0xb84687c269ef3bfb, 0xe65829b3046b0afa, 0x8ff71a0fe2c2e6dc, 0xb3f4e093db73a093, 0xe0f218b8d25088b8, 0x8c974f7383725573, 0xafbd2350644eead0, 0xdbac6c247d62a584, 0x894bc396ce5da772, 0xab9eb47c81f5114f, 0xd686619ba27255a3, 0x8613fd0145877586, 0xa798fc4196e952e7, 0xd17f3b51fca3a7a1, 0x82ef85133de648c5, 0xa3ab66580d5fdaf6, 0xcc963fee10b7d1b3, 0xffbbcfe994e5c620, 0x9fd561f1fd0f9bd4, 0xc7caba6e7c5382c9, 0xf9bd690a1b68637b, 0x9c1661a651213e2d, 0xc31bfa0fe5698db8, 0xf3e2f893dec3f126, 0x986ddb5c6b3a76b8, 0xbe89523386091466, 0xee2ba6c0678b597f, 0x94db483840b717f0, 0xba121a4650e4ddec, 0xe896a0d7e51e1566, 0x915e2486ef32cd60, 0xb5b5ada8aaff80b8, 0xe3231912d5bf60e6, 0x8df5efabc5979c90, 0xb1736b96b6fd83b4, 0xddd0467c64bce4a1, 0x8aa22c0dbef60ee4, 0xad4ab7112eb3929e, 0xd89d64d57a607745, 0x87625f056c7c4a8b, 0xa93af6c6c79b5d2e, 0xd389b47879823479, 0x843610cb4bf160cc, 0xa54394fe1eedb8ff, 0xce947a3da6a9273e, 0x811ccc668829b887, 0xa163ff802a3426a9, 0xc9bcff6034c13053, 0xfc2c3f3841f17c68, 0x9d9ba7832936edc1, 0xc5029163f384a931, 0xf64335bcf065d37d, 0x99ea0196163fa42e, 0xc06481fb9bcf8d3a, 0xf07da27a82c37088, 0x964e858c91ba2655, 0xbbe226efb628afeb, 0xeadab0aba3b2dbe5, 0x92c8ae6b464fc96f, 0xb77ada0617e3bbcb, 0xe55990879ddcaabe, 0x8f57fa54c2a9eab7, 0xb32df8e9f3546564, 0xdff9772470297ebd, 0x8bfbea76c619ef36, 0xaefae51477a06b04, 0xdab99e59958885c5, 0x88b402f7fd75539b, 0xaae103b5fcd2a882, 0xd59944a37c0752a2, 0x857fcae62d8493a5, 0xa6dfbd9fb8e5b88f, 0xd097ad07a71f26b2, 0x825ecc24c8737830, 0xa2f67f2dfa90563b, 0xcbb41ef979346bca, 0xfea126b7d78186bd, 0x9f24b832e6b0f436, 0xc6ede63fa05d3144, 0xf8a95fcf88747d94, 0x9b69dbe1b548ce7d, 0xc24452da229b021c, 0xf2d56790ab41c2a3, 0x97c560ba6b0919a6, 0xbdb6b8e905cb600f, 0xed246723473e3813, 0x9436c0760c86e30c, 0xb94470938fa89bcf, 0xe7958cb87392c2c3, 0x90bd77f3483bb9ba, 0xb4ecd5f01a4aa828, 0xe2280b6c20dd5232, 0x8d590723948a535f, 0xb0af48ec79ace837, 0xdcdb1b2798182245, 0x8a08f0f8bf0f156b, 0xac8b2d36eed2dac6, 0xd7adf884aa879177, 0x86ccbb52ea94baeb, 0xa87fea27a539e9a5, 0xd29fe4b18e88640f, 0x83a3eeeef9153e89, 0xa48ceaaab75a8e2b, 0xcdb02555653131b6, 0x808e17555f3ebf12, 0xa0b19d2ab70e6ed6, 0xc8de047564d20a8c, 0xfb158592be068d2f, 0x9ced737bb6c4183d, 0xc428d05aa4751e4d, 0xf53304714d9265e0, 0x993fe2c6d07b7fac, 0xbf8fdb78849a5f97, 0xef73d256a5c0f77d, 0x95a8637627989aae, 0xbb127c53b17ec159, 0xe9d71b689dde71b0, 0x9226712162ab070e, 0xb6b00d69bb55c8d1, 0xe45c10c42a2b3b06, 0x8eb98a7a9a5b04e3, 0xb267ed1940f1c61c, 0xdf01e85f912e37a3, 0x8b61313bbabce2c6, 0xae397d8aa96c1b78, 0xd9c7dced53c72256, 0x881cea14545c7575, 0xaa242499697392d3, 0xd4ad2dbfc3d07788, 0x84ec3c97da624ab5, 0xa6274bbdd0fadd62, 0xcfb11ead453994ba, 0x81ceb32c4b43fcf5, 0xa2425ff75e14fc32, 0xcad2f7f5359a3b3e, 0xfd87b5f28300ca0e, 0x9e74d1b791e07e48, 0xc612062576589ddb, 0xf79687aed3eec551, 0x9abe14cd44753b53, 0xc16d9a0095928a27, 0xf1c90080baf72cb1, 0x971da05074da7bef, 0xbce5086492111aeb, 0xec1e4a7db69561a5, 0x9392ee8e921d5d07, 0xb877aa3236a4b449, 0xe69594bec44de15b, 0x901d7cf73ab0acd9, 0xb424dc35095cd80f, 0xe12e13424bb40e13, 0x8cbccc096f5088cc, 0xafebff0bcb24aaff, 0xdbe6fecebdedd5bf, 0x89705f4136b4a597, 0xabcc77118461cefd, 0xd6bf94d5e57a42bc, 0x8637bd05af6c69b6, 0xa7c5ac471b478423, 0xd1b71758e219652c, 0x83126e978d4fdf3b, 0xa3d70a3d70a3d70a, 0xcccccccccccccccd, 0x8000000000000000, 0xa000000000000000, 0xc800000000000000, 0xfa00000000000000, 0x9c40000000000000, 0xc350000000000000, 0xf424000000000000, 0x9896800000000000, 0xbebc200000000000, 0xee6b280000000000, 0x9502f90000000000, 0xba43b74000000000, 0xe8d4a51000000000, 0x9184e72a00000000, 0xb5e620f480000000, 0xe35fa931a0000000, 0x8e1bc9bf04000000, 0xb1a2bc2ec5000000, 0xde0b6b3a76400000, 0x8ac7230489e80000, 0xad78ebc5ac620000, 0xd8d726b7177a8000, 0x878678326eac9000, 0xa968163f0a57b400, 0xd3c21bcecceda100, 0x84595161401484a0, 0xa56fa5b99019a5c8, 0xcecb8f27f4200f3a, 0x813f3978f8940984, 0xa18f07d736b90be5, 0xc9f2c9cd04674edf, 0xfc6f7c4045812296, 0x9dc5ada82b70b59e, 0xc5371912364ce305, 0xf684df56c3e01bc7, 0x9a130b963a6c115c, 0xc097ce7bc90715b3, 0xf0bdc21abb48db20, 0x96769950b50d88f4, 0xbc143fa4e250eb31, 0xeb194f8e1ae525fd, 0x92efd1b8d0cf37be, 0xb7abc627050305ae, 0xe596b7b0c643c719, 0x8f7e32ce7bea5c70, 0xb35dbf821ae4f38c, 0xe0352f62a19e306f, 0x8c213d9da502de45, 0xaf298d050e4395d7, 0xdaf3f04651d47b4c, 0x88d8762bf324cd10, 0xab0e93b6efee0054, 0xd5d238a4abe98068, 0x85a36366eb71f041, 0xa70c3c40a64e6c52, 0xd0cf4b50cfe20766, 0x82818f1281ed44a0, 0xa321f2d7226895c8, 0xcbea6f8ceb02bb3a, 0xfee50b7025c36a08, 0x9f4f2726179a2245, 0xc722f0ef9d80aad6, 0xf8ebad2b84e0d58c, 0x9b934c3b330c8577, 0xc2781f49ffcfa6d5, 0xf316271c7fc3908b, 0x97edd871cfda3a57, 0xbde94e8e43d0c8ec, 0xed63a231d4c4fb27, 0x945e455f24fb1cf9, 0xb975d6b6ee39e437, 0xe7d34c64a9c85d44, 0x90e40fbeea1d3a4b, 0xb51d13aea4a488dd, 0xe264589a4dcdab15, 0x8d7eb76070a08aed, 0xb0de65388cc8ada8, 0xdd15fe86affad912, 0x8a2dbf142dfcc7ab, 0xacb92ed9397bf996, 0xd7e77a8f87daf7fc, 0x86f0ac99b4e8dafd, 0xa8acd7c0222311bd, 0xd2d80db02aabd62c, 0x83c7088e1aab65db, 0xa4b8cab1a1563f52, 0xcde6fd5e09abcf27, 0x80b05e5ac60b6178, 0xa0dc75f1778e39d6, 0xc913936dd571c84c, 0xfb5878494ace3a5f, 0x9d174b2dcec0e47b, 0xc45d1df942711d9a, 0xf5746577930d6501, 0x9968bf6abbe85f20, 0xbfc2ef456ae276e9, 0xefb3ab16c59b14a3, 0x95d04aee3b80ece6, 0xbb445da9ca61281f, 0xea1575143cf97227, 0x924d692ca61be758, 0xb6e0c377cfa2e12e, 0xe498f455c38b997a, 0x8edf98b59a373fec, 0xb2977ee300c50fe7, 0xdf3d5e9bc0f653e1, 0x8b865b215899f46d, 0xae67f1e9aec07188, 0xda01ee641a708dea, 0x884134fe908658b2, 0xaa51823e34a7eedf, 0xd4e5e2cdc1d1ea96, 0x850fadc09923329e, 0xa6539930bf6bff46, 0xcfe87f7cef46ff17, 0x81f14fae158c5f6e, 0xa26da3999aef774a, 0xcb090c8001ab551c, 0xfdcb4fa002162a63, 0x9e9f11c4014dda7e, 0xc646d63501a1511e, 0xf7d88bc24209a565, 0x9ae757596946075f, 0xc1a12d2fc3978937, 0xf209787bb47d6b85, 0x9745eb4d50ce6333, 0xbd176620a501fc00, 0xec5d3fa8ce427b00, 0x93ba47c980e98ce0, 0xb8a8d9bbe123f018, 0xe6d3102ad96cec1e, 0x9043ea1ac7e41393, 0xb454e4a179dd1877, 0xe16a1dc9d8545e95, 0x8ce2529e2734bb1d, 0xb01ae745b101e9e4, 0xdc21a1171d42645d, 0x899504ae72497eba, 0xabfa45da0edbde69, 0xd6f8d7509292d603, 0x865b86925b9bc5c2, 0xa7f26836f282b733, 0xd1ef0244af2364ff, 0x8335616aed761f1f, 0xa402b9c5a8d3a6e7, 0xcd036837130890a1, 0x802221226be55a65, 0xa02aa96b06deb0fe, 0xc83553c5c8965d3d, 0xfa42a8b73abbf48d, 0x9c69a97284b578d8, 0xc38413cf25e2d70e, 0xf46518c2ef5b8cd1, 0x98bf2f79d5993803, 0xbeeefb584aff8604, 0xeeaaba2e5dbf6785, 0x952ab45cfa97a0b3, 0xba756174393d88e0, 0xe912b9d1478ceb17, 0x91abb422ccb812ef, 0xb616a12b7fe617aa, 0xe39c49765fdf9d95, 0x8e41ade9fbebc27d, 0xb1d219647ae6b31c, 0xde469fbd99a05fe3, 0x8aec23d680043bee, 0xada72ccc20054aea, 0xd910f7ff28069da4, 0x87aa9aff79042287, 0xa99541bf57452b28, 0xd3fa922f2d1675f2, 0x847c9b5d7c2e09b7, 0xa59bc234db398c25, 0xcf02b2c21207ef2f, 0x8161afb94b44f57d, 0xa1ba1ba79e1632dc, 0xca28a291859bbf93, 0xfcb2cb35e702af78, 0x9defbf01b061adab, 0xc56baec21c7a1916, 0xf6c69a72a3989f5c, 0x9a3c2087a63f6399, 0xc0cb28a98fcf3c80, 0xf0fdf2d3f3c30b9f, 0x969eb7c47859e744, 0xbc4665b596706115, 0xeb57ff22fc0c795a, 0x9316ff75dd87cbd8, 0xb7dcbf5354e9bece, 0xe5d3ef282a242e82, 0x8fa475791a569d11, 0xb38d92d760ec4455, 0xe070f78d3927556b, 0x8c469ab843b89563, 0xaf58416654a6babb, 0xdb2e51bfe9d0696a, 0x88fcf317f22241e2, 0xab3c2fddeeaad25b, 0xd60b3bd56a5586f2, 0x85c7056562757457, 0xa738c6bebb12d16d, 0xd106f86e69d785c8, 0x82a45b450226b39d, 0xa34d721642b06084, 0xcc20ce9bd35c78a5, 0xff290242c83396ce, 0x9f79a169bd203e41, 0xc75809c42c684dd1, 0xf92e0c3537826146, 0x9bbcc7a142b17ccc, 0xc2abf989935ddbfe, 0xf356f7ebf83552fe, 0x98165af37b2153df, 0xbe1bf1b059e9a8d6, 0xeda2ee1c7064130c, 0x9485d4d1c63e8be8, 0xb9a74a0637ce2ee1, 0xe8111c87c5c1ba9a, 0x910ab1d4db9914a0, 0xb54d5e4a127f59c8, 0xe2a0b5dc971f303a, 0x8da471a9de737e24, 0xb10d8e1456105dad, 0xdd50f1996b947519, 0x8a5296ffe33cc930, 0xace73cbfdc0bfb7b, 0xd8210befd30efa5a, 0x8714a775e3e95c78, 0xa8d9d1535ce3b396, 0xd31045a8341ca07c, 0x83ea2b892091e44e, 0xa4e4b66b68b65d61, 0xce1de40642e3f4b9, 0x80d2ae83e9ce78f4, 0xa1075a24e4421731, 0xc94930ae1d529cfd, 0xfb9b7cd9a4a7443c, 0x9d412e0806e88aa6, 0xc491798a08a2ad4f, 0xf5b5d7ec8acb58a3, 0x9991a6f3d6bf1766, 0xbff610b0cc6edd3f, 0xeff394dcff8a948f, 0x95f83d0a1fb69cd9, 0xbb764c4ca7a44410, 0xea53df5fd18d5514, 0x92746b9be2f8552c, 0xb7118682dbb66a77, 0xe4d5e82392a40515, 0x8f05b1163ba6832d, 0xb2c71d5bca9023f8, 0xdf78e4b2bd342cf7, 0x8bab8eefb6409c1a, 0xae9672aba3d0c321, 0xda3c0f568cc4f3e9, 0x8865899617fb1871, 0xaa7eebfb9df9de8e, 0xd51ea6fa85785631, 0x8533285c936b35df, 0xa67ff273b8460357, 0xd01fef10a657842c, 0x8213f56a67f6b29c, 0xa298f2c501f45f43, 0xcb3f2f7642717713, 0xfe0efb53d30dd4d8, 0x9ec95d1463e8a507, 0xc67bb4597ce2ce49, 0xf81aa16fdc1b81db, 0x9b10a4e5e9913129, 0xc1d4ce1f63f57d73, 0xf24a01a73cf2dcd0, 0x976e41088617ca02, 0xbd49d14aa79dbc82, 0xec9c459d51852ba3, 0x93e1ab8252f33b46, 0xb8da1662e7b00a17, 0xe7109bfba19c0c9d, 0x906a617d450187e2, 0xb484f9dc9641e9db, 0xe1a63853bbd26451, 0x8d07e33455637eb3, 0xb049dc016abc5e60, 0xdc5c5301c56b75f7, 0x89b9b3e11b6329bb, 0xac2820d9623bf429, 0xd732290fbacaf134, 0x867f59a9d4bed6c0, 0xa81f301449ee8c70, 0xd226fc195c6a2f8c, 0x83585d8fd9c25db8, 0xa42e74f3d032f526, 0xcd3a1230c43fb26f, 0x80444b5e7aa7cf85, 0xa0555e361951c367, 0xc86ab5c39fa63441, 0xfa856334878fc151, 0x9c935e00d4b9d8d2, 0xc3b8358109e84f07, 0xf4a642e14c6262c9, 0x98e7e9cccfbd7dbe, 0xbf21e44003acdd2d, 0xeeea5d5004981478, 0x95527a5202df0ccb, 0xbaa718e68396cffe, 0xe950df20247c83fd, 0x91d28b7416cdd27e, 0xb6472e511c81471e, 0xe3d8f9e563a198e5, 0x8e679c2f5e44ff8f, 0xb201833b35d63f73, 0xde81e40a034bcf50, 0x8b112e86420f6192, 0xadd57a27d29339f6, 0xd94ad8b1c7380874, 0x87cec76f1c830549, 0xa9c2794ae3a3c69b, 0xd433179d9c8cb841, 0x849feec281d7f329, 0xa5c7ea73224deff3, 0xcf39e50feae16bf0, 0x81842f29f2cce376, 0xa1e53af46f801c53, 0xca5e89b18b602368, 0xfcf62c1dee382c42, 0x9e19db92b4e31ba9, 0xc5a05277621be294, 0xf70867153aa2db39, 0x9a65406d44a5c903, 0xc0fe908895cf3b44, 0xf13e34aabb430a15, 0x96c6e0eab509e64d, 0xbc789925624c5fe1, 0xeb96bf6ebadf77d9, 0x933e37a534cbaae8, 0xb80dc58e81fe95a1, 0xe61136f2227e3b0a, 0x8fcac257558ee4e6, 0xb3bd72ed2af29e20, 0xe0accfa875af45a8, 0x8c6c01c9498d8b89, 0xaf87023b9bf0ee6b, 0xdb68c2ca82ed2a06, 0x892179be91d43a44, 0xab69d82e364948d4 }; +static const int powers_ten_e[] = { -1203, -1200, -1196, -1193, -1190, -1186, -1183, -1180, -1176, -1173, -1170, -1166, -1163, -1160, -1156, -1153, -1150, -1146, -1143, -1140, -1136, -1133, -1130, -1127, -1123, -1120, -1117, -1113, -1110, -1107, -1103, -1100, -1097, -1093, -1090, -1087, -1083, -1080, -1077, -1073, -1070, -1067, -1063, -1060, -1057, -1053, -1050, -1047, -1043, -1040, -1037, -1034, -1030, -1027, -1024, -1020, -1017, -1014, -1010, -1007, -1004, -1000, -997, -994, -990, -987, -984, -980, -977, -974, -970, -967, -964, -960, -957, -954, -950, -947, -944, -940, -937, -934, -931, -927, -924, -921, -917, -914, -911, -907, -904, -901, -897, -894, -891, -887, -884, -881, -877, -874, -871, -867, -864, -861, -857, -854, -851, -847, -844, -841, -838, -834, -831, -828, -824, -821, -818, -814, -811, -808, -804, -801, -798, -794, -791, -788, -784, -781, -778, -774, -771, -768, -764, -761, -758, -754, -751, -748, -744, -741, -738, -735, -731, -728, -725, -721, -718, -715, -711, -708, -705, -701, -698, -695, -691, -688, -685, -681, -678, -675, -671, -668, -665, -661, -658, -655, -651, -648, -645, -642, -638, -635, -632, -628, -625, -622, -618, -615, -612, -608, -605, -602, -598, -595, -592, -588, -585, -582, -578, -575, -572, -568, -565, -562, -558, -555, -552, -549, -545, -542, -539, -535, -532, -529, -525, -522, -519, -515, -512, -509, -505, -502, -499, -495, -492, -489, -485, -482, -479, -475, -472, -469, -465, -462, -459, -455, -452, -449, -446, -442, -439, -436, -432, -429, -426, -422, -419, -416, -412, -409, -406, -402, -399, -396, -392, -389, -386, -382, -379, -376, -372, -369, -366, -362, -359, -356, -353, -349, -346, -343, -339, -336, -333, -329, -326, -323, -319, -316, -313, -309, -306, -303, -299, -296, -293, -289, -286, -283, -279, -276, -273, -269, -266, -263, -259, -256, -253, -250, -246, -243, -240, -236, -233, -230, -226, -223, -220, -216, -213, -210, -206, -203, -200, -196, -193, -190, -186, -183, -180, -176, -173, -170, -166, -163, -160, -157, -153, -150, -147, -143, -140, -137, -133, -130, -127, -123, -120, -117, -113, -110, -107, -103, -100, -97, -93, -90, -87, -83, -80, -77, -73, -70, -67, -63, -60, -57, -54, -50, -47, -44, -40, -37, -34, -30, -27, -24, -20, -17, -14, -10, -7, -4, 0, 3, 6, 10, 13, 16, 20, 23, 26, 30, 33, 36, 39, 43, 46, 49, 53, 56, 59, 63, 66, 69, 73, 76, 79, 83, 86, 89, 93, 96, 99, 103, 106, 109, 113, 116, 119, 123, 126, 129, 132, 136, 139, 142, 146, 149, 152, 156, 159, 162, 166, 169, 172, 176, 179, 182, 186, 189, 192, 196, 199, 202, 206, 209, 212, 216, 219, 222, 226, 229, 232, 235, 239, 242, 245, 249, 252, 255, 259, 262, 265, 269, 272, 275, 279, 282, 285, 289, 292, 295, 299, 302, 305, 309, 312, 315, 319, 322, 325, 328, 332, 335, 338, 342, 345, 348, 352, 355, 358, 362, 365, 368, 372, 375, 378, 382, 385, 388, 392, 395, 398, 402, 405, 408, 412, 415, 418, 422, 425, 428, 431, 435, 438, 441, 445, 448, 451, 455, 458, 461, 465, 468, 471, 475, 478, 481, 485, 488, 491, 495, 498, 501, 505, 508, 511, 515, 518, 521, 524, 528, 531, 534, 538, 541, 544, 548, 551, 554, 558, 561, 564, 568, 571, 574, 578, 581, 584, 588, 591, 594, 598, 601, 604, 608, 611, 614, 617, 621, 624, 627, 631, 634, 637, 641, 644, 647, 651, 654, 657, 661, 664, 667, 671, 674, 677, 681, 684, 687, 691, 694, 697, 701, 704, 707, 711, 714, 717, 720, 724, 727, 730, 734, 737, 740, 744, 747, 750, 754, 757, 760, 764, 767, 770, 774, 777, 780, 784, 787, 790, 794, 797, 800, 804, 807, 810, 813, 817, 820, 823, 827, 830, 833, 837, 840, 843, 847, 850, 853, 857, 860, 863, 867, 870, 873, 877, 880, 883, 887, 890, 893, 897, 900, 903, 907, 910, 913, 916, 920, 923, 926, 930, 933, 936, 940, 943, 946, 950, 953, 956, 960, 963, 966, 970, 973, 976, 980, 983, 986, 990, 993, 996, 1000, 1003, 1006, 1009, 1013, 1016, 1019, 1023, 1026, 1029, 1033, 1036, 1039, 1043, 1046, 1049, 1053, 1056, 1059, 1063, 1066, 1069, 1073, 1076 }; + +inline +diy_fp_t cached_power(int k) +{ + diy_fp_t res; + int index = 343 + k; + res.f = powers_ten[index]; + res.e = powers_ten_e[index]; + return res; +} + +// double + +typedef union { + double d; + uint64_t n; +} converter_t; + +inline +uint64_t double_to_uint64(double d) { converter_t tmp; tmp.d = d; return tmp.n; } + +inline +double uint64_to_double(uint64_t d64) { converter_t tmp; tmp.n = d64; return tmp.d; } + +constexpr int dp_significand_size = 52; +constexpr int dp_exponent_bias = (0x3FF + dp_significand_size); +constexpr int dp_min_exponent = (-dp_exponent_bias); +constexpr uint64_t dp_exponent_mask = 0x7FF0000000000000; +constexpr uint64_t dp_significand_mask = 0x000FFFFFFFFFFFFF; +constexpr uint64_t dp_hidden_bit = 0x0010000000000000; + +inline +diy_fp_t normalize_diy_fp(diy_fp_t in) +{ + diy_fp_t res = in; + /* Normalize now */ + /* the original number could have been a denormal. */ + while (!(res.f & dp_hidden_bit)) + { + res.f <<= 1; + res.e--; + } + /* do the final shifts in one go. Don't forget the hidden bit (the '-1') */ + res.f <<= (diy_significand_size - dp_significand_size - 1); + res.e = res.e - (diy_significand_size - dp_significand_size - 1); + return res; +} + +inline +diy_fp_t double2diy_fp(double d) +{ + uint64_t d64 = double_to_uint64(d); + int biased_e = (d64 & dp_exponent_mask) >> dp_significand_size; + uint64_t significand = (d64 & dp_significand_mask); + diy_fp_t res; + if (biased_e != 0) + { + res.f = significand + dp_hidden_bit; + res.e = biased_e - dp_exponent_bias; + } + else + { + res.f = significand; + res.e = dp_min_exponent + 1; + } + return res; +} + +inline +diy_fp_t normalize_boundary(diy_fp_t in) +{ + diy_fp_t res = in; + /* Normalize now */ + /* the original number could have been a denormal. */ + while (!(res.f & (dp_hidden_bit << 1))) + { + res.f <<= 1; + res.e--; + } + /* do the final shifts in one go. Don't forget the hidden bit (the '-1') */ + res.f <<= (diy_significand_size - dp_significand_size - 2); + res.e = res.e - (diy_significand_size - dp_significand_size - 2); + return res; +} + +inline +void normalized_boundaries(double d, diy_fp_t *out_m_minus, diy_fp_t *out_m_plus) +{ + diy_fp_t v = double2diy_fp(d); + diy_fp_t pl, mi; + bool significand_is_zero = v.f == dp_hidden_bit; + pl.f = (v.f << 1) + 1; pl.e = v.e - 1; + pl = normalize_boundary(pl); + if (significand_is_zero) + { + mi.f = (v.f << 2) - 1; + mi.e = v.e - 2; + } else + { + mi.f = (v.f << 1) - 1; + mi.e = v.e - 1; + } + mi.f <<= mi.e - pl.e; + mi.e = pl.e; + *out_m_plus = pl; + *out_m_minus = mi; +} + +inline +double random_double() +{ + uint64_t tmp = 0; + int i; + for (i = 0; i < 8; i++) + { + tmp <<= 8; + tmp += rand() % 256; + } + return uint64_to_double(tmp); +} + +// fast_exponent +template +void fill_exponent(int K, Result& result) +{ + if (K < 0) + { + result.push_back('-'); + K = -K; + } + else + { + result.push_back('+'); // compatibility with sprintf + } + if (K >= 100) + { + result.push_back((char)('0' + K / 100)); K %= 100; + result.push_back((char)('0' + K / 10)); K %= 10; + result.push_back((char)('0' + K)); + } + else if (K >= 10) + { + result.push_back((char)('0' + K / 10)); K %= 10; + result.push_back((char)('0' + K)); + } + else + { + result.push_back('0'); // compatibility with sprintf + result.push_back((char)('0' + K)); + } +} + +template +void prettify_string(const char *buffer, size_t length, int k, int min_exp, int max_exp, Result& result) +{ + int nb_digits = (int)length; + int offset; + /* v = buffer * 10^k + kk is such that 10^(kk-1) <= v < 10^kk + this way kk gives the position of the decimal point. + */ + int kk = nb_digits + k; + + if (nb_digits <= kk && kk <= max_exp) + { + /* the first digits are already in. Add some 0s and call it a day. */ + /* the max_exp is a personal choice. Only 16 digits could possibly be relevant. + * Basically we want to print 12340000000 rather than 1234.0e7 or 1.234e10 */ + for (int i = 0; i < nb_digits; ++i) + { + result.push_back(buffer[i]); + } + for (int i = nb_digits; i < kk; ++i) + { + result.push_back('0'); + } + result.push_back('.'); + result.push_back('0'); + } + else if (0 < kk && kk <= max_exp) + { + /* comma number. Just insert a '.' at the correct location. */ + for (int i = 0; i < kk; ++i) + { + result.push_back(buffer[i]); + } + result.push_back('.'); + for (int i = kk; i < nb_digits; ++i) + { + result.push_back(buffer[i]); + } + } + else if (min_exp < kk && kk <= 0) + { + offset = 2 - kk; + + result.push_back('0'); + result.push_back('.'); + for (int i = 2; i < offset; ++i) + result.push_back('0'); + for (int i = 0; i < nb_digits; ++i) + { + result.push_back(buffer[i]); + } + } + else if (nb_digits == 1) + { + result.push_back(buffer[0]); + result.push_back('e'); + fill_exponent(kk - 1, result); + } + else + { + result.push_back(buffer[0]); + result.push_back('.'); + for (int i = 1; i < nb_digits; ++i) + { + result.push_back(buffer[i]); + } + result.push_back('e'); + fill_exponent(kk - 1, result); + } +} + +// grisu3 + +inline +bool round_weed(char *buffer, int len, + uint64_t wp_W, uint64_t Delta, + uint64_t rest, uint64_t ten_kappa, + uint64_t ulp) +{ + uint64_t wp_Wup = wp_W - ulp; + uint64_t wp_Wdown = wp_W + ulp; + while (rest < wp_Wup && /// round1 + Delta - rest >= ten_kappa && + (rest + ten_kappa < wp_Wup || /// closer + wp_Wup - rest >= rest + ten_kappa - wp_Wup)) + { + buffer[len - 1]--; rest += ten_kappa; + } + if (rest < wp_Wdown && /// round2 + Delta - rest >= ten_kappa && + (rest + ten_kappa < wp_Wdown || + wp_Wdown - rest > rest + ten_kappa - wp_Wdown)) return 0; + return 2 * ulp <= rest && rest <= Delta - 4 * ulp; /// weed +} + +inline +bool digit_gen(diy_fp_t Wm, diy_fp_t W, diy_fp_t Wp, + char *buffer, int *len, int *K) +{ + const uint32_t TEN2 = 100; + + uint32_t div, p1; uint64_t p2, tmp, unit = 1; + int d, kappa; + diy_fp_t one, wp_W, Delta; + Delta = minus(Wp, Wm); Delta.f += 2 * unit; + wp_W = minus(Wp, W); wp_W.f += unit; + one.f = ((uint64_t)1) << -Wp.e; one.e = Wp.e; + p1 = static_cast((Wp.f + 1) >> -one.e); + p2 = (Wp.f + 1) & (one.f - 1); + *len = 0; kappa = 3; div = TEN2; + while (kappa > 0) + { + d = p1 / div; + if (d || *len) buffer[(*len)++] = (char)('0' + d); + p1 %= div; kappa--; + tmp = (((uint64_t)p1) << -one.e) + p2; + if (tmp < Delta.f) + { + *K += kappa; + return round_weed(buffer, *len, wp_W.f, Delta.f, tmp, + ((uint64_t)div) << -one.e, unit); + } + div /= 10; + } + while (1) + { + p2 *= 10; Delta.f *= 10; unit *= 10; + d = static_cast(p2 >> -one.e); + if (d || *len) buffer[(*len)++] = (char)('0' + d); + p2 &= one.f - 1; kappa--; + if (p2 < Delta.f) + { + *K += kappa; + return round_weed(buffer, *len, wp_W.f * unit, Delta.f, p2, + one.f, unit); + } + } +} + +inline +bool grisu3(double v, char *buffer, int *length, int *K) +{ + diy_fp_t w_m, w_p; + int q = 64, alpha = -59, gamma = -56; + normalized_boundaries(v, &w_m, &w_p); + diy_fp_t w = normalize_diy_fp(double2diy_fp(v)); + int mk = k_comp(w_p.e + q, alpha, gamma); + diy_fp_t c_mk = cached_power(mk); + diy_fp_t W = multiply(w, c_mk); + diy_fp_t Wp = multiply(w_p, c_mk); + diy_fp_t Wm = multiply(w_m, c_mk); + *K = -mk; + bool result = digit_gen(Wm, W, Wp, buffer, length, K); + buffer[*length] = 0; + return result; +} + +}} // namespace detail namespace jsoncons + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/detail/heap_only_string.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/detail/heap_only_string.hpp new file mode 100644 index 0000000000..a90d863d49 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/detail/heap_only_string.hpp @@ -0,0 +1,156 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_DETAIL_HEAP_ONLY_STRING_HPP +#define JSONCONS_DETAIL_HEAP_ONLY_STRING_HPP + +#include +#include +#include +#include +#include // std::memcpy +#include // std::allocator +#include + +namespace jsoncons { namespace detail { + +template +class heap_only_string_base +{ + Allocator allocator_; +public: + Allocator& get_allocator() + { + return allocator_; + } + + const Allocator& get_allocator() const + { + return allocator_; + } +protected: + heap_only_string_base(const Allocator& allocator) + : allocator_(allocator) + { + } + + ~heap_only_string_base() {} +}; + +template +class heap_only_string_factory; + +template +class heap_only_string : public heap_only_string_base +{ + typedef typename std::allocator_traits::template rebind_alloc allocator_type; + typedef std::allocator_traits allocator_traits_type; + typedef typename allocator_traits_type::pointer pointer; + + friend class heap_only_string_factory; +public: + typedef CharT char_type; + typedef heap_only_string value_type; + + ~heap_only_string() {} + + const char_type* c_str() const { return to_plain_pointer(p_); } + const char_type* data() const { return to_plain_pointer(p_); } + size_t length() const { return length_; } + + using heap_only_string_base::get_allocator; + + + friend std::basic_ostream& operator<<(std::basic_ostream& os, const heap_only_string& s) + { + os.write(s.data(),s.length()); + return os; + } +private: + heap_only_string() + : heap_only_string_base(Allocator()) + { + + } + heap_only_string(const Allocator& allocator) + : heap_only_string_base(allocator) + { + + } + + pointer p_; + size_t length_; + + heap_only_string(const heap_only_string&) = delete; + heap_only_string& operator=(const heap_only_string&) = delete; + +}; + +template +class heap_only_string_factory +{ + typedef CharT char_type; + typedef typename std::allocator_traits::template rebind_alloc byte_allocator_type; + typedef std::allocator_traits byte_allocator_traits_type; + typedef typename byte_allocator_traits_type::pointer byte_pointer; + typedef typename heap_only_string::pointer pointer; +public: + + typedef typename std::allocator_traits::template rebind_alloc> string_allocator_type; + typedef std::allocator_traits string_allocator_traits_type; + typedef typename string_allocator_traits_type::pointer string_pointer; + + typedef heap_only_string* raw_string_pointer_type; + + struct string_storage + { + heap_only_string data; + char_type c[1]; + }; + typedef typename std::aligned_storage::type storage_type; + + static size_t aligned_size(size_t n) + { + return sizeof(storage_type) + n; + } +public: + static string_pointer create(const char_type* s, size_t length) + { + return create(s, length, Allocator()); + } + static string_pointer create(const char_type* s, size_t length, const Allocator& allocator) + { + size_t mem_size = aligned_size(length*sizeof(char_type)); + + byte_allocator_type alloc(allocator); + byte_pointer ptr = alloc.allocate(mem_size); + + char* storage = to_plain_pointer(ptr); + raw_string_pointer_type ps = new(storage)heap_only_string(alloc); + auto psa = reinterpret_cast(storage); + + CharT* p = new(&psa->c)char_type[length + 1]; + std::memcpy(p, s, length*sizeof(char_type)); + p[length] = 0; + ps->p_ = std::pointer_traits::pointer_to(*p); + ps->length_ = length; + return std::pointer_traits::pointer_to(*ps); + } + + static void destroy(string_pointer ptr) + { + raw_string_pointer_type rawp = to_plain_pointer(ptr); + char* p = reinterpret_cast(rawp); + size_t mem_size = aligned_size(ptr->length_*sizeof(char_type)); + byte_allocator_type alloc(ptr->get_allocator()); + alloc.deallocate(p,mem_size); + } +}; + + +}} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/detail/parse_number.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/detail/parse_number.hpp new file mode 100644 index 0000000000..221bc4512c --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/detail/parse_number.hpp @@ -0,0 +1,526 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_DETAIL_PARSE_NUMBER_HPP +#define JSONCONS_DETAIL_PARSE_NUMBER_HPP + +#include +#include +#include +#include +#include +#include // std::numeric_limits +#include // std::enable_if +#include +#include +#include + +namespace jsoncons { namespace detail { + +enum class to_integer_errc : uint8_t {ok=0,overflow,invalid_digit}; + +template +struct to_integer_result +{ + T value; + to_integer_errc ec; +}; + +class to_integer_error_category_impl + : public std::error_category +{ +public: + const char* name() const noexcept override + { + return "jsoncons/to_integer"; + } + std::string message(int ev) const override + { + switch (static_cast(ev)) + { + case to_integer_errc::overflow: + return "Integer overflow"; + case to_integer_errc::invalid_digit: + return "Invalid digit"; + default: + return "Unknown to_integer error"; + } + } +}; + +inline +const std::error_category& to_integer_error_category() +{ + static to_integer_error_category_impl instance; + return instance; +} + +inline +std::error_code make_error_code(to_integer_errc e) +{ + return std::error_code(static_cast(e),to_integer_error_category()); +} + +template +bool is_integer(const CharT* s, size_t length) +{ + const CharT* end = s + length; + if (s == end) + { + return false; + } + if (*s == '-') + { + ++s; + } + if (s == end) + { + return false; + } + for (;s < end; ++s) + { + if (!(*s >= '0' && *s <= '9')) + { + return false; + } + } + return true; +} + +template +bool is_uinteger(const CharT* s, size_t length) +{ + const CharT* end = s + length; + if (s == end) + { + return false; + } + for (;s < end; ++s) + { + if (!(*s >= '0' && *s <= '9')) + { + return false; + } + } + return true; +} + +// Precondition: s satisfies + +// digit +// digit1-digits +// - digit +// - digit1-digits + +template +typename std::enable_if::value && std::is_signed::value,to_integer_result>::type +to_integer(const CharT* s, size_t length) +{ + static_assert(std::numeric_limits::is_specialized, "Integer type not specialized"); + JSONCONS_ASSERT(length > 0); + + to_integer_errc ec{}; + + T n = 0; + const CharT* end = s + length; + if (*s == '-') + { + static const T min_value = (std::numeric_limits::lowest)(); + static const T min_value_div_10 = min_value / 10; + ++s; + for (; s < end; ++s) + { + T x = *s - '0'; + if (n < min_value_div_10) + { + ec = to_integer_errc::overflow; + break; + } + n = n * 10; + if (n < min_value + x) + { + ec = to_integer_errc::overflow; + break; + } + + n -= x; + } + } + else + { + static const T max_value = (std::numeric_limits::max)(); + static const T max_value_div_10 = max_value / 10; + for (; s < end; ++s) + { + T x = *s - '0'; + if (n > max_value_div_10) + { + ec = to_integer_errc::overflow; + break; + } + n = n * 10; + if (n > max_value - x) + { + ec = to_integer_errc::overflow; + break; + } + + n += x; + } + } + + return to_integer_result({n,ec}); +} + +// Precondition: s satisfies + +// digit +// digit1-digits +// - digit +// - digit1-digits + +template +typename std::enable_if::value && !std::is_signed::value,to_integer_result>::type +to_integer(const CharT* s, size_t length) +{ + static_assert(std::numeric_limits::is_specialized, "Integer type not specialized"); + JSONCONS_ASSERT(length > 0); + + T n = 0; + to_integer_errc ec{}; + + const CharT* end = s + length; + + static const T max_value = (std::numeric_limits::max)(); + static const T max_value_div_10 = max_value / 10; + for (; s < end; ++s) + { + T x = *s - '0'; + if (n > max_value_div_10) + { + ec = to_integer_errc::overflow; + break; + } + n = n * 10; + if (n > max_value - x) + { + ec = to_integer_errc::overflow; + break; + } + + n += x; + } + + return to_integer_result({ n,ec }); +} + +// base16_to_integer + +template +typename std::enable_if::value && std::is_signed::value,to_integer_result>::type +base16_to_integer(const CharT* s, size_t length) +{ + static_assert(std::numeric_limits::is_specialized, "Integer type not specialized"); + JSONCONS_ASSERT(length > 0); + + T n = 0; + to_integer_errc ec{}; + const CharT* end = s + length; + if (*s == '-') + { + static const T min_value = (std::numeric_limits::lowest)(); + static const T min_value_div_16 = min_value / 16; + ++s; + for (; s < end; ++s) + { + CharT c = *s; + T x = 0; + switch (c) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + x = c - '0'; + break; + case 'a':case 'b':case 'c':case 'd':case 'e':case 'f': + x = c - ('a' - 10); + break; + case 'A':case 'B':case 'C':case 'D':case 'E':case 'F': + x = c - ('A' - 10); + break; + default: + throw std::runtime_error("Invalid hex digit"); + } + if (n < min_value_div_16) + { + ec = to_integer_errc::overflow; + break; + } + n = n * 16; + if (n < min_value + x) + { + ec = to_integer_errc::overflow; + break; + } + n -= x; + } + } + else + { + static const T max_value = (std::numeric_limits::max)(); + static const T max_value_div_16 = max_value / 16; + for (; s < end; ++s) + { + CharT c = *s; + T x = 0; + switch (c) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + x = c - '0'; + break; + case 'a':case 'b':case 'c':case 'd':case 'e':case 'f': + x = c - ('a' - 10); + break; + case 'A':case 'B':case 'C':case 'D':case 'E':case 'F': + x = c - ('A' - 10); + break; + default: + throw std::runtime_error("Invalid hex digit"); + } + if (n > max_value_div_16) + { + ec = to_integer_errc::overflow; + break; + } + n = n * 16; + if (n > max_value - x) + { + ec = to_integer_errc::overflow; + break; + } + + n += x; + } + } + + return to_integer_result({ n,ec }); +} + +template +typename std::enable_if::value && !std::is_signed::value,to_integer_result>::type +base16_to_integer(const CharT* s, size_t length) +{ + static_assert(std::numeric_limits::is_specialized, "Integer type not specialized"); + JSONCONS_ASSERT(length > 0); + + T n = 0; + to_integer_errc ec{}; + const CharT* end = s + length; + + static const T max_value = (std::numeric_limits::max)(); + static const T max_value_div_16 = max_value / 16; + for (; s < end; ++s) + { + CharT c = *s; + T x = *s; + switch (c) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + x = c - '0'; + break; + case 'a':case 'b':case 'c':case 'd':case 'e':case 'f': + x = c - ('a' - 10); + break; + case 'A':case 'B':case 'C':case 'D':case 'E':case 'F': + x = c - ('A' - 10); + break; + default: + throw std::runtime_error("Invalid hex digit"); + } + if (n > max_value_div_16) + { + ec = to_integer_errc::overflow; + break; + } + n = n * 16; + if (n > max_value - x) + { + ec = to_integer_errc::overflow; + break; + } + + n += x; + } + + return to_integer_result({ n,ec }); +} + +#if defined(JSONCONS_HAS_MSC__STRTOD_L) + +class string_to_double +{ +private: + _locale_t locale_; +public: + string_to_double() + { + locale_ = _create_locale(LC_NUMERIC, "C"); + } + ~string_to_double() + { + _free_locale(locale_); + } + + char get_decimal_point() const + { + return '.'; + } + + template + typename std::enable_if::value,double>::type + operator()(const CharT* s, size_t) const + { + CharT *end = nullptr; + double val = _strtod_l(s, &end, locale_); + if (s == end) + { + JSONCONS_THROW(json_runtime_error("Convert string to double failed")); + } + return val; + } + + template + typename std::enable_if::value,double>::type + operator()(const CharT* s, size_t) const + { + CharT *end = nullptr; + double val = _wcstod_l(s, &end, locale_); + if (s == end) + { + JSONCONS_THROW(json_runtime_error("Convert string to double failed")); + } + return val; + } +private: + // noncopyable and nonmoveable + string_to_double(const string_to_double&) = delete; + string_to_double& operator=(const string_to_double&) = delete; +}; + +#elif defined(JSONCONS_HAS_STRTOLD_L) + +class string_to_double +{ +private: + locale_t locale_; +public: + string_to_double() + { + locale_ = newlocale(LC_ALL_MASK, "C", (locale_t) 0); + } + ~string_to_double() + { + freelocale(locale_); + } + + char get_decimal_point() const + { + return '.'; + } + + template + typename std::enable_if::value,double>::type + operator()(const CharT* s, size_t length) const + { + char *end = nullptr; + double val = strtold_l(s, &end, locale_); + if (s == end) + { + JSONCONS_THROW(json_runtime_error("Convert string to double failed")); + } + return val; + } + + template + typename std::enable_if::value,double>::type + operator()(const CharT* s, size_t length) const + { + CharT *end = nullptr; + double val = wcstold_l(s, &end, locale_); + if (s == end) + { + JSONCONS_THROW(json_runtime_error("Convert string to double failed")); + } + return val; + } + +private: + // noncopyable and nonmoveable + string_to_double(const string_to_double& fr) = delete; + string_to_double& operator=(const string_to_double& fr) = delete; +}; + +#else +class string_to_double +{ +private: + std::vector buffer_; + char decimal_point_; +public: + string_to_double() + : buffer_() + { + struct lconv * lc = localeconv(); + if (lc != nullptr && lc->decimal_point[0] != 0) + { + decimal_point_ = lc->decimal_point[0]; + } + else + { + decimal_point_ = '.'; + } + buffer_.reserve(100); + } + + char get_decimal_point() const + { + return decimal_point_; + } + + template + typename std::enable_if::value,double>::type + operator()(const CharT* s, size_t /*length*/) const + { + CharT *end = nullptr; + double val = strtod(s, &end); + if (s == end) + { + JSONCONS_THROW(json_runtime_error("Convert string to double failed")); + } + return val; + } + + template + typename std::enable_if::value,double>::type + operator()(const CharT* s, size_t /*length*/) const + { + CharT *end = nullptr; + double val = wcstod(s, &end); + if (s == end) + { + JSONCONS_THROW(json_runtime_error("Convert string to double failed")); + } + return val; + } + +private: + // noncopyable and nonmoveable + string_to_double(const string_to_double& fr) = delete; + string_to_double& operator=(const string_to_double& fr) = delete; +}; +#endif + +}} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/detail/print_number.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/detail/print_number.hpp new file mode 100644 index 0000000000..8fa870d3f7 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/detail/print_number.hpp @@ -0,0 +1,344 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_DETAIL_PRINT_NUMBER_HPP +#define JSONCONS_DETAIL_PRINT_NUMBER_HPP + +#include +#include +#include +#include +#include // std::numeric_limits +#include +#include +#include +#include +#include + +namespace jsoncons { namespace detail { + +// print_integer + +template +size_t print_integer(int64_t value, Result& result) +{ + typedef typename Result::value_type char_type; + + size_t count = 0; + + char_type buf[255]; + uint64_t u = (value < 0) ? static_cast(-value) : static_cast(value); + char_type* p = buf; + do + { + *p++ = static_cast(48 + u%10); + } + while (u /= 10); + count += (p-buf); + if (value < 0) + { + result.push_back('-'); + ++count; + } + while (--p >= buf) + { + result.push_back(*p); + } + + return count; +} + +// print_uinteger + +template +size_t print_uinteger(uint64_t value, Result& result) +{ + typedef typename Result::value_type char_type; + + size_t count = 0; + + char_type buf[255]; + char_type* p = buf; + do + { + *p++ = static_cast(48 + value % 10); + } + while (value /= 10); + count += (p-buf); + while (--p >= buf) + { + result.push_back(*p); + } + return count; +} + +// print_integer + +template +size_t integer_to_hex_string(int64_t value, Result& result) +{ + typedef typename Result::value_type char_type; + + size_t count = 0; + + char_type buf[255]; + uint64_t u = (value < 0) ? static_cast(-value) : static_cast(value); + char_type* p = buf; + do + { + *p++ = to_hex_character(u%16); + } + while (u /= 16); + count += (p-buf); + if (value < 0) + { + result.push_back('-'); + ++count; + } + while (--p >= buf) + { + result.push_back(*p); + } + + return count; +} + +// print_uinteger + +template +size_t uinteger_to_hex_string(uint64_t value, Result& result) +{ + typedef typename Result::value_type char_type; + + size_t count = 0; + + char_type buf[255]; + char_type* p = buf; + do + { + *p++ = to_hex_character(value % 16); + } + while (value /= 16); + count += (p-buf); + while (--p >= buf) + { + result.push_back(*p); + } + return count; +} + +// print_double + +template +void dump_buffer(const char* buffer, size_t length, char decimal_point, Result& result) +{ + const char* sbeg = buffer; + const char* send = sbeg + length; + + if (sbeg != send) + { + bool needs_dot = true; + for (const char* q = sbeg; q < send; ++q) + { + switch (*q) + { + case '-':case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':case '+': + result.push_back(*q); + break; + case 'e': + case 'E': + result.push_back('e'); + needs_dot = false; + break; + default: + if (*q == decimal_point) + { + needs_dot = false; + result.push_back('.'); + } + break; + } + } + if (needs_dot) + { + result.push_back('.'); + result.push_back('0'); + needs_dot = true; + } + } +} + +template +bool dtoa(double val, char decimal_point, Result& result, std::false_type) +{ + if (val == 0) + { + result.push_back('0'); + result.push_back('.'); + result.push_back('0'); + return true; + } + + jsoncons::detail::string_to_double to_double_; + + char buffer[100]; + int precision = std::numeric_limits::digits10; + int length = snprintf(buffer, sizeof(buffer), "%1.*g", precision, val); + if (length < 0) + { + return false; + } + if (to_double_(buffer,sizeof(buffer)) != val) + { + const int precision2 = std::numeric_limits::max_digits10; + length = snprintf(buffer, sizeof(buffer), "%1.*g", precision2, val); + if (length < 0) + { + return false; + } + } + dump_buffer(buffer, length, decimal_point, result); + return true; +} + +template +bool dtoa(double v, char decimal_point, Result& result, std::true_type) +{ + if (v == 0) + { + result.push_back('0'); + result.push_back('.'); + result.push_back('0'); + return true; + } + + int length = 0; + int k; + + char buffer[100]; + + double u = std::signbit(v) ? -v : v; + if (jsoncons::detail::grisu3(u, buffer, &length, &k)) + { + if (std::signbit(v)) + { + result.push_back('-'); + } + // min exp: -4 is consistent with sprintf + // max exp: std::numeric_limits::max_digits10 + jsoncons::detail::prettify_string(buffer, length, k, -4, std::numeric_limits::max_digits10, result); + return true; + } + else + { + return dtoa(v, decimal_point, result, std::false_type()); + } +} + +template +bool dtoa(double v, char decimal_point, Result& result) +{ + return dtoa(v, decimal_point, result, std::integral_constant::is_iec559>()); +} + +class print_double +{ +private: + string_to_double to_double_; + floating_point_options override_; + char decimal_point_; +public: + print_double(const floating_point_options& options) + : override_(options) + { +#if !defined(JSONCONS_NO_LOCALECONV) + struct lconv * lc = localeconv(); + if (lc != nullptr && lc->decimal_point[0] != 0) + { + decimal_point_ = lc->decimal_point[0]; + } + else +#endif + { + decimal_point_ = '.'; + } + } + + template + size_t operator()(double val, Result& result) + { + size_t count = 0; + + chars_format format = override_.format() != chars_format() ? override_.format() : chars_format::general; + + int decimal_places; + if (override_.decimal_places() != 0) + { + decimal_places = override_.decimal_places(); + } + else + { + format = chars_format::general; + decimal_places = 0; + } + + char number_buffer[200]; + int length = 0; + + switch (format) + { + case chars_format::fixed: + { + length = snprintf(number_buffer, sizeof(number_buffer), "%1.*f", decimal_places, val); + if (length < 0) + { + JSONCONS_THROW(json_runtime_error("print_double failed.")); + } + dump_buffer(number_buffer, length, decimal_point_, result); + } + break; + case chars_format::scientific: + { + length = snprintf(number_buffer, sizeof(number_buffer), "%1.*e", decimal_places, val); + if (length < 0) + { + JSONCONS_THROW(json_runtime_error("print_double failed.")); + } + dump_buffer(number_buffer, length, decimal_point_, result); + } + break; + case chars_format::general: + { + if (override_.precision() != 0) + { + int precision = override_.precision(); + length = snprintf(number_buffer, sizeof(number_buffer), "%1.*g", precision, val); + if (length < 0) + { + JSONCONS_THROW(json_runtime_error("print_double failed.")); + } + dump_buffer(number_buffer, length, decimal_point_, result); + } + else + { + if (!dtoa(val, decimal_point_, result)) + { + JSONCONS_THROW(json_runtime_error("print_double failed.")); + } + } + break; + } + default: + JSONCONS_THROW(json_runtime_error("print_double failed.")); + break; + } + return count; + } +}; + +}} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/detail/string_view.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/detail/string_view.hpp new file mode 100644 index 0000000000..e85abff6b8 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/detail/string_view.hpp @@ -0,0 +1,525 @@ +// Copyright 2019 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_STRING_VIEW_HPP +#define JSONCONS_STRING_VIEW_HPP + +#include +#include +#include +#include +#include +#include // std::find, std::min, std::reverse +#include +#include +#include +#include +#include // std::basic_istream + +namespace jsoncons { namespace detail { + +template > +class basic_string_view +{ +private: + const CharT* data_; + size_t length_; +public: + typedef CharT value_type; + typedef const CharT& const_reference; + typedef Traits traits_type; + typedef std::size_t size_type; + static const size_type npos = size_type(-1); + typedef const CharT* const_iterator; + typedef const CharT* iterator; + typedef std::reverse_iterator const_reverse_iterator; + + basic_string_view() + : data_(nullptr), length_(0) + { + } + basic_string_view(const CharT* data, size_t length) + : data_(data), length_(length) + { + } + basic_string_view(const CharT* data) + : data_(data), length_(Traits::length(data)) + { + } + basic_string_view(const basic_string_view& other) = default; + + template + basic_string_view(const std::basic_string& s) + : data_(s.data()), length_(s.length()) + { + } + + template + explicit operator std::basic_string() const + { + return std::basic_string(data_,length_); + } + + // iterator support + const_iterator begin() const noexcept + { + return data_; + } + const_iterator end() const noexcept + { + return data_ + length_; + } + const_iterator cbegin() const noexcept + { + return data_; + } + const_iterator cend() const noexcept + { + return data_ + length_; + } + const_reverse_iterator rbegin() const noexcept + { + return const_reverse_iterator(end()); + } + const_reverse_iterator rend() const noexcept + { + return const_reverse_iterator(begin()); + } + const_reverse_iterator crbegin() const noexcept + { + return const_reverse_iterator(end()); + } + const_reverse_iterator crend() const noexcept + { + return const_reverse_iterator(begin()); + } + + // capacity + + size_t size() const + { + return length_; + } + + size_t length() const + { + return length_; + } + size_type max_size() const noexcept + { + return length_; + } + bool empty() const noexcept + { + return length_ == 0; + } + + // element access + + const_reference operator[](size_type pos) const + { + return data_[pos]; + } + + const_reference at(size_t pos) const + { + if (pos >= length_) + { + throw std::out_of_range("pos exceeds length"); + } + return data_[pos]; + } + + const_reference front() const + { + return data_[0]; + } + const_reference back() const + { + return data_[length_-1]; + } + + const CharT* data() const + { + return data_; + } + + // string operations + + basic_string_view substr(size_type pos, size_type n=npos) const + { + if (pos > length_) + { + throw std::out_of_range("pos exceeds size"); + } + if (n == npos || pos + n > length_) + { + n = length_ - pos; + } + return basic_string_view(data_ + pos, n); + } + + int compare(const basic_string_view& s) const + { + const int rc = Traits::compare(data_, s.data_, (std::min)(length_, s.length_)); + return rc != 0 ? rc : (length_ == s.length_ ? 0 : length_ < s.length_ ? -1 : 1); + } + + int compare(const CharT* data) const + { + const size_t length = Traits::length(data); + const int rc = Traits::compare(data_, data, (std::min)(length_, length)); + return rc != 0 ? rc : (length_ == length? 0 : length_ < length? -1 : 1); + } + + template + int compare(const std::basic_string& s) const + { + const int rc = Traits::compare(data_, s.data(), (std::min)(length_, s.length())); + return rc != 0 ? rc : (length_ == s.length() ? 0 : length_ < s.length() ? -1 : 1); + } + + size_type find(basic_string_view s, size_type pos = 0) const noexcept + { + if (pos > length_) + { + return npos; + } + if (s.length_ == 0) + { + return pos; + } + const_iterator it = std::search(cbegin() + pos, cend(), + s.cbegin(), s.cend(), Traits::eq); + return it == cend() ? npos : std::distance(cbegin(), it); + } + size_type find(CharT ch, size_type pos = 0) const noexcept + { + return find(basic_string_view(&ch, 1), pos); + } + size_type find(const CharT* s, size_type pos, size_type n) const noexcept + { + return find(basic_string_view(s, n), pos); + } + size_type find(const CharT* s, size_type pos = 0) const noexcept + { + return find(basic_string_view(s), pos); + } + + size_type rfind(basic_string_view s, size_type pos = npos) const noexcept + { + if (length_ < s.length_) + { + return npos; + } + if (pos > length_ - s.length_) + { + pos = length_ - s.length_; + } + if (s.length_ == 0) + { + return pos; + } + for (const CharT* p = data_ + pos; true; --p) + { + if (Traits::compare(p, s.data_, s.length_) == 0) + { + return p - data_; + } + if (p == data_) + { + return npos; + } + }; + } + size_type rfind(CharT ch, size_type pos = npos) const noexcept + { + return rfind(basic_string_view(&ch, 1), pos); + } + size_type rfind(const CharT* s, size_type pos, size_type n) const noexcept + { + return rfind(basic_string_view(s, n), pos); + } + size_type rfind(const CharT* s, size_type pos = npos) const noexcept + { + return rfind(basic_string_view(s), pos); + } + + size_type find_first_of(basic_string_view s, size_type pos = 0) const noexcept + { + if (pos >= length_ || s.length_ == 0) + { + return npos; + } + const_iterator it = std::find_first_of + (cbegin() + pos, cend(), s.cbegin(), s.cend(), Traits::eq); + return it == cend() ? npos : std::distance (cbegin(), it); + } + size_type find_first_of(CharT ch, size_type pos = 0) const noexcept + { + return find_first_of(basic_string_view(&ch, 1), pos); + } + size_type find_first_of(const CharT* s, size_type pos, size_type n) const noexcept + { + return find_first_of(basic_string_view(s, n), pos); + } + size_type find_first_of(const CharT* s, size_type pos = 0) const noexcept + { + return find_first_of(basic_string_view(s), pos); + } + + size_type find_last_of(basic_string_view s, size_type pos = npos) const noexcept + { + if (s.length_ == 0) + { + return npos; + } + if (pos >= length_) + { + pos = 0; + } + else + { + pos = length_ - (pos+1); + } + const_reverse_iterator it = std::find_first_of + (crbegin() + pos, crend(), s.cbegin(), s.cend(), Traits::eq); + return it == crend() ? npos : (length_ - 1 - std::distance(crbegin(), it)); + } + size_type find_last_of(CharT ch, size_type pos = npos) const noexcept + { + return find_last_of(basic_string_view(&ch, 1), pos); + } + size_type find_last_of(const CharT* s, size_type pos, size_type n) const noexcept + { + return find_last_of(basic_string_view(s, n), pos); + } + size_type find_last_of(const CharT* s, size_type pos = npos) const noexcept + { + return find_last_of(basic_string_view(s), pos); + } + + size_type find_first_not_of(basic_string_view s, size_type pos = 0) const noexcept + { + if (pos >= length_) + return npos; + if (s.length_ == 0) + return pos; + + const_iterator it = cend(); + for (auto p = cbegin()+pos; p != cend(); ++p) + { + if (Traits::find(s.data_, s.length_, *p) == 0) + { + it = p; + break; + } + } + return it == cend() ? npos : std::distance (cbegin(), it); + } + size_type find_first_not_of(CharT ch, size_type pos = 0) const noexcept + { + return find_first_not_of(basic_string_view(&ch, 1), pos); + } + size_type find_first_not_of(const CharT* s, size_type pos, size_type n) const noexcept + { + return find_first_not_of(basic_string_view(s, n), pos); + } + size_type find_first_not_of(const CharT* s, size_type pos = 0) const noexcept + { + return find_first_not_of(basic_string_view(s), pos); + } + + size_type find_last_not_of(basic_string_view s, size_type pos = npos) const noexcept + { + if (pos >= length_) + { + pos = length_ - 1; + } + if (s.length_ == 0) + { + return pos; + } + pos = length_ - (pos+1); + + const_iterator it = crend(); + for (auto p = crbegin()+pos; p != crend(); ++p) + { + if (Traits::find(s.data_, s.length_, *p) == 0) + { + it = p; + break; + } + } + return it == crend() ? npos : (length_ - 1 - std::distance(crbegin(), it)); + } + size_type find_last_not_of(CharT ch, size_type pos = npos) const noexcept + { + return find_last_not_of(basic_string_view(&ch, 1), pos); + } + size_type find_last_not_of(const CharT* s, size_type pos, size_type n) const noexcept + { + return find_last_not_of(basic_string_view(s, n), pos); + } + size_type find_last_not_of(const CharT* s, size_type pos = npos) const noexcept + { + return find_last_not_of(basic_string_view(s), pos); + } + + friend std::basic_ostream& operator<<(std::basic_ostream& os, const basic_string_view& sv) + { + os.write(sv.data_,sv.length_); + return os; + } +}; + +// == +template +bool operator==(const basic_string_view& lhs, + const basic_string_view& rhs) +{ + return lhs.compare(rhs) == 0; +} +template +bool operator==(const basic_string_view& lhs, + const std::basic_string& rhs) +{ + return lhs.compare(rhs) == 0; +} +template +bool operator==(const std::basic_string& lhs, + const basic_string_view& rhs) +{ + return rhs.compare(lhs) == 0; +} +template +bool operator==(const basic_string_view& lhs, + const CharT* rhs) +{ + return lhs.compare(rhs) == 0; +} +template +bool operator==(const CharT* lhs, + const basic_string_view& rhs) +{ + return rhs.compare(lhs) == 0; +} + +// != +template +bool operator!=(const basic_string_view& lhs, + const basic_string_view& rhs) +{ + return lhs.compare(rhs) != 0; +} +template +bool operator!=(const basic_string_view& lhs, + const std::basic_string& rhs) +{ + return lhs.compare(rhs) != 0; +} +template +bool operator!=(const std::basic_string& lhs, + const basic_string_view& rhs) +{ + return rhs.compare(lhs) != 0; +} +template +bool operator!=(const basic_string_view& lhs, + const CharT* rhs) +{ + return lhs.compare(rhs) != 0; +} +template +bool operator!=(const CharT* lhs, + const basic_string_view& rhs) +{ + return rhs.compare(lhs) != 0; +} + +// <= +template +bool operator<=(const basic_string_view& lhs, + const basic_string_view& rhs) +{ + return lhs.compare(rhs) <= 0; +} +template +bool operator<=(const basic_string_view& lhs, + const std::basic_string& rhs) +{ + return lhs.compare(rhs) <= 0; +} +template +bool operator<=(const std::basic_string& lhs, + const basic_string_view& rhs) +{ + return rhs.compare(lhs) >= 0; +} + +// < +template +bool operator<(const basic_string_view& lhs, + const basic_string_view& rhs) +{ + return lhs.compare(rhs) < 0; +} +template +bool operator<(const basic_string_view& lhs, + const std::basic_string& rhs) +{ + return lhs.compare(rhs) < 0; +} +template +bool operator<(const std::basic_string& lhs, + const basic_string_view& rhs) +{ + return rhs.compare(lhs) > 0; +} + +// >= +template +bool operator>=(const basic_string_view& lhs, + const basic_string_view& rhs) +{ + return lhs.compare(rhs) >= 0; +} +template +bool operator>=(const basic_string_view& lhs, + const std::basic_string& rhs) +{ + return lhs.compare(rhs) >= 0; +} +template +bool operator>=(const std::basic_string& lhs, + const basic_string_view& rhs) +{ + return rhs.compare(lhs) <= 0; +} + +// > +template +bool operator>(const basic_string_view& lhs, + const basic_string_view& rhs) +{ + return lhs.compare(rhs) > 0; +} +template +bool operator>(const basic_string_view& lhs, + const std::basic_string& rhs) +{ + return lhs.compare(rhs) > 0; +} +template +bool operator>(const std::basic_string& lhs, + const basic_string_view& rhs) +{ + return rhs.compare(lhs) < 0; +} + +}} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/detail/type_traits.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/detail/type_traits.hpp new file mode 100644 index 0000000000..53c5514376 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/detail/type_traits.hpp @@ -0,0 +1,228 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_DETAIL_TYPE_TRAITS_HPP +#define JSONCONS_DETAIL_TYPE_TRAITS_HPP + +#include +#include +#include +#include // std::enable_if, std::true_type +#include +#include // std::iterator_traits +#include +#include +#include +#include + +namespace jsoncons +{ +// static_max + +template +struct static_max; + +template +struct static_max +{ + static const size_t value = arg; +}; + +template +struct static_max +{ + static const size_t value = arg1 >= arg2 ? + static_max::value : + static_max::value; +}; + +// type_wrapper + +template +struct type_wrapper +{ + typedef T* pointer_type; + typedef const T* const_pointer_type; + typedef T value_type; + typedef T& reference; + typedef const T& const_reference; +}; + +template +struct type_wrapper +{ + typedef T* pointer_type; + typedef const T* const_pointer_type; + typedef T value_type; + typedef T& reference; + typedef const T& const_reference; +}; + +template +struct type_wrapper +{ + typedef T* pointer_type; + typedef const T* const_pointer_type; + typedef T value_type; + typedef T& reference; + typedef const T& const_reference; +}; + +template +struct type_wrapper +{ + typedef T* pointer_type; + typedef const T* const_pointer_type; + typedef T value_type; + typedef T& reference; + typedef const T& const_reference; +}; + +inline +char to_hex_character(uint8_t c) +{ + JSONCONS_ASSERT(c <= 0xF); + + return (char)((c < 10) ? ('0' + c) : ('A' - 10 + c)); +} + +inline +bool is_control_character(uint32_t c) +{ + return c <= 0x1F || c == 0x7f; +} + +inline +bool is_non_ascii_codepoint(uint32_t cp) +{ + return cp >= 0x80; +} + +template +struct is_stateless + : public std::integral_constant::value && + std::is_empty::value)> +{}; + +// type traits extensions + + +namespace detail { + +// to_plain_pointer + +template inline +typename std::pointer_traits::element_type* to_plain_pointer(Pointer ptr) +{ + return (std::addressof(*ptr)); +} + +template inline +T * to_plain_pointer(T * ptr) +{ + return (ptr); +} + +// has_char_traits_member_type + +template +struct has_char_traits_member_type : std::false_type {}; + +template +struct has_char_traits_member_type::value +>::type> : std::true_type {}; + + +// is_string_like + +template +struct is_string_like : std::false_type {}; + +template +struct is_string_like::value && !std::is_void::value && !std::is_void::value +>::type> : std::true_type {}; + +// is_string_view_like + +template +struct is_string_view_like : std::false_type {}; + +template +struct is_string_view_like::value && !std::is_void::value && !is_string_like::value +>::type> : std::true_type {}; + +// is_integer_like + +template +struct is_integer_like : std::false_type {}; + +template +struct is_integer_like::value && + std::is_signed::value && + !std::is_same::value>::type> : std::true_type {}; + +// is_uinteger_like + +template +struct is_uinteger_like : std::false_type {}; + +template +struct is_uinteger_like::value && + !std::is_signed::value && + !std::is_same::value>::type> : std::true_type {}; + +// is_floating_point_like + +template +struct is_floating_point_like : std::false_type {}; + +template +struct is_floating_point_like::value>::type> : std::true_type {}; + +// is_map_like + +template +struct is_map_like : std::false_type {}; + +template +struct is_map_like::value>::type> + : std::true_type {}; + +// is_array_like +template +struct is_array_like : std::false_type {}; + +template +struct is_array_like> : std::true_type {}; + +// is_vector_like + +template +struct is_vector_like : std::false_type {}; + +template +struct is_vector_like::value && + !std::is_void::value_type>::value && + !is_array_like::value && + !has_char_traits_member_type::value && + !is_map_like::value +>::type> + : std::true_type {}; + +} + +} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/encode_decode_json.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/encode_decode_json.hpp new file mode 100644 index 0000000000..196b2244b9 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/encode_decode_json.hpp @@ -0,0 +1,280 @@ +// Copyright 2017 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_ENCODE_DECODE_JSON_HPP +#define JSONCONS_ENCODE_DECODE_JSON_HPP + +#include +#include +#include +#include +#include // std::basic_istream +#include +#include + +namespace jsoncons { + +// decode_json + +template +typename std::enable_if::value,T>::type +decode_json(const std::basic_string& s, + const basic_json_decode_options& options = basic_json_options::default_options()) +{ + jsoncons::json_decoder decoder; + basic_json_reader> reader(s, decoder, options); + reader.read(); + return decoder.get_result(); +} + +template +typename std::enable_if::value,T>::type +decode_json(const std::basic_string& s, + const basic_json_decode_options& options = basic_json_options::default_options()) +{ + basic_json_cursor reader(s, options); + T val; + read_from(basic_json(), reader, val); + return val; +} + +template +typename std::enable_if::value,T>::type +decode_json(std::basic_istream& is, + const basic_json_decode_options& options = basic_json_options::default_options()) +{ + jsoncons::json_decoder decoder; + basic_json_reader> reader(is, decoder, options); + reader.read(); + return decoder.get_result(); +} + +template +typename std::enable_if::value,T>::type +decode_json(std::basic_istream& is, + const basic_json_decode_options& options = basic_json_options::default_options()) +{ + basic_json_cursor reader(is, options); + T val; + read_from(basic_json(), reader, val); + return val; +} + +template +T decode_json(const basic_json& j, + const std::basic_string& s, + const basic_json_decode_options& options = basic_json_options::default_options()) +{ + basic_json_cursor reader(s, options); + T val; + read_from(j, reader, val); + return val; +} + +template +T decode_json(const basic_json& j, + std::basic_istream& is, + const basic_json_decode_options& options = basic_json_options::default_options()) +{ + basic_json_cursor reader(is, options); + T val; + read_from(j, reader, val); + return val; +} + +// encode_json + +template +void encode_json(const T& val, + basic_json_content_handler& receiver) +{ + write_to(basic_json(), val, receiver); + receiver.flush(); +} + +// to stream + +template +typename std::enable_if::value>::type +encode_json(const T& val, + std::basic_ostream& os, + const basic_json_encode_options& options = basic_json_options::default_options(), + indenting line_indent = indenting::no_indent) +{ + if (line_indent == indenting::indent) + { + basic_json_encoder encoder(os, options); + val.dump(encoder); + } + else + { + basic_json_compressed_encoder encoder(os, options); + val.dump(encoder); + } +} + +template +typename std::enable_if::value>::type +encode_json(const T& val, + std::basic_ostream& os, + const basic_json_encode_options& options = basic_json_options::default_options(), + indenting line_indent = indenting::no_indent) +{ + if (line_indent == indenting::indent) + { + basic_json_encoder encoder(os, options); + encode_json(val, encoder); + } + else + { + basic_json_compressed_encoder encoder(os, options); + encode_json(val, encoder); + } +} + +template +void encode_json(const T& val, + std::basic_ostream& os, + indenting line_indent) +{ + encode_json(val, os, basic_json_options::default_options(), line_indent); +} + +// to string + +template +typename std::enable_if::value>::type +encode_json(const T& val, + std::basic_string& s, + const basic_json_encode_options& options = basic_json_options::default_options(), + indenting line_indent = indenting::no_indent) +{ + if (line_indent == indenting::indent) + { + basic_json_encoder>> encoder(s, options); + val.dump(encoder); + } + else + { + basic_json_compressed_encoder>> encoder(s, options); + val.dump(encoder); + } +} + +template +typename std::enable_if::value>::type +encode_json(const T& val, + std::basic_string& s, + const basic_json_encode_options& options = basic_json_options::default_options(), + indenting line_indent = indenting::no_indent) +{ + if (line_indent == indenting::indent) + { + basic_json_encoder>> encoder(s, options); + encode_json(val, encoder); + } + else + { + basic_json_compressed_encoder>> encoder(s, options); + encode_json(val, encoder); + } +} + +template +void encode_json(const T& val, + std::basic_string& s, + indenting line_indent) +{ + encode_json(val, s, basic_json_options::default_options(), line_indent); +} + +template +void encode_json(const basic_json& j, + const T& val, + basic_json_content_handler& receiver) +{ + write_to(j, val, receiver); + receiver.flush(); +} + +template +void encode_json(const basic_json& j, + const T& val, + std::basic_ostream& os, + const basic_json_encode_options& options = basic_json_options::default_options(), + indenting line_indent = indenting::no_indent) +{ + if (line_indent == indenting::indent) + { + basic_json_encoder encoder(os, options); + encode_json(j, val, encoder); + } + else + { + basic_json_compressed_encoder encoder(os, options); + encode_json(j, val, encoder); + } +} + +template +void encode_json(const basic_json& j, + const T& val, + std::basic_ostream& os, + indenting line_indent) +{ + if (line_indent == indenting::indent) + { + basic_json_encoder encoder(os, basic_json_options::default_options()); + encode_json(j, val, encoder); + } + else + { + basic_json_compressed_encoder encoder(os, basic_json_options::default_options()); + encode_json(j, val, encoder); + } +} + +template +void encode_json(const basic_json& j, + const T& val, + std::basic_string& s, + const basic_json_encode_options& options = basic_json_options::default_options(), + indenting line_indent = indenting::no_indent) +{ + if (line_indent == indenting::indent) + { + basic_json_encoder>> encoder(s, options); + encode_json(j, val, encoder); + } + else + { + basic_json_compressed_encoder>> encoder(s, options); + encode_json(j, val, encoder); + } +} + +template +void encode_json(const basic_json& j, + const T& val, + std::basic_string& s, + indenting line_indent) +{ + if (line_indent == indenting::indent) + { + basic_json_encoder>> encoder(s, basic_json_options::default_options()); + encode_json(j, val, encoder); + } + else + { + basic_json_compressed_encoder>> encoder(s, basic_json_options::default_options()); + encode_json(j, val, encoder); + } +} + +} + +#endif + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json.hpp new file mode 100644 index 0000000000..0dad529e33 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json.hpp @@ -0,0 +1,14 @@ +// Copyright 2018 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_HPP +#define JSONCONS_JSON_HPP + +#include +#include + +#endif + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_container_types.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_container_types.hpp new file mode 100644 index 0000000000..8bc415a5b1 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_container_types.hpp @@ -0,0 +1,1962 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_CONTAINER_TYPES_HPP +#define JSONCONS_JSON_CONTAINER_TYPES_HPP + +#include +#include +#include +#include +#include +#include // std::sort, std::stable_sort, std::lower_bound, std::unique +#include +#include +#include // std::iterator_traits +#include // std::allocator +#include // std::move +#include // std::enable_if +#include +#include + +namespace jsoncons { + +// key_value + +template +class key_value +{ +public: + typedef KeyT key_type; + typedef ValueT value_type; + typedef typename KeyT::allocator_type allocator_type; + typedef typename value_type::string_view_type string_view_type; +private: + key_type key_; + value_type value_; +public: + + key_value() + { + } + + key_value(const key_type& name, const value_type& val) + : key_(name), value_(val) + { + } + + key_value(const string_view_type& name) + : key_(name) + { + } + + template + key_value(key_type&& name, T&& val) + : key_(std::forward(name)), + value_(std::forward(val)) + { + } + + template + key_value(key_type&& name, + T&& val, + const allocator_type& allocator) + : key_(std::forward(name)), value_(std::forward(val), allocator) + { + } + + key_value(const key_value& member) + : key_(member.key_), value_(member.value_) + { + } + + key_value(key_value&& member) + : key_(std::move(member.key_)), value_(std::move(member.value_)) + { + } + + string_view_type key() const + { + return string_view_type(key_.data(),key_.size()); + } + + value_type& value() + { + return value_; + } + + const value_type& value() const + { + return value_; + } + + template + void value(T&& value) + { + value_ = std::forward(value); + } + + void swap(key_value& member) + { + key_.swap(member.key_); + value_.swap(member.value_); + } + + key_value& operator=(const key_value& member) + { + if (this != & member) + { + key_ = member.key_; + value_ = member.value_; + } + return *this; + } + + key_value& operator=(key_value&& member) + { + if (this != &member) + { + key_.swap(member.key_); + value_.swap(member.value_); + } + return *this; + } + + void shrink_to_fit() + { + key_.shrink_to_fit(); + value_.shrink_to_fit(); + } +#if !defined(JSONCONS_NO_DEPRECATED) + const key_type& name() const + { + return key_; + } +#endif + + friend bool operator==(const key_value& lhs, const key_value& rhs) + { + return lhs.key_ == rhs.key_ && lhs.value_ == rhs.value_; + } + + friend bool operator!=(const key_value& lhs, const key_value& rhs) + { + return !(lhs == rhs); + } + + friend bool operator<(const key_value& lhs, const key_value& rhs) + { + if (lhs.key_ < rhs.key_) + { + return true; + } + if (lhs.key_ == rhs.key_ && lhs.value_ < rhs.value_) + { + return true; + } + return false; + } + + friend bool operator<=(const key_value& lhs, const key_value& rhs) + { + return !(rhs < lhs); + } + + friend bool operator>(const key_value& lhs, const key_value& rhs) + { + return !(lhs <= rhs); + } + + friend bool operator>=(const key_value& lhs, const key_value& rhs) + { + return !(lhs < rhs); + } +}; + +template +struct get_key_value +{ + typedef key_value key_value_type; + + template + key_value_type operator()(const std::pair& p) + { + return key_value_type(p.first,p.second); + } + template + key_value_type operator()(std::pair&& p) + { + return key_value_type(std::forward(p.first),std::forward(p.second)); + } + template + const key_value_type& operator()(const key_value& p) + { + return p; + } + template + key_value_type operator()(key_value&& p) + { + return std::move(p); + } +}; + +// json_array + +template +class container_base +{ +public: + typedef Allocator allocator_type; +private: + allocator_type allocator_; +public: + container_base() + : allocator_() + { + } + container_base(const allocator_type& allocator) + : allocator_(allocator) + { + } + + allocator_type get_allocator() const + { + return allocator_; + } +}; + +// json_array + +template +class json_array : public container_base +{ +public: + typedef typename Json::allocator_type allocator_type; + typedef Json value_type; +private: + typedef typename Json::implementation_policy implementation_policy; + typedef typename std::allocator_traits:: template rebind_alloc value_allocator_type; + using value_container_type = typename implementation_policy::template sequence_container_type; + value_container_type elements_; +public: + typedef typename value_container_type::iterator iterator; + typedef typename value_container_type::const_iterator const_iterator; + typedef typename std::iterator_traits::reference reference; + typedef typename std::iterator_traits::reference const_reference; + + using container_base::get_allocator; + + json_array() + { + } + + explicit json_array(const allocator_type& allocator) + : container_base(allocator), + elements_(value_allocator_type(allocator)) + { + } + + explicit json_array(size_t n, + const allocator_type& allocator = allocator_type()) + : container_base(allocator), + elements_(n,Json(),value_allocator_type(allocator)) + { + } + + explicit json_array(size_t n, + const Json& value, + const allocator_type& allocator = allocator_type()) + : container_base(allocator), + elements_(n,value,value_allocator_type(allocator)) + { + } + + template + json_array(InputIterator begin, InputIterator end, const allocator_type& allocator = allocator_type()) + : container_base(allocator), + elements_(begin,end,value_allocator_type(allocator)) + { + } + json_array(const json_array& val) + : container_base(val.get_allocator()), + elements_(val.elements_) + { + } + json_array(const json_array& val, const allocator_type& allocator) + : container_base(allocator), + elements_(val.elements_,value_allocator_type(allocator)) + { + } + + json_array(json_array&& val) noexcept + : container_base(val.get_allocator()), + elements_(std::move(val.elements_)) + { + } + json_array(json_array&& val, const allocator_type& allocator) + : container_base(allocator), + elements_(std::move(val.elements_),value_allocator_type(allocator)) + { + } + + json_array(std::initializer_list init) + : container_base(), + elements_(std::move(init)) + { + } + + json_array(std::initializer_list init, + const allocator_type& allocator) + : container_base(allocator), + elements_(std::move(init),value_allocator_type(allocator)) + { + } + ~json_array() + { + } + + void swap(json_array& val) + { + elements_.swap(val.elements_); + } + + size_t size() const {return elements_.size();} + + size_t capacity() const {return elements_.capacity();} + + void clear() {elements_.clear();} + + void shrink_to_fit() + { + for (size_t i = 0; i < elements_.size(); ++i) + { + elements_[i].shrink_to_fit(); + } + elements_.shrink_to_fit(); + } + + void reserve(size_t n) {elements_.reserve(n);} + + void resize(size_t n) {elements_.resize(n);} + + void resize(size_t n, const Json& val) {elements_.resize(n,val);} + +#if !defined(JSONCONS_NO_DEPRECATED) + void remove_range(size_t from_index, size_t to_index) + { + JSONCONS_ASSERT(from_index <= to_index); + JSONCONS_ASSERT(to_index <= elements_.size()); + elements_.erase(elements_.cbegin()+from_index,elements_.cbegin()+to_index); + } +#endif + void erase(const_iterator pos) + { +#if defined(JSONCONS_NO_ERASE_TAKING_CONST_ITERATOR) + iterator it = elements_.begin() + (pos - elements_.begin()); + elements_.erase(it); +#else + elements_.erase(pos); +#endif + } + + void erase(const_iterator first, const_iterator last) + { +#if defined(JSONCONS_NO_ERASE_TAKING_CONST_ITERATOR) + iterator it1 = elements_.begin() + (first - elements_.begin()); + iterator it2 = elements_.begin() + (last - elements_.begin()); + elements_.erase(it1,it2); +#else + elements_.erase(first,last); +#endif + } + + Json& operator[](size_t i) {return elements_[i];} + + const Json& operator[](size_t i) const {return elements_[i];} + + // push_back + + template + typename std::enable_if::value,void>::type + push_back(T&& value) + { + elements_.emplace_back(std::forward(value)); + } + + template + typename std::enable_if::value,void>::type + push_back(T&& value) + { + elements_.emplace_back(std::forward(value),get_allocator()); + } + + template + typename std::enable_if::value,iterator>::type + insert(const_iterator pos, T&& value) + { +#if defined(JSONCONS_NO_ERASE_TAKING_CONST_ITERATOR) + iterator it = elements_.begin() + (pos - elements_.begin()); + return elements_.emplace(it, std::forward(value)); +#else + return elements_.emplace(pos, std::forward(value)); +#endif + } + template + typename std::enable_if::value,iterator>::type + insert(const_iterator pos, T&& value) + { +#if defined(JSONCONS_NO_ERASE_TAKING_CONST_ITERATOR) + iterator it = elements_.begin() + (pos - elements_.begin()); + return elements_.emplace(it, std::forward(value), get_allocator()); +#else + return elements_.emplace(pos, std::forward(value), get_allocator()); +#endif + } + + template + iterator insert(const_iterator pos, InputIt first, InputIt last) + { +#if defined(JSONCONS_NO_ERASE_TAKING_CONST_ITERATOR) + iterator it = elements_.begin() + (pos - elements_.begin()); + elements_.insert(it, first, last); + return first == last ? it : it + 1; +#else + return elements_.insert(pos, first, last); +#endif + } + + template + typename std::enable_if::value,iterator>::type + emplace(const_iterator pos, Args&&... args) + { +#if defined(JSONCONS_NO_ERASE_TAKING_CONST_ITERATOR) + iterator it = elements_.begin() + (pos - elements_.begin()); + return elements_.emplace(it, std::forward(args)...); +#else + return elements_.emplace(pos, std::forward(args)...); +#endif + } + + template + Json& emplace_back(Args&&... args) + { + elements_.emplace_back(std::forward(args)...); + return elements_.back(); + } + + iterator begin() {return elements_.begin();} + + iterator end() {return elements_.end();} + + const_iterator begin() const {return elements_.begin();} + + const_iterator end() const {return elements_.end();} + + bool operator==(const json_array& rhs) const + { + return elements_ == rhs.elements_; + } + + bool operator<(const json_array& rhs) const + { + return elements_ < rhs.elements_; + } +private: + + json_array& operator=(const json_array&) = delete; +}; + +struct sorted_unique_range_tag +{ +}; + +// json_object + +template +class json_object +{ +}; + +// Sort keys +template +class json_object::type> : + public container_base +{ +public: + typedef typename Json::allocator_type allocator_type; + typedef KeyT key_type; + typedef key_value key_value_type; + typedef typename Json::char_type char_type; + typedef typename Json::string_view_type string_view_type; +private: + typedef typename Json::implementation_policy implementation_policy; + typedef typename std::allocator_traits:: template rebind_alloc key_value_allocator_type; + using key_value_container_type = typename implementation_policy::template sequence_container_type; + + key_value_container_type members_; +public: + typedef typename key_value_container_type::iterator iterator; + typedef typename key_value_container_type::const_iterator const_iterator; + + using container_base::get_allocator; + + json_object() + { + } + + explicit json_object(const allocator_type& allocator) + : container_base(allocator), + members_(key_value_allocator_type(allocator)) + { + } + + json_object(const json_object& val) + : container_base(val.get_allocator()), + members_(val.members_) + { + } + + json_object(json_object&& val) + : container_base(val.get_allocator()), + members_(std::move(val.members_)) + { + } + + json_object(const json_object& val, const allocator_type& allocator) + : container_base(allocator), + members_(val.members_,key_value_allocator_type(allocator)) + { + } + + json_object(json_object&& val,const allocator_type& allocator) + : container_base(allocator), members_(std::move(val.members_),key_value_allocator_type(allocator)) + { + } + + template + json_object(InputIt first, InputIt last) + { + size_t count = std::distance(first,last); + members_.reserve(count); + for (auto s = first; s != last; ++s) + { + members_.emplace_back(get_key_value()(*s)); + } + std::stable_sort(members_.begin(),members_.end(), + [](const key_value_type& a, const key_value_type& b){return a.key().compare(b.key()) < 0;}); + auto it = std::unique(members_.begin(), members_.end(), + [](const key_value_type& a, const key_value_type& b){ return !(a.key().compare(b.key()));}); + members_.erase(it, members_.end()); + } + + template + json_object(InputIt first, InputIt last, + const allocator_type& allocator) + : container_base(allocator), + members_(key_value_allocator_type(allocator)) + { + size_t count = std::distance(first,last); + members_.reserve(count); + for (auto s = first; s != last; ++s) + { + members_.emplace_back(get_key_value()(*s)); + } + std::stable_sort(members_.begin(),members_.end(), + [](const key_value_type& a, const key_value_type& b){return a.key().compare(b.key()) < 0;}); + auto it = std::unique(members_.begin(), members_.end(), + [](const key_value_type& a, const key_value_type& b){ return !(a.key().compare(b.key()));}); + members_.erase(it, members_.end()); + } + + json_object(std::initializer_list init) + { + for (const auto& element : init) + { + if (element.size() != 2 || !element[0].is_string()) + { + JSONCONS_THROW(json_runtime_error("Cannot create object from initializer list")); + break; + } + } + for (auto& element : init) + { + insert_or_assign(element[0].as_string_view(), std::move(element[1])); + } + } + + json_object(std::initializer_list init, + const allocator_type& allocator) + : container_base(allocator), + members_(key_value_allocator_type(allocator)) + { + for (const auto& element : init) + { + if (element.size() != 2 || !element[0].is_string()) + { + JSONCONS_THROW(json_runtime_error("Cannot create object from initializer list")); + break; + } + } + for (auto& element : init) + { + insert_or_assign(element[0].as_string_view(), std::move(element[1])); + } + } + + void swap(json_object& val) + { + members_.swap(val.members_); + } + + iterator begin() + { + return members_.begin(); + } + + iterator end() + { + return members_.end(); + } + + const_iterator begin() const + { + return members_.begin(); + } + + const_iterator end() const + { + return members_.end(); + } + + size_t size() const {return members_.size();} + + size_t capacity() const {return members_.capacity();} + + void clear() {members_.clear();} + + void shrink_to_fit() + { + for (size_t i = 0; i < members_.size(); ++i) + { + members_[i].shrink_to_fit(); + } + members_.shrink_to_fit(); + } + + void reserve(size_t n) {members_.reserve(n);} + + Json& at(size_t i) + { + if (i >= members_.size()) + { + JSONCONS_THROW(json_runtime_error("Invalid array subscript")); + } + return members_[i].value(); + } + + const Json& at(size_t i) const + { + if (i >= members_.size()) + { + JSONCONS_THROW(json_runtime_error("Invalid array subscript")); + } + return members_[i].value(); + } + + iterator find(const string_view_type& name) + { + auto it = std::lower_bound(members_.begin(),members_.end(), name, + [](const key_value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + auto result = (it != members_.end() && it->key() == name) ? it : members_.end(); + return result; + } + + const_iterator find(const string_view_type& name) const + { + auto it = std::lower_bound(members_.begin(),members_.end(), + name, + [](const key_value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + auto result = (it != members_.end() && it->key() == name) ? it : members_.end(); + return result; + } + + void erase(const_iterator pos) + { +#if defined(JSONCONS_NO_ERASE_TAKING_CONST_ITERATOR) + iterator it = members_.begin() + (pos - members_.begin()); + members_.erase(it); +#else + members_.erase(pos); +#endif + } + + void erase(const_iterator first, const_iterator last) + { +#if defined(JSONCONS_NO_ERASE_TAKING_CONST_ITERATOR) + iterator it1 = members_.begin() + (first - members_.begin()); + iterator it2 = members_.begin() + (last - members_.begin()); + members_.erase(it1,it2); +#else + members_.erase(first,last); +#endif + } + + void erase(const string_view_type& name) + { + auto it = std::lower_bound(members_.begin(),members_.end(), name, + [](const key_value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + if (it != members_.end() && it->key() == name) + { + members_.erase(it); + } + } + + template + void insert(InputIt first, InputIt last, Convert convert) + { + size_t count = std::distance(first,last); + members_.reserve(members_.size() + count); + for (auto s = first; s != last; ++s) + { + members_.emplace_back(convert(*s)); + } + std::stable_sort(members_.begin(),members_.end(), + [](const key_value_type& a, const key_value_type& b){return a.key().compare(b.key()) < 0;}); + auto it = std::unique(members_.begin(), members_.end(), + [](const key_value_type& a, const key_value_type& b){ return !(a.key().compare(b.key()));}); + members_.erase(it, members_.end()); + } + + template + void insert(sorted_unique_range_tag, InputIt first, InputIt last, Convert convert) + { + if (first != last) + { + size_t count = std::distance(first,last); + members_.reserve(members_.size() + count); + + auto it = find(convert(*first).key()); + if (it != members_.end()) + { + for (auto s = first; s != last; ++s) + { + it = members_.emplace(it, convert(*s)); + } + } + else + { + for (auto s = first; s != last; ++s) + { + members_.emplace_back(convert(*s)); + } + } + } + } + + // insert_or_assign + + template + typename std::enable_if::value,std::pair>::type + insert_or_assign(const string_view_type& name, T&& value) + { + bool inserted; + auto it = std::lower_bound(members_.begin(),members_.end(), name, + [](const key_value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + if (it == members_.end()) + { + members_.emplace_back(key_type(name.begin(),name.end()), + std::forward(value)); + inserted = true; + it = members_.begin() + members_.size() - 1; + } + else if (it->key() == name) + { + it->value(Json(std::forward(value))); + inserted = false; // assigned + } + else + { + it = members_.emplace(it, + key_type(name.begin(),name.end()), + std::forward(value)); + inserted = true; + } + return std::make_pair(it,inserted); + } + + template + typename std::enable_if::value,std::pair>::type + insert_or_assign(const string_view_type& name, T&& value) + { + bool inserted; + auto it = std::lower_bound(members_.begin(),members_.end(), name, + [](const key_value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + if (it == members_.end()) + { + members_.emplace_back(key_type(name.begin(),name.end(), get_allocator()), + std::forward(value),get_allocator()); + inserted = true; + it = members_.begin() + members_.size() - 1; + } + else if (it->key() == name) + { + it->value(Json(std::forward(value), get_allocator())); + inserted = false; // assigned + } + else + { + it = members_.emplace(it, + key_type(name.begin(),name.end(), get_allocator()), + std::forward(value),get_allocator()); + inserted = true; + } + return std::make_pair(it,inserted); + } + + // try_emplace + + template + typename std::enable_if::value,std::pair>::type + try_emplace(const string_view_type& name, Args&&... args) + { + bool inserted; + auto it = std::lower_bound(members_.begin(),members_.end(), name, + [](const key_value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + if (it == members_.end()) + { + members_.emplace_back(key_type(name.begin(),name.end()), + std::forward(args)...); + it = members_.begin() + members_.size() - 1; + inserted = true; + } + else if (it->key() == name) + { + inserted = false; + } + else + { + it = members_.emplace(it, + key_type(name.begin(),name.end()), + std::forward(args)...); + inserted = true; + } + return std::make_pair(it,inserted); + } + + template + typename std::enable_if::value,std::pair>::type + try_emplace(const string_view_type& name, Args&&... args) + { + bool inserted; + auto it = std::lower_bound(members_.begin(),members_.end(), name, + [](const key_value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + if (it == members_.end()) + { + members_.emplace_back(key_type(name.begin(),name.end(), get_allocator()), + std::forward(args)...); + it = members_.begin() + members_.size() - 1; + inserted = true; + } + else if (it->key() == name) + { + inserted = false; + } + else + { + it = members_.emplace(it, + key_type(name.begin(),name.end(), get_allocator()), + std::forward(args)...); + inserted = true; + } + return std::make_pair(it,inserted); + } + + template + typename std::enable_if::value,iterator>::type + try_emplace(iterator hint, const string_view_type& name, Args&&... args) + { + iterator it = hint; + + if (hint != members_.end() && hint->key() <= name) + { + it = std::lower_bound(hint,members_.end(), name, + [](const key_value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + else + { + it = std::lower_bound(members_.begin(),members_.end(), name, + [](const key_value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + + if (it == members_.end()) + { + members_.emplace_back(key_type(name.begin(),name.end()), + std::forward(args)...); + it = members_.begin() + (members_.size() - 1); + } + else if (it->key() == name) + { + } + else + { + it = members_.emplace(it, + key_type(name.begin(),name.end()), + std::forward(args)...); + } + + return it; + } + + template + typename std::enable_if::value,iterator>::type + try_emplace(iterator hint, const string_view_type& name, Args&&... args) + { + iterator it = hint; + if (hint != members_.end() && hint->key() <= name) + { + it = std::lower_bound(hint,members_.end(), name, + [](const key_value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + else + { + it = std::lower_bound(members_.begin(),members_.end(), name, + [](const key_value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + + if (it == members_.end()) + { + members_.emplace_back(key_type(name.begin(),name.end(), get_allocator()), + std::forward(args)...); + it = members_.begin() + (members_.size() - 1); + } + else if (it->key() == name) + { + } + else + { + it = members_.emplace(it, + key_type(name.begin(),name.end(), get_allocator()), + std::forward(args)...); + } + return it; + } + + // insert_or_assign + + template + typename std::enable_if::value,iterator>::type + insert_or_assign(iterator hint, const string_view_type& name, T&& value) + { + iterator it; + if (hint != members_.end() && hint->key() <= name) + { + it = std::lower_bound(hint,members_.end(), name, + [](const key_value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + else + { + it = std::lower_bound(members_.begin(),members_.end(), name, + [](const key_value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + + if (it == members_.end()) + { + members_.emplace_back(key_type(name.begin(),name.end()), + std::forward(value)); + it = members_.begin() + (members_.size() - 1); + } + else if (it->key() == name) + { + it->value(Json(std::forward(value))); + } + else + { + it = members_.emplace(it, + key_type(name.begin(),name.end()), + std::forward(value)); + } + return it; + } + + template + typename std::enable_if::value,iterator>::type + insert_or_assign(iterator hint, const string_view_type& name, T&& value) + { + iterator it; + if (hint != members_.end() && hint->key() <= name) + { + it = std::lower_bound(hint,members_.end(), name, + [](const key_value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + else + { + it = std::lower_bound(members_.begin(),members_.end(), name, + [](const key_value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + + if (it == members_.end()) + { + members_.emplace_back(key_type(name.begin(),name.end(), get_allocator()), + std::forward(value),get_allocator()); + it = members_.begin() + (members_.size() - 1); + } + else if (it->key() == name) + { + it->value(Json(std::forward(value),get_allocator())); + } + else + { + it = members_.emplace(it, + key_type(name.begin(),name.end(), get_allocator()), + std::forward(value),get_allocator()); + } + return it; + } + + // merge + + void merge(const json_object& source) + { + for (auto it = source.begin(); it != source.end(); ++it) + { + try_emplace(it->key(),it->value()); + } + } + + void merge(json_object&& source) + { + auto it = std::make_move_iterator(source.begin()); + auto end = std::make_move_iterator(source.end()); + for (; it != end; ++it) + { + auto pos = std::lower_bound(members_.begin(),members_.end(), it->key(), + [](const key_value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + if (pos == members_.end() ) + { + members_.emplace_back(*it); + } + else if (it->key() != pos->key()) + { + members_.emplace(pos,*it); + } + } + } + + void merge(iterator hint, const json_object& source) + { + for (auto it = source.begin(); it != source.end(); ++it) + { + hint = try_emplace(hint, it->key(),it->value()); + } + } + + void merge(iterator hint, json_object&& source) + { + auto it = std::make_move_iterator(source.begin()); + auto end = std::make_move_iterator(source.end()); + for (; it != end; ++it) + { + iterator pos; + if (hint != members_.end() && hint->key() <= it->key()) + { + pos = std::lower_bound(hint,members_.end(), it->key(), + [](const key_value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + else + { + pos = std::lower_bound(members_.begin(),members_.end(), it->key(), + [](const key_value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + if (pos == members_.end() ) + { + members_.emplace_back(*it); + hint = members_.begin() + (members_.size() - 1); + } + else if (it->key() != pos->key()) + { + hint = members_.emplace(pos,*it); + } + } + } + + // merge_or_update + + void merge_or_update(const json_object& source) + { + for (auto it = source.begin(); it != source.end(); ++it) + { + insert_or_assign(it->key(),it->value()); + } + } + + void merge_or_update(json_object&& source) + { + auto it = std::make_move_iterator(source.begin()); + auto end = std::make_move_iterator(source.end()); + for (; it != end; ++it) + { + auto pos = std::lower_bound(members_.begin(),members_.end(), it->key(), + [](const key_value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + if (pos == members_.end() ) + { + members_.emplace_back(*it); + } + else + { + pos->value(it->value()); + } + } + } + + void merge_or_update(iterator hint, const json_object& source) + { + for (auto it = source.begin(); it != source.end(); ++it) + { + hint = insert_or_assign(hint, it->key(),it->value()); + } + } + + void merge_or_update(iterator hint, json_object&& source) + { + auto it = std::make_move_iterator(source.begin()); + auto end = std::make_move_iterator(source.end()); + for (; it != end; ++it) + { + iterator pos; + if (hint != members_.end() && hint->key() <= it->key()) + { + pos = std::lower_bound(hint,members_.end(), it->key(), + [](const key_value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + else + { + pos = std::lower_bound(members_.begin(),members_.end(), it->key(), + [](const key_value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + if (pos == members_.end() ) + { + members_.emplace_back(*it); + hint = members_.begin() + (members_.size() - 1); + } + else + { + pos->value(it->value()); + hint = pos; + } + } + } + + bool operator==(const json_object& rhs) const + { + return members_ == rhs.members_; + } + + bool operator<(const json_object& rhs) const + { + return members_ < rhs.members_; + } +private: + json_object& operator=(const json_object&) = delete; +}; + +// Preserve order +template +class json_object::type> : + public container_base +{ +public: + typedef typename Json::allocator_type allocator_type; + typedef typename Json::char_type char_type; + typedef KeyT key_type; + typedef typename Json::string_view_type string_view_type; + typedef key_value key_value_type; +private: + typedef typename Json::implementation_policy implementation_policy; + typedef typename std::allocator_traits:: template rebind_alloc key_value_allocator_type; + using key_value_container_type = typename implementation_policy::template sequence_container_type; + typedef typename std::allocator_traits:: template rebind_alloc index_allocator_type; + using index_container_type = typename implementation_policy::template sequence_container_type; + + key_value_container_type members_; + index_container_type index_; +public: + typedef typename key_value_container_type::iterator iterator; + typedef typename key_value_container_type::const_iterator const_iterator; + + using container_base::get_allocator; + + json_object() + { + } + json_object(const allocator_type& allocator) + : container_base(allocator), + members_(key_value_allocator_type(allocator)), + index_(index_allocator_type(allocator)) + { + } + + json_object(const json_object& val) + : container_base(val.get_allocator()), + members_(val.members_), + index_(val.index_) + { + } + + json_object(json_object&& val) + : container_base(val.get_allocator()), + members_(std::move(val.members_)), + index_(std::move(val.index_)) + { + } + + json_object(const json_object& val, const allocator_type& allocator) + : container_base(allocator), + members_(val.members_,key_value_allocator_type(allocator)), + index_(val.index_,index_allocator_type(allocator)) + { + } + + json_object(json_object&& val,const allocator_type& allocator) + : container_base(allocator), + members_(std::move(val.members_),key_value_allocator_type(allocator)), + index_(std::move(val.index_),index_allocator_type(allocator)) + { + } + + template + json_object(InputIt first, InputIt last) + { + size_t count = std::distance(first,last); + members_.reserve(count); + for (auto s = first; s != last; ++s) + { + members_.emplace_back(get_key_value()(*s)); + } + + build_index(); + auto last_unique = std::unique(index_.begin(), index_.end(), + [&](size_t a, size_t b) { return !(members_.at(a).key().compare(members_.at(b).key())); }); + + if (last_unique != index_.end()) + { + index_.erase(last_unique, index_.end()); + std::sort(index_.begin(), index_.end()); + + auto result = index_.rbegin(); + if (*result != members_.size()) + { + members_.erase(members_.begin() + (*result + 1), members_.end()); + } + for (auto it = index_.rbegin() + 1; it != index_.rend(); ++it, ++result) + { + if (*result - *it > 1) + { + members_.erase(members_.begin() + (*it + 1), members_.begin() + *result); + } + } + } + build_index(); + } + + template + json_object(InputIt first, InputIt last, + const allocator_type& allocator) + : container_base(allocator), + members_(key_value_allocator_type(allocator)), + index_(index_allocator_type(allocator)) + { + size_t count = std::distance(first,last); + members_.reserve(count); + for (auto s = first; s != last; ++s) + { + members_.emplace_back(get_key_value()(*s)); + } + + build_index(); + auto last_unique = std::unique(index_.begin(), index_.end(), + [&](size_t a, size_t b) { return !(members_.at(a).key().compare(members_.at(b).key())); }); + + if (last_unique != index_.end()) + { + index_.erase(last_unique, index_.end()); + std::sort(index_.begin(), index_.end()); + + auto result = index_.rbegin(); + if (*result != members_.size()) + { + members_.erase(members_.begin() + (*result + 1), members_.end()); + } + for (auto it = index_.rbegin() + 1; it != index_.rend(); ++it, ++result) + { + if (*result - *it > 1) + { + members_.erase(members_.begin() + (*it + 1), members_.begin() + *result); + } + } + } + build_index(); + } + + json_object(std::initializer_list init) + { + for (const auto& element : init) + { + if (element.size() != 2 || !element[0].is_string()) + { + JSONCONS_THROW(json_runtime_error("Cannot create object from initializer list")); + break; + } + } + for (auto& element : init) + { + insert_or_assign(element[0].as_string_view(), std::move(element[1])); + } + } + + json_object(std::initializer_list init, + const allocator_type& allocator) + : container_base(allocator), + members_(key_value_allocator_type(allocator)), + index_(index_allocator_type(allocator)) + { + for (const auto& element : init) + { + if (element.size() != 2 || !element[0].is_string()) + { + JSONCONS_THROW(json_runtime_error("Cannot create object from initializer list")); + break; + } + } + for (auto& element : init) + { + insert_or_assign(element[0].as_string_view(), std::move(element[1])); + } + } + + void swap(json_object& val) + { + members_.swap(val.members_); + } + + iterator begin() + { + return members_.begin(); + } + + iterator end() + { + return members_.end(); + } + + const_iterator begin() const + { + return members_.begin(); + } + + const_iterator end() const + { + return members_.end(); + } + + size_t size() const {return members_.size();} + + size_t capacity() const {return members_.capacity();} + + void clear() + { + members_.clear(); + index_.clear(); + } + + void shrink_to_fit() + { + for (size_t i = 0; i < members_.size(); ++i) + { + members_[i].shrink_to_fit(); + } + members_.shrink_to_fit(); + index_.shrink_to_fit(); + } + + void reserve(size_t n) {members_.reserve(n);} + + Json& at(size_t i) + { + if (i >= members_.size()) + { + JSONCONS_THROW(json_runtime_error("Invalid array subscript")); + } + return members_[i].value(); + } + + const Json& at(size_t i) const + { + if (i >= members_.size()) + { + JSONCONS_THROW(json_runtime_error("Invalid array subscript")); + } + return members_[i].value(); + } + + iterator find(const string_view_type& name) + { + auto it = std::lower_bound(index_.begin(),index_.end(), name, + [&](size_t i, const string_view_type& k){return members_.at(i).key().compare(k) < 0;}); + if (it != index_.end() && members_.at(*it).key() == name) + { + return members_.begin() + *it; + } + else + { + return members_.end(); + } + } + + const_iterator find(const string_view_type& name) const + { + auto it = std::lower_bound(index_.begin(),index_.end(), name, + [&](size_t i, const string_view_type& k){return members_.at(i).key().compare(k) < 0;}); + if (it != index_.end() && members_.at(*it).key() == name) + { + return members_.begin() + *it; + } + else + { + return members_.end(); + } + } + + void erase(const_iterator first, const_iterator last) + { + size_t pos1 = first == members_.end() ? members_.size() : first - members_.begin(); + size_t pos2 = last == members_.end() ? members_.size() : last - members_.begin(); + + if (pos1 < members_.size() && pos2 <= members_.size()) + { + erase_index_entries(pos1,pos2); + +#if defined(JSONCONS_NO_ERASE_TAKING_CONST_ITERATOR) + iterator it1 = members_.begin() + (first - members_.begin()); + iterator it2 = members_.begin() + (last - members_.begin()); + members_.erase(it1,it2); +#else + members_.erase(first,last); +#endif + } + } + + void erase(const string_view_type& name) + { + auto pos = find(name); + if (pos != members_.end()) + { + erase_index_entry(name); +#if defined(JSONCONS_NO_ERASE_TAKING_CONST_ITERATOR) + iterator it = members_.begin() + (pos - members_.begin()); + members_.erase(it); +#else + members_.erase(pos); +#endif + } + } + + template + void insert(InputIt first, InputIt last, Convert convert) + { + size_t count = std::distance(first,last); + members_.reserve(members_.size() + count); + for (auto s = first; s != last; ++s) + { + members_.emplace_back(convert(*s)); + } + + build_index(); + auto last_unique = std::unique(index_.begin(), index_.end(), + [&](size_t a, size_t b) { return !(members_.at(a).key().compare(members_.at(b).key())); }); + + if (last_unique != index_.end()) + { + index_.erase(last_unique, index_.end()); + std::sort(index_.begin(), index_.end()); + + auto result = index_.rbegin(); + if (*result != members_.size()) + { + members_.erase(members_.begin() + (*result + 1), members_.end()); + } + for (auto it = index_.rbegin() + 1; it != index_.rend(); ++it, ++result) + { + if (*result - *it > 1) + { + members_.erase(members_.begin() + (*it + 1), members_.begin() + *result); + } + } + } + build_index(); + } + + template + void insert(sorted_unique_range_tag, InputIt first, InputIt last, Convert convert) + { + size_t count = std::distance(first,last); + + members_.reserve(members_.size() + count); + for (auto s = first; s != last; ++s) + { + members_.emplace_back(convert(*s)); + } + + build_index(); + } + + template + typename std::enable_if::value,std::pair>::type + insert_or_assign(const string_view_type& name, T&& value) + { + auto result = insert_index_entry(name,members_.size()); + if (result.second) + { + members_.emplace_back(key_type(name.begin(), name.end()), std::forward(value)); + auto it = members_.begin() + result.first; + return std::make_pair(it,true); + } + else + { + auto it = members_.begin() + result.first; + it->value(Json(std::forward(value))); + return std::make_pair(it,false); + } + } + + template + typename std::enable_if::value,std::pair>::type + insert_or_assign(const string_view_type& name, T&& value) + { + auto result = insert_index_entry(name,members_.size()); + if (result.second) + { + members_.emplace_back(key_type(name.begin(),name.end(),get_allocator()), + std::forward(value),get_allocator()); + auto it = members_.begin() + result.first; + return std::make_pair(it,true); + } + else + { + auto it = members_.begin() + result.first; + it->value(Json(std::forward(value),get_allocator())); + return std::make_pair(it,false); + } + } + + template + typename std::enable_if::value,iterator>::type + insert_or_assign(iterator hint, const string_view_type& key, T&& value) + { + if (hint == members_.end()) + { + auto result = insert_or_assign(key, std::forward(value)); + return result.first; + } + else + { + size_t pos = hint - members_.begin(); + auto result = insert_index_entry(key,pos); + + if (result.second) + { + auto it = members_.emplace(hint, key_type(key.begin(), key.end()), std::forward(value)); + return it; + } + else + { + auto it = members_.begin() + result.first; + it->value(Json(std::forward(value))); + return it; + } + } + } + + template + typename std::enable_if::value,iterator>::type + insert_or_assign(iterator hint, const string_view_type& key, T&& value) + { + if (hint == members_.end()) + { + auto result = insert_or_assign(key, std::forward(value)); + return result.first; + } + else + { + size_t pos = hint - members_.begin(); + auto result = insert_index_entry(key,pos); + + if (result.second) + { + auto it = members_.emplace(hint, + key_type(key.begin(),key.end(),get_allocator()), + std::forward(value),get_allocator()); + return it; + } + else + { + auto it = members_.begin() + result.first; + it->value(Json(std::forward(value),get_allocator())); + return it; + } + } + } + + // merge + + void merge(const json_object& source) + { + for (auto it = source.begin(); it != source.end(); ++it) + { + try_emplace(it->key(),it->value()); + } + } + + void merge(json_object&& source) + { + auto it = std::make_move_iterator(source.begin()); + auto end = std::make_move_iterator(source.end()); + for (; it != end; ++it) + { + auto pos = find(it->key()); + if (pos == members_.end() ) + { + try_emplace(it->key(),std::move(it->value())); + } + } + } + + void merge(iterator hint, const json_object& source) + { + size_t pos = hint - members_.begin(); + for (auto it = source.begin(); it != source.end(); ++it) + { + hint = try_emplace(hint, it->key(),it->value()); + size_t newpos = hint - members_.begin(); + if (newpos == pos) + { + ++hint; + pos = hint - members_.begin(); + } + else + { + hint = members_.begin() + pos; + } + } + } + + void merge(iterator hint, json_object&& source) + { + size_t pos = hint - members_.begin(); + + auto it = std::make_move_iterator(source.begin()); + auto end = std::make_move_iterator(source.end()); + for (; it != end; ++it) + { + hint = try_emplace(hint, it->key(), std::move(it->value())); + size_t newpos = hint - members_.begin(); + if (newpos == pos) + { + ++hint; + pos = hint - members_.begin(); + } + else + { + hint = members_.begin() + pos; + } + } + } + + // merge_or_update + + void merge_or_update(const json_object& source) + { + for (auto it = source.begin(); it != source.end(); ++it) + { + insert_or_assign(it->key(),it->value()); + } + } + + void merge_or_update(json_object&& source) + { + auto it = std::make_move_iterator(source.begin()); + auto end = std::make_move_iterator(source.end()); + for (; it != end; ++it) + { + auto pos = find(it->key()); + if (pos == members_.end() ) + { + insert_or_assign(it->key(),std::move(it->value())); + } + else + { + pos->value(std::move(it->value())); + } + } + } + + void merge_or_update(iterator hint, const json_object& source) + { + size_t pos = hint - members_.begin(); + for (auto it = source.begin(); it != source.end(); ++it) + { + hint = insert_or_assign(hint, it->key(),it->value()); + size_t newpos = hint - members_.begin(); + if (newpos == pos) + { + ++hint; + pos = hint - members_.begin(); + } + else + { + hint = members_.begin() + pos; + } + } + } + + void merge_or_update(iterator hint, json_object&& source) + { +/* + auto it = std::make_move_iterator(source.begin()); + auto end = std::make_move_iterator(source.end()); + for (; it != end; ++it) + { + auto pos = find(it->key()); + if (pos == members_.end() ) + { + hint = try_emplace(hint,it->key(),std::move(it->value())); + } + else + { + pos->value(std::move(it->value())); + hint = pos; + } + } +*/ + size_t pos = hint - members_.begin(); + auto it = std::make_move_iterator(source.begin()); + auto end = std::make_move_iterator(source.end()); + for (; it != end; ++it) + { + hint = insert_or_assign(hint, it->key(),std::move(it->value())); + size_t newpos = hint - members_.begin(); + if (newpos == pos) + { + ++hint; + pos = hint - members_.begin(); + } + else + { + hint = members_.begin() + pos; + } + } + } + + // try_emplace + + template + typename std::enable_if::value,std::pair>::type + try_emplace(const string_view_type& name, Args&&... args) + { + auto result = insert_index_entry(name,members_.size()); + if (result.second) + { + members_.emplace_back(key_type(name.begin(), name.end()), std::forward(args)...); + auto it = members_.begin() + result.first; + return std::make_pair(it,true); + } + else + { + auto it = members_.begin() + result.first; + return std::make_pair(it,false); + } + } + + template + typename std::enable_if::value,std::pair>::type + try_emplace(const string_view_type& key, Args&&... args) + { + auto result = insert_index_entry(key,members_.size()); + if (result.second) + { + members_.emplace_back(key_type(key.begin(),key.end(), get_allocator()), + std::forward(args)...); + auto it = members_.begin() + result.first; + return std::make_pair(it,true); + } + else + { + auto it = members_.begin() + result.first; + return std::make_pair(it,false); + } + } + + template + typename std::enable_if::value,iterator>::type + try_emplace(iterator hint, const string_view_type& key, Args&&... args) + { + if (hint == members_.end()) + { + auto result = try_emplace(key, std::forward(args)...); + return result.first; + } + else + { + size_t pos = hint - members_.begin(); + auto result = insert_index_entry(key, pos); + + if (result.second) + { + auto it = members_.emplace(hint, key_type(key.begin(), key.end()), std::forward(args)...); + return it; + } + else + { + auto it = members_.begin() + result.first; + return it; + } + } + } + + template + typename std::enable_if::value,iterator>::type + try_emplace(iterator hint, const string_view_type& key, Args&&... args) + { + if (hint == members_.end()) + { + auto result = try_emplace(key, std::forward(args)...); + return result.first; + } + else + { + size_t pos = hint - members_.begin(); + auto result = insert_index_entry(key, pos); + + if (result.second) + { + auto it = members_.emplace(hint, + key_type(key.begin(),key.end(), get_allocator()), + std::forward(args)...); + return it; + } + else + { + auto it = members_.begin() + result.first; + return it; + } + } + } + + bool operator==(const json_object& rhs) const + { + return members_ == rhs.members_; + } + + bool operator<(const json_object& rhs) const + { + return members_ < rhs.members_; + } +private: + + std::pair insert_index_entry(const string_view_type& key, size_t pos) + { + JSONCONS_ASSERT(pos <= index_.size()); + + auto it = std::lower_bound(index_.begin(),index_.end(), key, + [&](size_t i, const string_view_type& k){return members_.at(i).key().compare(k) < 0;}); + + if (it == index_.end()) + { + size_t count = index_.size() - pos; + for (size_t i = 0; count > 0 && i < index_.size(); ++i) + { + if (index_[i] >= pos) + { + ++index_[i]; + --count; + } + } + index_.push_back(pos); + return std::make_pair(pos,true); + } + else if (members_.at(*it).key() != key) + { + size_t count = index_.size() - pos; + for (size_t i = 0; count > 0 && i < index_.size(); ++i) + { + if (index_[i] >= pos) + { + ++index_[i]; + --count; + } + } + auto it2 = index_.insert(it, pos); + return std::make_pair(*it2,true); + } + else + { + return std::make_pair(*it,false); + } + } + + void erase_index_entry(const string_view_type& key) + { + auto it = std::lower_bound(index_.begin(),index_.end(), key, + [&](size_t i, const string_view_type& k){return members_.at(i).key().compare(k) < 0;}); + + if (it != index_.end() && members_.at(*it).key() != key) + { + size_t pos = *it; + size_t count = index_.size() - pos; + for (size_t i = 0; i < index_.size() && count > 0; ++i) + { + if (index_[i] > pos) + { + --index_[i]; + --count; + } + } + index_.erase(it); + } + } + + void erase_index_entries(size_t pos1, size_t pos2) + { + for (size_t i = 0; i < index_.size(); ++i) + { + if (index_[i] >= pos1 && index_[i] < pos2) + { + index_.erase(index_.begin()+index_[i]); + } + else if (index_[i] > pos2) + { + --index_[i]; + } + } + } + + void build_index() + { + index_.clear(); + index_.reserve(members_.size()); + for (size_t i = 0; i < members_.size(); ++i) + { + index_.push_back(i); + } + std::stable_sort(index_.begin(),index_.end(), + [&](size_t a, size_t b){return members_.at(a).key().compare(members_.at(b).key()) < 0;}); + } + + json_object& operator=(const json_object&) = delete; +}; + +} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_content_handler.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_content_handler.hpp new file mode 100644 index 0000000000..131e2b6729 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_content_handler.hpp @@ -0,0 +1,431 @@ +// Copyright 2018 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_CONTENT_HANDLER_HPP +#define JSONCONS_JSON_CONTENT_HANDLER_HPP + +#include +#include +#include +#include +#include + +namespace jsoncons { + +// null_type + +struct null_type +{ +}; + +enum class semantic_tag : uint8_t +{ + none = 0, + undefined = 0x01, + datetime = 0x02, + timestamp = 0x03, + bigint = 0x04, + bigdec = 0x05, + bigfloat = 0x06, + base16 = 0x07, + base64 = 0x08, + base64url = 0x09, + uri = 0x0a +#if !defined(JSONCONS_NO_DEPRECATED) + , big_integer = bigint + , big_decimal = bigdec + , big_float = bigfloat + , date_time = datetime +#endif +}; + +#if !defined(JSONCONS_NO_DEPRECATED) + typedef semantic_tag semantic_tag_type; +#endif + +template +class basic_json_content_handler +{ +#if !defined(JSONCONS_NO_DEPRECATED) + std::basic_string buffer_; +#endif +public: + typedef CharT char_type; + typedef std::char_traits char_traits_type; + + typedef basic_string_view string_view_type; + + basic_json_content_handler(basic_json_content_handler&&) = default; + + basic_json_content_handler& operator=(basic_json_content_handler&&) = default; + + basic_json_content_handler() = default; + + virtual ~basic_json_content_handler() {} + + void flush() + { + do_flush(); + } + + bool begin_object(semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()) + { + return do_begin_object(tag, context); + } + + bool begin_object(size_t length, + semantic_tag tag=semantic_tag::none, + const ser_context& context = null_ser_context()) + { + return do_begin_object(length, tag, context); + } + + bool end_object(const ser_context& context = null_ser_context()) + { + return do_end_object(context); + } + + bool begin_array(semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()) + { + return do_begin_array(tag, context); + } + + bool begin_array(size_t length, + semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()) + { + return do_begin_array(length, tag, context); + } + + bool end_array(const ser_context& context=null_ser_context()) + { + return do_end_array(context); + } + + bool name(const string_view_type& name, const ser_context& context=null_ser_context()) + { + return do_name(name, context); + } + + bool string_value(const string_view_type& value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()) + { + return do_string_value(value, tag, context); + } + + bool byte_string_value(const byte_string_view& b, + semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()) + { + return do_byte_string_value(b, tag, context); + } + + bool byte_string_value(const uint8_t* p, size_t size, + semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()) + { + return do_byte_string_value(byte_string(p, size), tag, context); + } +#if !defined(JSONCONS_NO_DEPRECATED) + bool byte_string_value(const byte_string_view& b, + byte_string_chars_format encoding_hint, + semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()) + { + switch (encoding_hint) + { + case byte_string_chars_format::base16: + tag = semantic_tag::base16; + break; + case byte_string_chars_format::base64: + tag = semantic_tag::base64; + break; + case byte_string_chars_format::base64url: + tag = semantic_tag::base64url; + break; + default: + break; + } + return do_byte_string_value(b, tag, context); + } + + bool byte_string_value(const uint8_t* p, size_t size, + byte_string_chars_format encoding_hint, + semantic_tag tag=semantic_tag::none, + const ser_context& context=null_ser_context()) + { + switch (encoding_hint) + { + case byte_string_chars_format::base16: + tag = semantic_tag::base16; + break; + case byte_string_chars_format::base64: + tag = semantic_tag::base64; + break; + case byte_string_chars_format::base64url: + tag = semantic_tag::base64url; + break; + default: + break; + } + return do_byte_string_value(byte_string(p, size), tag, context); + } + bool big_integer_value(const string_view_type& s, const ser_context& context=null_ser_context()) + { + return do_string_value(s, semantic_tag::bigint, context); + } + + bool big_decimal_value(const string_view_type& s, const ser_context& context=null_ser_context()) + { + return do_string_value(s, semantic_tag::bigdec, context); + } + + bool date_time_value(const string_view_type& s, const ser_context& context=null_ser_context()) + { + return do_string_value(s, semantic_tag::datetime, context); + } + + bool timestamp_value(int64_t val, const ser_context& context=null_ser_context()) + { + return do_int64_value(val, semantic_tag::timestamp, context); + } +#endif + + bool int64_value(int64_t value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()) + { + return do_int64_value(value, tag, context); + } + + bool uint64_value(uint64_t value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()) + { + return do_uint64_value(value, tag, context); + } + + bool double_value(double value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()) + { + return do_double_value(value, tag, context); + } + + bool bool_value(bool value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()) + { + return do_bool_value(value, tag, context); + } + + bool null_value(semantic_tag tag = semantic_tag::none, + const ser_context& context=null_ser_context()) + { + return do_null_value(tag, context); + } + +#if !defined(JSONCONS_NO_DEPRECATED) + + bool begin_document() + { + return true; + } + + bool end_document() + { + flush(); + return true; + } + + void begin_json() + { + } + + void end_json() + { + end_document(); + } + + void name(const CharT* p, size_t length, const ser_context& context) + { + name(string_view_type(p, length), context); + } + + void integer_value(int64_t value) + { + int64_value(value); + } + + void integer_value(int64_t value, const ser_context& context) + { + int64_value(value,context); + } + + void uinteger_value(uint64_t value) + { + uint64_value(value); + } + + void uinteger_value(uint64_t value, const ser_context& context) + { + uint64_value(value,context); + } + + bool bignum_value(const string_view_type& s, const ser_context& context=null_ser_context()) + { + return do_string_value(s, semantic_tag::bigint, context); + } + + bool decimal_value(const string_view_type& s, const ser_context& context=null_ser_context()) + { + return do_string_value(s, semantic_tag::bigdec, context); + } + + bool epoch_time_value(int64_t val, const ser_context& context=null_ser_context()) + { + return do_int64_value(val, semantic_tag::timestamp, context); + } + +#endif + +private: + virtual void do_flush() = 0; + + virtual bool do_begin_object(semantic_tag, const ser_context& context) = 0; + + virtual bool do_begin_object(size_t, semantic_tag tag, const ser_context& context) + { + return do_begin_object(tag, context); + } + + virtual bool do_end_object(const ser_context& context) = 0; + + virtual bool do_begin_array(semantic_tag, const ser_context& context) = 0; + + virtual bool do_begin_array(size_t, semantic_tag tag, const ser_context& context) + { + return do_begin_array(tag, context); + } + + virtual bool do_end_array(const ser_context& context) = 0; + + virtual bool do_name(const string_view_type& name, const ser_context& context) = 0; + + virtual bool do_null_value(semantic_tag, const ser_context& context) = 0; + + virtual bool do_string_value(const string_view_type& value, semantic_tag tag, const ser_context& context) = 0; + + virtual bool do_byte_string_value(const byte_string_view& b, + semantic_tag tag, + const ser_context& context) = 0; + + virtual bool do_double_value(double value, + semantic_tag tag, + const ser_context& context) = 0; + + virtual bool do_int64_value(int64_t value, + semantic_tag tag, + const ser_context& context) = 0; + + virtual bool do_uint64_value(uint64_t value, + semantic_tag tag, + const ser_context& context) = 0; + + virtual bool do_bool_value(bool value, semantic_tag tag, const ser_context& context) = 0; +}; + +template +class basic_null_json_content_handler final : public basic_json_content_handler +{ +public: + using typename basic_json_content_handler::string_view_type; +private: + void do_flush() override + { + } + + bool do_begin_object(semantic_tag, const ser_context&) override + { + return true; + } + + bool do_end_object(const ser_context&) override + { + return true; + } + + bool do_begin_array(semantic_tag, const ser_context&) override + { + return true; + } + + bool do_end_array(const ser_context&) override + { + return true; + } + + bool do_name(const string_view_type&, const ser_context&) override + { + return true; + } + + bool do_null_value(semantic_tag, const ser_context&) override + { + return true; + } + + bool do_string_value(const string_view_type&, semantic_tag, const ser_context&) override + { + return true; + } + + bool do_byte_string_value(const byte_string_view&, + semantic_tag, + const ser_context&) override + { + return true; + } + + bool do_int64_value(int64_t, + semantic_tag, + const ser_context&) override + { + return true; + } + + bool do_uint64_value(uint64_t, + semantic_tag, + const ser_context&) override + { + return true; + } + + bool do_double_value(double, + semantic_tag, + const ser_context&) override + { + return true; + } + + bool do_bool_value(bool, semantic_tag, const ser_context&) override + { + return true; + } +}; + +typedef basic_json_content_handler json_content_handler; +typedef basic_json_content_handler wjson_content_handler; + +typedef basic_null_json_content_handler null_json_content_handler; +typedef basic_null_json_content_handler wnull_json_content_handler; + +} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_conversion_traits.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_conversion_traits.hpp new file mode 100644 index 0000000000..2aee25a233 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_conversion_traits.hpp @@ -0,0 +1,196 @@ +// Copyright 2017 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_CONVERSION_TRAITS_HPP +#define JSONCONS_JSON_CONVERSION_TRAITS_HPP + +#include +#include +#include +#include +#include // std::enable_if +#include +#include +#include +#include +#include +#include +#include + +namespace jsoncons { + +template +void read_from(const Json& j, basic_staj_reader& reader, T& val, std::error_code& ec); + +template +void read_from(const Json& j, basic_staj_reader& reader, T& val) +{ + std::error_code ec; + read_from(j, reader, val, ec); + if (ec) + { + throw ser_error(ec, reader.context().line(), reader.context().column()); + } +} + +template +void write_to(const T&val, basic_json_content_handler& receiver); + +} // namespace jsoncons + +#include + +namespace jsoncons { + +template +struct json_conversion_traits +{ + template + static T decode(basic_staj_reader& reader, std::error_code& ec) + { + json_decoder decoder; + reader.accept(decoder, ec); + return decoder.get_result().template as(); + } + + template + static void encode(const T& val, basic_json_content_handler& receiver) + { + auto j = json_type_traits::to_json(val); + j.dump(receiver); + } +}; + +// specializations + +// vector like + +template +struct json_conversion_traits::value && jsoncons::detail::is_vector_like::value +>::type> +{ + typedef typename T::value_type value_type; + + template + static T decode(basic_staj_reader& reader, std::error_code& ec) + { + T v; + basic_staj_array_iterator end; + basic_staj_array_iterator it(reader, ec); + + while (it != end && !ec) + { + v.push_back(*it); + it.increment(ec); + } + return v; + } + + template + static void encode(const T& val, basic_json_content_handler& receiver) + { + receiver.begin_array(); + for (auto it = std::begin(val); it != std::end(val); ++it) + { + json_conversion_traits::template encode(*it,receiver); + } + receiver.end_array(); + receiver.flush(); + } +}; +// std::array + +template +struct json_conversion_traits> +{ + typedef typename std::array::value_type value_type; + + template + static std::array decode(basic_staj_reader& reader, std::error_code& ec) + { + std::array v; + v.fill(T{}); + basic_staj_array_iterator end; + basic_staj_array_iterator it(reader, ec); + + for (size_t i = 0; it != end && i < N && !ec; ++i) + { + v[i] = *it; + it.increment(ec); + } + return v; + } + + template + static void encode(const std::array& val, basic_json_content_handler& receiver) + { + receiver.begin_array(); + for (auto it = std::begin(val); it != std::end(val); ++it) + { + json_conversion_traits::template encode(*it,receiver); + } + receiver.end_array(); + receiver.flush(); + } +}; + +// map like + +template +struct json_conversion_traits::value && jsoncons::detail::is_map_like::value +>::type> +{ + typedef typename T::mapped_type mapped_type; + typedef typename T::value_type value_type; + typedef typename T::key_type key_type; + + template + static T decode(basic_staj_reader& reader, std::error_code& ec) + { + T m; + basic_staj_object_iterator end; + basic_staj_object_iterator it(reader, ec); + + while (it != end && !ec) + { + m.emplace(it->first,it->second); + it.increment(ec); + } + return m; + } + + template + static void encode(const T& val, basic_json_content_handler& receiver) + { + receiver.begin_object(); + for (auto it = std::begin(val); it != std::end(val); ++it) + { + receiver.name(it->first); + json_conversion_traits::template encode(it->second,receiver); + } + receiver.end_object(); + receiver.flush(); + } +}; + +template +void read_from(const Json&, basic_staj_reader& reader, T& val, std::error_code& ec) +{ + val = json_conversion_traits::template decode(reader,ec); +} + +template +void write_to(const Json&, const T&val, basic_json_content_handler& receiver) +{ + json_conversion_traits::template encode(val, receiver); +} + +} + +#endif + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_cursor.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_cursor.hpp new file mode 100644 index 0000000000..8659eb4911 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_cursor.hpp @@ -0,0 +1,680 @@ +// Copyright 2018 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_CURSOR_HPP +#define JSONCONS_JSON_CURSOR_HPP + +#include // std::allocator +#include +#include +#include +#include +#include +#include // std::basic_istream +#include +#include +#include +#include +#include +#include +#include +#include + +namespace jsoncons { + +template +class basic_staj_event_handler final : public basic_json_content_handler +{ +public: + using typename basic_json_content_handler::string_view_type; +private: + basic_staj_event event_; +public: + basic_staj_event_handler() + : event_(staj_event_type::null_value) + { + } + + basic_staj_event_handler(staj_event_type event_type) + : event_(event_type) + { + } + + const basic_staj_event& event() const + { + return event_; + } +private: + + bool do_begin_object(semantic_tag, const ser_context&) override + { + event_ = basic_staj_event(staj_event_type::begin_object); + return false; + } + + bool do_end_object(const ser_context&) override + { + event_ = basic_staj_event(staj_event_type::end_object); + return false; + } + + bool do_begin_array(semantic_tag, const ser_context&) override + { + event_ = basic_staj_event(staj_event_type::begin_array); + return false; + } + + bool do_end_array(const ser_context&) override + { + event_ = basic_staj_event(staj_event_type::end_array); + return false; + } + + bool do_name(const string_view_type& name, const ser_context&) override + { + event_ = basic_staj_event(name.data(), name.length(), staj_event_type::name); + return false; + } + + bool do_null_value(semantic_tag, const ser_context&) override + { + event_ = basic_staj_event(staj_event_type::null_value); + return false; + } + + bool do_bool_value(bool value, semantic_tag, const ser_context&) override + { + event_ = basic_staj_event(value); + return false; + } + + bool do_string_value(const string_view_type& s, semantic_tag tag, const ser_context&) override + { + event_ = basic_staj_event(s.data(), s.length(), staj_event_type::string_value, tag); + return false; + } + + bool do_byte_string_value(const byte_string_view&, + semantic_tag, + const ser_context&) override + { + JSONCONS_UNREACHABLE(); + } + + bool do_int64_value(int64_t value, + semantic_tag tag, + const ser_context&) override + { + event_ = basic_staj_event(value, tag); + return false; + } + + bool do_uint64_value(uint64_t value, + semantic_tag tag, + const ser_context&) override + { + event_ = basic_staj_event(value, tag); + return false; + } + + bool do_double_value(double value, + semantic_tag tag, + const ser_context&) override + { + event_ = basic_staj_event(value, tag); + return false; + } + + void do_flush() override + { + } +}; + +template,class Allocator=std::allocator> +class basic_json_cursor : public basic_staj_reader, private virtual ser_context +{ +public: + typedef Src source_type; + typedef CharT char_type; + typedef Allocator allocator_type; +private: + static const size_t default_max_buffer_length = 16384; + + basic_staj_event_handler event_handler_; + default_parse_error_handler default_err_handler_; + + default_basic_staj_filter default_filter_; + + typedef typename std::allocator_traits:: template rebind_alloc char_allocator_type; + + basic_json_parser parser_; + basic_staj_filter& filter_; + source_type source_; + std::vector buffer_; + size_t buffer_length_; + bool eof_; + bool begin_; + + // Noncopyable and nonmoveable + basic_json_cursor(const basic_json_cursor&) = delete; + basic_json_cursor& operator=(const basic_json_cursor&) = delete; + +public: + typedef basic_string_view string_view_type; + + // Constructors that throw parse exceptions + template + basic_json_cursor(Source&& source) + : basic_json_cursor(std::forward(source), + default_filter_, + basic_json_options::default_options(), + default_err_handler_) + { + } + + template + basic_json_cursor(Source&& source, + basic_staj_filter& filter) + : basic_json_cursor(std::forward(source), + filter,basic_json_options::default_options(), + default_err_handler_) + { + } + + template + basic_json_cursor(Source&& source, + parse_error_handler& err_handler) + : basic_json_cursor(std::forward(source), + default_filter_, + basic_json_options::default_options(), + err_handler) + { + } + + template + basic_json_cursor(Source&& source, + basic_staj_filter& filter, + parse_error_handler& err_handler) + : basic_json_cursor(std::forward(source), + filter, + basic_json_options::default_options(), + err_handler) + { + } + + template + basic_json_cursor(Source&& source, + const basic_json_decode_options& options) + : basic_json_cursor(std::forward(source), + default_filter_, + options, + default_err_handler_) + { + } + + template + basic_json_cursor(Source&& source, + basic_staj_filter& filter, + const basic_json_decode_options& options) + : basic_json_cursor(std::forward(source), + filter, + options, + default_err_handler_) + { + } + + template + basic_json_cursor(Source&& source, + basic_staj_filter& filter, + const basic_json_decode_options& options, + parse_error_handler& err_handler, + typename std::enable_if,Source>::value>::type* = 0) + : parser_(options,err_handler), + filter_(filter), + source_(source), + buffer_length_(default_max_buffer_length), + eof_(false), + begin_(true) + { + buffer_.reserve(buffer_length_); + if (!done()) + { + next(); + } + } + + template + basic_json_cursor(Source&& source, + basic_staj_filter& filter, + const basic_json_decode_options& options, + parse_error_handler& err_handler, + typename std::enable_if,Source>::value>::type* = 0) + : parser_(options,err_handler), + filter_(filter), + buffer_length_(0), + eof_(false), + begin_(false) + { + basic_string_view sv(std::forward(source)); + auto result = unicons::skip_bom(sv.begin(), sv.end()); + if (result.ec != unicons::encoding_errc()) + { + throw ser_error(result.ec,parser_.line(),parser_.column()); + } + size_t offset = result.it - sv.begin(); + parser_.update(sv.data()+offset,sv.size()-offset); + if (!done()) + { + next(); + } + } + + // Constructors that set parse error codes + template + basic_json_cursor(Source&& source, + std::error_code& ec) + : basic_json_cursor(std::forward(source),default_filter_,basic_json_options::default_options(),default_err_handler_,ec) + { + } + + template + basic_json_cursor(Source&& source, + basic_staj_filter& filter, + std::error_code& ec) + : basic_json_cursor(std::forward(source), + filter, + basic_json_options::default_options(), + default_err_handler_, + ec) + { + } + + template + basic_json_cursor(Source&& source, + parse_error_handler& err_handler, + std::error_code& ec) + : basic_json_cursor(std::forward(source), + default_filter_, + basic_json_options::default_options(), + err_handler, + ec) + { + } + + template + basic_json_cursor(Source&& source, + basic_staj_filter& filter, + parse_error_handler& err_handler, + std::error_code& ec) + : basic_json_cursor(std::forward(source), + filter, + basic_json_options::default_options(), + err_handler, + ec) + { + } + + template + basic_json_cursor(Source&& source, + const basic_json_decode_options& options, + std::error_code& ec) + : basic_json_cursor(std::forward(source), + default_filter_, + options, + default_err_handler_, + ec) + { + } + + template + basic_json_cursor(Source&& source, + basic_staj_filter& filter, + const basic_json_decode_options& options, + std::error_code& ec) + : basic_json_cursor(std::forward(source), + filter,options, + default_err_handler_, + ec) + { + } + + template + basic_json_cursor(Source&& source, + basic_staj_filter& filter, + const basic_json_decode_options& options, + parse_error_handler& err_handler, + std::error_code& ec, + typename std::enable_if,Source>::value>::type* = 0) + : parser_(options,err_handler), + filter_(filter), + source_(source), + eof_(false), + buffer_length_(default_max_buffer_length), + begin_(true) + { + buffer_.reserve(buffer_length_); + if (!done()) + { + next(ec); + } + } + + template + basic_json_cursor(Source&& source, + basic_staj_filter& filter, + const basic_json_decode_options& options, + parse_error_handler& err_handler, + std::error_code& ec, + typename std::enable_if,Source>::value>::type* = 0) + : parser_(options,err_handler), + filter_(filter), + eof_(false), + buffer_length_(0), + begin_(false) + { + basic_string_view sv(std::forward(source)); + auto result = unicons::skip_bom(sv.begin(), sv.end()); + if (result.ec != unicons::encoding_errc()) + { + ec = result.ec; + return; + } + size_t offset = result.it - sv.begin(); + parser_.update(sv.data()+offset,sv.size()-offset); + if (!done()) + { + next(ec); + } + } + + size_t buffer_length() const + { + return buffer_length_; + } + + void buffer_length(size_t length) + { + buffer_length_ = length; + buffer_.reserve(buffer_length_); + } + + bool done() const override + { + return parser_.done(); + } + + const basic_staj_event& current() const override + { + return event_handler_.event(); + } + + void accept(basic_json_content_handler& handler) override + { + std::error_code ec; + accept(handler, ec); + if (ec) + { + throw ser_error(ec,parser_.line(),parser_.column()); + } + } + + void accept(basic_json_content_handler& handler, + std::error_code& ec) override + { + switch (event_handler_.event().event_type()) + { + case staj_event_type::begin_array: + if (!handler.begin_array(semantic_tag::none, *this)) + { + return; + } + break; + case staj_event_type::end_array: + if (!handler.end_array(*this)) + { + return; + } + break; + case staj_event_type::begin_object: + if (!handler.begin_object(semantic_tag::none, *this)) + { + return; + } + break; + case staj_event_type::end_object: + if (!handler.end_object(*this)) + { + return; + } + break; + case staj_event_type::name: + if (!handler.name(event_handler_.event().template as>(), *this)) + { + return; + } + break; + case staj_event_type::string_value: + if (!handler.string_value(event_handler_.event().template as>(), semantic_tag::none, *this)) + { + return; + } + break; + case staj_event_type::null_value: + if (!handler.null_value(semantic_tag::none, *this)) + { + return; + } + break; + case staj_event_type::bool_value: + if (!handler.bool_value(event_handler_.event().template as(), semantic_tag::none, *this)) + { + return; + } + break; + case staj_event_type::int64_value: + if (!handler.int64_value(event_handler_.event().template as(), semantic_tag::none, *this)) + { + return; + } + break; + case staj_event_type::uint64_value: + if (!handler.uint64_value(event_handler_.event().template as(), semantic_tag::none, *this)) + { + return; + } + break; + case staj_event_type::double_value: + if (!handler.double_value(event_handler_.event().template as(), semantic_tag::none, *this)) + { + return; + } + break; + default: + break; + } + do + { + read_next(handler, ec); + } + while (!ec && !done() && !filter_.accept(event_handler_.event(), *this)); + } + + void next() override + { + std::error_code ec; + next(ec); + if (ec) + { + throw ser_error(ec,parser_.line(),parser_.column()); + } + } + + void next(std::error_code& ec) override + { + do + { + read_next(ec); + } + while (!ec && !done() && !filter_.accept(event_handler_.event(), *this)); + } + + void read_buffer(std::error_code& ec) + { + buffer_.clear(); + buffer_.resize(buffer_length_); + size_t count = source_.read(buffer_.data(), buffer_length_); + buffer_.resize(static_cast(count)); + if (buffer_.size() == 0) + { + eof_ = true; + } + else if (begin_) + { + auto result = unicons::skip_bom(buffer_.begin(), buffer_.end()); + if (result.ec != unicons::encoding_errc()) + { + ec = result.ec; + return; + } + size_t offset = result.it - buffer_.begin(); + parser_.update(buffer_.data()+offset,buffer_.size()-offset); + begin_ = false; + } + else + { + parser_.update(buffer_.data(),buffer_.size()); + } + } + + void read_next(std::error_code& ec) + { + read_next(event_handler_, ec); + } + + void read_next(basic_json_content_handler& handler, std::error_code& ec) + { + parser_.restart(); + while (!parser_.stopped()) + { + if (parser_.source_exhausted()) + { + if (!source_.eof()) + { + read_buffer(ec); + if (ec) return; + } + else + { + eof_ = true; + } + } + parser_.parse_some(handler, ec); + if (ec) return; + } + } + + void check_done() + { + std::error_code ec; + check_done(ec); + if (ec) + { + throw ser_error(ec,parser_.line(),parser_.column()); + } + } + + const ser_context& context() const override + { + return *this; + } + + void check_done(std::error_code& ec) + { + try + { + if (source_.is_error()) + { + ec = json_errc::source_error; + return; + } + if (eof_) + { + parser_.check_done(ec); + if (ec) return; + } + else + { + while (!eof_) + { + if (parser_.source_exhausted()) + { + if (!source_.eof()) + { + read_buffer(ec); + if (ec) return; + } + else + { + eof_ = true; + } + } + if (!eof_) + { + parser_.check_done(ec); + if (ec) return; + } + } + } + } + catch (const ser_error& e) + { + ec = e.code(); + } + } + + bool eof() const + { + return eof_; + } + + size_t line() const override + { + return parser_.line(); + } + + size_t column() const override + { + return parser_.column(); + } +private: +}; + +typedef basic_json_cursor json_cursor; +typedef basic_json_cursor wjson_cursor; + +#if !defined(JSONCONS_NO_DEPRECATED) +template> +using basic_json_pull_reader = basic_json_cursor; +typedef basic_json_cursor json_pull_reader; +typedef basic_json_cursor wjson_pull_reader; + +template> +using basic_json_stream_reader = basic_json_cursor; + +template> +using basic_json_staj_reader = basic_json_cursor; + +typedef basic_json_cursor json_stream_reader; +typedef basic_json_cursor wjson_stream_reader; + +typedef basic_json_cursor json_staj_reader; +typedef basic_json_cursor wjson_staj_reader; +#endif + +} + +#endif + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_decoder.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_decoder.hpp new file mode 100644 index 0000000000..653d48addc --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_decoder.hpp @@ -0,0 +1,357 @@ +// Copyright 2013-2016 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_DECODER_HPP +#define JSONCONS_JSON_DECODER_HPP + +#include +#include +#include // std::true_type +#include // std::allocator +#include // std::make_move_iterator +#include // std::move +#include +#include + +namespace jsoncons { + +template > +class json_decoder final : public basic_json_content_handler +{ +public: + typedef typename Json::char_type char_type; + using typename basic_json_content_handler::string_view_type; + + typedef typename Json::key_value_type key_value_type; + typedef typename Json::string_type string_type; + typedef typename Json::array array; + typedef typename Json::object object; + typedef typename Json::allocator_type json_allocator_type; + typedef typename string_type::allocator_type json_string_allocator; + typedef typename array::allocator_type json_array_allocator; + typedef typename object::allocator_type json_object_allocator; + typedef typename std::allocator_traits:: template rebind_alloc json_byte_allocator_type; +private: + json_string_allocator string_allocator_; + json_object_allocator object_allocator_; + json_array_allocator array_allocator_; + json_byte_allocator_type byte_allocator_; + + Json result_; + + struct stack_item + { + template + stack_item(std::true_type, Args&& ... args) + : name_(std::forward(args)...) + { + } + template + stack_item(std::false_type, Args&& ... args) + : value_(std::forward(args)...) + { + } + + stack_item() = default; + stack_item(const stack_item&) = default; + stack_item(stack_item&&) = default; + stack_item& operator=(const stack_item&) = default; + stack_item& operator=(stack_item&&) = default; + + string_type name_; + Json value_; + }; + + enum class container_type {root_t, array_t, object_t}; + + struct structure_offset + { + size_t offset_; + container_type type_; + }; + + typedef Allocator allocator_type; + typedef typename std::allocator_traits:: template rebind_alloc stack_item_allocator_type; + typedef typename std::allocator_traits:: template rebind_alloc size_t_allocator_type; + + + std::vector stack_; + std::vector stack_offsets_; + bool is_valid_; + +public: + json_decoder(const json_allocator_type& jallocator = json_allocator_type()) + : string_allocator_(jallocator), + object_allocator_(jallocator), + array_allocator_(jallocator), + is_valid_(false) + + { + stack_.reserve(1000); + stack_offsets_.reserve(100); + stack_offsets_.push_back({0,container_type::root_t}); + } + + bool is_valid() const + { + return is_valid_; + } + + Json get_result() + { + is_valid_ = false; + return std::move(result_); + } + +#if !defined(JSONCONS_NO_DEPRECATED) + Json& root() + { + return result_; + } +#endif + +private: + + void do_flush() override + { + } + + bool do_begin_object(semantic_tag tag, const ser_context&) override + { + switch (stack_offsets_.back().type_) + { + case container_type::object_t: + stack_.back().value_ = Json(object(object_allocator_), tag); + break; + case container_type::array_t: + stack_.emplace_back(std::false_type(), object(object_allocator_), tag); + break; + case container_type::root_t: + stack_.clear(); + is_valid_ = false; + stack_.emplace_back(std::false_type(), object(object_allocator_), tag); + break; + } + stack_offsets_.push_back({stack_.size()-1,container_type::object_t}); + return true; + } + + bool do_end_object(const ser_context&) override + { + JSONCONS_ASSERT(stack_offsets_.size() > 0); + JSONCONS_ASSERT(stack_offsets_.back().type_ == container_type::object_t); + const size_t structure_index = stack_offsets_.back().offset_; + JSONCONS_ASSERT(stack_.size() > structure_index); + const size_t count = stack_.size() - (structure_index + 1); + auto first = stack_.begin() + (structure_index+1); + auto last = first + count; + stack_[structure_index].value_.object_value().insert( + std::make_move_iterator(first), + std::make_move_iterator(last), + [](stack_item&& val){return key_value_type(std::move(val.name_), std::move(val.value_));} + ); + stack_.erase(stack_.begin()+structure_index+1, stack_.end()); + stack_offsets_.pop_back(); + if (stack_offsets_.back().type_ == container_type::root_t) + { + result_.swap(stack_.front().value_); + stack_.pop_back(); + is_valid_ = true; + return false; + } + return true; + } + + bool do_begin_array(semantic_tag tag, const ser_context&) override + { + switch (stack_offsets_.back().type_) + { + case container_type::object_t: + stack_.back().value_ = Json(array(array_allocator_), tag); + break; + case container_type::array_t: + stack_.emplace_back(std::false_type(), array(array_allocator_), tag); + break; + case container_type::root_t: + stack_.clear(); + is_valid_ = false; + stack_.emplace_back(std::false_type(), array(array_allocator_), tag); + break; + } + stack_offsets_.push_back({stack_.size()-1,container_type::array_t}); + return true; + } + + bool do_end_array(const ser_context&) override + { + JSONCONS_ASSERT(stack_offsets_.size() > 0); + JSONCONS_ASSERT(stack_offsets_.back().type_ == container_type::array_t); + const size_t structure_index = stack_offsets_.back().offset_; + JSONCONS_ASSERT(stack_.size() > structure_index); + const size_t count = stack_.size() - (structure_index + 1); + auto first = stack_.begin() + (structure_index+1); + auto last = first + count; + auto& j = stack_[structure_index].value_; + j.reserve(count); + while (first != last) + { + j.push_back(std::move(first->value_)); + ++first; + } + stack_.erase(stack_.begin()+structure_index+1, stack_.end()); + stack_offsets_.pop_back(); + if (stack_offsets_.back().type_ == container_type::root_t) + { + result_.swap(stack_.front().value_); + stack_.pop_back(); + is_valid_ = true; + return false; + } + return true; + } + + bool do_name(const string_view_type& name, const ser_context&) override + { + stack_.emplace_back(std::true_type(), name.data(), name.length(), string_allocator_); + return true; + } + + bool do_string_value(const string_view_type& sv, semantic_tag tag, const ser_context&) override + { + switch (stack_offsets_.back().type_) + { + case container_type::object_t: + stack_.back().value_ = Json(sv, tag, string_allocator_); + break; + case container_type::array_t: + stack_.emplace_back(std::false_type(), sv, tag, string_allocator_); + break; + case container_type::root_t: + result_ = Json(sv, tag, string_allocator_); + is_valid_ = true; + return false; + } + return true; + } + + bool do_byte_string_value(const byte_string_view& b, semantic_tag tag, const ser_context&) override + { + switch (stack_offsets_.back().type_) + { + case container_type::object_t: + stack_.back().value_ = Json(b, tag, byte_allocator_); + break; + case container_type::array_t: + stack_.emplace_back(std::false_type(), b, tag, byte_allocator_); + break; + case container_type::root_t: + result_ = Json(b, tag, byte_allocator_); + is_valid_ = true; + return false; + } + return true; + } + + bool do_int64_value(int64_t value, + semantic_tag tag, + const ser_context&) override + { + switch (stack_offsets_.back().type_) + { + case container_type::object_t: + stack_.back().value_ = Json(value,tag); + break; + case container_type::array_t: + stack_.emplace_back(std::false_type(), value, tag); + break; + case container_type::root_t: + result_ = Json(value,tag); + is_valid_ = true; + return false; + } + return true; + } + + bool do_uint64_value(uint64_t value, + semantic_tag tag, + const ser_context&) override + { + switch (stack_offsets_.back().type_) + { + case container_type::object_t: + stack_.back().value_ = Json(value,tag); + break; + case container_type::array_t: + stack_.emplace_back(std::false_type(), value, tag); + break; + case container_type::root_t: + result_ = Json(value,tag); + is_valid_ = true; + return false; + } + return true; + } + + bool do_double_value(double value, + semantic_tag tag, + const ser_context&) override + { + switch (stack_offsets_.back().type_) + { + case container_type::object_t: + stack_.back().value_ = Json(value, tag); + break; + case container_type::array_t: + stack_.emplace_back(std::false_type(), value, tag); + break; + case container_type::root_t: + result_ = Json(value, tag); + is_valid_ = true; + return false; + } + return true; + } + + bool do_bool_value(bool value, semantic_tag tag, const ser_context&) override + { + switch (stack_offsets_.back().type_) + { + case container_type::object_t: + stack_.back().value_ = Json(value, tag); + break; + case container_type::array_t: + stack_.emplace_back(std::false_type(), value, tag); + break; + case container_type::root_t: + result_ = Json(value, tag); + is_valid_ = true; + return false; + } + return true; + } + + bool do_null_value(semantic_tag tag, const ser_context&) override + { + switch (stack_offsets_.back().type_) + { + case container_type::object_t: + stack_.back().value_ = Json(null_type(),tag); + break; + case container_type::array_t: + stack_.emplace_back(std::false_type(), null_type(), tag); + break; + case container_type::root_t: + result_ = Json(null_type(), tag); + is_valid_ = true; + return false; + } + return true; + } +}; + +} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_encoder.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_encoder.hpp new file mode 100644 index 0000000000..356348c15a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_encoder.hpp @@ -0,0 +1,1470 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_ENCODER_HPP +#define JSONCONS_JSON_ENCODER_HPP + +#include // std::array +#include +#include +#include // std::isfinite, std::isnan +#include // std::numeric_limits +#include +#include // std::move +#include +#include +#include +#include +#include +#include +#include +#include + +namespace jsoncons { namespace detail { +template +size_t escape_string(const CharT* s, size_t length, + bool escape_all_non_ascii, bool escape_solidus, + Result& result) +{ + size_t count = 0; + const CharT* begin = s; + const CharT* end = s + length; + for (const CharT* it = begin; it != end; ++it) + { + CharT c = *it; + switch (c) + { + case '\\': + result.push_back('\\'); + result.push_back('\\'); + count += 2; + break; + case '"': + result.push_back('\\'); + result.push_back('\"'); + count += 2; + break; + case '\b': + result.push_back('\\'); + result.push_back('b'); + count += 2; + break; + case '\f': + result.push_back('\\'); + result.push_back('f'); + count += 2; + break; + case '\n': + result.push_back('\\'); + result.push_back('n'); + count += 2; + break; + case '\r': + result.push_back('\\'); + result.push_back('r'); + count += 2; + break; + case '\t': + result.push_back('\\'); + result.push_back('t'); + count += 2; + break; + default: + if (escape_solidus && c == '/') + { + result.push_back('\\'); + result.push_back('/'); + count += 2; + } + else if (is_control_character(c) || escape_all_non_ascii) + { + // convert utf8 to codepoint + unicons::sequence_generator g(it, end, unicons::conv_flags::strict); + if (g.done() || g.status() != unicons::conv_errc()) + { + throw ser_error(json_errc::illegal_codepoint); + } + uint32_t cp = g.get().codepoint(); + it += (g.get().length() - 1); + if (is_non_ascii_codepoint(cp) || is_control_character(c)) + { + if (cp > 0xFFFF) + { + cp -= 0x10000; + uint32_t first = (cp >> 10) + 0xD800; + uint32_t second = ((cp & 0x03FF) + 0xDC00); + + result.push_back('\\'); + result.push_back('u'); + result.push_back(to_hex_character(first >> 12 & 0x000F)); + result.push_back(to_hex_character(first >> 8 & 0x000F)); + result.push_back(to_hex_character(first >> 4 & 0x000F)); + result.push_back(to_hex_character(first & 0x000F)); + result.push_back('\\'); + result.push_back('u'); + result.push_back(to_hex_character(second >> 12 & 0x000F)); + result.push_back(to_hex_character(second >> 8 & 0x000F)); + result.push_back(to_hex_character(second >> 4 & 0x000F)); + result.push_back(to_hex_character(second & 0x000F)); + count += 12; + } + else + { + result.push_back('\\'); + result.push_back('u'); + result.push_back(to_hex_character(cp >> 12 & 0x000F)); + result.push_back(to_hex_character(cp >> 8 & 0x000F)); + result.push_back(to_hex_character(cp >> 4 & 0x000F)); + result.push_back(to_hex_character(cp & 0x000F)); + count += 6; + } + } + else + { + result.push_back(c); + ++count; + } + } + else + { + result.push_back(c); + ++count; + } + break; + } + } + return count; +} + +inline +byte_string_chars_format resolve_byte_string_chars_format(byte_string_chars_format format1, + byte_string_chars_format format2, + byte_string_chars_format default_format = byte_string_chars_format::base64url) +{ + byte_string_chars_format result; + switch (format1) + { + case byte_string_chars_format::base16: + case byte_string_chars_format::base64: + case byte_string_chars_format::base64url: + result = format1; + break; + default: + switch (format2) + { + case byte_string_chars_format::base64url: + case byte_string_chars_format::base64: + case byte_string_chars_format::base16: + result = format2; + break; + default: // base64url + { + result = default_format; + break; + } + } + break; + } + return result; +} + +}} + +namespace jsoncons { + +template> +class basic_json_encoder final : public basic_json_content_handler +{ + static const std::array& null_k() + { + static constexpr std::array k{'n','u','l','l'}; + return k; + } + static const std::array& true_k() + { + static constexpr std::array k{'t','r','u','e'}; + return k; + } + static const std::array& false_k() + { + static constexpr std::array k{'f','a','l','s','e'}; + return k; + } +public: + typedef CharT char_type; + using typename basic_json_content_handler::string_view_type; + typedef Result result_type; + typedef typename basic_json_options::string_type string_type; + +private: + enum class container_type {object, array}; + + class encoding_context + { + container_type type_; + size_t count_; + line_split_kind line_splits_; + bool indent_before_; + bool new_line_after_; + size_t begin_pos_; + size_t data_pos_; + public: + encoding_context(container_type type, line_split_kind split_lines, bool indent_once, + size_t begin_pos, size_t data_pos) + : type_(type), count_(0), line_splits_(split_lines), indent_before_(indent_once), new_line_after_(false), + begin_pos_(begin_pos), data_pos_(data_pos) + { + } + + void set_position(size_t pos) + { + data_pos_ = pos; + } + + size_t begin_pos() const + { + return begin_pos_; + } + + size_t data_pos() const + { + return data_pos_; + } + + size_t count() const + { + return count_; + } + + void increment_count() + { + ++count_; + } + + bool new_line_after() const + { + return new_line_after_; + } + + void new_line_after(bool value) + { + new_line_after_ = value; + } + + bool is_object() const + { + return type_ == container_type::object; + } + + bool is_array() const + { + return type_ == container_type::array; + } + + bool is_same_line() const + { + return line_splits_ == line_split_kind::same_line; + } + + bool is_new_line() const + { + return line_splits_ == line_split_kind::new_line; + } + + bool is_multi_line() const + { + return line_splits_ == line_split_kind::multi_line; + } + + bool is_indent_once() const + { + return count_ == 0 ? indent_before_ : false; + } + + }; + + size_t indent_size_; + + const basic_json_encode_options& options_; + + jsoncons::detail::print_double fp_; + + Result result_; + + std::vector stack_; + int indent_amount_; + size_t column_; + std::basic_string colon_str_; + std::basic_string comma_str_; + std::basic_string open_object_brace_str_; + std::basic_string close_object_brace_str_; + std::basic_string open_array_bracket_str_; + std::basic_string close_array_bracket_str_; + + // Noncopyable and nonmoveable + basic_json_encoder(const basic_json_encoder&) = delete; + basic_json_encoder& operator=(const basic_json_encoder&) = delete; +public: + basic_json_encoder(result_type result) + : basic_json_encoder(std::move(result), basic_json_options::default_options()) + { + } + + basic_json_encoder(result_type result, + const basic_json_encode_options& options) + : options_(options), + fp_(floating_point_options(options.floating_point_format(), + options.precision(), + 0)), + result_(std::move(result)), + indent_amount_(0), + column_(0) + { + switch (options.spaces_around_colon()) + { + case spaces_option::space_after: + colon_str_ = std::basic_string({':',' '}); + break; + case spaces_option::space_before: + colon_str_ = std::basic_string({' ',':'}); + break; + case spaces_option::space_before_and_after: + colon_str_ = std::basic_string({' ',':',' '}); + break; + default: + colon_str_.push_back(':'); + break; + } + switch (options.spaces_around_comma()) + { + case spaces_option::space_after: + comma_str_ = std::basic_string({',',' '}); + break; + case spaces_option::space_before: + comma_str_ = std::basic_string({' ',','}); + break; + case spaces_option::space_before_and_after: + comma_str_ = std::basic_string({' ',',',' '}); + break; + default: + comma_str_.push_back(','); + break; + } + if (options.pad_inside_object_braces()) + { + open_object_brace_str_ = std::basic_string({'{', ' '}); + close_object_brace_str_ = std::basic_string({' ', '}'}); + } + else + { + open_object_brace_str_.push_back('{'); + close_object_brace_str_.push_back('}'); + } + if (options.pad_inside_array_brackets()) + { + open_array_bracket_str_ = std::basic_string({'[', ' '}); + close_array_bracket_str_ = std::basic_string({' ', ']'}); + } + else + { + open_array_bracket_str_.push_back('['); + close_array_bracket_str_.push_back(']'); + } + } + + ~basic_json_encoder() + { + try + { + result_.flush(); + } + catch (...) + { + } + } + +private: + // Implementing methods + void do_flush() override + { + result_.flush(); + } + + bool do_begin_object(semantic_tag, const ser_context&) override + { + if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0) + { + result_.append(comma_str_.data(),comma_str_.length()); + column_ += comma_str_.length(); + } + + if (!stack_.empty()) // object or array + { + if (stack_.back().is_object()) + { + switch (options_.object_object_line_splits()) + { + case line_split_kind::same_line: + if (column_ >= options_.line_length_limit()) + { + break_line(); + } + break; + case line_split_kind::new_line: + if (column_ >= options_.line_length_limit()) + { + break_line(); + } + break; + default: // multi_line + break; + } + stack_.emplace_back(container_type::object,options_.object_object_line_splits(), false, + column_, column_+open_object_brace_str_.length()); + } + else // array + { + switch (options_.array_object_line_splits()) + { + case line_split_kind::same_line: + if (column_ >= options_.line_length_limit()) + { + //stack_.back().new_line_after(true); + new_line(); + } + break; + case line_split_kind::new_line: + stack_.back().new_line_after(true); + new_line(); + break; + default: // multi_line + stack_.back().new_line_after(true); + new_line(); + break; + } + stack_.emplace_back(container_type::object,options_.array_object_line_splits(), false, + column_, column_+open_object_brace_str_.length()); + } + } + else + { + stack_.emplace_back(container_type::object, line_split_kind::multi_line, false, + column_, column_+open_object_brace_str_.length()); + } + indent(); + + result_.append(open_object_brace_str_.data(), open_object_brace_str_.length()); + column_ += open_object_brace_str_.length(); + return true; + } + + bool do_end_object(const ser_context&) override + { + JSONCONS_ASSERT(!stack_.empty()); + unindent(); + if (stack_.back().new_line_after()) + { + new_line(); + } + stack_.pop_back(); + result_.append(close_object_brace_str_.data(), close_object_brace_str_.length()); + column_ += close_object_brace_str_.length(); + + end_value(); + return true; + } + + bool do_begin_array(semantic_tag, const ser_context&) override + { + if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0) + { + result_.append(comma_str_.data(),comma_str_.length()); + column_ += comma_str_.length(); + } + if (!stack_.empty()) + { + if (stack_.back().is_object()) + { + switch (options_.object_array_line_splits()) + { + case line_split_kind::same_line: + stack_.emplace_back(container_type::array,options_.object_array_line_splits(),false, + column_, column_ + open_array_bracket_str_.length()); + break; + case line_split_kind::new_line: + { + stack_.emplace_back(container_type::array,options_.object_array_line_splits(),true, + column_, column_+open_array_bracket_str_.length()); + break; + } + default: // multi_line + stack_.emplace_back(container_type::array,options_.object_array_line_splits(),true, + column_, column_+open_array_bracket_str_.length()); + break; + } + } + else // array + { + switch (options_.array_array_line_splits()) + { + case line_split_kind::same_line: + if (stack_.back().is_multi_line()) + { + stack_.back().new_line_after(true); + new_line(); + } + stack_.emplace_back(container_type::array,options_.array_array_line_splits(), false, + column_, column_+open_array_bracket_str_.length()); + break; + case line_split_kind::new_line: + stack_.back().new_line_after(true); + new_line(); + stack_.emplace_back(container_type::array,options_.array_array_line_splits(), false, + column_, column_+open_array_bracket_str_.length()); + break; + default: // multi_line + stack_.back().new_line_after(true); + new_line(); + stack_.emplace_back(container_type::array,options_.array_array_line_splits(), false, + column_, column_+open_array_bracket_str_.length()); + //new_line(); + break; + } + } + } + else + { + stack_.emplace_back(container_type::array, line_split_kind::multi_line, false, + column_, column_+open_array_bracket_str_.length()); + } + indent(); + result_.append(open_array_bracket_str_.data(), open_array_bracket_str_.length()); + column_ += open_array_bracket_str_.length(); + return true; + } + + bool do_end_array(const ser_context&) override + { + JSONCONS_ASSERT(!stack_.empty()); + unindent(); + if (stack_.back().new_line_after()) + { + new_line(); + } + stack_.pop_back(); + result_.append(close_array_bracket_str_.data(), close_array_bracket_str_.length()); + column_ += close_array_bracket_str_.length(); + end_value(); + return true; + } + + bool do_name(const string_view_type& name, const ser_context&) override + { + JSONCONS_ASSERT(!stack_.empty()); + if (stack_.back().count() > 0) + { + result_.append(comma_str_.data(),comma_str_.length()); + column_ += comma_str_.length(); + } + + if (stack_.back().is_multi_line()) + { + stack_.back().new_line_after(true); + new_line(); + } + else if (stack_.back().count() > 0 && column_ >= options_.line_length_limit()) + { + //stack_.back().new_line_after(true); + new_line(stack_.back().data_pos()); + } + + if (stack_.back().count() == 0) + { + stack_.back().set_position(column_); + } + result_.push_back('\"'); + size_t length = jsoncons::detail::escape_string(name.data(), name.length(),options_.escape_all_non_ascii(),options_.escape_solidus(),result_); + result_.push_back('\"'); + result_.append(colon_str_.data(),colon_str_.length()); + column_ += (length+2+colon_str_.length()); + return true; + } + + bool do_null_value(semantic_tag, const ser_context&) override + { + if (!stack_.empty()) + { + if (stack_.back().is_array()) + { + begin_scalar_value(); + } + if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit()) + { + break_line(); + } + } + + result_.append(null_k().data(), null_k().size()); + column_ += null_k().size(); + + end_value(); + return true; + } + + bool do_string_value(const string_view_type& sv, semantic_tag tag, const ser_context&) override + { + if (!stack_.empty()) + { + if (stack_.back().is_array()) + { + begin_scalar_value(); + } + if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit()) + { + break_line(); + } + } + + switch (tag) + { + case semantic_tag::bigint: + write_bigint_value(sv); + break; + default: + { + result_.push_back('\"'); + size_t length = jsoncons::detail::escape_string(sv.data(), sv.length(),options_.escape_all_non_ascii(),options_.escape_solidus(),result_); + result_.push_back('\"'); + column_ += (length+2); + break; + } + } + + end_value(); + return true; + } + + bool do_byte_string_value(const byte_string_view& b, + semantic_tag tag, + const ser_context&) override + { + if (!stack_.empty()) + { + if (stack_.back().is_array()) + { + begin_scalar_value(); + } + if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit()) + { + break_line(); + } + } + + byte_string_chars_format encoding_hint; + switch (tag) + { + case semantic_tag::base16: + encoding_hint = byte_string_chars_format::base16; + break; + case semantic_tag::base64: + encoding_hint = byte_string_chars_format::base64; + break; + case semantic_tag::base64url: + encoding_hint = byte_string_chars_format::base64url; + break; + default: + encoding_hint = byte_string_chars_format::none; + break; + } + + byte_string_chars_format format = jsoncons::detail::resolve_byte_string_chars_format(options_.byte_string_format(), + encoding_hint, + byte_string_chars_format::base64url); + switch (format) + { + case byte_string_chars_format::base16: + { + result_.push_back('\"'); + size_t length = encode_base16(b.begin(),b.end(),result_); + result_.push_back('\"'); + column_ += (length + 2); + break; + } + case byte_string_chars_format::base64: + { + result_.push_back('\"'); + size_t length = encode_base64(b.begin(), b.end(), result_); + result_.push_back('\"'); + column_ += (length + 2); + break; + } + case byte_string_chars_format::base64url: + { + result_.push_back('\"'); + size_t length = encode_base64url(b.begin(),b.end(),result_); + result_.push_back('\"'); + column_ += (length + 2); + break; + } + default: + { + JSONCONS_UNREACHABLE(); + } + } + + end_value(); + return true; + } + + bool do_double_value(double value, + semantic_tag, + const ser_context& context) override + { + if (!stack_.empty()) + { + if (stack_.back().is_array()) + { + begin_scalar_value(); + } + if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit()) + { + break_line(); + } + } + + if (!std::isfinite(value)) + { + if ((std::isnan)(value)) + { + if (options_.is_nan_to_num()) + { + result_.append(options_.nan_to_num().data(), options_.nan_to_num().length()); + column_ += options_.nan_to_num().length(); + } + else if (options_.is_nan_to_str()) + { + do_string_value(options_.nan_to_str(), semantic_tag::none, context); + } + else + { + result_.append(null_k().data(), null_k().size()); + column_ += null_k().size(); + } + } + else if (value == std::numeric_limits::infinity()) + { + if (options_.is_inf_to_num()) + { + result_.append(options_.inf_to_num().data(), options_.inf_to_num().length()); + column_ += options_.inf_to_num().length(); + } + else if (options_.is_inf_to_str()) + { + do_string_value(options_.inf_to_str(), semantic_tag::none, context); + } + else + { + result_.append(null_k().data(), null_k().size()); + column_ += null_k().size(); + } + } + else + { + if (options_.is_neginf_to_num()) + { + result_.append(options_.neginf_to_num().data(), options_.neginf_to_num().length()); + column_ += options_.neginf_to_num().length(); + } + else if (options_.is_neginf_to_str()) + { + do_string_value(options_.neginf_to_str(), semantic_tag::none, context); + } + else + { + result_.append(null_k().data(), null_k().size()); + column_ += null_k().size(); + } + } + } + else + { + size_t length = fp_(value, result_); + column_ += length; + } + + end_value(); + return true; + } + + bool do_int64_value(int64_t value, + semantic_tag, + const ser_context&) override + { + if (!stack_.empty()) + { + if (stack_.back().is_array()) + { + begin_scalar_value(); + } + if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit()) + { + break_line(); + } + } + size_t length = jsoncons::detail::print_integer(value, result_); + column_ += length; + end_value(); + return true; + } + + bool do_uint64_value(uint64_t value, + semantic_tag, + const ser_context&) override + { + if (!stack_.empty()) + { + if (stack_.back().is_array()) + { + begin_scalar_value(); + } + if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit()) + { + break_line(); + } + } + size_t length = jsoncons::detail::print_uinteger(value, result_); + column_ += length; + end_value(); + return true; + } + + bool do_bool_value(bool value, semantic_tag, const ser_context&) override + { + if (!stack_.empty()) + { + if (stack_.back().is_array()) + { + begin_scalar_value(); + } + if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit()) + { + break_line(); + } + } + + if (value) + { + result_.append(true_k().data(), true_k().size()); + column_ += true_k().size(); + } + else + { + result_.append(false_k().data(), false_k().size()); + column_ += false_k().size(); + } + + end_value(); + return true; + } + + void begin_scalar_value() + { + if (!stack_.empty()) + { + if (stack_.back().count() > 0) + { + result_.append(comma_str_.data(),comma_str_.length()); + column_ += comma_str_.length(); + } + if (stack_.back().is_multi_line() || stack_.back().is_indent_once()) + { + stack_.back().new_line_after(true); + new_line(); + } + } + } + + void write_bigint_value(const string_view_type& sv) + { + switch (options_.bigint_format()) + { + case bigint_chars_format::number: + { + result_.append(sv.data(),sv.size()); + column_ += sv.size(); + break; + } + case bigint_chars_format::base64: + { + bignum n(sv.data(), sv.length()); + int signum; + std::vector v; + n.dump(signum, v); + + result_.push_back('\"'); + if (signum == -1) + { + result_.push_back('~'); + ++column_; + } + size_t length = encode_base64(v.begin(), v.end(), result_); + result_.push_back('\"'); + column_ += (length+2); + break; + } + case bigint_chars_format::base64url: + { + bignum n(sv.data(), sv.length()); + int signum; + std::vector v; + n.dump(signum, v); + + result_.push_back('\"'); + if (signum == -1) + { + result_.push_back('~'); + ++column_; + } + size_t length = encode_base64url(v.begin(), v.end(), result_); + result_.push_back('\"'); + column_ += (length+2); + break; + } + default: + { + result_.push_back('\"'); + result_.append(sv.data(),sv.size()); + result_.push_back('\"'); + column_ += (sv.size() + 2); + break; + } + } + } + + void end_value() + { + if (!stack_.empty()) + { + stack_.back().increment_count(); + } + } + + void indent() + { + indent_amount_ += static_cast(options_.indent_size()); + } + + void unindent() + { + indent_amount_ -= static_cast(options_.indent_size()); + } + + void new_line() + { + result_.append(options_.new_line_chars().data(),options_.new_line_chars().length()); + for (int i = 0; i < indent_amount_; ++i) + { + result_.push_back(' '); + } + column_ = indent_amount_; + } + + void new_line(size_t len) + { + result_.append(options_.new_line_chars().data(),options_.new_line_chars().length()); + for (size_t i = 0; i < len; ++i) + { + result_.push_back(' '); + } + column_ = len; + } + + void break_line() + { + stack_.back().new_line_after(true); + new_line(); + } +}; + +template> +class basic_json_compressed_encoder final : public basic_json_content_handler +{ + static const std::array& null_k() + { + static constexpr std::array k{'n','u','l','l'}; + return k; + } + static const std::array& true_k() + { + static constexpr std::array k{'t','r','u','e'}; + return k; + } + static const std::array& false_k() + { + static constexpr std::array k{'f','a','l','s','e'}; + return k; + } +public: + typedef CharT char_type; + using typename basic_json_content_handler::string_view_type; + typedef Result result_type; + typedef typename basic_json_options::string_type string_type; + +private: + enum class container_type {object, array}; + + class encoding_context + { + container_type type_; + size_t count_; + public: + encoding_context(container_type type) + : type_(type), count_(0) + { + } + + size_t count() const + { + return count_; + } + + void increment_count() + { + ++count_; + } + + bool is_array() const + { + return type_ == container_type::array; + } + }; + + const basic_json_encode_options& options_; + + std::vector stack_; + jsoncons::detail::print_double fp_; + Result result_; + + // Noncopyable and nonmoveable + basic_json_compressed_encoder(const basic_json_compressed_encoder&) = delete; + basic_json_compressed_encoder& operator=(const basic_json_compressed_encoder&) = delete; +public: + basic_json_compressed_encoder(result_type result) + : basic_json_compressed_encoder(std::move(result), basic_json_options::default_options()) + { + } + + basic_json_compressed_encoder(result_type result, + const basic_json_encode_options& options) + : options_(options), + fp_(floating_point_options(options.floating_point_format(), + options.precision(), + 0)), + result_(std::move(result)) + { + } + + ~basic_json_compressed_encoder() + { + try + { + result_.flush(); + } + catch (...) + { + } + } + + +private: + // Implementing methods + void do_flush() override + { + result_.flush(); + } + + bool do_begin_object(semantic_tag, const ser_context&) override + { + if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0) + { + result_.push_back(','); + } + + stack_.emplace_back(container_type::object); + result_.push_back('{'); + return true; + } + + bool do_end_object(const ser_context&) override + { + JSONCONS_ASSERT(!stack_.empty()); + stack_.pop_back(); + result_.push_back('}'); + + if (!stack_.empty()) + { + stack_.back().increment_count(); + } + return true; + } + + + bool do_begin_array(semantic_tag, const ser_context&) override + { + if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0) + { + result_.push_back(','); + } + stack_.emplace_back(container_type::array); + result_.push_back('['); + return true; + } + + bool do_end_array(const ser_context&) override + { + JSONCONS_ASSERT(!stack_.empty()); + stack_.pop_back(); + result_.push_back(']'); + if (!stack_.empty()) + { + stack_.back().increment_count(); + } + return true; + } + + bool do_name(const string_view_type& name, const ser_context&) override + { + if (!stack_.empty() && stack_.back().count() > 0) + { + result_.push_back(','); + } + + result_.push_back('\"'); + jsoncons::detail::escape_string(name.data(), name.length(),options_.escape_all_non_ascii(),options_.escape_solidus(),result_); + result_.push_back('\"'); + result_.push_back(':'); + return true; + } + + bool do_null_value(semantic_tag, const ser_context&) override + { + if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0) + { + result_.push_back(','); + } + + result_.append(null_k().data(), null_k().size()); + + if (!stack_.empty()) + { + stack_.back().increment_count(); + } + return true; + } + + void write_bigint_value(const string_view_type& sv) + { + switch (options_.bigint_format()) + { + case bigint_chars_format::number: + { + result_.append(sv.data(),sv.size()); + break; + } + case bigint_chars_format::base64: + { + bignum n(sv.data(), sv.length()); + int signum; + std::vector v; + n.dump(signum, v); + + result_.push_back('\"'); + if (signum == -1) + { + result_.push_back('~'); + } + encode_base64(v.begin(), v.end(), result_); + result_.push_back('\"'); + break; + } + case bigint_chars_format::base64url: + { + bignum n(sv.data(), sv.length()); + int signum; + std::vector v; + n.dump(signum, v); + + result_.push_back('\"'); + if (signum == -1) + { + result_.push_back('~'); + } + encode_base64url(v.begin(), v.end(), result_); + result_.push_back('\"'); + break; + } + default: + { + result_.push_back('\"'); + result_.append(sv.data(),sv.size()); + result_.push_back('\"'); + break; + } + } + } + + bool do_string_value(const string_view_type& sv, semantic_tag tag, const ser_context&) override + { + if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0) + { + result_.push_back(','); + } + + switch (tag) + { + case semantic_tag::bigint: + write_bigint_value(sv); + break; + default: + { + result_.push_back('\"'); + jsoncons::detail::escape_string(sv.data(), sv.length(),options_.escape_all_non_ascii(),options_.escape_solidus(),result_); + result_.push_back('\"'); + break; + } + } + + if (!stack_.empty()) + { + stack_.back().increment_count(); + } + return true; + } + + bool do_byte_string_value(const byte_string_view& b, + semantic_tag tag, + const ser_context&) override + { + if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0) + { + result_.push_back(','); + } + + byte_string_chars_format encoding_hint; + switch (tag) + { + case semantic_tag::base16: + encoding_hint = byte_string_chars_format::base16; + break; + case semantic_tag::base64: + encoding_hint = byte_string_chars_format::base64; + break; + case semantic_tag::base64url: + encoding_hint = byte_string_chars_format::base64url; + break; + default: + encoding_hint = byte_string_chars_format::none; + break; + } + + byte_string_chars_format format = jsoncons::detail::resolve_byte_string_chars_format(options_.byte_string_format(), + encoding_hint, + byte_string_chars_format::base64url); + switch (format) + { + case byte_string_chars_format::base16: + { + result_.push_back('\"'); + encode_base16(b.begin(),b.end(),result_); + result_.push_back('\"'); + break; + } + case byte_string_chars_format::base64: + { + result_.push_back('\"'); + encode_base64(b.begin(), b.end(), result_); + result_.push_back('\"'); + break; + } + case byte_string_chars_format::base64url: + { + result_.push_back('\"'); + encode_base64url(b.begin(),b.end(),result_); + result_.push_back('\"'); + break; + } + default: + { + JSONCONS_UNREACHABLE(); + } + } + + if (!stack_.empty()) + { + stack_.back().increment_count(); + } + return true; + } + + bool do_double_value(double value, + semantic_tag, + const ser_context& context) override + { + if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0) + { + result_.push_back(','); + } + + if (JSONCONS_UNLIKELY(!std::isfinite(value))) + { + if ((std::isnan)(value)) + { + if (options_.is_nan_to_num()) + { + result_.append(options_.nan_to_num().data(), options_.nan_to_num().length()); + } + else if (options_.is_nan_to_str()) + { + do_string_value(options_.nan_to_str(), semantic_tag::none, context); + } + else + { + result_.append(null_k().data(), null_k().size()); + } + } + else if (value == std::numeric_limits::infinity()) + { + if (options_.is_inf_to_num()) + { + result_.append(options_.inf_to_num().data(), options_.inf_to_num().length()); + } + else if (options_.is_inf_to_str()) + { + do_string_value(options_.inf_to_str(), semantic_tag::none, context); + } + else + { + result_.append(null_k().data(), null_k().size()); + } + } + else + { + if (options_.is_neginf_to_num()) + { + result_.append(options_.neginf_to_num().data(), options_.neginf_to_num().length()); + } + else if (options_.is_neginf_to_str()) + { + do_string_value(options_.neginf_to_str(), semantic_tag::none, context); + } + else + { + result_.append(null_k().data(), null_k().size()); + } + } + } + else + { + fp_(value, result_); + } + + if (!stack_.empty()) + { + stack_.back().increment_count(); + } + return true; + } + + bool do_int64_value(int64_t value, + semantic_tag, + const ser_context&) override + { + if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0) + { + result_.push_back(','); + } + jsoncons::detail::print_integer(value, result_); + if (!stack_.empty()) + { + stack_.back().increment_count(); + } + return true; + } + + bool do_uint64_value(uint64_t value, + semantic_tag, + const ser_context&) override + { + if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0) + { + result_.push_back(','); + } + jsoncons::detail::print_uinteger(value, result_); + if (!stack_.empty()) + { + stack_.back().increment_count(); + } + return true; + } + + bool do_bool_value(bool value, semantic_tag, const ser_context&) override + { + if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0) + { + result_.push_back(','); + } + + if (value) + { + result_.append(true_k().data(), true_k().size()); + } + else + { + result_.append(false_k().data(), false_k().size()); + } + + if (!stack_.empty()) + { + stack_.back().increment_count(); + } + return true; + } +}; + +typedef basic_json_encoder> json_encoder; +typedef basic_json_encoder> wjson_encoder; + +typedef basic_json_compressed_encoder> json_compressed_encoder; +typedef basic_json_compressed_encoder> wjson_compressed_encoder; + +typedef basic_json_encoder> json_string_encoder; +typedef basic_json_encoder> wjson_string_encoder; + +typedef basic_json_compressed_encoder> json_compressed_string_encoder; +typedef basic_json_compressed_encoder> wjson_compressed_string_encoder; + +#if !defined(JSONCONS_NO_DEPRECATED) +template> +using basic_json_serializer = basic_json_encoder; + +template> +using basic_json_compressed_serializer = basic_json_compressed_encoder; + +typedef basic_json_serializer> json_serializer; +typedef basic_json_serializer> wjson_encoder; + +typedef basic_json_compressed_serializer> json_compressed_serializer; +typedef basic_json_compressed_serializer> wjson_compressed_serializer; + +typedef basic_json_serializer> json_string_serializer; +typedef basic_json_serializer> wjson_string_serializer; + +typedef basic_json_compressed_serializer> json_compressed_string_serializer; +typedef basic_json_compressed_serializer> wjson_compressed_string_serializer; +#endif + +} +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_error.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_error.hpp new file mode 100644 index 0000000000..90410a41a1 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_error.hpp @@ -0,0 +1,154 @@ +/// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_ERROR_HPP +#define JSONCONS_JSON_ERROR_HPP + +#include +#include + +namespace jsoncons { + + enum class json_errc + { + ok = 0, + unexpected_eof = 1, + source_error, + invalid_json_text, + extra_character, + max_depth_exceeded, + single_quote, + illegal_character_in_string, + extra_comma, + expected_name, + expected_value, + invalid_value, + expected_colon, + illegal_control_character, + illegal_escaped_character, + expected_codepoint_surrogate_pair, + invalid_hex_escape_sequence, + invalid_unicode_escape_sequence, + leading_zero, + invalid_number, + expected_comma_or_right_brace, + expected_comma_or_right_bracket, + unexpected_right_bracket, + unexpected_right_brace, + illegal_comment, + expected_continuation_byte, + over_long_utf8_sequence, + illegal_codepoint, + illegal_surrogate_value, + unpaired_high_surrogate + }; + +class json_error_category_impl + : public std::error_category +{ +public: + const char* name() const noexcept override + { + return "jsoncons/json"; + } + std::string message(int ev) const override + { + switch (static_cast(ev)) + { + case json_errc::unexpected_eof: + return "Unexpected end of file"; + case json_errc::source_error: + return "Source error"; + case json_errc::invalid_json_text: + return "Invalid JSON text"; + case json_errc::extra_character: + return "Unexpected non-whitespace character after JSON text"; + case json_errc::max_depth_exceeded: + return "Maximum JSON depth exceeded"; + case json_errc::single_quote: + return "JSON strings cannot be quoted with single quotes"; + case json_errc::illegal_character_in_string: + return "Illegal character in string"; + case json_errc::extra_comma: + return "Extra comma"; + case json_errc::expected_name: + return "Expected object member name"; + case json_errc::expected_value: + return "Expected value"; + case json_errc::invalid_value: + return "Invalid value"; + case json_errc::expected_colon: + return "Expected name separator ':'"; + case json_errc::illegal_control_character: + return "Illegal control character in string"; + case json_errc::illegal_escaped_character: + return "Illegal escaped character in string"; + case json_errc::expected_codepoint_surrogate_pair: + return "Invalid codepoint, expected another \\u token to begin the second half of a codepoint surrogate pair."; + case json_errc::invalid_hex_escape_sequence: + return "Invalid codepoint, expected hexadecimal digit."; + case json_errc::invalid_unicode_escape_sequence: + return "Invalid codepoint, expected four hexadecimal digits."; + case json_errc::leading_zero: + return "A number cannot have a leading zero"; + case json_errc::invalid_number: + return "Invalid number"; + case json_errc::expected_comma_or_right_brace: + return "Expected comma or right brace '}'"; + case json_errc::expected_comma_or_right_bracket: + return "Expected comma or right bracket ']'"; + case json_errc::unexpected_right_brace: + return "Unexpected right brace '}'"; + case json_errc::unexpected_right_bracket: + return "Unexpected right bracket ']'"; + case json_errc::illegal_comment: + return "Illegal comment"; + case json_errc::expected_continuation_byte: + return "Expected continuation byte"; + case json_errc::over_long_utf8_sequence: + return "Over long UTF-8 sequence"; + case json_errc::illegal_codepoint: + return "Illegal codepoint (>= 0xd800 && <= 0xdfff)"; + case json_errc::illegal_surrogate_value: + return "UTF-16 surrogate values are illegal in UTF-32"; + case json_errc::unpaired_high_surrogate: + return "Expected low surrogate following the high surrogate"; + default: + return "Unknown JSON parser error"; + } + } +}; + +inline +const std::error_category& json_error_category() +{ + static json_error_category_impl instance; + return instance; +} + +inline +std::error_code make_error_code(json_errc result) +{ + return std::error_code(static_cast(result),json_error_category()); +} + +#if !defined(JSONCONS_NO_DEPRECATED) +typedef json_errc json_parser_errc; + +typedef json_errc json_parse_errc; +#endif + + +} + +namespace std { + template<> + struct is_error_code_enum : public true_type + { + }; +} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_exception.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_exception.hpp new file mode 100644 index 0000000000..87269c7d5e --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_exception.hpp @@ -0,0 +1,183 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSON_EXCEPTION_HPP +#define JSON_EXCEPTION_HPP + +#include // std::string +#include // std::ostringstream +#include // std::error_code +#include // unicons::convert +#include + +namespace jsoncons { + +// json_exception + +class json_exception +{ +public: + virtual const char* what() const noexcept = 0; +}; + +template +class json_runtime_error : public Base, public virtual json_exception +{ +public: + json_runtime_error(const std::string& s) noexcept + : Base(""), message_(s) + { + } + ~json_runtime_error() noexcept + { + } + const char* what() const noexcept override + { + return message_.c_str(); + } +private: + std::string message_; +}; + +class key_not_found : public std::out_of_range, public virtual json_exception +{ +public: + template + explicit key_not_found(const CharT* key, size_t length) noexcept + : std::out_of_range("") + { + buffer_.append("Key '"); + unicons::convert(key, key+length, std::back_inserter(buffer_), + unicons::conv_flags::strict); + buffer_.append("' not found"); + } + ~key_not_found() noexcept + { + } + const char* what() const noexcept override + { + return buffer_.c_str(); + } +private: + std::string buffer_; +}; + +class not_an_object : public std::runtime_error, public virtual json_exception +{ +public: + template + explicit not_an_object(const CharT* key, size_t length) noexcept + : std::runtime_error("") + { + buffer_.append("Attempting to access or modify '"); + unicons::convert(key, key+length, std::back_inserter(buffer_), + unicons::conv_flags::strict); + buffer_.append("' on a value that is not an object"); + } + ~not_an_object() noexcept + { + } + const char* what() const noexcept override + { + return buffer_.c_str(); + } +private: + std::string buffer_; +}; + +class ser_error : public std::system_error, public virtual json_exception +{ +public: + ser_error(std::error_code ec) + : std::system_error(ec), line_number_(0), column_number_(0) + { + } + ser_error(std::error_code ec, size_t position) + : std::system_error(ec), line_number_(0), column_number_(position) + { + } + ser_error(std::error_code ec, size_t line, size_t column) + : std::system_error(ec), line_number_(line), column_number_(column) + { + } + ser_error(const ser_error& other) = default; + + ser_error(ser_error&& other) = default; + + const char* what() const noexcept override + { + try + { + std::ostringstream os; + os << this->code().message(); + if (line_number_ != 0 && column_number_ != 0) + { + os << " at line " << line_number_ << " and column " << column_number_; + } + else if (column_number_ != 0) + { + os << " at position " << column_number_; + } + const_cast(buffer_) = os.str(); + return buffer_.c_str(); + } + catch (...) + { + return std::system_error::what(); + } + } + + size_t line() const noexcept + { + return line_number_; + } + + size_t column() const noexcept + { + return column_number_; + } + +#if !defined(JSONCONS_NO_DEPRECATED) + size_t line_number() const noexcept + { + return line(); + } + + size_t column_number() const noexcept + { + return column(); + } +#endif +private: + std::string buffer_; + size_t line_number_; + size_t column_number_; +}; + +#if !defined(JSONCONS_NO_DEPRECATED) +typedef ser_error serialization_error; +typedef ser_error json_parse_exception; +typedef ser_error parse_exception; +typedef ser_error parse_error; +#endif + +#define JSONCONS_STR2(x) #x +#define JSONCONS_STR(x) JSONCONS_STR2(x) + +#ifdef _DEBUG +#define JSONCONS_ASSERT(x) if (!(x)) { \ + throw jsoncons::json_runtime_error("assertion '" #x "' failed at " __FILE__ ":" \ + JSONCONS_STR(__LINE__)); } +#else +#define JSONCONS_ASSERT(x) if (!(x)) { \ + throw jsoncons::json_runtime_error("assertion '" #x "' failed at <> :" \ + JSONCONS_STR( 0 )); } +#endif // _DEBUG + +#define JSONCONS_THROW(x) throw (x) + +} +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_filter.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_filter.hpp new file mode 100644 index 0000000000..116e6b822e --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_filter.hpp @@ -0,0 +1,382 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_FILTER_HPP +#define JSONCONS_JSON_FILTER_HPP + +#include + +#include +#include + +namespace jsoncons { + +template +class basic_json_filter : public basic_json_content_handler +{ +public: + using typename basic_json_content_handler::string_view_type; +private: + basic_json_content_handler& to_handler_; + + // noncopyable and nonmoveable + basic_json_filter(const basic_json_filter&) = delete; + basic_json_filter& operator=(const basic_json_filter&) = delete; +public: + basic_json_filter(basic_json_content_handler& handler) + : to_handler_(handler) + { + } + +#if !defined(JSONCONS_NO_DEPRECATED) + basic_json_content_handler& input_handler() + { + return to_handler_; + } + + basic_json_content_handler& downstream_handler() + { + return to_handler_; + } + + basic_json_content_handler& destination_handler() + { + return to_handler_; + } +#endif + + basic_json_content_handler& to_handler() + { + return to_handler_; + } + +private: + void do_flush() override + { + to_handler_.flush(); + } + + bool do_begin_object(semantic_tag tag, const ser_context& context) override + { + return to_handler_.begin_object(tag, context); + } + + bool do_begin_object(size_t length, semantic_tag tag, const ser_context& context) override + { + return to_handler_.begin_object(length, tag, context); + } + + bool do_end_object(const ser_context& context) override + { + return to_handler_.end_object(context); + } + + bool do_begin_array(semantic_tag tag, const ser_context& context) override + { + return to_handler_.begin_array(tag, context); + } + + bool do_begin_array(size_t length, semantic_tag tag, const ser_context& context) override + { + return to_handler_.begin_array(length, tag, context); + } + + bool do_end_array(const ser_context& context) override + { + return to_handler_.end_array(context); + } + + bool do_name(const string_view_type& name, + const ser_context& context) override + { + return to_handler_.name(name, context); + } + + bool do_string_value(const string_view_type& value, + semantic_tag tag, + const ser_context& context) override + { + return to_handler_.string_value(value, tag, context); + } + + bool do_byte_string_value(const byte_string_view& b, + semantic_tag tag, + const ser_context& context) override + { + return to_handler_.byte_string_value(b, tag, context); + } + + bool do_double_value(double value, + semantic_tag tag, + const ser_context& context) override + { + return to_handler_.double_value(value, tag, context); + } + + bool do_int64_value(int64_t value, + semantic_tag tag, + const ser_context& context) override + { + return to_handler_.int64_value(value, tag, context); + } + + bool do_uint64_value(uint64_t value, + semantic_tag tag, + const ser_context& context) override + { + return to_handler_.uint64_value(value, tag, context); + } + + bool do_bool_value(bool value, semantic_tag tag, const ser_context& context) override + { + return to_handler_.bool_value(value, tag, context); + } + + bool do_null_value(semantic_tag tag, const ser_context& context) override + { + return to_handler_.null_value(tag, context); + } + +}; + +// Filters out begin_document and end_document events +template +class basic_json_fragment_filter : public basic_json_filter +{ +public: + using typename basic_json_filter::string_view_type; + + basic_json_fragment_filter(basic_json_content_handler& handler) + : basic_json_filter(handler) + { + } +private: + void do_flush() override + { + } +}; + +template +class basic_rename_object_member_filter : public basic_json_filter +{ +public: + using typename basic_json_filter::string_view_type; + +private: + std::basic_string name_; + std::basic_string new_name_; +public: + basic_rename_object_member_filter(const std::basic_string& name, + const std::basic_string& new_name, + basic_json_content_handler& handler) + : basic_json_filter(handler), + name_(name), new_name_(new_name) + { + } + +private: + bool do_name(const string_view_type& name, + const ser_context& context) override + { + if (name == name_) + { + return this->to_handler().name(new_name_,context); + } + else + { + return this->to_handler().name(name,context); + } + } +}; + +template +class json_content_handler_adaptor : public From +{ +public: + using typename From::string_view_type; +private: + To* to_handler_; + + // noncopyable + json_content_handler_adaptor(const json_content_handler_adaptor&) = delete; + json_content_handler_adaptor& operator=(const json_content_handler_adaptor&) = delete; +public: + + json_content_handler_adaptor() + : to_handler_(nullptr) + { + } + json_content_handler_adaptor(To& handler) + : to_handler_(std::addressof(handler)) + { + } + + // moveable + json_content_handler_adaptor(json_content_handler_adaptor&&) = default; + json_content_handler_adaptor& operator=(json_content_handler_adaptor&&) = default; + + To& to_handler() + { + return *to_handler_; + } + +private: + void do_flush() override + { + to_handler_->flush(); + } + + bool do_begin_object(semantic_tag tag, + const ser_context& context) override + { + return to_handler_->begin_object(tag, context); + } + + bool do_begin_object(size_t length, + semantic_tag tag, + const ser_context& context) override + { + return to_handler_->begin_object(length, tag, context); + } + + bool do_end_object(const ser_context& context) override + { + return to_handler_->end_object(context); + } + + bool do_begin_array(semantic_tag tag, + const ser_context& context) override + { + return to_handler_->begin_array(tag, context); + } + + bool do_begin_array(size_t length, + semantic_tag tag, + const ser_context& context) override + { + return to_handler_->begin_array(length, tag, context); + } + + bool do_end_array(const ser_context& context) override + { + return to_handler_->end_array(context); + } + + bool do_name(const string_view_type& name, + const ser_context& context) override + { + std::basic_string target; + auto result = unicons::convert(name.begin(),name.end(),std::back_inserter(target),unicons::conv_flags::strict); + if (result.ec != unicons::conv_errc()) + { + throw ser_error(result.ec); + } + return to_handler().name(target, context); + } + + bool do_string_value(const string_view_type& value, + semantic_tag tag, + const ser_context& context) override + { + std::basic_string target; + auto result = unicons::convert(value.begin(),value.end(),std::back_inserter(target),unicons::conv_flags::strict); + if (result.ec != unicons::conv_errc()) + { + throw ser_error(result.ec); + } + return to_handler().string_value(target, tag, context); + } + + bool do_byte_string_value(const byte_string_view& b, + semantic_tag tag, + const ser_context& context) override + { + return to_handler_->byte_string_value(b, tag, context); + } + + bool do_double_value(double value, + semantic_tag tag, + const ser_context& context) override + { + return to_handler_->double_value(value, tag, context); + } + + bool do_int64_value(int64_t value, + semantic_tag tag, + const ser_context& context) override + { + return to_handler_->int64_value(value, tag, context); + } + + bool do_uint64_value(uint64_t value, + semantic_tag tag, + const ser_context& context) override + { + return to_handler_->uint64_value(value, tag, context); + } + + bool do_bool_value(bool value, semantic_tag tag, const ser_context& context) override + { + return to_handler_->bool_value(value, tag, context); + } + + bool do_null_value(semantic_tag tag, const ser_context& context) override + { + return to_handler_->null_value(tag, context); + } + +}; + +template +class json_content_handler_adaptor::value>::type> +{ +public: + typedef typename From::char_type char_type; + typedef typename From::char_traits_type char_traits_type; + typedef typename From::string_view_type string_view_type; +private: + To* to_handler_; +public: + json_content_handler_adaptor() + : to_handler_(nullptr) + { + } + json_content_handler_adaptor(To& handler) + : to_handler_(std::addressof(handler)) + { + } + + operator From&() { return *to_handler_; } + + // moveable + json_content_handler_adaptor(json_content_handler_adaptor&&) = default; + json_content_handler_adaptor& operator=(json_content_handler_adaptor&&) = default; + + To& to_handler() + { + return *to_handler_; + } +}; + +template +json_content_handler_adaptor make_json_content_handler_adaptor(To& to) +{ + return json_content_handler_adaptor(to); +} + +typedef basic_json_filter json_filter; +typedef basic_json_filter wjson_filter; +typedef basic_rename_object_member_filter rename_object_member_filter; +typedef basic_rename_object_member_filter wrename_object_member_filter; + +#if !defined(JSONCONS_NO_DEPRECATED) +typedef basic_rename_object_member_filter rename_name_filter; +typedef basic_rename_object_member_filter wrename_name_filter; +#endif + +} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_fwd.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_fwd.hpp new file mode 100644 index 0000000000..d9b44cf8b1 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_fwd.hpp @@ -0,0 +1,23 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_FWD_HPP +#define JSONCONS_JSON_FWD_HPP + +#include // std::allocator + +namespace jsoncons { + +struct sorted_policy; + +template > +class basic_json; + +} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_options.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_options.hpp new file mode 100644 index 0000000000..fa434ee934 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_options.hpp @@ -0,0 +1,837 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_OPTIONS_HPP +#define JSONCONS_JSON_OPTIONS_HPP + +#include +#include // std::numeric_limits +#include +#include +#include + +namespace jsoncons { + +#if !defined(JSONCONS_NO_TO_CHARS) +using chars_format = std::chars_format; +#else +enum class chars_format : uint8_t {fixed=1,scientific=2,hex=4,general=fixed|scientific}; +#endif + +// floating_point_options + +class floating_point_options +{ + chars_format format_; + int precision_; + uint8_t decimal_places_; +public: + floating_point_options() + : format_(chars_format::general), precision_(0), decimal_places_(0) + { + } + + floating_point_options(chars_format format, int precision, uint8_t decimal_places = 0) + : format_(format), precision_(precision), decimal_places_(decimal_places) + { + } + + explicit floating_point_options(chars_format format) + : format_(format), precision_(0), decimal_places_(0) + { + } + + floating_point_options(const floating_point_options&) = default; + floating_point_options(floating_point_options&&) = default; + floating_point_options& operator=(const floating_point_options& e) = default; + floating_point_options& operator=(floating_point_options&& e) = default; + + int precision() const + { + return precision_; + } + + uint8_t decimal_places() const + { + return decimal_places_; + } + + chars_format format() const + { + return format_; + } +}; + +enum class indenting : uint8_t {no_indent = 0, indent = 1}; + +enum class line_split_kind : uint8_t {same_line,new_line,multi_line}; + +enum class bigint_chars_format : uint8_t {number, base10, base64, base64url +#if !defined(JSONCONS_NO_DEPRECATED) +,integer = number +#endif +}; + +#if !defined(JSONCONS_NO_DEPRECATED) +typedef bigint_chars_format bignum_chars_format; +typedef bigint_chars_format big_integer_chars_format; +#endif + +enum class byte_string_chars_format : uint8_t {none=0,base16,base64,base64url}; + +enum class spaces_option{no_spaces=0,space_after,space_before,space_before_and_after}; + +template +class basic_json_decode_options +{ +public: + typedef std::basic_string string_type; + + virtual ~basic_json_decode_options() = default; + + virtual size_t max_nesting_depth() const = 0; + + virtual bool is_str_to_nan() const = 0; + + virtual std::basic_string nan_to_str() const = 0; + + virtual bool is_str_to_inf() const = 0; + + virtual std::basic_string inf_to_str() const = 0; + + virtual bool is_str_to_neginf() const = 0; + + virtual std::basic_string neginf_to_str() const = 0; + + virtual bool lossless_number() const = 0; +}; + +template +class basic_json_encode_options +{ +public: + typedef std::basic_string string_type; + + virtual ~basic_json_encode_options() = default; + + virtual size_t max_nesting_depth() const = 0; + + virtual byte_string_chars_format byte_string_format() const = 0; + + virtual bigint_chars_format bigint_format() const = 0; + + virtual line_split_kind object_object_line_splits() const = 0; + + virtual line_split_kind array_object_line_splits() const = 0; + + virtual line_split_kind object_array_line_splits() const = 0; + + virtual line_split_kind array_array_line_splits() const = 0; + + virtual size_t indent_size() const = 0; + + virtual size_t line_length_limit() const = 0; + + virtual chars_format floating_point_format() const = 0; + + virtual int precision() const = 0; + + virtual bool escape_all_non_ascii() const = 0; + + virtual bool escape_solidus() const = 0; + + virtual spaces_option spaces_around_colon() const = 0; + + virtual spaces_option spaces_around_comma() const = 0; + + virtual bool pad_inside_object_braces() const = 0; + + virtual bool pad_inside_array_brackets() const = 0; + + virtual std::basic_string new_line_chars() const = 0; + + virtual bool is_nan_to_num() const = 0; + + virtual std::basic_string nan_to_num() const = 0; + + virtual bool is_inf_to_num() const = 0; + + virtual std::basic_string inf_to_num() const = 0; + + virtual bool is_neginf_to_num() const = 0; + + virtual std::basic_string neginf_to_num() const = 0; + + virtual bool is_nan_to_str() const = 0; + + virtual std::basic_string nan_to_str() const = 0; + + virtual bool is_inf_to_str() const = 0; + + virtual std::basic_string inf_to_str() const = 0; + + virtual bool is_neginf_to_str() const = 0; + + virtual std::basic_string neginf_to_str() const = 0; +}; + +template +class basic_json_options : public virtual basic_json_decode_options, + public virtual basic_json_encode_options +{ +public: + typedef CharT char_type; + typedef std::basic_string string_type; +private: + size_t indent_size_; + chars_format floating_point_format_; + int precision_; +#if !defined(JSONCONS_NO_DEPRECATED) + bool can_read_nan_replacement_; + bool can_read_pos_inf_replacement_; + bool can_read_neg_inf_replacement_; + string_type nan_replacement_; + string_type pos_inf_replacement_; + string_type neg_inf_replacement_; +#endif + bool escape_all_non_ascii_; + bool escape_solidus_; + byte_string_chars_format byte_string_format_; + bigint_chars_format bigint_format_; + line_split_kind object_object_line_splits_; + line_split_kind object_array_line_splits_; + line_split_kind array_array_line_splits_; + line_split_kind array_object_line_splits_; + size_t line_length_limit_; + + size_t max_nesting_depth_; + spaces_option spaces_around_colon_; + spaces_option spaces_around_comma_; + bool pad_inside_object_braces_; + bool pad_inside_array_brackets_; + std::basic_string new_line_chars_; + + bool is_nan_to_num_; + bool is_inf_to_num_; + bool is_neginf_to_num_; + bool is_nan_to_str_; + bool is_inf_to_str_; + bool is_neginf_to_str_; + bool is_str_to_nan_; + bool is_str_to_inf_; + bool is_str_to_neginf_; + + std::basic_string nan_to_num_; + std::basic_string inf_to_num_; + std::basic_string neginf_to_num_; + std::basic_string nan_to_str_; + std::basic_string inf_to_str_; + std::basic_string neginf_to_str_; + + bool lossless_number_; +public: + static const size_t indent_size_default = 4; + static const size_t line_length_limit_default = 120; + + static const basic_json_options& default_options() + { + static basic_json_options options{}; + return options; + } + +// Constructors + + basic_json_options() + : indent_size_(indent_size_default), + floating_point_format_(chars_format()), + precision_(0), +#if !defined(JSONCONS_NO_DEPRECATED) + can_read_nan_replacement_(false), + can_read_pos_inf_replacement_(false), + can_read_neg_inf_replacement_(false), +#endif + escape_all_non_ascii_(false), + escape_solidus_(false), + byte_string_format_(byte_string_chars_format::none), + bigint_format_(bigint_chars_format::base10), + object_object_line_splits_(line_split_kind::multi_line), + object_array_line_splits_(line_split_kind::same_line), + array_array_line_splits_(line_split_kind::new_line), + array_object_line_splits_(line_split_kind::multi_line), + line_length_limit_(line_length_limit_default), + max_nesting_depth_((std::numeric_limits::max)()), + spaces_around_colon_(spaces_option::space_after), + spaces_around_comma_(spaces_option::space_after), + pad_inside_object_braces_(false), + pad_inside_array_brackets_(false), + is_nan_to_num_(false), + is_inf_to_num_(false), + is_neginf_to_num_(false), + is_nan_to_str_(false), + is_inf_to_str_(false), + is_neginf_to_str_(false), + is_str_to_nan_(false), + is_str_to_inf_(false), + is_str_to_neginf_(false), + lossless_number_(false) + { + new_line_chars_.push_back('\n'); + } + +// Properties + byte_string_chars_format byte_string_format() const override {return byte_string_format_;} + basic_json_options& byte_string_format(byte_string_chars_format value) {byte_string_format_ = value; return *this;} + + bigint_chars_format bigint_format() const override {return bigint_format_;} + basic_json_options& bigint_format(bigint_chars_format value) {bigint_format_ = value; return *this;} + +#if !defined(JSONCONS_NO_DEPRECATED) + basic_json_options& big_integer_format(bigint_chars_format value) {bigint_format_ = value; return *this;} + bignum_chars_format bignum_format() const {return bigint_format_;} + basic_json_options& bignum_format(bignum_chars_format value) {bigint_format_ = value; return *this;} +#endif + line_split_kind object_object_line_splits() const override {return object_object_line_splits_;} + basic_json_options& object_object_line_splits(line_split_kind value) {object_object_line_splits_ = value; return *this;} + + line_split_kind array_object_line_splits() const override {return array_object_line_splits_;} + basic_json_options& array_object_line_splits(line_split_kind value) {array_object_line_splits_ = value; return *this;} + + line_split_kind object_array_line_splits() const override {return object_array_line_splits_;} + basic_json_options& object_array_line_splits(line_split_kind value) {object_array_line_splits_ = value; return *this;} + + line_split_kind array_array_line_splits() const override {return array_array_line_splits_;} + basic_json_options& array_array_line_splits(line_split_kind value) {array_array_line_splits_ = value; return *this;} + + size_t indent_size() const override + { + return indent_size_; + } + + basic_json_options& indent_size(size_t value) + { + indent_size_ = value; + return *this; + } + + spaces_option spaces_around_colon() const override + { + return spaces_around_colon_; + } + + basic_json_options& spaces_around_colon(spaces_option value) + { + spaces_around_colon_ = value; + return *this; + } + + spaces_option spaces_around_comma() const override + { + return spaces_around_comma_; + } + + basic_json_options& spaces_around_comma(spaces_option value) + { + spaces_around_comma_ = value; + return *this; + } + + bool pad_inside_object_braces() const override + { + return pad_inside_object_braces_; + } + + basic_json_options& pad_inside_object_braces(bool value) + { + pad_inside_object_braces_ = value; + return *this; + } + + bool pad_inside_array_brackets() const override + { + return pad_inside_array_brackets_; + } + + basic_json_options& pad_inside_array_brackets(bool value) + { + pad_inside_array_brackets_ = value; + return *this; + } + + std::basic_string new_line_chars() const override + { + return new_line_chars_; + } + + basic_json_options& new_line_chars(const std::basic_string& value) + { + new_line_chars_ = value; + return *this; + } + + bool is_nan_to_num() const override + { + return is_nan_to_num_; + } + + bool is_inf_to_num() const override + { + return is_inf_to_num_; + } + + bool is_neginf_to_num() const override + { + return is_neginf_to_num_ || is_inf_to_num_; + } + + bool is_nan_to_str() const override + { + return is_nan_to_str_; + } + + bool is_str_to_nan() const override + { + return is_str_to_nan_; + } + + bool is_inf_to_str() const override + { + return is_inf_to_str_; + } + + bool is_str_to_inf() const override + { + return is_str_to_inf_; + } + + bool is_neginf_to_str() const override + { + return is_neginf_to_str_ || is_inf_to_str_; + } + + bool is_str_to_neginf() const override + { + return is_str_to_neginf_ || is_str_to_inf_; + } + + std::basic_string nan_to_num() const override + { + if (is_nan_to_num_) + { + return nan_to_num_; + } +#if !defined(JSONCONS_NO_DEPRECATED) + else if (!can_read_nan_replacement_) // not string + { + return nan_replacement_; + } +#endif + else + { + return nan_to_num_; // empty string + } + } + + basic_json_options& nan_to_num(const std::basic_string& value) + { + is_nan_to_num_ = true; + nan_to_str_.clear(); + nan_to_num_ = value; + return *this; + } + + std::basic_string inf_to_num() const override + { + if (is_inf_to_num_) + { + return inf_to_num_; + } +#if !defined(JSONCONS_NO_DEPRECATED) + else if (!can_read_pos_inf_replacement_) // not string + { + return pos_inf_replacement_; + } +#endif + else + { + return inf_to_num_; // empty string + } + } + + basic_json_options& inf_to_num(const std::basic_string& value) + { + is_inf_to_num_ = true; + inf_to_str_.clear(); + inf_to_num_ = value; + return *this; + } + + std::basic_string neginf_to_num() const override + { + if (is_neginf_to_num_) + { + return neginf_to_num_; + } + else if (is_inf_to_num_) + { + std::basic_string s; + s.push_back('-'); + s.append(inf_to_num_); + return s; + } +#if !defined(JSONCONS_NO_DEPRECATED) + else if (!can_read_neg_inf_replacement_) // not string + { + return neg_inf_replacement_; + } +#endif + else + { + return neginf_to_num_; // empty string + } + } + + basic_json_options& neginf_to_num(const std::basic_string& value) + { + is_neginf_to_num_ = true; + neginf_to_str_.clear(); + neginf_to_num_ = value; + return *this; + } + + std::basic_string nan_to_str() const override + { + if (is_nan_to_str_) + { + return nan_to_str_; + } +#if !defined(JSONCONS_NO_DEPRECATED) + else if (can_read_nan_replacement_ && nan_replacement_.size() >= 2) // string + { + return nan_replacement_.substr(1,nan_replacement_.size()-2); // Remove quotes + } +#endif + else + { + return nan_to_str_; // empty string + } + } + + basic_json_options& nan_to_str(const std::basic_string& value, bool is_str_to_nan = true) + { + is_nan_to_str_ = true; + is_str_to_nan_ = is_str_to_nan; + nan_to_num_.clear(); + nan_to_str_ = value; + return *this; + } + + std::basic_string inf_to_str() const override + { + if (is_inf_to_str_) + { + return inf_to_str_; + } +#if !defined(JSONCONS_NO_DEPRECATED) + else if (can_read_pos_inf_replacement_ && pos_inf_replacement_.size() >= 2) // string + { + return pos_inf_replacement_.substr(1,pos_inf_replacement_.size()-2); // Strip quotes + } +#endif + else + { + return inf_to_str_; // empty string + } + } + + basic_json_options& inf_to_str(const std::basic_string& value, bool is_inf_to_str = true) + { + is_inf_to_str_ = true; + is_inf_to_str_ = is_inf_to_str; + inf_to_num_.clear(); + inf_to_str_ = value; + return *this; + } + + std::basic_string neginf_to_str() const override + { + if (is_neginf_to_str_) + { + return neginf_to_str_; + } + else if (is_inf_to_str_) + { + std::basic_string s; + s.push_back('-'); + s.append(inf_to_str_); + return s; + } +#if !defined(JSONCONS_NO_DEPRECATED) + else if (can_read_neg_inf_replacement_ && neg_inf_replacement_.size() >= 2) // string + { + return neg_inf_replacement_.substr(1,neg_inf_replacement_.size()-2); // Strip quotes + } +#endif + else + { + return neginf_to_str_; // empty string + } + } + + basic_json_options& neginf_to_str(const std::basic_string& value, bool is_neginf_to_str = true) + { + is_neginf_to_str_ = true; + is_neginf_to_str_ = is_neginf_to_str; + neginf_to_num_.clear(); + neginf_to_str_ = value; + return *this; + } + + bool lossless_number() const override + { + return lossless_number_; + } + + basic_json_options& lossless_number(bool value) + { + lossless_number_ = value; + return *this; + } + + size_t line_length_limit() const override + { + return line_length_limit_; + } + + basic_json_options& line_length_limit(size_t value) + { + line_length_limit_ = value; + return *this; + } + + chars_format floating_point_format() const override + { + return floating_point_format_; + } + + basic_json_options& floating_point_format(chars_format value) + { + floating_point_format_ = value; + return *this; + } + + int precision() const override + { + return precision_; + } + + basic_json_options& precision(int value) + { + precision_ = value; + return *this; + } + + bool escape_all_non_ascii() const override + { + return escape_all_non_ascii_; + } + + basic_json_options& escape_all_non_ascii(bool value) + { + escape_all_non_ascii_ = value; + return *this; + } + + bool escape_solidus() const override + { + return escape_solidus_; + } + + basic_json_options& escape_solidus(bool value) + { + escape_solidus_ = value; + return *this; + } + + size_t max_nesting_depth() const override + { + return max_nesting_depth_; + } + + void max_nesting_depth(size_t value) + { + max_nesting_depth_ = value; + } + +#if !defined(JSONCONS_NO_DEPRECATED) + + bool dec_to_str() const + { + return lossless_number_; + } + + basic_json_options& dec_to_str(bool value) + { + lossless_number_ = value; + return *this; + } + + size_t indent() const + { + return indent_size(); + } + + basic_json_options& indent(size_t value) + { + return indent_size(value); + } + + bool can_read_nan_replacement() const {return can_read_nan_replacement_;} + + bool can_read_pos_inf_replacement() const {return can_read_pos_inf_replacement_;} + + bool can_read_neg_inf_replacement() const {return can_read_neg_inf_replacement_;} + + bool can_write_nan_replacement() const {return !nan_replacement_.empty();} + + bool can_write_pos_inf_replacement() const {return !pos_inf_replacement_.empty();} + + bool can_write_neg_inf_replacement() const {return !neg_inf_replacement_.empty();} + + basic_json_options& replace_inf(bool replace) + { + can_read_pos_inf_replacement_ = replace; + can_read_neg_inf_replacement_ = replace; + return *this; + } + + basic_json_options& replace_pos_inf(bool replace) + { + can_read_pos_inf_replacement_ = replace; + return *this; + } + + basic_json_options& replace_neg_inf(bool replace) + { + can_read_neg_inf_replacement_ = replace; + return *this; + } + + const string_type& nan_replacement() const + { + return nan_replacement_; + } + + basic_json_options& nan_replacement(const string_type& value) + { + nan_replacement_ = value; + + can_read_nan_replacement_ = is_string(value); + + return *this; + } + + const string_type& pos_inf_replacement() const + { + return pos_inf_replacement_; + } + + basic_json_options& pos_inf_replacement(const string_type& value) + { + pos_inf_replacement_ = value; + can_read_pos_inf_replacement_ = is_string(value); + return *this; + } + + const string_type& neg_inf_replacement() const + { + return neg_inf_replacement_; + } + + basic_json_options& neg_inf_replacement(const string_type& value) + { + neg_inf_replacement_ = value; + can_read_neg_inf_replacement_ = is_string(value); + return *this; + } + + line_split_kind object_object_split_lines() const {return object_object_line_splits_;} + basic_json_options& object_object_split_lines(line_split_kind value) {object_object_line_splits_ = value; return *this;} + + line_split_kind array_object_split_lines() const {return array_object_line_splits_;} + basic_json_options& array_object_split_lines(line_split_kind value) {array_object_line_splits_ = value; return *this;} + + line_split_kind object_array_split_lines() const {return object_array_line_splits_;} + basic_json_options& object_array_split_lines(line_split_kind value) {object_array_line_splits_ = value; return *this;} + + line_split_kind array_array_split_lines() const {return array_array_line_splits_;} + basic_json_options& array_array_split_lines(line_split_kind value) {array_array_line_splits_ = value; return *this;} +#endif +private: + enum class input_state {initial,begin_quote,character,end_quote,escape,error}; + bool is_string(const string_type& s) const + { + input_state state = input_state::initial; + for (CharT c : s) + { + switch (c) + { + case '\t': case ' ': case '\n': case'\r': + break; + case '\\': + state = input_state::escape; + break; + case '\"': + switch (state) + { + case input_state::initial: + state = input_state::begin_quote; + break; + case input_state::begin_quote: + state = input_state::end_quote; + break; + case input_state::character: + state = input_state::end_quote; + break; + case input_state::end_quote: + state = input_state::error; + break; + case input_state::escape: + state = input_state::character; + break; + default: + state = input_state::character; + break; + } + break; + default: + break; + } + + } + return state == input_state::end_quote; + } +}; + +typedef basic_json_options json_options; +typedef basic_json_options wjson_options; + +typedef basic_json_decode_options json_decode_options; +typedef basic_json_decode_options wjson_decode_options; + +typedef basic_json_encode_options json_encode_options; +typedef basic_json_encode_options wjson_encode_options; + +#if !defined(JSONCONS_NO_DEPRECATED) +typedef basic_json_options output_format; +typedef basic_json_options woutput_format; +typedef basic_json_options serialization_options; +typedef basic_json_options wserialization_options; +typedef basic_json_options json_serializing_options; +typedef basic_json_options wjson_serializing_options; +#endif + +} +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_parser.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_parser.hpp new file mode 100644 index 0000000000..7f6747a746 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_parser.hpp @@ -0,0 +1,2841 @@ +// Copyright 2015 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_PARSER_HPP +#define JSONCONS_JSON_PARSER_HPP + +#include // std::allocator +#include +#include +#include +#include +#include // std::numeric_limits +#include +#include +#include +#include +#include +#include +#include + +#define JSONCONS_ILLEGAL_CONTROL_CHARACTER \ + case 0x00:case 0x01:case 0x02:case 0x03:case 0x04:case 0x05:case 0x06:case 0x07:case 0x08:case 0x0b: \ + case 0x0c:case 0x0e:case 0x0f:case 0x10:case 0x11:case 0x12:case 0x13:case 0x14:case 0x15:case 0x16: \ + case 0x17:case 0x18:case 0x19:case 0x1a:case 0x1b:case 0x1c:case 0x1d:case 0x1e:case 0x1f + +namespace jsoncons { + +namespace detail { + +template +class replacement_filter : public basic_json_filter +{ + typedef typename basic_json_content_handler::string_view_type string_view_type; + typedef typename basic_json_options::string_type string_type; + + bool is_str_to_nan_; + bool is_str_to_inf_; + bool is_str_to_neginf_; + string_type nan_to_str_; + string_type inf_to_str_; + string_type neginf_to_str_; + +public: + replacement_filter() = delete; + + replacement_filter(basic_json_content_handler& handler, + bool is_str_to_nan, + bool is_str_to_inf, + bool is_str_to_neginf, + const string_type& nan_to_str, + const string_type& inf_to_str, + const string_type& neginf_to_str) + : basic_json_filter(handler), + is_str_to_nan_(is_str_to_nan), + is_str_to_inf_(is_str_to_inf), + is_str_to_neginf_(is_str_to_neginf), + nan_to_str_(nan_to_str), + inf_to_str_(inf_to_str), + neginf_to_str_(neginf_to_str) + { + } + + bool do_string_value(const string_view_type& s, + semantic_tag tag, + const ser_context& context) override + { + if (tag == semantic_tag::none) + { + if (is_str_to_nan_ && s == nan_to_str_) + { + return this->to_handler().double_value(std::nan(""), tag, context); + } + else if (is_str_to_inf_ && s == inf_to_str_) + { + return this->to_handler().double_value(std::numeric_limits::infinity(), tag, context); + } + else if (is_str_to_neginf_ && s == neginf_to_str_) + { + return this->to_handler().double_value(-std::numeric_limits::infinity(), tag, context); + } + else + { + return this->to_handler().string_value(s, tag, context); + } + } + else + { + return this->to_handler().string_value(s, tag, context); + } + } +}; + +} + +enum class json_parse_state : uint8_t +{ + root, + start, + before_done, + slash, + slash_slash, + slash_star, + slash_star_star, + expect_comma_or_end, + object, + expect_member_name_or_end, + expect_member_name, + expect_colon, + expect_value_or_end, + expect_value, + array, + string, + member_name, + escape, + escape_u1, + escape_u2, + escape_u3, + escape_u4, + escape_expect_surrogate_pair1, + escape_expect_surrogate_pair2, + escape_u6, + escape_u7, + escape_u8, + escape_u9, + minus, + zero, + integer, + fraction1, + fraction2, + exp1, + exp2, + exp3, + n, + nu, + nul, + t, + tr, + tru, + f, + fa, + fal, + fals, + cr, + done +}; + +template > +class basic_json_parser : public ser_context +{ + typedef std::basic_string string_type; + typedef typename basic_json_content_handler::string_view_type string_view_type; + typedef Allocator allocator_type; + typedef typename std::allocator_traits:: template rebind_alloc char_allocator_type; + typedef typename std::allocator_traits:: template rebind_alloc numeral_allocator_type; + typedef typename std::allocator_traits:: template rebind_alloc byte_allocator_type; + + static const size_t initial_string_buffer_capacity_ = 1024; + static const int default_initial_stack_capacity_ = 100; + + default_parse_error_handler default_err_handler_; + + const basic_json_decode_options& options_; + + parse_error_handler& err_handler_; + int initial_stack_capacity_; + size_t nesting_depth_; + uint32_t cp_; + uint32_t cp2_; + size_t line_; + size_t column_; + const CharT* begin_input_; + const CharT* input_end_; + const CharT* input_ptr_; + json_parse_state state_; + bool continue_; + bool done_; + + std::basic_string,char_allocator_type> string_buffer_; + jsoncons::detail::string_to_double to_double_; + + typedef typename std::allocator_traits:: template rebind_alloc parse_state_allocator_type; + std::vector state_stack_; + + // Noncopyable and nonmoveable + basic_json_parser(const basic_json_parser&) = delete; + basic_json_parser& operator=(const basic_json_parser&) = delete; + +public: + basic_json_parser() + : basic_json_parser(basic_json_options::default_options(), default_err_handler_) + { + } + + basic_json_parser(parse_error_handler& err_handler) + : basic_json_parser(basic_json_options::default_options(), err_handler) + { + } + + basic_json_parser(const basic_json_decode_options& options) + : basic_json_parser(options, default_err_handler_) + { + } + + basic_json_parser(const basic_json_decode_options& options, + parse_error_handler& err_handler) + : options_(options), + err_handler_(err_handler), + initial_stack_capacity_(default_initial_stack_capacity_), + nesting_depth_(0), + cp_(0), + cp2_(0), + line_(1), + column_(1), + begin_input_(nullptr), + input_end_(nullptr), + input_ptr_(nullptr), + state_(json_parse_state::start), + continue_(true), + done_(false) + { + string_buffer_.reserve(initial_string_buffer_capacity_); + + state_stack_.reserve(initial_stack_capacity_); + push_state(json_parse_state::root); + } + + void set_column_number(size_t column) + { + column_ = column; + } + + bool source_exhausted() const + { + return input_ptr_ == input_end_; + } + + ~basic_json_parser() + { + } + +#if !defined(JSONCONS_NO_DEPRECATED) + size_t max_nesting_depth() const + { + return options_.max_nesting_depth(); + } + + void max_nesting_depth(size_t value) + { + options_.max_nesting_depth() = value; + } +#endif + json_parse_state parent() const + { + JSONCONS_ASSERT(state_stack_.size() >= 1); + return state_stack_.back(); + } + + bool done() const + { + return done_; + } + + bool stopped() const + { + return !continue_; + } + + bool finished() const + { + return !continue_ && state_ != json_parse_state::before_done; + } + + void skip_space() + { + const CharT* local_input_end = input_end_; + while (input_ptr_ != local_input_end) + { + switch (*input_ptr_) + { + case ' ': + case '\t': + ++input_ptr_; + ++column_; + break; + case '\r': + push_state(state_); + ++input_ptr_; + ++column_; + state_ = json_parse_state::cr; + return; + case '\n': + ++input_ptr_; + ++line_; + column_ = 1; + return; + default: + return; + } + } + } + + void skip_whitespace() + { + const CharT* local_input_end = input_end_; + + while (input_ptr_ != local_input_end) + { + switch (state_) + { + case json_parse_state::cr: + ++line_; + column_ = 1; + switch (*input_ptr_) + { + case '\n': + ++input_ptr_; + state_ = pop_state(); + break; + default: + state_ = pop_state(); + break; + } + break; + + default: + switch (*input_ptr_) + { + case ' ': + case '\t': + case '\n': + case '\r': + skip_space(); + break; + default: + return; + } + break; + } + } + } + + void begin_object(basic_json_content_handler& handler, std::error_code& ec) + { + if (++nesting_depth_ > options_.max_nesting_depth()) + { + continue_ = err_handler_.error(json_errc::max_depth_exceeded, *this); + if (!continue_) + { + ec = json_errc::max_depth_exceeded; + return; + } + } + push_state(json_parse_state::object); + state_ = json_parse_state::expect_member_name_or_end; + continue_ = handler.begin_object(semantic_tag::none, *this); + } + + void end_object(basic_json_content_handler& handler, std::error_code& ec) + { + if (nesting_depth_ < 1) + { + err_handler_.fatal_error(json_errc::unexpected_right_brace, *this); + ec = json_errc::unexpected_right_brace; + continue_ = false; + return; + } + --nesting_depth_; + state_ = pop_state(); + if (state_ == json_parse_state::object) + { + continue_ = handler.end_object(*this); + } + else if (state_ == json_parse_state::array) + { + err_handler_.fatal_error(json_errc::expected_comma_or_right_bracket, *this); + ec = json_errc::expected_comma_or_right_bracket; + continue_ = false; + return; + } + else + { + err_handler_.fatal_error(json_errc::unexpected_right_brace, *this); + ec = json_errc::unexpected_right_brace; + continue_ = false; + return; + } + + if (parent() == json_parse_state::root) + { + state_ = json_parse_state::before_done; + } + else + { + state_ = json_parse_state::expect_comma_or_end; + } + } + + void begin_array(basic_json_content_handler& handler, std::error_code& ec) + { + if (++nesting_depth_ > options_.max_nesting_depth()) + { + continue_ = err_handler_.error(json_errc::max_depth_exceeded, *this); + if (!continue_) + { + ec = json_errc::max_depth_exceeded; + return; + } + } + push_state(json_parse_state::array); + state_ = json_parse_state::expect_value_or_end; + continue_ = handler.begin_array(semantic_tag::none, *this); + } + + void end_array(basic_json_content_handler& handler, std::error_code& ec) + { + if (nesting_depth_ < 1) + { + err_handler_.fatal_error(json_errc::unexpected_right_bracket, *this); + ec = json_errc::unexpected_right_bracket; + continue_ = false; + return; + } + --nesting_depth_; + state_ = pop_state(); + if (state_ == json_parse_state::array) + { + continue_ = handler.end_array(*this); + } + else if (state_ == json_parse_state::object) + { + err_handler_.fatal_error(json_errc::expected_comma_or_right_brace, *this); + ec = json_errc::expected_comma_or_right_brace; + continue_ = false; + return; + } + else + { + err_handler_.fatal_error(json_errc::unexpected_right_bracket, *this); + ec = json_errc::unexpected_right_bracket; + continue_ = false; + return; + } + if (parent() == json_parse_state::root) + { + state_ = json_parse_state::before_done; + } + else + { + state_ = json_parse_state::expect_comma_or_end; + } + } + + void reset() + { + state_stack_.clear(); + state_stack_.reserve(initial_stack_capacity_); + push_state(json_parse_state::root); + state_ = json_parse_state::start; + continue_ = true; + done_ = false; + line_ = 1; + column_ = 1; + nesting_depth_ = 0; + } + + void restart() + { + continue_ = true; + } + + void check_done() + { + std::error_code ec; + check_done(ec); + if (ec) + { + throw ser_error(ec,line_,column_); + } + } + + void check_done(std::error_code& ec) + { + for (; input_ptr_ != input_end_; ++input_ptr_) + { + CharT curr_char_ = *input_ptr_; + switch (curr_char_) + { + case '\n': + case '\r': + case '\t': + case ' ': + break; + default: + continue_ = err_handler_.error(json_errc::extra_character, *this); + if (!continue_) + { + ec = json_errc::extra_character; + return; + } + break; + } + } + } + + json_parse_state state() const + { + return state_; + } + + void update(const string_view_type sv) + { + update(sv.data(),sv.length()); + } + + void update(const CharT* data, size_t length) + { + begin_input_ = data; + input_end_ = data + length; + input_ptr_ = begin_input_; + } + + void parse_some(basic_json_content_handler& handler) + { + std::error_code ec; + parse_some(handler, ec); + if (ec) + { + throw ser_error(ec,line_,column_); + } + } + + void parse_some(basic_json_content_handler& handler, std::error_code& ec) + { + if (options_.is_str_to_nan() || options_.is_str_to_inf() || options_.is_str_to_neginf()) + { + jsoncons::detail::replacement_filter h(handler, + options_.is_str_to_nan(), + options_.is_str_to_inf(), + options_.is_str_to_neginf(), + options_.nan_to_str(), + options_.inf_to_str(), + options_.neginf_to_str()); + parse_some_(h, ec); + } + else + { + parse_some_(handler, ec); + } + } + + void finish_parse(basic_json_content_handler& handler) + { + std::error_code ec; + finish_parse(handler, ec); + if (ec) + { + throw ser_error(ec,line_,column_); + } + } + + void finish_parse(basic_json_content_handler& handler, std::error_code& ec) + { + while (!finished()) + { + parse_some(handler, ec); + } + } + + void parse_some_(basic_json_content_handler& handler, std::error_code& ec) + { + if (state_ == json_parse_state::before_done) + { + handler.flush(); + done_ = true; + state_ = json_parse_state::done; + continue_ = false; + return; + } + const CharT* local_input_end = input_end_; + + if (input_ptr_ == local_input_end && continue_) + { + switch (state_) + { + case json_parse_state::zero: + case json_parse_state::integer: + end_integer_value(handler, ec); + if (ec) return; + break; + case json_parse_state::fraction2: + end_fraction_value(handler, ec); + if (ec) return; + break; + case json_parse_state::exp3: + end_fraction_value(handler, ec); + if (ec) return; + break; + case json_parse_state::before_done: + handler.flush(); + done_ = true; + state_ = json_parse_state::done; + continue_ = false; + break; + case json_parse_state::done: + continue_ = false; + break; + case json_parse_state::cr: + state_ = pop_state(); + break; + default: + err_handler_.fatal_error(json_errc::unexpected_eof, *this); + ec = json_errc::unexpected_eof; + continue_ = false; + return; + } + } + + while ((input_ptr_ < local_input_end) && continue_) + { + switch (state_) + { + case json_parse_state::before_done: + handler.flush(); + done_ = true; + state_ = json_parse_state::done; + continue_ = false; + break; + case json_parse_state::cr: + ++line_; + column_ = 1; + switch (*input_ptr_) + { + case '\n': + ++input_ptr_; + state_ = pop_state(); + break; + default: + state_ = pop_state(); + break; + } + break; + case json_parse_state::start: + { + switch (*input_ptr_) + { + JSONCONS_ILLEGAL_CONTROL_CHARACTER: + continue_ = err_handler_.error(json_errc::illegal_control_character, *this); + if (!continue_) + { + ec = json_errc::illegal_control_character; + return; + } + break; + case '\r': + push_state(state_); + ++input_ptr_; + ++column_; + state_ = json_parse_state::cr; + break; + case '\n': + ++input_ptr_; + ++line_; + column_ = 1; + break; + case ' ':case '\t': + skip_space(); + break; + case '/': + ++input_ptr_; + ++column_; + push_state(state_); + state_ = json_parse_state::slash; + break; + case '{': + begin_object(handler, ec); + if (ec) return; + ++input_ptr_; + ++column_; + break; + case '[': + begin_array(handler, ec); + if (ec) return; + ++input_ptr_; + ++column_; + break; + case '\"': + state_ = json_parse_state::string; + ++input_ptr_; + ++column_; + string_buffer_.clear(); + parse_string(handler, ec); + if (ec) return; + break; + case '-': + string_buffer_.clear(); + string_buffer_.push_back('-'); + ++input_ptr_; + ++column_; + state_ = json_parse_state::minus; + parse_number(handler, ec); + if (ec) {return;} + break; + case '0': + string_buffer_.clear(); + string_buffer_.push_back(static_cast(*input_ptr_)); + state_ = json_parse_state::zero; + ++input_ptr_; + ++column_; + parse_number(handler, ec); + if (ec) {return;} + break; + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + string_buffer_.clear(); + string_buffer_.push_back(static_cast(*input_ptr_)); + ++input_ptr_; + ++column_; + state_ = json_parse_state::integer; + parse_number(handler, ec); + if (ec) {return;} + break; + case 'n': + parse_null(handler, ec); + if (ec) {return;} + break; + case 't': + parse_true(handler, ec); + if (ec) {return;} + break; + case 'f': + parse_false(handler, ec); + if (ec) {return;} + break; + case '}': + err_handler_.fatal_error(json_errc::unexpected_right_brace, *this); + ec = json_errc::unexpected_right_brace; + continue_ = false; + return; + case ']': + err_handler_.fatal_error(json_errc::unexpected_right_bracket, *this); + ec = json_errc::unexpected_right_bracket; + continue_ = false; + return; + default: + err_handler_.fatal_error(json_errc::invalid_json_text, *this); + ec = json_errc::invalid_json_text; + continue_ = false; + return; + } + } + break; + + case json_parse_state::expect_comma_or_end: + { + switch (*input_ptr_) + { + JSONCONS_ILLEGAL_CONTROL_CHARACTER: + continue_ = err_handler_.error(json_errc::illegal_control_character, *this); + if (!continue_) + { + ec = json_errc::illegal_control_character; + return; + } + ++input_ptr_; + ++column_; + break; + case '\r': + ++input_ptr_; + ++column_; + push_state(state_); + state_ = json_parse_state::cr; + break; + case '\n': + ++input_ptr_; + ++line_; + column_ = 1; + break; + case ' ':case '\t': + skip_space(); + break; + case '/': + ++input_ptr_; + ++column_; + push_state(state_); + state_ = json_parse_state::slash; + break; + case '}': + end_object(handler, ec); + if (ec) return; + ++input_ptr_; + ++column_; + break; + case ']': + end_array(handler, ec); + if (ec) return; + ++input_ptr_; + ++column_; + break; + case ',': + begin_member_or_element(ec); + if (ec) return; + ++input_ptr_; + ++column_; + break; + default: + if (parent() == json_parse_state::array) + { + continue_ = err_handler_.error(json_errc::expected_comma_or_right_bracket, *this); + if (!continue_) + { + ec = json_errc::expected_comma_or_right_bracket; + return; + } + } + else if (parent() == json_parse_state::object) + { + continue_ = err_handler_.error(json_errc::expected_comma_or_right_brace, *this); + if (!continue_) + { + ec = json_errc::expected_comma_or_right_brace; + return; + } + } + ++input_ptr_; + ++column_; + break; + } + } + break; + case json_parse_state::expect_member_name_or_end: + { + switch (*input_ptr_) + { + JSONCONS_ILLEGAL_CONTROL_CHARACTER: + continue_ = err_handler_.error(json_errc::illegal_control_character, *this); + if (!continue_) + { + ec = json_errc::illegal_control_character; + return; + } + ++input_ptr_; + ++column_; + break; + case '\r': + ++input_ptr_; + ++column_; + push_state(state_); + state_ = json_parse_state::cr; + break; + case '\n': + ++input_ptr_; + ++line_; + column_ = 1; + break; + case ' ':case '\t': + skip_space(); + break; + case '/': + ++input_ptr_; + ++column_; + push_state(state_); + state_ = json_parse_state::slash; + break; + case '}': + end_object(handler, ec); + if (ec) return; + ++input_ptr_; + ++column_; + break; + case '\"': + ++input_ptr_; + ++column_; + push_state(json_parse_state::member_name); + state_ = json_parse_state::string; + string_buffer_.clear(); + parse_string(handler, ec); + if (ec) return; + break; + case '\'': + continue_ = err_handler_.error(json_errc::single_quote, *this); + if (!continue_) + { + ec = json_errc::single_quote; + return; + } + ++input_ptr_; + ++column_; + break; + default: + continue_ = err_handler_.error(json_errc::expected_name, *this); + if (!continue_) + { + ec = json_errc::expected_name; + return; + } + ++input_ptr_; + ++column_; + break; + } + } + break; + case json_parse_state::expect_member_name: + { + switch (*input_ptr_) + { + JSONCONS_ILLEGAL_CONTROL_CHARACTER: + continue_ = err_handler_.error(json_errc::illegal_control_character, *this); + if (!continue_) + { + ec = json_errc::illegal_control_character; + return; + } + ++input_ptr_; + ++column_; + break; + case '\r': + ++input_ptr_; + ++column_; + push_state(state_); + state_ = json_parse_state::cr; + break; + case '\n': + ++input_ptr_; + ++line_; + column_ = 1; + break; + case ' ':case '\t': + skip_space(); + break; + case '/': + ++input_ptr_; + ++column_; + push_state(state_); + state_ = json_parse_state::slash; + break; + case '\"': + ++input_ptr_; + ++column_; + push_state(json_parse_state::member_name); + state_ = json_parse_state::string; + string_buffer_.clear(); + parse_string(handler, ec); + if (ec) return; + break; + case '}': + continue_ = err_handler_.error(json_errc::extra_comma, *this); + if (!continue_) + { + ec = json_errc::extra_comma; + return; + } + end_object(handler, ec); // Recover + if (ec) return; + ++input_ptr_; + ++column_; + break; + case '\'': + continue_ = err_handler_.error(json_errc::single_quote, *this); + if (!continue_) + { + ec = json_errc::single_quote; + return; + } + ++input_ptr_; + ++column_; + break; + default: + continue_ = err_handler_.error(json_errc::expected_name, *this); + if (!continue_) + { + ec = json_errc::expected_name; + return; + } + ++input_ptr_; + ++column_; + break; + } + } + break; + case json_parse_state::expect_colon: + { + switch (*input_ptr_) + { + JSONCONS_ILLEGAL_CONTROL_CHARACTER: + continue_ = err_handler_.error(json_errc::illegal_control_character, *this); + if (!continue_) + { + ec = json_errc::illegal_control_character; + return; + } + ++input_ptr_; + ++column_; + break; + case '\r': + push_state(state_); + state_ = json_parse_state::cr; + ++input_ptr_; + ++column_; + break; + case '\n': + ++input_ptr_; + ++line_; + column_ = 1; + break; + case ' ':case '\t': + skip_space(); + break; + case '/': + push_state(state_); + state_ = json_parse_state::slash; + ++input_ptr_; + ++column_; + break; + case ':': + state_ = json_parse_state::expect_value; + ++input_ptr_; + ++column_; + break; + default: + continue_ = err_handler_.error(json_errc::expected_colon, *this); + if (!continue_) + { + ec = json_errc::expected_colon; + return; + } + ++input_ptr_; + ++column_; + break; + } + } + break; + + case json_parse_state::expect_value: + { + switch (*input_ptr_) + { + JSONCONS_ILLEGAL_CONTROL_CHARACTER: + continue_ = err_handler_.error(json_errc::illegal_control_character, *this); + if (!continue_) + { + ec = json_errc::illegal_control_character; + return; + } + ++input_ptr_; + ++column_; + break; + case '\r': + push_state(state_); + ++input_ptr_; + ++column_; + state_ = json_parse_state::cr; + break; + case '\n': + ++input_ptr_; + ++line_; + column_ = 1; + break; + case ' ':case '\t': + skip_space(); + break; + case '/': + push_state(state_); + ++input_ptr_; + ++column_; + state_ = json_parse_state::slash; + break; + case '{': + begin_object(handler, ec); + if (ec) return; + ++input_ptr_; + ++column_; + break; + case '[': + begin_array(handler, ec); + if (ec) return; + ++input_ptr_; + ++column_; + break; + case '\"': + ++input_ptr_; + ++column_; + state_ = json_parse_state::string; + string_buffer_.clear(); + parse_string(handler, ec); + if (ec) return; + break; + case '-': + string_buffer_.clear(); + string_buffer_.push_back('-'); + ++input_ptr_; + ++column_; + state_ = json_parse_state::minus; + parse_number(handler, ec); + if (ec) {return;} + break; + case '0': + string_buffer_.clear(); + string_buffer_.push_back(static_cast(*input_ptr_)); + ++input_ptr_; + ++column_; + state_ = json_parse_state::zero; + parse_number(handler, ec); + if (ec) {return;} + break; + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + string_buffer_.clear(); + string_buffer_.push_back(static_cast(*input_ptr_)); + ++input_ptr_; + ++column_; + state_ = json_parse_state::integer; + parse_number(handler, ec); + if (ec) {return;} + break; + case 'n': + parse_null(handler, ec); + if (ec) {return;} + break; + case 't': + parse_true(handler, ec); + if (ec) {return;} + break; + case 'f': + parse_false(handler, ec); + if (ec) {return;} + break; + case ']': + if (parent() == json_parse_state::array) + { + continue_ = err_handler_.error(json_errc::extra_comma, *this); + if (!continue_) + { + ec = json_errc::extra_comma; + return; + } + end_array(handler, ec); // Recover + if (ec) return; + } + else + { + continue_ = err_handler_.error(json_errc::expected_value, *this); + if (!continue_) + { + ec = json_errc::expected_value; + return; + } + } + ++input_ptr_; + ++column_; + break; + case '\'': + continue_ = err_handler_.error(json_errc::single_quote, *this); + if (!continue_) + { + ec = json_errc::single_quote; + return; + } + ++input_ptr_; + ++column_; + break; + default: + continue_ = err_handler_.error(json_errc::expected_value, *this); + if (!continue_) + { + ec = json_errc::expected_value; + return; + } + ++input_ptr_; + ++column_; + break; + } + } + break; + case json_parse_state::expect_value_or_end: + { + switch (*input_ptr_) + { + JSONCONS_ILLEGAL_CONTROL_CHARACTER: + continue_ = err_handler_.error(json_errc::illegal_control_character, *this); + if (!continue_) + { + ec = json_errc::illegal_control_character; + return; + } + ++input_ptr_; + ++column_; + break; + case '\r': + ++input_ptr_; + ++column_; + push_state(state_); + state_ = json_parse_state::cr; + break; + case '\n': + ++input_ptr_; + ++line_; + column_ = 1; + break; + case ' ':case '\t': + skip_space(); + break; + case '/': + ++input_ptr_; + ++column_; + push_state(state_); + state_ = json_parse_state::slash; + break; + case '{': + begin_object(handler, ec); + if (ec) return; + ++input_ptr_; + ++column_; + break; + case '[': + begin_array(handler, ec); + if (ec) return; + ++input_ptr_; + ++column_; + break; + case ']': + end_array(handler, ec); + if (ec) return; + ++input_ptr_; + ++column_; + break; + case '\"': + ++input_ptr_; + ++column_; + state_ = json_parse_state::string; + string_buffer_.clear(); + parse_string(handler, ec); + if (ec) return; + break; + case '-': + string_buffer_.clear(); + string_buffer_.push_back('-'); + ++input_ptr_; + ++column_; + state_ = json_parse_state::minus; + parse_number(handler, ec); + if (ec) {return;} + break; + case '0': + string_buffer_.clear(); + string_buffer_.push_back(static_cast(*input_ptr_)); + ++input_ptr_; + ++column_; + state_ = json_parse_state::zero; + parse_number(handler, ec); + if (ec) {return;} + break; + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + string_buffer_.clear(); + string_buffer_.push_back(static_cast(*input_ptr_)); + ++input_ptr_; + ++column_; + state_ = json_parse_state::integer; + parse_number(handler, ec); + if (ec) {return;} + break; + case 'n': + parse_null(handler, ec); + if (ec) {return;} + break; + case 't': + parse_true(handler, ec); + if (ec) {return;} + break; + case 'f': + parse_false(handler, ec); + if (ec) {return;} + break; + case '\'': + continue_ = err_handler_.error(json_errc::single_quote, *this); + if (!continue_) + { + ec = json_errc::single_quote; + return; + } + ++input_ptr_; + ++column_; + break; + default: + continue_ = err_handler_.error(json_errc::expected_value, *this); + if (!continue_) + { + ec = json_errc::expected_value; + return; + } + ++input_ptr_; + ++column_; + break; + } + } + break; + case json_parse_state::string: + case json_parse_state::escape: + case json_parse_state::escape_u1: + case json_parse_state::escape_u2: + case json_parse_state::escape_u3: + case json_parse_state::escape_u4: + case json_parse_state::escape_expect_surrogate_pair1: + case json_parse_state::escape_expect_surrogate_pair2: + case json_parse_state::escape_u6: + case json_parse_state::escape_u7: + case json_parse_state::escape_u8: + case json_parse_state::escape_u9: + parse_string(handler, ec); + if (ec) return; + break; + case json_parse_state::minus: + case json_parse_state::zero: + case json_parse_state::integer: + case json_parse_state::fraction1: + case json_parse_state::fraction2: + case json_parse_state::exp1: + case json_parse_state::exp2: + case json_parse_state::exp3: + parse_number(handler, ec); + if (ec) return; + break; + case json_parse_state::t: + switch (*input_ptr_) + { + case 'r': + ++input_ptr_; + ++column_; + state_ = json_parse_state::tr; + break; + default: + err_handler_.fatal_error(json_errc::invalid_value, *this); + ec = json_errc::invalid_value; + continue_ = false; + return; + } + break; + case json_parse_state::tr: + switch (*input_ptr_) + { + case 'u': + state_ = json_parse_state::tru; + break; + default: + err_handler_.fatal_error(json_errc::invalid_value, *this); + ec = json_errc::invalid_value; + continue_ = false; + return; + } + ++input_ptr_; + ++column_; + break; + case json_parse_state::tru: + switch (*input_ptr_) + { + case 'e': + continue_ = handler.bool_value(true, semantic_tag::none, *this); + if (parent() == json_parse_state::root) + { + state_ = json_parse_state::before_done; + } + else + { + state_ = json_parse_state::expect_comma_or_end; + } + break; + default: + err_handler_.fatal_error(json_errc::invalid_value, *this); + ec = json_errc::invalid_value; + continue_ = false; + return; + } + ++input_ptr_; + ++column_; + break; + case json_parse_state::f: + switch (*input_ptr_) + { + case 'a': + ++input_ptr_; + ++column_; + state_ = json_parse_state::fa; + break; + default: + err_handler_.fatal_error(json_errc::invalid_value, *this); + ec = json_errc::invalid_value; + continue_ = false; + return; + } + break; + case json_parse_state::fa: + switch (*input_ptr_) + { + case 'l': + state_ = json_parse_state::fal; + break; + default: + err_handler_.fatal_error(json_errc::invalid_value, *this); + ec = json_errc::invalid_value; + continue_ = false; + return; + } + ++input_ptr_; + ++column_; + break; + case json_parse_state::fal: + switch (*input_ptr_) + { + case 's': + state_ = json_parse_state::fals; + break; + default: + err_handler_.fatal_error(json_errc::invalid_value, *this); + ec = json_errc::invalid_value; + continue_ = false; + return; + } + ++input_ptr_; + ++column_; + break; + case json_parse_state::fals: + switch (*input_ptr_) + { + case 'e': + continue_ = handler.bool_value(false, semantic_tag::none, *this); + if (parent() == json_parse_state::root) + { + state_ = json_parse_state::before_done; + } + else + { + state_ = json_parse_state::expect_comma_or_end; + } + break; + default: + err_handler_.fatal_error(json_errc::invalid_value, *this); + ec = json_errc::invalid_value; + continue_ = false; + return; + } + ++input_ptr_; + ++column_; + break; + case json_parse_state::n: + switch (*input_ptr_) + { + case 'u': + ++input_ptr_; + ++column_; + state_ = json_parse_state::nu; + break; + default: + err_handler_.fatal_error(json_errc::invalid_value, *this); + ec = json_errc::invalid_value; + continue_ = false; + return; + } + break; + case json_parse_state::nu: + switch (*input_ptr_) + { + case 'l': + state_ = json_parse_state::nul; + break; + default: + err_handler_.fatal_error(json_errc::invalid_value, *this); + ec = json_errc::invalid_value; + continue_ = false; + return; + } + ++input_ptr_; + ++column_; + break; + case json_parse_state::nul: + switch (*input_ptr_) + { + case 'l': + continue_ = handler.null_value(semantic_tag::none, *this); + if (parent() == json_parse_state::root) + { + state_ = json_parse_state::before_done; + } + else + { + state_ = json_parse_state::expect_comma_or_end; + } + break; + default: + err_handler_.fatal_error(json_errc::invalid_value, *this); + ec = json_errc::invalid_value; + continue_ = false; + return; + } + ++input_ptr_; + ++column_; + break; + case json_parse_state::slash: + { + switch (*input_ptr_) + { + case '*': + state_ = json_parse_state::slash_star; + continue_ = err_handler_.error(json_errc::illegal_comment, *this); + if (!continue_) + { + ec = json_errc::illegal_comment; + return; + } + break; + case '/': + state_ = json_parse_state::slash_slash; + continue_ = err_handler_.error(json_errc::illegal_comment, *this); + if (!continue_) + { + ec = json_errc::illegal_comment; + return; + } + break; + default: + continue_ = err_handler_.error(json_errc::invalid_json_text, *this); + if (!continue_) + { + ec = json_errc::invalid_json_text; + return; + } + break; + } + ++input_ptr_; + ++column_; + break; + } + case json_parse_state::slash_star: + { + switch (*input_ptr_) + { + case '\r': + push_state(state_); + state_ = json_parse_state::cr; + break; + case '\n': + ++line_; + column_ = 1; + break; + case '*': + state_ = json_parse_state::slash_star_star; + break; + } + ++input_ptr_; + ++column_; + break; + } + case json_parse_state::slash_slash: + { + switch (*input_ptr_) + { + case '\r': + state_ = pop_state(); + break; + case '\n': + state_ = pop_state(); + break; + default: + ++input_ptr_; + ++column_; + } + break; + } + case json_parse_state::slash_star_star: + { + switch (*input_ptr_) + { + case '/': + state_ = pop_state(); + break; + default: + state_ = json_parse_state::slash_star; + break; + } + ++input_ptr_; + ++column_; + break; + } + default: + JSONCONS_ASSERT(false); + break; + } + } + } + + void parse_true(basic_json_content_handler& handler, std::error_code& ec) + { + if (JSONCONS_LIKELY(input_end_ - input_ptr_ >= 4)) + { + if (*(input_ptr_+1) == 'r' && *(input_ptr_+2) == 'u' && *(input_ptr_+3) == 'e') + { + continue_ = handler.bool_value(true, semantic_tag::none, *this); + input_ptr_ += 4; + column_ += 4; + if (parent() == json_parse_state::root) + { + state_ = json_parse_state::before_done; + } + else + { + state_ = json_parse_state::expect_comma_or_end; + } + } + else + { + err_handler_.fatal_error(json_errc::invalid_value, *this); + ec = json_errc::invalid_value; + continue_ = false; + return; + } + } + else + { + ++input_ptr_; + ++column_; + state_ = json_parse_state::t; + } + } + + void parse_null(basic_json_content_handler& handler, std::error_code& ec) + { + if (JSONCONS_LIKELY(input_end_ - input_ptr_ >= 4)) + { + if (*(input_ptr_+1) == 'u' && *(input_ptr_+2) == 'l' && *(input_ptr_+3) == 'l') + { + continue_ = handler.null_value(semantic_tag::none, *this); + input_ptr_ += 4; + column_ += 4; + if (parent() == json_parse_state::root) + { + state_ = json_parse_state::before_done; + } + else + { + state_ = json_parse_state::expect_comma_or_end; + } + } + else + { + err_handler_.fatal_error(json_errc::invalid_value, *this); + ec = json_errc::invalid_value; + continue_ = false; + return; + } + } + else + { + ++input_ptr_; + ++column_; + state_ = json_parse_state::n; + } + } + + void parse_false(basic_json_content_handler& handler, std::error_code& ec) + { + if (JSONCONS_LIKELY(input_end_ - input_ptr_ >= 5)) + { + if (*(input_ptr_+1) == 'a' && *(input_ptr_+2) == 'l' && *(input_ptr_+3) == 's' && *(input_ptr_+4) == 'e') + { + continue_ = handler.bool_value(false, semantic_tag::none, *this); + input_ptr_ += 5; + column_ += 5; + if (parent() == json_parse_state::root) + { + state_ = json_parse_state::before_done; + } + else + { + state_ = json_parse_state::expect_comma_or_end; + } + } + else + { + err_handler_.fatal_error(json_errc::invalid_value, *this); + ec = json_errc::invalid_value; + continue_ = false; + return; + } + } + else + { + ++input_ptr_; + ++column_; + state_ = json_parse_state::f; + } + } + + void parse_number(basic_json_content_handler& handler, std::error_code& ec) + { + const CharT* local_input_end = input_end_; + + switch (state_) + { + case json_parse_state::minus: + goto minus_sign; + case json_parse_state::zero: + goto zero; + case json_parse_state::integer: + goto integer; + case json_parse_state::fraction1: + goto fraction1; + case json_parse_state::fraction2: + goto fraction2; + case json_parse_state::exp1: + goto exp1; + case json_parse_state::exp2: + goto exp2; + case json_parse_state::exp3: + goto exp3; + default: + JSONCONS_UNREACHABLE(); + } +minus_sign: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = json_parse_state::minus; + return; + } + switch (*input_ptr_) + { + case '0': + string_buffer_.push_back(static_cast(*input_ptr_)); + ++input_ptr_; + ++column_; + goto zero; + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + string_buffer_.push_back(static_cast(*input_ptr_)); + ++input_ptr_; + ++column_; + goto integer; + default: + err_handler_.fatal_error(json_errc::expected_value, *this); + ec = json_errc::expected_value; + continue_ = false; + return; + } +zero: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = json_parse_state::zero; + return; + } + switch (*input_ptr_) + { + case '\r': + end_integer_value(handler, ec); + if (ec) return; + ++input_ptr_; + ++column_; + push_state(state_); + state_ = json_parse_state::cr; + return; + case '\n': + end_integer_value(handler, ec); + if (ec) return; + ++input_ptr_; + ++line_; + column_ = 1; + return; + case ' ':case '\t': + end_integer_value(handler, ec); + if (ec) return; + skip_space(); + return; + case '/': + end_integer_value(handler, ec); + if (ec) return; + ++input_ptr_; + ++column_; + push_state(state_); + state_ = json_parse_state::slash; + return; + case '}': + end_integer_value(handler, ec); + if (ec) return; + state_ = json_parse_state::expect_comma_or_end; + return; + case ']': + end_integer_value(handler, ec); + if (ec) return; + state_ = json_parse_state::expect_comma_or_end; + return; + case '.': + string_buffer_.push_back(to_double_.get_decimal_point()); + ++input_ptr_; + ++column_; + goto fraction1; + case 'e':case 'E': + string_buffer_.push_back(static_cast(*input_ptr_)); + ++input_ptr_; + ++column_; + goto exp1; + case ',': + end_integer_value(handler, ec); + if (ec) return; + begin_member_or_element(ec); + if (ec) return; + ++input_ptr_; + ++column_; + return; + case '0': case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + err_handler_.fatal_error(json_errc::leading_zero, *this); + ec = json_errc::leading_zero; + continue_ = false; + state_ = json_parse_state::zero; + return; + default: + err_handler_.fatal_error(json_errc::invalid_number, *this); + ec = json_errc::invalid_number; + continue_ = false; + state_ = json_parse_state::zero; + return; + } +integer: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = json_parse_state::integer; + return; + } + switch (*input_ptr_) + { + case '\r': + end_integer_value(handler, ec); + if (ec) return; + push_state(state_); + ++input_ptr_; + ++column_; + state_ = json_parse_state::cr; + return; + case '\n': + end_integer_value(handler, ec); + if (ec) return; + ++input_ptr_; + ++line_; + column_ = 1; + return; + case ' ':case '\t': + end_integer_value(handler, ec); + if (ec) return; + skip_space(); + return; + case '/': + end_integer_value(handler, ec); + if (ec) return; + push_state(state_); + ++input_ptr_; + ++column_; + state_ = json_parse_state::slash; + return; + case '}': + end_integer_value(handler, ec); + if (ec) return; + state_ = json_parse_state::expect_comma_or_end; + return; + case ']': + end_integer_value(handler, ec); + if (ec) return; + state_ = json_parse_state::expect_comma_or_end; + return; + case '0': case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + string_buffer_.push_back(static_cast(*input_ptr_)); + ++input_ptr_; + ++column_; + goto integer; + case '.': + string_buffer_.push_back(to_double_.get_decimal_point()); + ++input_ptr_; + ++column_; + goto fraction1; + case 'e':case 'E': + string_buffer_.push_back(static_cast(*input_ptr_)); + ++input_ptr_; + ++column_; + goto exp1; + case ',': + end_integer_value(handler, ec); + if (ec) return; + begin_member_or_element(ec); + if (ec) return; + ++input_ptr_; + ++column_; + return; + default: + err_handler_.fatal_error(json_errc::invalid_number, *this); + ec = json_errc::invalid_number; + continue_ = false; + state_ = json_parse_state::integer; + return; + } +fraction1: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = json_parse_state::fraction1; + return; + } + switch (*input_ptr_) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + string_buffer_.push_back(static_cast(*input_ptr_)); + ++input_ptr_; + ++column_; + goto fraction2; + default: + err_handler_.fatal_error(json_errc::invalid_number, *this); + ec = json_errc::invalid_number; + continue_ = false; + state_ = json_parse_state::fraction1; + return; + } +fraction2: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = json_parse_state::fraction2; + return; + } + switch (*input_ptr_) + { + case '\r': + end_fraction_value(handler, ec); + if (ec) return; + push_state(state_); + ++input_ptr_; + ++column_; + state_ = json_parse_state::cr; + return; + case '\n': + end_fraction_value(handler, ec); + if (ec) return; + ++input_ptr_; + ++line_; + column_ = 1; + return; + case ' ':case '\t': + end_fraction_value(handler, ec); + if (ec) return; + skip_space(); + return; + case '/': + end_fraction_value(handler, ec); + if (ec) return; + push_state(state_); + ++input_ptr_; + ++column_; + state_ = json_parse_state::slash; + return; + case '}': + end_fraction_value(handler, ec); + if (ec) return; + state_ = json_parse_state::expect_comma_or_end; + return; + case ']': + end_fraction_value(handler, ec); + if (ec) return; + state_ = json_parse_state::expect_comma_or_end; + return; + case ',': + end_fraction_value(handler, ec); + if (ec) return; + begin_member_or_element(ec); + if (ec) return; + ++input_ptr_; + ++column_; + return; + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + string_buffer_.push_back(static_cast(*input_ptr_)); + ++input_ptr_; + ++column_; + goto fraction2; + case 'e':case 'E': + string_buffer_.push_back(static_cast(*input_ptr_)); + ++input_ptr_; + ++column_; + goto exp1; + default: + err_handler_.fatal_error(json_errc::invalid_number, *this); + ec = json_errc::invalid_number; + continue_ = false; + state_ = json_parse_state::fraction2; + return; + } +exp1: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = json_parse_state::exp1; + return; + } + switch (*input_ptr_) + { + case '+': + ++input_ptr_; + ++column_; + goto exp2; + case '-': + string_buffer_.push_back(static_cast(*input_ptr_)); + ++input_ptr_; + ++column_; + goto exp2; + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + string_buffer_.push_back(static_cast(*input_ptr_)); + ++input_ptr_; + ++column_; + goto exp3; + default: + err_handler_.fatal_error(json_errc::expected_value, *this); + ec = json_errc::expected_value; + continue_ = false; + state_ = json_parse_state::exp1; + return; + } +exp2: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = json_parse_state::exp2; + return; + } + switch (*input_ptr_) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + string_buffer_.push_back(static_cast(*input_ptr_)); + ++input_ptr_; + ++column_; + goto exp3; + default: + err_handler_.fatal_error(json_errc::expected_value, *this); + ec = json_errc::expected_value; + continue_ = false; + state_ = json_parse_state::exp2; + return; + } + +exp3: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = json_parse_state::exp3; + return; + } + switch (*input_ptr_) + { + case '\r': + end_fraction_value(handler, ec); + if (ec) return; + ++input_ptr_; + ++column_; + push_state(state_); + state_ = json_parse_state::cr; + return; + case '\n': + end_fraction_value(handler, ec); + if (ec) return; + ++input_ptr_; + ++line_; + column_ = 1; + return; + case ' ':case '\t': + end_fraction_value(handler, ec); + if (ec) return; + skip_space(); + return; + case '/': + end_fraction_value(handler, ec); + if (ec) return; + push_state(state_); + ++input_ptr_; + ++column_; + state_ = json_parse_state::slash; + return; + case '}': + end_fraction_value(handler, ec); + if (ec) return; + state_ = json_parse_state::expect_comma_or_end; + return; + case ']': + end_fraction_value(handler, ec); + if (ec) return; + state_ = json_parse_state::expect_comma_or_end; + return; + case ',': + end_fraction_value(handler, ec); + if (ec) return; + begin_member_or_element(ec); + if (ec) return; + ++input_ptr_; + ++column_; + return; + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + string_buffer_.push_back(static_cast(*input_ptr_)); + ++input_ptr_; + ++column_; + goto exp3; + default: + err_handler_.fatal_error(json_errc::invalid_number, *this); + ec = json_errc::invalid_number; + continue_ = false; + state_ = json_parse_state::exp3; + return; + } + + JSONCONS_UNREACHABLE(); + } + + void parse_string(basic_json_content_handler& handler, std::error_code& ec) + { + const CharT* local_input_end = input_end_; + const CharT* sb = input_ptr_; + + switch (state_) + { + case json_parse_state::string: + goto string_u1; + case json_parse_state::escape: + goto escape; + case json_parse_state::escape_u1: + goto escape_u1; + case json_parse_state::escape_u2: + goto escape_u2; + case json_parse_state::escape_u3: + goto escape_u3; + case json_parse_state::escape_u4: + goto escape_u4; + case json_parse_state::escape_expect_surrogate_pair1: + goto escape_expect_surrogate_pair1; + case json_parse_state::escape_expect_surrogate_pair2: + goto escape_expect_surrogate_pair2; + case json_parse_state::escape_u6: + goto escape_u6; + case json_parse_state::escape_u7: + goto escape_u7; + case json_parse_state::escape_u8: + goto escape_u8; + case json_parse_state::escape_u9: + goto escape_u9; + default: + JSONCONS_UNREACHABLE(); + } + +string_u1: + while (input_ptr_ < local_input_end) + { + switch (*input_ptr_) + { + JSONCONS_ILLEGAL_CONTROL_CHARACTER: + { + column_ += (input_ptr_ - sb + 1); + continue_ = err_handler_.error(json_errc::illegal_control_character, *this); + if (!continue_) + { + ec = json_errc::illegal_control_character; + state_ = json_parse_state::string; + return; + } + // recovery - skip + string_buffer_.append(sb,input_ptr_-sb); + ++input_ptr_; + state_ = json_parse_state::string; + return; + } + case '\r': + { + column_ += (input_ptr_ - sb + 1); + continue_ = err_handler_.error(json_errc::illegal_character_in_string, *this); + if (!continue_) + { + ec = json_errc::illegal_character_in_string; + state_ = json_parse_state::string; + return; + } + // recovery - keep + string_buffer_.append(sb, input_ptr_ - sb + 1); + ++input_ptr_; + push_state(state_); + state_ = json_parse_state::cr; + return; + } + case '\n': + { + ++line_; + column_ = 1; + continue_ = err_handler_.error(json_errc::illegal_character_in_string, *this); + if (!continue_) + { + ec = json_errc::illegal_character_in_string; + state_ = json_parse_state::string; + return; + } + // recovery - keep + string_buffer_.append(sb, input_ptr_ - sb + 1); + ++input_ptr_; + return; + } + case '\t': + { + column_ += (input_ptr_ - sb + 1); + continue_ = err_handler_.error(json_errc::illegal_character_in_string, *this); + if (!continue_) + { + ec = json_errc::illegal_character_in_string; + state_ = json_parse_state::string; + return; + } + // recovery - keep + string_buffer_.append(sb, input_ptr_ - sb + 1); + ++input_ptr_; + state_ = json_parse_state::string; + return; + } + case '\\': + { + string_buffer_.append(sb,input_ptr_-sb); + column_ += (input_ptr_ - sb + 1); + ++input_ptr_; + goto escape; + } + case '\"': + { + if (string_buffer_.length() == 0) + { + end_string_value(sb,input_ptr_-sb, handler, ec); + if (ec) {return;} + } + else + { + string_buffer_.append(sb,input_ptr_-sb); + end_string_value(string_buffer_.data(),string_buffer_.length(), handler, ec); + if (ec) {return;} + } + column_ += (input_ptr_ - sb + 1); + ++input_ptr_; + return; + } + default: + break; + } + ++input_ptr_; + } + + // Buffer exhausted + { + string_buffer_.append(sb,input_ptr_-sb); + column_ += (input_ptr_ - sb + 1); + state_ = json_parse_state::string; + return; + } + +escape: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = json_parse_state::escape; + return; + } + switch (*input_ptr_) + { + case '\"': + string_buffer_.push_back('\"'); + sb = ++input_ptr_; + ++column_; + goto string_u1; + case '\\': + string_buffer_.push_back('\\'); + sb = ++input_ptr_; + ++column_; + goto string_u1; + case '/': + string_buffer_.push_back('/'); + sb = ++input_ptr_; + ++column_; + goto string_u1; + case 'b': + string_buffer_.push_back('\b'); + sb = ++input_ptr_; + ++column_; + goto string_u1; + case 'f': + string_buffer_.push_back('\f'); + sb = ++input_ptr_; + ++column_; + goto string_u1; + case 'n': + string_buffer_.push_back('\n'); + sb = ++input_ptr_; + ++column_; + goto string_u1; + case 'r': + string_buffer_.push_back('\r'); + sb = ++input_ptr_; + ++column_; + goto string_u1; + case 't': + string_buffer_.push_back('\t'); + sb = ++input_ptr_; + ++column_; + goto string_u1; + case 'u': + cp_ = 0; + ++input_ptr_; + ++column_; + goto escape_u1; + default: + err_handler_.fatal_error(json_errc::illegal_escaped_character, *this); + ec = json_errc::illegal_escaped_character; + continue_ = false; + state_ = json_parse_state::escape; + return; + } + +escape_u1: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = json_parse_state::escape_u1; + return; + } + { + append_codepoint(*input_ptr_,ec); + if (ec) + { + state_ = json_parse_state::escape_u1; + return; + } + ++input_ptr_; + ++column_; + goto escape_u2; + } + +escape_u2: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = json_parse_state::escape_u2; + return; + } + { + append_codepoint(*input_ptr_, ec); + if (ec) + { + state_ = json_parse_state::escape_u2; + return; + } + ++input_ptr_; + ++column_; + goto escape_u3; + } + +escape_u3: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = json_parse_state::escape_u3; + return; + } + { + append_codepoint(*input_ptr_, ec); + if (ec) + { + state_ = json_parse_state::escape_u3; + return; + } + ++input_ptr_; + ++column_; + goto escape_u4; + } + +escape_u4: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = json_parse_state::escape_u4; + return; + } + { + append_codepoint(*input_ptr_, ec); + if (ec) + { + state_ = json_parse_state::escape_u4; + return; + } + if (unicons::is_high_surrogate(cp_)) + { + ++input_ptr_; + ++column_; + goto escape_expect_surrogate_pair1; + } + else + { + unicons::convert(&cp_, &cp_ + 1, std::back_inserter(string_buffer_)); + sb = ++input_ptr_; + ++column_; + state_ = json_parse_state::string; + return; + } + } + +escape_expect_surrogate_pair1: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = json_parse_state::escape_expect_surrogate_pair1; + return; + } + { + switch (*input_ptr_) + { + case '\\': + cp2_ = 0; + ++input_ptr_; + ++column_; + goto escape_expect_surrogate_pair2; + default: + err_handler_.fatal_error(json_errc::expected_codepoint_surrogate_pair, *this); + ec = json_errc::expected_codepoint_surrogate_pair; + continue_ = false; + state_ = json_parse_state::escape_expect_surrogate_pair1; + return; + } + } + +escape_expect_surrogate_pair2: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = json_parse_state::escape_expect_surrogate_pair2; + return; + } + { + switch (*input_ptr_) + { + case 'u': + ++input_ptr_; + ++column_; + goto escape_u6; + default: + err_handler_.fatal_error(json_errc::expected_codepoint_surrogate_pair, *this); + ec = json_errc::expected_codepoint_surrogate_pair; + continue_ = false; + state_ = json_parse_state::escape_expect_surrogate_pair2; + return; + } + } + +escape_u6: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = json_parse_state::escape_u6; + return; + } + { + append_second_codepoint(*input_ptr_, ec); + if (ec) + { + state_ = json_parse_state::escape_u6; + return; + } + } + ++input_ptr_; + ++column_; + goto escape_u7; + +escape_u7: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = json_parse_state::escape_u7; + return; + } + { + append_second_codepoint(*input_ptr_, ec); + if (ec) + { + state_ = json_parse_state::escape_u7; + return; + } + ++input_ptr_; + ++column_; + goto escape_u8; + } + +escape_u8: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = json_parse_state::escape_u8; + return; + } + { + append_second_codepoint(*input_ptr_, ec); + if (ec) + { + state_ = json_parse_state::escape_u8; + return; + } + ++input_ptr_; + ++column_; + goto escape_u9; + } + +escape_u9: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = json_parse_state::escape_u9; + return; + } + { + append_second_codepoint(*input_ptr_, ec); + if (ec) + { + state_ = json_parse_state::escape_u9; + return; + } + uint32_t cp = 0x10000 + ((cp_ & 0x3FF) << 10) + (cp2_ & 0x3FF); + unicons::convert(&cp, &cp + 1, std::back_inserter(string_buffer_)); + sb = ++input_ptr_; + ++column_; + goto string_u1; + } + + JSONCONS_UNREACHABLE(); + } + + void translate_conv_errc(unicons::conv_errc result, std::error_code& ec) + { + switch (result) + { + case unicons::conv_errc(): + break; + case unicons::conv_errc::over_long_utf8_sequence: + continue_ = err_handler_.error(json_errc::over_long_utf8_sequence, *this); + if (!continue_) + { + ec = json_errc::over_long_utf8_sequence; + return; + } + break; + case unicons::conv_errc::unpaired_high_surrogate: + continue_ = err_handler_.error(json_errc::unpaired_high_surrogate, *this); + if (!continue_) + { + ec = json_errc::unpaired_high_surrogate; + return; + } + break; + case unicons::conv_errc::expected_continuation_byte: + continue_ = err_handler_.error(json_errc::expected_continuation_byte, *this); + if (!continue_) + { + ec = json_errc::expected_continuation_byte; + return; + } + break; + case unicons::conv_errc::illegal_surrogate_value: + continue_ = err_handler_.error(json_errc::illegal_surrogate_value, *this); + if (!continue_) + { + ec = json_errc::illegal_surrogate_value; + return; + } + break; + default: + continue_ = err_handler_.error(json_errc::illegal_codepoint, *this); + if (!continue_) + { + ec = json_errc::illegal_codepoint; + return; + } + break; + } + } + +#if !defined(JSONCONS_NO_DEPRECATED) + + void end_parse(basic_json_content_handler& handler) + { + std::error_code ec; + finish_parse(handler, ec); + if (ec) + { + throw ser_error(ec,line_,column_); + } + } + + void end_parse(basic_json_content_handler& handler, std::error_code& ec) + { + while (!finished()) + { + parse_some(handler, ec); + } + } + + void set_source(const CharT* data, size_t length) + { + begin_input_ = data; + input_end_ = data + length; + input_ptr_ = begin_input_; + } +#endif + + size_t line() const override + { + return line_; + } + + size_t column() const override + { + return column_; + } +private: + + void end_integer_value(basic_json_content_handler& handler, std::error_code& ec) + { + if (string_buffer_[0] == '-') + { + end_negative_value(handler, ec); + } + else + { + end_positive_value(handler, ec); + } + } + + void end_negative_value(basic_json_content_handler& handler, std::error_code& ec) + { + auto result = jsoncons::detail::to_integer(string_buffer_.data(), string_buffer_.length()); + if (result.ec == jsoncons::detail::to_integer_errc()) + { + continue_ = handler.int64_value(result.value, semantic_tag::none, *this); + } + else // Must be overflow + { + continue_ = handler.string_value(string_buffer_, semantic_tag::bigint, *this); + } + after_value(ec); + } + + void end_positive_value(basic_json_content_handler& handler, std::error_code& ec) + { + auto result = jsoncons::detail::to_integer(string_buffer_.data(), string_buffer_.length()); + if (result.ec == jsoncons::detail::to_integer_errc()) + { + continue_ = handler.uint64_value(result.value, semantic_tag::none, *this); + } + else // Must be overflow + { + continue_ = handler.string_value(string_buffer_, semantic_tag::bigint, *this); + } + after_value(ec); + } + + void end_fraction_value(basic_json_content_handler& handler, std::error_code& ec) + { + try + { + if (options_.lossless_number()) + { + continue_ = handler.string_value(string_buffer_, semantic_tag::bigdec, *this); + } + else + { + double d = to_double_(string_buffer_.c_str(), string_buffer_.length()); + continue_ = handler.double_value(d, semantic_tag::none, *this); + } + } + catch (...) + { + continue_ = err_handler_.error(json_errc::invalid_number, *this); + if (!continue_) + { + ec = json_errc::invalid_number; + return; + } + continue_ = handler.null_value(semantic_tag::none, *this); // recovery + } + + after_value(ec); + } + + void append_codepoint(int c, std::error_code& ec) + { + switch (c) + { + case '0': case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + case 'a':case 'b':case 'c':case 'd':case 'e':case 'f': + case 'A':case 'B':case 'C':case 'D':case 'E':case 'F': + cp_ = append_to_codepoint(cp_, c, ec); + if (ec) return; + break; + default: + continue_ = err_handler_.error(json_errc::expected_value, *this); + if (!continue_) + { + ec = json_errc::expected_value; + return; + } + break; + } + } + + void append_second_codepoint(int c, std::error_code& ec) + { + switch (c) + { + case '0': + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + case 'a':case 'b':case 'c':case 'd':case 'e':case 'f': + case 'A':case 'B':case 'C':case 'D':case 'E':case 'F': + cp2_ = append_to_codepoint(cp2_, c, ec); + if (ec) return; + break; + default: + continue_ = err_handler_.error(json_errc::expected_value, *this); + if (!continue_) + { + ec = json_errc::expected_value; + return; + } + break; + } + } + + void end_string_value(const CharT* s, size_t length, basic_json_content_handler& handler, std::error_code& ec) + { + auto result = unicons::validate(s,s+length); + if (result.ec != unicons::conv_errc()) + { + translate_conv_errc(result.ec,ec); + column_ += (result.it - s); + return; + } + switch (parent()) + { + case json_parse_state::member_name: + continue_ = handler.name(string_view_type(s, length), *this); + state_ = pop_state(); + state_ = json_parse_state::expect_colon; + break; + case json_parse_state::object: + case json_parse_state::array: + continue_ = handler.string_value(string_view_type(s, length), semantic_tag::none, *this); + state_ = json_parse_state::expect_comma_or_end; + break; + case json_parse_state::root: + continue_ = handler.string_value(string_view_type(s, length), semantic_tag::none, *this); + state_ = json_parse_state::before_done; + break; + default: + continue_ = err_handler_.error(json_errc::invalid_json_text, *this); + if (!continue_) + { + ec = json_errc::invalid_json_text; + return; + } + break; + } + } + + void begin_member_or_element(std::error_code& ec) + { + switch (parent()) + { + case json_parse_state::object: + state_ = json_parse_state::expect_member_name; + break; + case json_parse_state::array: + state_ = json_parse_state::expect_value; + break; + case json_parse_state::root: + break; + default: + continue_ = err_handler_.error(json_errc::invalid_json_text, *this); + if (!continue_) + { + ec = json_errc::invalid_json_text; + return; + } + break; + } + } + + void after_value(std::error_code& ec) + { + switch (parent()) + { + case json_parse_state::array: + case json_parse_state::object: + state_ = json_parse_state::expect_comma_or_end; + break; + case json_parse_state::root: + state_ = json_parse_state::before_done; + break; + default: + continue_ = err_handler_.error(json_errc::invalid_json_text, *this); + if (!continue_) + { + ec = json_errc::invalid_json_text; + return; + } + break; + } + } + + void push_state(json_parse_state state) + { + state_stack_.push_back(state); + } + + json_parse_state pop_state() + { + JSONCONS_ASSERT(!state_stack_.empty()) + json_parse_state state = state_stack_.back(); + state_stack_.pop_back(); + return state; + } + + uint32_t append_to_codepoint(uint32_t cp, int c, std::error_code& ec) + { + cp *= 16; + if (c >= '0' && c <= '9') + { + cp += c - '0'; + } + else if (c >= 'a' && c <= 'f') + { + cp += c - 'a' + 10; + } + else if (c >= 'A' && c <= 'F') + { + cp += c - 'A' + 10; + } + else + { + continue_ = err_handler_.error(json_errc::invalid_hex_escape_sequence, *this); + if (!continue_) + { + ec = json_errc::invalid_hex_escape_sequence; + return cp; + } + } + return cp; + } +}; + +typedef basic_json_parser json_parser; +typedef basic_json_parser wjson_parser; + +} + +#endif + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_pull_reader.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_pull_reader.hpp new file mode 100644 index 0000000000..4a9b58a685 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_pull_reader.hpp @@ -0,0 +1,13 @@ +// Copyright 2018 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_PULL_READER_HPP +#define JSONCONS_JSON_PULL_READER_HPP + +#include + +#endif + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_reader.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_reader.hpp new file mode 100644 index 0000000000..d67d1ec12f --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_reader.hpp @@ -0,0 +1,514 @@ +// Copyright 2015 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_READER_HPP +#define JSONCONS_JSON_READER_HPP + +#include // std::allocator +#include +#include +#include +#include +#include +#include // std::move +#include +#include +#include +#include +#include + +namespace jsoncons { + +// utf8_other_json_input_adapter + +template +class json_utf8_other_content_handler_adapter : public json_content_handler +{ +public: + using json_content_handler::string_view_type; +private: + basic_null_json_content_handler default_content_handler_; + basic_json_content_handler& other_handler_; + //parse_error_handler& err_handler_; + + // noncopyable and nonmoveable + json_utf8_other_content_handler_adapter(const json_utf8_other_content_handler_adapter&) = delete; + json_utf8_other_content_handler_adapter& operator=(const json_utf8_other_content_handler_adapter&) = delete; + +public: + json_utf8_other_content_handler_adapter() + : other_handler_(default_content_handler_) + { + } + + json_utf8_other_content_handler_adapter(basic_json_content_handler& other_handler/*, + parse_error_handler& err_handler*/) + : other_handler_(other_handler)/*, + err_handler_(err_handler)*/ + { + } + +private: + + void do_flush() override + { + other_handler_.flush(); + } + + bool do_begin_object(semantic_tag tag, const ser_context& context) override + { + return other_handler_.begin_object(tag, context); + } + + bool do_end_object(const ser_context& context) override + { + return other_handler_.end_object(context); + } + + bool do_begin_array(semantic_tag tag, const ser_context& context) override + { + return other_handler_.begin_array(tag, context); + } + + bool do_end_array(const ser_context& context) override + { + return other_handler_.end_array(context); + } + + bool do_name(const string_view_type& name, const ser_context& context) override + { + std::basic_string target; + auto result = unicons::convert( + name.begin(), name.end(), std::back_inserter(target), + unicons::conv_flags::strict); + if (result.ec != unicons::conv_errc()) + { + throw ser_error(result.ec,context.line(),context.column()); + } + return other_handler_.name(target, context); + } + + bool do_string_value(const string_view_type& value, semantic_tag tag, const ser_context& context) override + { + std::basic_string target; + auto result = unicons::convert( + value.begin(), value.end(), std::back_inserter(target), + unicons::conv_flags::strict); + if (result.ec != unicons::conv_errc()) + { + throw ser_error(result.ec,context.line(),context.column()); + } + return other_handler_.string_value(target, tag, context); + } + + bool do_int64_value(int64_t value, + semantic_tag tag, + const ser_context& context) override + { + return other_handler_.int64_value(value, tag, context); + } + + bool do_uint64_value(uint64_t value, + semantic_tag tag, + const ser_context& context) override + { + return other_handler_.uint64_value(value, tag, context); + } + + bool do_double_value(double value, + semantic_tag tag, + const ser_context& context) override + { + return other_handler_.double_value(value, tag, context); + } + + bool do_bool_value(bool value, semantic_tag tag, const ser_context& context) override + { + return other_handler_.bool_value(value, tag, context); + } + + bool do_null_value(semantic_tag tag, const ser_context& context) override + { + return other_handler_.null_value(tag, context); + } +}; + +template,class Allocator=std::allocator> +class basic_json_reader +{ +public: + typedef CharT char_type; + typedef Src source_type; + typedef basic_string_view string_view_type; + typedef Allocator allocator_type; +private: + typedef typename std::allocator_traits:: template rebind_alloc char_allocator_type; + + static const size_t default_max_buffer_length = 16384; + + basic_null_json_content_handler default_content_handler_; + default_parse_error_handler default_err_handler_; + + basic_json_content_handler& handler_; + + basic_json_parser parser_; + + source_type source_; + std::vector buffer_; + size_t buffer_length_; + bool eof_; + bool begin_; + + // Noncopyable and nonmoveable + basic_json_reader(const basic_json_reader&) = delete; + basic_json_reader& operator=(const basic_json_reader&) = delete; + +public: + template + explicit basic_json_reader(Source&& source) + : basic_json_reader(std::forward(source), + default_content_handler_, + basic_json_options::default_options(), + default_err_handler_) + { + } + + template + basic_json_reader(Source&& source, + const basic_json_decode_options& options) + : basic_json_reader(std::forward(source), + default_content_handler_, + options, + default_err_handler_) + { + } + + template + basic_json_reader(Source&& source, + parse_error_handler& err_handler) + : basic_json_reader(std::forward(source), + default_content_handler_, + basic_json_options::default_options(), + err_handler) + { + } + + template + basic_json_reader(Source&& source, + const basic_json_decode_options& options, + parse_error_handler& err_handler) + : basic_json_reader(std::forward(source), + default_content_handler_, + options, + err_handler) + { + } + + template + basic_json_reader(Source&& source, + basic_json_content_handler& handler) + : basic_json_reader(std::forward(source), + handler, + basic_json_options::default_options(), + default_err_handler_) + { + } + + template + basic_json_reader(Source&& source, + basic_json_content_handler& handler, + const basic_json_decode_options& options) + : basic_json_reader(std::forward(source), + handler, + options, + default_err_handler_) + { + } + + template + basic_json_reader(Source&& source, + basic_json_content_handler& handler, + parse_error_handler& err_handler) + : basic_json_reader(std::forward(source), + handler, + basic_json_options::default_options(), + err_handler) + { + } + + template + basic_json_reader(Source&& source, + basic_json_content_handler& handler, + const basic_json_decode_options& options, + parse_error_handler& err_handler, + typename std::enable_if,Source>::value>::type* = 0) + : handler_(handler), + parser_(options,err_handler), + source_(std::forward(source)), + buffer_length_(default_max_buffer_length), + eof_(false), + begin_(true) + { + buffer_.reserve(buffer_length_); + } + + template + basic_json_reader(Source&& source, + basic_json_content_handler& handler, + const basic_json_decode_options& options, + parse_error_handler& err_handler, + typename std::enable_if,Source>::value>::type* = 0) + : handler_(handler), + parser_(options,err_handler), + buffer_length_(0), + eof_(false), + begin_(false) + { + basic_string_view sv(std::forward(source)); + auto result = unicons::skip_bom(sv.begin(), sv.end()); + if (result.ec != unicons::encoding_errc()) + { + throw ser_error(result.ec,parser_.line(),parser_.column()); + } + size_t offset = result.it - sv.begin(); + parser_.update(sv.data()+offset,sv.size()-offset); + } + + size_t buffer_length() const + { + return buffer_length_; + } + + void buffer_length(size_t length) + { + buffer_length_ = length; + buffer_.reserve(buffer_length_); + } +#if !defined(JSONCONS_NO_DEPRECATED) + size_t max_nesting_depth() const + { + return parser_.max_nesting_depth(); + } + + void max_nesting_depth(size_t depth) + { + parser_.max_nesting_depth(depth); + } +#endif + void read_next() + { + std::error_code ec; + read_next(ec); + if (ec) + { + throw ser_error(ec,parser_.line(),parser_.column()); + } + } + + void read_next(std::error_code& ec) + { + try + { + if (source_.is_error()) + { + ec = json_errc::source_error; + return; + } + parser_.reset(); + while (!parser_.finished()) + { + if (parser_.source_exhausted()) + { + if (!source_.eof()) + { + read_buffer(ec); + if (ec) return; + } + else + { + eof_ = true; + } + } + parser_.parse_some(handler_, ec); + if (ec) return; + } + + while (!eof_) + { + parser_.skip_whitespace(); + if (parser_.source_exhausted()) + { + if (!source_.eof()) + { + read_buffer(ec); + if (ec) return; + } + else + { + eof_ = true; + } + } + else + { + break; + } + } + } + catch (const ser_error& e) + { + ec = e.code(); + } + } + + void check_done() + { + std::error_code ec; + check_done(ec); + if (ec) + { + throw ser_error(ec,parser_.line(),parser_.column()); + } + } + + size_t line() const + { + return parser_.line(); + } + + size_t column() const + { + return parser_.column(); + } + + void check_done(std::error_code& ec) + { + try + { + if (source_.is_error()) + { + ec = json_errc::source_error; + return; + } + if (eof_) + { + parser_.check_done(ec); + if (ec) return; + } + else + { + while (!eof_) + { + if (parser_.source_exhausted()) + { + if (!source_.eof()) + { + read_buffer(ec); + if (ec) return; + } + else + { + eof_ = true; + } + } + if (!eof_) + { + parser_.check_done(ec); + if (ec) return; + } + } + } + } + catch (const ser_error& e) + { + ec = e.code(); + } + } + + bool eof() const + { + return eof_; + } + + void read() + { + read_next(); + check_done(); + } + + void read(std::error_code& ec) + { + read_next(ec); + if (!ec) + { + check_done(ec); + } + } + +#if !defined(JSONCONS_NO_DEPRECATED) + + size_t buffer_capacity() const + { + return buffer_length_; + } + + void buffer_capacity(size_t length) + { + buffer_length_ = length; + buffer_.reserve(buffer_length_); + } + size_t max_depth() const + { + return parser_.max_nesting_depth(); + } + + void max_depth(size_t depth) + { + parser_.max_nesting_depth(depth); + } +#endif + +private: + + void read_buffer(std::error_code& ec) + { + buffer_.clear(); + buffer_.resize(buffer_length_); + size_t count = source_.read(buffer_.data(), buffer_length_); + buffer_.resize(static_cast(count)); + if (buffer_.size() == 0) + { + eof_ = true; + } + else if (begin_) + { + auto result = unicons::skip_bom(buffer_.begin(), buffer_.end()); + if (result.ec != unicons::encoding_errc()) + { + ec = result.ec; + return; + } + size_t offset = result.it - buffer_.begin(); + parser_.update(buffer_.data()+offset,buffer_.size()-offset); + begin_ = false; + } + else + { + parser_.update(buffer_.data(),buffer_.size()); + } + } +}; + +typedef basic_json_reader json_reader; +typedef basic_json_reader wjson_reader; +#if !defined(JSONCONS_NO_DEPRECATED) +typedef basic_json_reader> json_string_reader; +typedef basic_json_reader> wjson_string_reader; +#endif + +} + +#endif + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_serializer.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_serializer.hpp new file mode 100644 index 0000000000..2db2635cda --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_serializer.hpp @@ -0,0 +1,12 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_SERIALIZER_HPP +#define JSONCONS_JSON_SERIALIZER_HPP + +#include + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_type_traits.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_type_traits.hpp new file mode 100644 index 0000000000..d21995eca0 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_type_traits.hpp @@ -0,0 +1,1047 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_TYPE_TRAITS_HPP +#define JSONCONS_JSON_TYPE_TRAITS_HPP + +#include +#include +#include +#include +#include +#include +#include +#include // std::swap +#include // std::numeric_limits +#include // std::enable_if +#include // std::iterator_traits, std::input_iterator_tag +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace jsoncons { + + +template +struct is_basic_json_class : std::false_type +{}; + +#if defined(_MSC_VER) && _MSC_VER < 1916 +template +struct is_basic_json_class::value && + !std::is_void::value && + !std::is_void::value>::type> : std::true_type +{}; +#else +template +struct is_basic_json_class>(),void())> : std::true_type +{}; +#endif + +template +struct is_json_type_traits_declared : public std::false_type +{}; + +#if !defined(JSONCONS_NO_DEPRECATED) +template +using is_json_type_traits_impl = is_json_type_traits_declared; +#endif + +// json_type_traits + +template +struct unimplemented : std::false_type +{}; + +template +struct json_type_traits +{ + typedef typename Json::allocator_type allocator_type; + + static constexpr bool is_compatible = false; + + static constexpr bool is(const Json&) + { + return false; + } + + static T as(const Json&) + { + static_assert(unimplemented::value, "as not implemented"); + } + + static Json to_json(const T&, allocator_type = allocator_type()) + { + static_assert(unimplemented::value, "to_json not implemented"); + } +}; + +namespace detail { + +// is_incompatible +template +struct is_incompatible : std::false_type {}; + + +// is_incompatible +template +struct is_incompatible::is_compatible>::value>::type +> : std::true_type {}; + +// is_compatible_string_type +template +struct is_compatible_string_type : std::false_type {}; + +template +struct is_compatible_string_type::value && + jsoncons::detail::is_string_like::value && + !is_incompatible::value_type>::value +>::type> : std::true_type {}; + +// is_compatible_string_view_type +template +struct is_compatible_string_view_type : std::false_type {}; + +template +struct is_compatible_string_view_type::value && + jsoncons::detail::is_string_view_like::value && + !is_incompatible::value_type>::value +>::type> : std::true_type {}; + +// is_compatible_array_type +template +struct is_compatible_array_type : std::false_type {}; + +template +struct is_compatible_array_type::value && + jsoncons::detail::is_vector_like::value && + !is_incompatible::value_type>::value +>::type> : std::true_type {}; + +// is_compatible_object_type +template +struct is_compatible_object_type : std::false_type {}; + +template +struct is_compatible_object_type::value +>::type> : std::true_type {}; + +template +class json_array_input_iterator +{ +public: + typedef typename Json::const_array_iterator iterator_base; + typedef typename std::iterator_traits::value_type value_type; + typedef typename std::iterator_traits::difference_type difference_type; + typedef typename std::iterator_traits::pointer pointer; + typedef T reference; + typedef std::input_iterator_tag iterator_category; + + json_array_input_iterator() + { + } + + json_array_input_iterator(iterator_base it) + : it_(it) + { + } + + json_array_input_iterator& operator=(json_array_input_iterator rhs) + { + swap(*this,rhs); + return *this; + } + + json_array_input_iterator& operator++() + { + ++it_; + return *this; + } + + json_array_input_iterator operator++(int) // postfix increment + { + json_array_input_iterator temp(*this); + ++it_; + return temp; + } + + json_array_input_iterator& operator--() + { + --it_; + return *this; + } + + json_array_input_iterator operator--(int) + { + json_array_input_iterator temp(*this); + --it_; + return temp; + } + + reference operator*() const + { + return json_type_traits::as(*it_); + } + + friend bool operator==(const json_array_input_iterator& it1, const json_array_input_iterator& it2) + { + return it1.it_ == it2.it_; + } + friend bool operator!=(const json_array_input_iterator& it1, const json_array_input_iterator& it2) + { + return !(it1.it_ == it2.it_); + } + friend void swap(json_array_input_iterator& lhs, json_array_input_iterator& rhs) + { + using std::swap; + swap(lhs.it_,rhs.it_); + swap(lhs.empty_,rhs.empty_); + } + +private: + iterator_base it_; +}; + +template +class json_object_input_iterator +{ +public: + typedef typename Json::const_object_iterator iterator_base; + typedef typename std::iterator_traits::value_type value_type; + typedef typename std::iterator_traits::difference_type difference_type; + typedef typename std::iterator_traits::pointer pointer; + typedef T reference; + typedef std::input_iterator_tag iterator_category; + typedef typename T::first_type key_type; + typedef typename T::second_type mapped_type; + + json_object_input_iterator() + { + } + + json_object_input_iterator(iterator_base it) + : it_(it) + { + } + + json_object_input_iterator& operator=(json_object_input_iterator rhs) + { + swap(*this,rhs); + return *this; + } + + json_object_input_iterator& operator++() + { + ++it_; + return *this; + } + + json_object_input_iterator operator++(int) // postfix increment + { + json_object_input_iterator temp(*this); + ++it_; + return temp; + } + + json_object_input_iterator& operator--() + { + --it_; + return *this; + } + + json_object_input_iterator operator--(int) + { + json_object_input_iterator temp(*this); + --it_; + return temp; + } + + reference operator*() const + { + return T(key_type(it_->key()),json_type_traits::as(it_->value())); + } + + friend bool operator==(const json_object_input_iterator& it1, const json_object_input_iterator& it2) + { + return it1.it_ == it2.it_; + } + friend bool operator!=(const json_object_input_iterator& it1, const json_object_input_iterator& it2) + { + return !(it1.it_ == it2.it_); + } + friend void swap(json_object_input_iterator& lhs, json_object_input_iterator& rhs) + { + using std::swap; + swap(lhs.it_,rhs.it_); + swap(lhs.empty_,rhs.empty_); + } + +private: + iterator_base it_; +}; + +} + +template +struct json_type_traits::const_pointer_type> +{ + typedef typename Json::char_type char_type; + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) noexcept + { + return j.is_string(); + } + static const char_type* as(const Json& j) + { + return j.as_cstring(); + } + template + static Json to_json(const char_type* s, Args&&... args) + { + return Json(s, semantic_tag::none, std::forward(args)...); + } +}; + +template +struct json_type_traits::pointer_type> +{ + typedef typename Json::char_type char_type; + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) noexcept + { + return j.is_string(); + } + template + static Json to_json(const char_type* s, Args&&... args) + { + return Json(s, semantic_tag::none, std::forward(args)...); + } +}; + +// integral + +template +struct json_type_traits::value +>::type> +{ + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) noexcept + { + if (j.is_int64()) + { + return (j.template as_integer() >= (std::numeric_limits::lowest)()) && (j.template as_integer() <= (std::numeric_limits::max)()); + } + else if (j.is_uint64()) + { + return j.template as_integer() <= static_cast((std::numeric_limits::max)()); + } + else + { + return false; + } + } + static T as(const Json& j) + { + return j.template as_integer(); + } + static Json to_json(T val, allocator_type = allocator_type()) + { + return Json(val, semantic_tag::none); + } +}; + +template +struct json_type_traits::value>::type> +{ + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) noexcept + { + if (j.is_int64()) + { + return j.template as_integer() >= 0 && static_cast(j.template as_integer()) <= (std::numeric_limits::max)(); + } + else if (j.is_uint64()) + { + return j.template as_integer() <= (std::numeric_limits::max)(); + } + else + { + return false; + } + } + + static T as(const Json& j) + { + return j.template as_integer(); + } + + static Json to_json(T val, allocator_type = allocator_type()) + { + return Json(val, semantic_tag::none); + } +}; + +template +struct json_type_traits::value +>::type> +{ + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) noexcept + { + return j.is_double(); + } + static T as(const Json& j) + { + return static_cast(j.as_double()); + } + static Json to_json(T val, allocator_type = allocator_type()) + { + return Json(val, semantic_tag::none); + } +}; + +template +struct json_type_traits +{ + typedef typename Json::object json_object; + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) noexcept + { + return j.is_object(); + } + static Json to_json(const json_object& o) + { + return Json(o,semantic_tag::none); + } +}; + +template +struct json_type_traits +{ + typedef typename Json::array json_array; + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) noexcept + { + return j.is_array(); + } + static Json to_json(const json_array& a) + { + return Json(a, semantic_tag::none); + } +}; + +template +struct json_type_traits +{ + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json&) noexcept + { + return true; + } + static Json as(Json j) + { + return j; + } + static Json to_json(const Json& val, allocator_type = allocator_type()) + { + return val; + } +}; + +template +struct json_type_traits +{ + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) noexcept + { + return j.is_null(); + } + static typename jsoncons::null_type as(const Json& j) + { + JSONCONS_ASSERT(j.is_null()); + return jsoncons::null_type(); + } + static Json to_json(jsoncons::null_type, allocator_type = allocator_type()) + { + return Json::null(); + } +}; + +template +struct json_type_traits +{ + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) noexcept + { + return j.is_bool(); + } + static bool as(const Json& j) + { + return j.as_bool(); + } + static Json to_json(bool val, allocator_type = allocator_type()) + { + return Json(val, semantic_tag::none); + } +}; + +template +struct json_type_traits::const_reference>::value, + std::vector::const_reference, + void>::type>::value>::type> +{ + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) noexcept + { + return j.is_bool(); + } + static bool as(const Json& j) + { + return j.as_bool(); + } + static Json to_json(bool val, allocator_type = allocator_type()) + { + return Json(val, semantic_tag::none); + } +}; + +template +struct json_type_traits::reference> +{ + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) noexcept + { + return j.is_bool(); + } + static bool as(const Json& j) + { + return j.as_bool(); + } + static Json to_json(bool val, allocator_type = allocator_type()) + { + return Json(val, semantic_tag::none); + } +}; + +template +struct json_type_traits::value && jsoncons::detail::is_compatible_array_type::value>::type> +{ + typedef typename std::iterator_traits::value_type element_type; + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) noexcept + { + bool result = j.is_array(); + if (result) + { + for (auto e : j.array_range()) + { + if (!e.template is()) + { + result = false; + break; + } + } + } + return result; + } + + template + static typename std::enable_if::value && !std::is_same::value),T>::type + as(const Json& j) + { + if (j.is_array()) + { + T v(jsoncons::detail::json_array_input_iterator(j.array_range().begin()), + jsoncons::detail::json_array_input_iterator(j.array_range().end())); + return v; + } + else + { + JSONCONS_THROW(json_runtime_error("Attempt to cast json non-array to array")); + } + } + + template + static typename std::enable_if::value && !std::is_same::value,T>::type + as(const Json& j) + { + if (j.is_array()) + { + T v(jsoncons::detail::json_array_input_iterator(j.array_range().begin()), + jsoncons::detail::json_array_input_iterator(j.array_range().end())); + return v; + } + else if (j.is_byte_string_view()) + { + T v(j.as_byte_string_view().begin(),j.as_byte_string_view().end()); + return v; + } + else if (j.is_byte_string()) + { + auto s = j.as_byte_string(); + T v(s.begin(),s.end()); + return v; + } + else + { + JSONCONS_THROW(json_runtime_error("Attempt to cast json non-array to array")); + } + } + + static Json to_json(const T& val) + { + Json j = typename Json::array(); + auto first = std::begin(val); + auto last = std::end(val); + size_t size = std::distance(first,last); + j.reserve(size); + for (auto it = first; it != last; ++it) + { + j.push_back(*it); + } + return j; + } + + static Json to_json(const T& val, const allocator_type& allocator) + { + Json j = typename Json::array(allocator); + auto first = std::begin(val); + auto last = std::end(val); + size_t size = std::distance(first, last); + j.reserve(size); + for (auto it = first; it != last; ++it) + { + j.push_back(*it); + } + return j; + } +}; + +template +struct json_type_traits::value && jsoncons::detail::is_compatible_string_type::value>::type> +{ + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) noexcept + { + return j.is_string(); + } + + static T as(const Json& j) + { + return T(j.as_string()); + } + + static Json to_json(const T& val) + { + return Json(val, semantic_tag::none); + } + + static Json to_json(const T& val, const allocator_type& allocator) + { + return Json(val, semantic_tag::none, allocator); + } +}; + +template +struct json_type_traits::value && jsoncons::detail::is_compatible_string_view_type::value>::type> +{ + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) noexcept + { + return j.is_string_view(); + } + + static T as(const Json& j) + { + return T(j.as_string_view().data(),j.as_string_view().size()); + } + + static Json to_json(const T& val) + { + return Json(val, semantic_tag::none); + } + + static Json to_json(const T& val, const allocator_type& allocator) + { + return Json(val, semantic_tag::none, allocator); + } +}; + +template +struct json_type_traits::value && jsoncons::detail::is_compatible_object_type::value>::type +> +{ + typedef typename T::mapped_type mapped_type; + typedef typename T::value_type value_type; + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) noexcept + { + bool result = j.is_object(); + for (auto member : j.object_range()) + { + if (!member.value().template is()) + { + result = false; + } + } + return result; + } + + static T as(const Json& j) + { + T v(jsoncons::detail::json_object_input_iterator(j.object_range().begin()), + jsoncons::detail::json_object_input_iterator(j.object_range().end())); + return v; + } + + static Json to_json(const T& val) + { + Json j = typename Json::object(val.begin(), val.end()); + return j; + } + + static Json to_json(const T& val, const allocator_type& allocator) + { + Json j = typename Json::object(val.begin(), val.end(), allocator); + return j; + } +}; + +template +struct json_type_traits> +{ + typedef typename Json::allocator_type allocator_type; + + typedef E element_type; + + static bool is(const Json& j) noexcept + { + bool result = j.is_array() && j.size() == N; + if (result) + { + for (auto e : j.array_range()) + { + if (!e.template is()) + { + result = false; + break; + } + } + } + return result; + } + + static std::array as(const Json& j) + { + std::array buff; + JSONCONS_ASSERT(j.size() == N); + for (size_t i = 0; i < N; i++) + { + buff[i] = j[i].template as(); + } + return buff; + } + + static Json to_json(const std::array& val) + { + Json j = typename Json::array(); + j.reserve(N); + for (auto it = val.begin(); it != val.end(); ++it) + { + j.push_back(*it); + } + return j; + } + + static Json to_json(const std::array& val, + const allocator_type& allocator) + { + Json j = typename Json::array(allocator); + j.reserve(N); + for (auto it = val.begin(); it != val.end(); ++it) + { + j.push_back(*it); + } + return j; + } +}; + +namespace detail +{ + +template +struct json_tuple_helper +{ + using element_type = typename std::tuple_element::type; + using next = json_tuple_helper; + + static bool is(const Json& j) noexcept + { + if(j[Pos - 1].template is()) + { + return next::is(j); + } + else + { + return false; + } + } + + static void as(Tuple& tuple, const Json& j) + { + std::get(tuple) = j[Pos - 1].template as(); + next::as(tuple, j); + } + + static void to_json(const Tuple& tuple, std::array::value>& jsons) + { + jsons[Pos - 1] = json_type_traits::to_json(std::get(tuple)); + next::to_json(tuple, jsons); + } +}; + +template +struct json_tuple_helper<0, Json, Tuple> +{ + static bool is(const Json&) noexcept + { + return true; + } + + static void as(Tuple&, const Json&) + { + } + + static void to_json(const Tuple&, std::array::value>&) + { + } +}; + +} + +template +struct json_type_traits> +{ +private: + using helper = jsoncons::detail::json_tuple_helper>; + +public: + static bool is(const Json& j) noexcept + { + return helper::is(j); + } + + static std::tuple as(const Json& j) + { + std::tuple buff; + helper::as(buff, j); + return buff; + } + + static Json to_json(const std::tuple& val) + { + std::array buf; + helper::to_json(val, buf); + return Json(typename Json::array(buf.begin(), buf.end())); + } +}; + +template +struct json_type_traits> +{ +public: + static bool is(const Json& j) noexcept + { + return j.is_array() && j.size() == 2; + } + + static std::pair as(const Json& j) + { + return std::make_pair(j[0].template as(),j[1].template as()); + } + + static Json to_json(const std::pair& val) + { + return typename Json::array{val.first,val.second}; + } +}; + +template +struct json_type_traits> +{ +public: + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) noexcept + { + return j.is_byte_string(); + } + + static basic_byte_string as(const Json& j) + { + return j.template as_byte_string(); + } + + static Json to_json(const basic_byte_string& val, + const allocator_type& allocator = allocator_type()) + { + return Json(val, semantic_tag::none, allocator); + } +}; + +template +struct json_type_traits +{ +public: + static bool is(const Json& j) noexcept + { + return j.is_byte_string_view(); + } + + static byte_string_view as(const Json& j) + { + return j.as_byte_string_view(); + } + + static Json to_json(const byte_string_view& val) + { + return Json(val); + } +}; + +// basic_bignum + +template +struct json_type_traits> +{ +public: + static bool is(const Json& j) noexcept + { + return j.is_bignum(); + } + + static basic_bignum as(const Json& j) + { + return j.as_bignum(); + } + + static Json to_json(const basic_bignum& val) + { + std::basic_string s; + val.dump(s); + return Json(s,semantic_tag::bigint); + } +}; + +// std::valarray + +template +struct json_type_traits> +{ + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) noexcept + { + bool result = j.is_array(); + if (result) + { + for (auto e : j.array_range()) + { + if (!e.template is()) + { + result = false; + break; + } + } + } + return result; + } + + static std::valarray as(const Json& j) + { + if (j.is_array()) + { + std::valarray v(j.size()); + for (size_t i = 0; i < j.size(); ++i) + { + v[i] = j[i].template as(); + } + return v; + } + else + { + JSONCONS_THROW(json_runtime_error("Attempt to cast json non-array to array")); + } + } + + static Json to_json(const std::valarray& val) + { + Json j = typename Json::array(); + auto first = std::begin(val); + auto last = std::end(val); + size_t size = std::distance(first,last); + j.reserve(size); + for (auto it = first; it != last; ++it) + { + j.push_back(*it); + } + return j; + } + + static Json to_json(const std::valarray& val, const allocator_type& allocator) + { + Json j = typename Json::array(allocator); + auto first = std::begin(val); + auto last = std::end(val); + size_t size = std::distance(first,last); + j.reserve(size); + for (auto it = first; it != last; ++it) + { + j.push_back(*it); + } + return j; + } +}; + +} // jsoncons + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_type_traits_macros.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_type_traits_macros.hpp new file mode 100644 index 0000000000..8d29fed0c3 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/json_type_traits_macros.hpp @@ -0,0 +1,181 @@ +// Copyright 2019 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_TYPE_TRAITS_MACROS_HPP +#define JSONCONS_JSON_TYPE_TRAITS_MACROS_HPP + +#include +#include +#include +#include +#include +#include +#include +#include // std::swap +#include // std::numeric_limits +#include // std::enable_if +#include // std::iterator_traits, std::input_iterator_tag +#include +#include +#include +#include +#include +#include +#include +#include + +// This follows https://github.com/Loki-Astari/ThorsSerializer/blob/master/src/Serialize/Traits.h + +#define JSONCONS_EXPAND(X) X + +#define JSONCONS_NARGS(...) JSONCONS_NARG_(__VA_ARGS__, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) +#define JSONCONS_NARG_(...) JSONCONS_EXPAND( JSONCONS_ARG_N(__VA_ARGS__) ) +#define JSONCONS_ARG_N(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15, e16, e17, e18, e19, e20, e21, e22, e23, e24, e25, e26, e27, e28, e29, e30, e31, e32, e33, e34, e35, e36, e37, e38, e39, e40, e41, e42, e43, e44, e45, e46, e47, e48, e49, e50, N, ...) N + +#define JSONCONS_QUOTE(A) JSONCONS_EXPAND(#A) + +#define JSONCONS_GENERATE(Call, TC, JVal, TVal, P2) Call(TC, JVal, TVal, P2) + +#define JSONCONS_REP_N(Call, TC, JVal, TVal, ...) JSONCONS_REP_OF_N(Call, TC, JVal, TVal, JSONCONS_NARGS(__VA_ARGS__), __VA_ARGS__) +#define JSONCONS_REP_OF_N(Call, TC, JVal, TVal, Count, ...) JSONCONS_REP_OF_N_(Call, TC, JVal, TVal, Count, __VA_ARGS__) +#define JSONCONS_REP_OF_N_(Call, TC, JVal, TVal, Count, ...) JSONCONS_EXPAND(JSONCONS_REP_OF_ ## Count(Call, TC, JVal, TVal, __VA_ARGS__)) + +#define JSONCONS_REP_OF_50(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_49(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_49(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_48(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_48(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_47(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_47(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_46(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_46(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_45(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_45(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_44(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_44(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_43(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_43(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_42(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_42(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_41(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_41(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_40(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_40(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_39(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_39(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_38(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_38(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_37(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_37(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_36(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_36(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_35(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_35(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_34(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_34(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_33(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_33(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_32(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_32(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_31(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_31(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_30(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_30(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_29(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_29(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_28(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_28(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_27(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_27(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_26(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_26(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_25(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_25(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_24(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_24(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_23(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_23(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_22(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_22(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_21(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_21(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_20(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_20(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_19(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_19(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_18(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_18(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_17(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_17(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_16(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_16(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_15(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_15(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_14(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_14(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_13(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_13(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_12(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_12(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_11(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_11(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_10(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_10(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_9(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_9(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_8(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_8(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_7(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_7(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_6(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_6(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_5(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_5(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_4(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_4(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_3(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_3(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal ,P2) JSONCONS_EXPAND(JSONCONS_REP_OF_2(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_2(Call, TC, JVal, TVal, P2, ...) JSONCONS_GENERATE(Call, TC, JVal, TVal, P2) JSONCONS_EXPAND(JSONCONS_REP_OF_1(Call, TC, JVal, TVal, __VA_ARGS__)) +#define JSONCONS_REP_OF_1(Call, TC, JVal, TVal, P2) JSONCONS_EXPAND(Call ## _LAST(TC, JVal, TVal, P2)) + +#define JSONCONS_IS(TC, JVal, TVal, Member) if (!(JVal).contains(JSONCONS_QUOTE(Member))) return false; +#define JSONCONS_IS_LAST(TC, JVal, TVal, Member) if (!(JVal).contains(JSONCONS_QUOTE(Member))) return false; + +#define JSONCONS_TO_JSON(TC, JVal, TVal, Member) (JVal).try_emplace(JSONCONS_QUOTE(Member), TVal.Member); +#define JSONCONS_TO_JSON_LAST(TC, JVal, TVal, Member) (JVal).try_emplace(JSONCONS_QUOTE(Member), TVal.Member); + +#define JSONCONS_AS(TC, JVal, TVal, Member) if ((JVal).contains(JSONCONS_QUOTE(Member))) {val.Member = (JVal).at(JSONCONS_QUOTE(Member)).template as();} +#define JSONCONS_AS_LAST(TC, JVal, TVal, Member) if ((JVal).contains(JSONCONS_QUOTE(Member))) {val.Member = (JVal).at(JSONCONS_QUOTE(Member)).template as();} + +#define JSONCONS_MEMBER_TRAITS_DECL(ValueType, ...) \ +namespace jsoncons \ +{ \ + template \ + struct json_type_traits \ + { \ + typedef ValueType value_type; \ + typedef typename Json::allocator_type allocator_type; \ + static bool is(const Json& j) noexcept \ + { \ + if (!j.is_object()) return false; \ + JSONCONS_REP_N(JSONCONS_IS, 0, j, void(), __VA_ARGS__)\ + return true; \ + } \ + static ValueType as(const Json& j) \ + { \ + ValueType val{}; \ + JSONCONS_REP_N(JSONCONS_AS, 0, j, val, __VA_ARGS__) \ + return val; \ + } \ + static Json to_json(const ValueType& val, allocator_type allocator=allocator_type()) \ + { \ + Json j(allocator); \ + JSONCONS_REP_N(JSONCONS_TO_JSON, 0, j, val, __VA_ARGS__) \ + return j; \ + } \ + }; \ +} \ + /**/ + +#define JSONCONS_IS2(TC, JVal, TVal, Member) if (!(JVal).contains(JSONCONS_QUOTE(Member))) return false; +#define JSONCONS_IS2_LAST(TC, JVal, TVal, Member) if (!(JVal).contains(JSONCONS_QUOTE(Member))) return false; + +#define JSONCONS_TO_JSON2(TC, JVal, TVal, Member) (JVal).try_emplace(JSONCONS_QUOTE(Member), TVal.Member() ); +#define JSONCONS_TO_JSON2_LAST(TC, JVal, TVal, Member) (JVal).try_emplace(JSONCONS_QUOTE(Member), TVal.Member() ); + +#define JSONCONS_AS2(TC, JVal, TVal, Member) ((JVal).at(JSONCONS_QUOTE(Member))).template asMember())>::type>(), +#define JSONCONS_AS2_LAST(TC, JVal, TVal, Member) ((JVal).at(JSONCONS_QUOTE(Member))).template asMember())>::type>() + +#define JSONCONS_GETTER_CTOR_TRAITS_DECL(ValueType, ...) \ +namespace jsoncons \ +{ \ + template \ + struct json_type_traits \ + { \ + typedef ValueType value_type; \ + typedef typename Json::allocator_type allocator_type; \ + static bool is(const Json& j) noexcept \ + { \ + if (!j.is_object()) return false; \ + JSONCONS_REP_N(JSONCONS_IS2, 0, j, void(), __VA_ARGS__)\ + return true; \ + } \ + static value_type as(const Json& j) \ + { \ + return value_type ( JSONCONS_REP_N(JSONCONS_AS2, 0, j, void(), __VA_ARGS__) ); \ + } \ + static Json to_json(const value_type& val, allocator_type allocator=allocator_type()) \ + { \ + Json j(allocator); \ + JSONCONS_REP_N(JSONCONS_TO_JSON2, 0, j, val, __VA_ARGS__) \ + return j; \ + } \ + }; \ +} \ + /**/ + +#define JSONCONS_TYPE_TRAITS_FRIEND \ + template \ + friend struct jsoncons::json_type_traits + +#if !defined(JSONCONS_NO_DEPRECATED) +#define JSONCONS_TYPE_TRAITS_DECL JSONCONS_MEMBER_TRAITS_DECL +#endif + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/parse_error_handler.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/parse_error_handler.hpp new file mode 100644 index 0000000000..0f8b86e948 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/parse_error_handler.hpp @@ -0,0 +1,74 @@ +/// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_PARSE_ERROR_HANDLER_HPP +#define JSONCONS_PARSE_ERROR_HANDLER_HPP + +#include +#include +#include + +namespace jsoncons { + +class parse_error_handler +{ +public: + virtual ~parse_error_handler() + { + } + + bool error(std::error_code ec, + const ser_context& context) noexcept + { + return do_error(ec,context); + } + + void fatal_error(std::error_code ec, + const ser_context& context) noexcept + { + do_fatal_error(ec,context); + } + +private: + virtual bool do_error(std::error_code, + const ser_context& context) noexcept = 0; + + virtual void do_fatal_error(std::error_code, + const ser_context&) noexcept + { + } +}; + +class default_parse_error_handler : public parse_error_handler +{ +private: + bool do_error(std::error_code code, + const ser_context&) noexcept override + { + static const std::error_code illegal_comment = make_error_code(json_errc::illegal_comment); + + if (code == illegal_comment) + { + return true; // Recover, allow comments + } + else + { + return false; + } + } +}; + +class strict_parse_error_handler : public parse_error_handler +{ +private: + bool do_error(std::error_code, const ser_context&) noexcept override + { + return false; + } +}; + +} +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/pretty_print.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/pretty_print.hpp new file mode 100644 index 0000000000..4ddf20eec2 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/pretty_print.hpp @@ -0,0 +1,89 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_PRETTY_PRINT_HPP +#define JSONCONS_PRETTY_PRINT_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace jsoncons { + +template +class json_printable +{ +public: + typedef typename Json::char_type char_type; + + json_printable(const Json& j, indenting line_indent) + : j_(&j), indenting_(line_indent) + { + } + + json_printable(const Json& j, + const basic_json_options& options, + indenting line_indent) + : j_(&j), options_(options), indenting_(line_indent) + { + } + + void dump(std::basic_ostream& os) const + { + j_->dump(os, options_, indenting_); + } + + friend std::basic_ostream& operator<<(std::basic_ostream& os, const json_printable& pr) + { + pr.dump(os); + return os; + } + + const Json *j_; + basic_json_options options_; + indenting indenting_; +private: + json_printable(); +}; + +template +json_printable print(const Json& j) +{ + return json_printable(j, indenting::no_indent); +} + +template +json_printable print(const Json& j, + const basic_json_options& options) +{ + return json_printable(j, options, indenting::no_indent); +} + +template +json_printable pretty_print(const Json& j) +{ + return json_printable(j, indenting::indent); +} + +template +json_printable pretty_print(const Json& j, + const basic_json_options& options) +{ + return json_printable(j, options, indenting::indent); +} + +} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/result.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/result.hpp new file mode 100644 index 0000000000..d53341f2fe --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/result.hpp @@ -0,0 +1,284 @@ +// Copyright 2018 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_RESULT_HPP +#define JSONCONS_RESULT_HPP + +#include +#include +#include +#include +#include +#include +#include // std::addressof +#include // std::memcpy +#include +#include + +namespace jsoncons { + +// stream_result + +template +class stream_result +{ +public: + typedef CharT value_type; + typedef std::basic_ostream output_type; + +private: + static const size_t default_buffer_length = 16384; + + std::basic_ostream* os_; + std::vector buffer_; + CharT * begin_buffer_; + const CharT* end_buffer_; + CharT* p_; + + // Noncopyable + stream_result(const stream_result&) = delete; + stream_result& operator=(const stream_result&) = delete; + +public: + stream_result(stream_result&&) = default; + + stream_result(std::basic_ostream& os) + : os_(std::addressof(os)), buffer_(default_buffer_length), begin_buffer_(buffer_.data()), end_buffer_(begin_buffer_+buffer_.size()), p_(begin_buffer_) + { + } + stream_result(std::basic_ostream& os, size_t buflen) + : os_(std::addressof(os)), buffer_(buflen), begin_buffer_(buffer_.data()), end_buffer_(begin_buffer_+buffer_.size()), p_(begin_buffer_) + { + } + ~stream_result() + { + os_->write(begin_buffer_, buffer_length()); + os_->flush(); + } + + stream_result& operator=(stream_result&&) = default; + + void flush() + { + os_->write(begin_buffer_, buffer_length()); + os_->flush(); + p_ = buffer_.data(); + } + + void append(const CharT* s, size_t length) + { + size_t diff = end_buffer_ - p_; + if (diff >= length) + { + std::memcpy(p_, s, length*sizeof(CharT)); + p_ += length; + } + else + { + os_->write(begin_buffer_, buffer_length()); + os_->write(s,length); + p_ = begin_buffer_; + } + } + + void push_back(CharT ch) + { + if (p_ < end_buffer_) + { + *p_++ = ch; + } + else + { + os_->write(begin_buffer_, buffer_length()); + p_ = begin_buffer_; + push_back(ch); + } + } +private: + + size_t buffer_length() const + { + return p_ - begin_buffer_; + } +}; + +// binary_stream_result + +class binary_stream_result +{ +public: + typedef uint8_t value_type; + typedef std::basic_ostream output_type; +private: + static const size_t default_buffer_length = 16384; + + std::basic_ostream* os_; + std::vector buffer_; + uint8_t * begin_buffer_; + const uint8_t* end_buffer_; + uint8_t* p_; + + // Noncopyable + binary_stream_result(const binary_stream_result&) = delete; + binary_stream_result& operator=(const binary_stream_result&) = delete; + +public: + binary_stream_result(binary_stream_result&&) = default; + + binary_stream_result(std::basic_ostream& os) + : os_(std::addressof(os)), + buffer_(default_buffer_length), + begin_buffer_(buffer_.data()), + end_buffer_(begin_buffer_+buffer_.size()), + p_(begin_buffer_) + { + } + binary_stream_result(std::basic_ostream& os, size_t buflen) + : os_(std::addressof(os)), + buffer_(buflen), + begin_buffer_(buffer_.data()), + end_buffer_(begin_buffer_+buffer_.size()), + p_(begin_buffer_) + { + } + ~binary_stream_result() + { + os_->write((char*)begin_buffer_, buffer_length()); + os_->flush(); + } + + binary_stream_result& operator=(binary_stream_result&&) = default; + + void flush() + { + os_->write((char*)begin_buffer_, buffer_length()); + p_ = buffer_.data(); + } + + void append(const uint8_t* s, size_t length) + { + size_t diff = end_buffer_ - p_; + if (diff >= length) + { + std::memcpy(p_, s, length*sizeof(uint8_t)); + p_ += length; + } + else + { + os_->write((char*)begin_buffer_, buffer_length()); + os_->write((const char*)s,length); + p_ = begin_buffer_; + } + } + + void push_back(uint8_t ch) + { + if (p_ < end_buffer_) + { + *p_++ = ch; + } + else + { + os_->write((char*)begin_buffer_, buffer_length()); + p_ = begin_buffer_; + push_back(ch); + } + } +private: + + size_t buffer_length() const + { + return p_ - begin_buffer_; + } +}; + +// string_result + +template +class string_result +{ +public: + typedef typename StringT::value_type value_type; + typedef StringT output_type; +private: + output_type* s_; + + // Noncopyable + string_result(const string_result&) = delete; + string_result& operator=(const string_result&) = delete; +public: + string_result(string_result&& val) + : s_(nullptr) + { + std::swap(s_,val.s_); + } + + string_result(output_type& s) + : s_(std::addressof(s)) + { + } + + string_result& operator=(string_result&& val) + { + std::swap(s_, val.s_); + } + + void flush() + { + } + + void append(const value_type* s, size_t length) + { + s_->insert(s_->end(), s, s+length); + } + + void push_back(value_type ch) + { + s_->push_back(ch); + } +}; + +// bytes_result + +class bytes_result +{ +public: + typedef uint8_t value_type; + typedef std::vector output_type; +private: + output_type& s_; + + // Noncopyable + bytes_result(const bytes_result&) = delete; + bytes_result& operator=(const bytes_result&) = delete; +public: + bytes_result(bytes_result&&) = default; + + bytes_result(output_type& s) + : s_(s) + { + } + + bytes_result& operator=(bytes_result&&) = default; + + void flush() + { + } + + void append(const uint8_t* s, size_t length) + { + s_.insert(s_.end(), s, s+length); + } + + void push_back(uint8_t ch) + { + s_.push_back(ch); + } +}; + +} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/ser_context.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/ser_context.hpp new file mode 100644 index 0000000000..12397d0134 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/ser_context.hpp @@ -0,0 +1,50 @@ +/// Copyright 2013-2018 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_SER_CONTEXT_HPP +#define JSONCONS_SER_CONTEXT_HPP + +namespace jsoncons { + +class ser_context +{ +public: + virtual ~ser_context() = default; + + virtual size_t line() const = 0; + + virtual size_t column() const = 0; + +#if !defined(JSONCONS_NO_DEPRECATED) + size_t line_number() const + { + return line(); + } + + size_t column_number() const + { + return column(); + } +#endif +}; + +class null_ser_context : public ser_context +{ +private: + size_t line() const override { return 0; } + + size_t column() const override { return 0; } +}; + +#if !defined(JSONCONS_NO_DEPRECATED) +typedef ser_context parsing_context; +typedef ser_context serializing_context; +typedef null_ser_context null_parsing_context; +typedef null_ser_context null_serializing_context; +#endif + +} +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/source.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/source.hpp new file mode 100644 index 0000000000..f1feec5706 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/source.hpp @@ -0,0 +1,746 @@ +// Copyright 2018 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_SOURCE_HPP +#define JSONCONS_SOURCE_HPP + +#include +#include +#include +#include +#include // std::addressof +#include // std::memcpy +#include +#include // std::enable_if +#include +#include // jsoncons::byte_traits + +namespace jsoncons { + +template +class basic_null_istream : public std::basic_istream +{ + class null_buffer : public std::basic_streambuf + { + public: + using typename std::basic_streambuf::int_type; + using typename std::basic_streambuf::traits_type; + + null_buffer() = default; + null_buffer(const null_buffer&) = default; + null_buffer& operator=(const null_buffer&) = default; + + int_type overflow( int_type ch = traits_type::eof() ) override + { + return ch; + } + } nb_; +public: + basic_null_istream() + : std::basic_istream(&nb_) + { + } + basic_null_istream(basic_null_istream&&) = default; + + basic_null_istream& operator=(basic_null_istream&&) = default; +}; + +// text sources + +template +class stream_source +{ +public: + typedef CharT value_type; + typedef std::char_traits traits_type; +private: + basic_null_istream null_is_; + std::basic_istream* is_; + std::basic_streambuf* sbuf_; + size_t position_; + + // Noncopyable + stream_source(const stream_source&) = delete; + stream_source& operator=(const stream_source&) = delete; +public: + stream_source() + : is_(&null_is_), sbuf_(null_is_.rdbuf()), position_(0) + { + } + + stream_source(std::basic_istream& is) + : is_(std::addressof(is)), sbuf_(is.rdbuf()), position_(0) + { + } + + stream_source(stream_source&& other) + { + std::swap(is_,other.is_); + std::swap(sbuf_,other.sbuf_); + std::swap(position_,other.position_); + } + + ~stream_source() + { + } + + stream_source& operator=(stream_source&& other) + { + std::swap(is_,other.is_); + std::swap(sbuf_,other.sbuf_); + std::swap(position_,other.position_); + return *this; + } + + bool eof() const + { + return is_->eof(); + } + + bool is_error() const + { + return is_->bad(); + } + + size_t position() const + { + return position_; + } + + size_t get(value_type& c) + { + try + { + int val = sbuf_->sbumpc(); + if (!(val == traits_type::eof())) + { + c = (value_type)val; + ++position_; + return 1; + } + else + { + is_->clear(is_->rdstate() | std::ios::eofbit); + return 0; + } + } + catch (const std::exception&) + { + is_->clear(is_->rdstate() | std::ios::badbit | std::ios::eofbit); + return 0; + } + } + + int get() + { + try + { + int c = sbuf_->sbumpc(); + if (c == traits_type::eof()) + { + is_->clear(is_->rdstate() | std::ios::eofbit); + } + else + { + ++position_; + } + return c; + } + catch (const std::exception&) + { + is_->clear(is_->rdstate() | std::ios::badbit | std::ios::eofbit); + return traits_type::eof(); + } + } + + void ignore(size_t count) + { + try + { + for (size_t i = 0; i < count; ++i) + { + int c = sbuf_->sbumpc(); + if (c == traits_type::eof()) + { + is_->clear(is_->rdstate() | std::ios::eofbit); + return; + } + else + { + ++position_; + } + } + } + catch (const std::exception&) + { + is_->clear(is_->rdstate() | std::ios::badbit | std::ios::eofbit); + } + } + + int peek() + { + try + { + int c = sbuf_->sgetc(); + if (c == traits_type::eof()) + { + is_->clear(is_->rdstate() | std::ios::eofbit); + } + return c; + } + catch (const std::exception&) + { + is_->clear(is_->rdstate() | std::ios::badbit); + return traits_type::eof(); + } + } + + size_t read(value_type* p, size_t length) + { + try + { + std::streamsize count = sbuf_->sgetn(p, length); // never negative + if (static_cast(count) < length) + { + is_->clear(is_->rdstate() | std::ios::eofbit); + } + position_ += length; + return static_cast(count); + } + catch (const std::exception&) + { + is_->clear(is_->rdstate() | std::ios::badbit | std::ios::eofbit); + return 0; + } + } + + template + typename std::enable_if::value,size_t>::type + read(OutputIt p, size_t length) + { + size_t count = 0; + try + { + for (count = 0; count < length; ++count) + { + int c = sbuf_->sbumpc(); + if (c == traits_type::eof()) + { + is_->clear(is_->rdstate() | std::ios::eofbit); + return count; + } + else + { + ++position_; + } + *p++ = (value_type)c; + } + return count; + } + catch (const std::exception&) + { + is_->clear(is_->rdstate() | std::ios::badbit | std::ios::eofbit); + return count; + } + } +}; + +// string_source + +template +struct is_string_sourceable : std::false_type {}; + +template +struct is_string_sourceable::value>::type> : std::true_type {}; + +template +class string_source +{ +public: + typedef CharT value_type; + typedef std::char_traits traits_type; + typedef jsoncons::basic_string_view string_view_type; +private: + const value_type* data_; + const value_type* input_ptr_; + const value_type* input_end_; + bool eof_; + + // Noncopyable + string_source(const string_source&) = delete; + string_source& operator=(const string_source&) = delete; +public: + string_source() + : data_(nullptr), input_ptr_(nullptr), input_end_(nullptr), eof_(true) + { + } + + template + string_source(const Source& s, + typename std::enable_if::type>::value>::type* = 0) + : data_(s.data()), input_ptr_(s.data()), input_end_(s.data()+s.size()), eof_(s.size() == 0) + { + } + + string_source(const value_type* data, size_t size) + : data_(data), input_ptr_(data), input_end_(data+size), eof_(size == 0) + { + } + + string_source(string_source&& val) + : data_(nullptr), input_ptr_(nullptr), input_end_(nullptr), eof_(true) + { + std::swap(data_,val.data_); + std::swap(input_ptr_,val.input_ptr_); + std::swap(input_end_,val.input_end_); + std::swap(eof_,val.eof_); + } + + string_source& operator=(string_source&& val) + { + std::swap(data_,val.data_); + std::swap(input_ptr_,val.input_ptr_); + std::swap(input_end_,val.input_end_); + std::swap(eof_,val.eof_); + return *this; + } + + bool eof() const + { + return eof_; + } + + bool is_error() const + { + return false; + } + + size_t position() const + { + return (input_ptr_ - data_)/sizeof(value_type) + 1; + } + + size_t get(value_type& c) + { + if (input_ptr_ < input_end_) + { + c = *input_ptr_++; + return 1; + } + else + { + eof_ = true; + input_ptr_ = input_end_; + return 0; + } + } + + int get() + { + if (input_ptr_ < input_end_) + { + return *input_ptr_++; + } + else + { + eof_ = true; + input_ptr_ = input_end_; + return traits_type::eof(); + } + } + + void ignore(size_t count) + { + size_t len; + if ((size_t)(input_end_ - input_ptr_) < count) + { + len = input_end_ - input_ptr_; + eof_ = true; + } + else + { + len = count; + } + input_ptr_ += len; + } + + int peek() + { + return input_ptr_ < input_end_ ? *input_ptr_ : traits_type::eof(); + } + + size_t read(value_type* p, size_t length) + { + size_t len; + if ((size_t)(input_end_ - input_ptr_) < length) + { + len = input_end_ - input_ptr_; + eof_ = true; + } + else + { + len = length; + } + std::memcpy(p, input_ptr_, len*sizeof(value_type)); + input_ptr_ += len; + return len; + } + + template + typename std::enable_if::value,size_t>::type + read(OutputIt d_first, size_t count) + { + size_t len; + if ((size_t)(input_end_ - input_ptr_) < count) + { + len = input_end_ - input_ptr_; + eof_ = true; + } + else + { + len = count; + } + for (size_t i = 0; i < len; ++i) + { + *d_first++ = *input_ptr_++; + } + return len; + } +}; + +// binary sources + +class binary_stream_source +{ +public: + typedef uint8_t value_type; + typedef byte_traits traits_type; +private: + basic_null_istream null_is_; + std::istream* is_; + std::streambuf* sbuf_; + size_t position_; + + // Noncopyable + binary_stream_source(const binary_stream_source&) = delete; + binary_stream_source& operator=(const binary_stream_source&) = delete; +public: + binary_stream_source() + : is_(&null_is_), sbuf_(null_is_.rdbuf()), position_(0) + { + } + + binary_stream_source(std::istream& is) + : is_(std::addressof(is)), sbuf_(is.rdbuf()), position_(0) + { + } + + binary_stream_source(binary_stream_source&& other) + { + std::swap(is_,other.is_); + std::swap(sbuf_,other.sbuf_); + std::swap(position_,other.position_); + } + + ~binary_stream_source() + { + } + + binary_stream_source& operator=(binary_stream_source&& other) + { + std::swap(is_,other.is_); + std::swap(sbuf_,other.sbuf_); + std::swap(position_,other.position_); + return *this; + } + + bool eof() const + { + return is_->eof(); + } + + bool is_error() const + { + return is_->bad(); + } + + size_t position() const + { + return position_; + } + + size_t get(value_type& c) + { + try + { + int val = sbuf_->sbumpc(); + if (!(val == traits_type::eof())) + { + c = (value_type)val; + ++position_; + return 1; + } + else + { + is_->clear(is_->rdstate() | std::ios::eofbit); + return 0; + } + } + catch (const std::exception&) + { + is_->clear(is_->rdstate() | std::ios::badbit | std::ios::eofbit); + return 0; + } + } + + int get() + { + try + { + int c = sbuf_->sbumpc(); + if (c == traits_type::eof()) + { + is_->clear(is_->rdstate() | std::ios::eofbit); + } + else + { + ++position_; + } + return c; + } + catch (const std::exception&) + { + is_->clear(is_->rdstate() | std::ios::badbit | std::ios::eofbit); + return traits_type::eof(); + } + } + + void ignore(size_t count) + { + try + { + for (size_t i = 0; i < count; ++i) + { + int c = sbuf_->sbumpc(); + if (c == traits_type::eof()) + { + is_->clear(is_->rdstate() | std::ios::eofbit); + return; + } + else + { + ++position_; + } + } + } + catch (const std::exception&) + { + is_->clear(is_->rdstate() | std::ios::badbit | std::ios::eofbit); + } + } + + int peek() + { + try + { + int c = sbuf_->sgetc(); + if (c == traits_type::eof()) + { + is_->clear(is_->rdstate() | std::ios::eofbit); + } + return c; + } + catch (const std::exception&) + { + is_->clear(is_->rdstate() | std::ios::badbit); + return traits_type::eof(); + } + } + + template + size_t read(OutputIt p, size_t length) + { + size_t count = 0; + try + { + for (count = 0; count < length; ++count) + { + int c = sbuf_->sbumpc(); + if (c == traits_type::eof()) + { + is_->clear(is_->rdstate() | std::ios::eofbit); + return count; + } + else + { + ++position_; + } + *p++ = (value_type)c; + } + return count; + } + catch (const std::exception&) + { + is_->clear(is_->rdstate() | std::ios::badbit | std::ios::eofbit); + return count; + } + } +}; + +template +struct is_bytes_sourceable : std::false_type {}; + +template +struct is_bytes_sourceable::value>::type> : std::true_type {}; + +class bytes_source +{ +public: + typedef uint8_t value_type; + typedef byte_traits traits_type; +private: + const value_type* data_; + const value_type* input_ptr_; + const value_type* input_end_; + bool eof_; + + // Noncopyable + bytes_source(const bytes_source&) = delete; + bytes_source& operator=(const bytes_source&) = delete; +public: + bytes_source() + : data_(nullptr), input_ptr_(nullptr), input_end_(nullptr), eof_(true) + { + } + + template + bytes_source(const Source& s, + typename std::enable_if::type>::value>::type* = 0) + : data_(s.data()), + input_ptr_(s.data()), + input_end_(s.data()+s.size()), + eof_(s.size() == 0) + { + } + + bytes_source(const value_type* data, size_t size) + : data_(data), + input_ptr_(data), + input_end_(data+size), + eof_(size == 0) + { + } + + bytes_source(bytes_source&&) = default; + + bytes_source& operator=(bytes_source&&) = default; + + bool eof() const + { + return eof_; + } + + bool is_error() const + { + return false; + } + + size_t position() const + { + return input_ptr_ - data_ + 1; + } + + size_t get(value_type& c) + { + if (input_ptr_ < input_end_) + { + c = *input_ptr_++; + return 1; + } + else + { + eof_ = true; + input_ptr_ = input_end_; + return 0; + } + } + + int get() + { + if (input_ptr_ < input_end_) + { + return *input_ptr_++; + } + else + { + eof_ = true; + input_ptr_ = input_end_; + return traits_type::eof(); + } + } + + void ignore(size_t count) + { + size_t len; + if ((size_t)(input_end_ - input_ptr_) < count) + { + len = input_end_ - input_ptr_; + eof_ = true; + } + else + { + len = count; + } + input_ptr_ += len; + } + + int peek() + { + return input_ptr_ < input_end_ ? *input_ptr_ : traits_type::eof(); + } + + size_t read(value_type* p, size_t length) + { + size_t len; + if ((size_t)(input_end_ - input_ptr_) < length) + { + len = input_end_ - input_ptr_; + eof_ = true; + } + else + { + len = length; + } + std::memcpy(p, input_ptr_, len); + input_ptr_ += len; + return len; + } + + template + typename std::enable_if::value,size_t>::type + read(OutputIt d_first, size_t count) + { + size_t len; + if ((size_t)(input_end_ - input_ptr_) < count) + { + len = input_end_ - input_ptr_; + eof_ = true; + } + else + { + len = count; + } + for (size_t i = 0; i < len; ++i) + { + *d_first++ = *input_ptr_++; + } + return len; + } +}; + +} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/staj_iterator.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/staj_iterator.hpp new file mode 100644 index 0000000000..5937972952 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/staj_iterator.hpp @@ -0,0 +1,354 @@ +// Copyright 2018 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_STAJ_ITERATOR_HPP +#define JSONCONS_STAJ_ITERATOR_HPP + +#include +#include +#include +#include +#include +#include // std::input_iterator_tag +#include +#include +#include + +namespace jsoncons { + +template> +class basic_staj_array_iterator +{ + typedef CharT char_type; + + basic_staj_reader* reader_; + T value_; +public: + typedef T value_type; + typedef std::ptrdiff_t difference_type; + typedef T* pointer; + typedef T& reference; + typedef std::input_iterator_tag iterator_category; + + basic_staj_array_iterator() noexcept + : reader_(nullptr) + { + } + + basic_staj_array_iterator(basic_staj_reader& reader) + : reader_(std::addressof(reader)) + { + if (reader_->current().event_type() == staj_event_type::begin_array) + { + next(); + } + else + { + reader_ = nullptr; + } + } + + basic_staj_array_iterator(basic_staj_reader& reader, + std::error_code& ec) + : reader_(std::addressof(reader)) + { + if (reader_->current().event_type() == staj_event_type::begin_array) + { + next(ec); + if (ec) + { + reader_ = nullptr; + } + } + else + { + reader_ = nullptr; + } + } + + const T& operator*() const + { + return value_; + } + + const T* operator->() const + { + return &value_; + } + + basic_staj_array_iterator& operator++() + { + next(); + return *this; + } + + basic_staj_array_iterator& increment(std::error_code& ec) + { + next(ec); + if (ec) + { + reader_ = nullptr; + } + return *this; + } + + basic_staj_array_iterator operator++(int) // postfix increment + { + basic_staj_array_iterator temp(*this); + next(); + return temp; + } + + friend bool operator==(const basic_staj_array_iterator& a, const basic_staj_array_iterator& b) + { + return (!a.reader_ && !b.reader_) + || (!a.reader_ && b.done()) + || (!b.reader_ && a.done()); + } + + friend bool operator!=(const basic_staj_array_iterator& a, const basic_staj_array_iterator& b) + { + return !(a == b); + } + +private: + + bool done() const + { + return reader_->done() || reader_->current().event_type() == staj_event_type::end_array; + } + + void next(); + + void next(std::error_code& ec); +}; + +template +basic_staj_array_iterator begin(basic_staj_array_iterator iter) noexcept +{ + return iter; +} + +template +basic_staj_array_iterator end(const basic_staj_array_iterator&) noexcept +{ + return basic_staj_array_iterator(); +} + +template +class basic_staj_object_iterator +{ +public: + typedef CharT char_type; + typedef std::basic_string key_type; + typedef std::pair value_type; + typedef std::ptrdiff_t difference_type; + typedef value_type* pointer; + typedef value_type& reference; + typedef std::input_iterator_tag iterator_category; + +private: + basic_staj_reader* reader_; + value_type kv_; +public: + + basic_staj_object_iterator() noexcept + : reader_(nullptr) + { + } + + basic_staj_object_iterator(basic_staj_reader& reader) + : reader_(std::addressof(reader)) + { + if (reader_->current().event_type() == staj_event_type::begin_object) + { + next(); + } + else + { + reader_ = nullptr; + } + } + + basic_staj_object_iterator(basic_staj_reader& reader, + std::error_code& ec) + : reader_(std::addressof(reader)) + { + if (reader_->current().event_type() == staj_event_type::begin_object) + { + next(ec); + if (ec) + { + reader_ = nullptr; + } + } + else + { + reader_ = nullptr; + } + } + + const value_type& operator*() const + { + return kv_; + } + + const value_type* operator->() const + { + return &kv_; + } + + basic_staj_object_iterator& operator++() + { + next(); + return *this; + } + + basic_staj_object_iterator& increment(std::error_code& ec) + { + next(ec); + if (ec) + { + reader_ = nullptr; + } + return *this; + } + + basic_staj_object_iterator operator++(int) // postfix increment + { + basic_staj_object_iterator temp(*this); + next(); + return temp; + } + + friend bool operator==(const basic_staj_object_iterator& a, const basic_staj_object_iterator& b) + { + return (!a.reader_ && !b.reader_) + || (!a.reader_ && b.done()) + || (!b.reader_ && a.done()); + } + + friend bool operator!=(const basic_staj_object_iterator& a, const basic_staj_object_iterator& b) + { + return !(a == b); + } + +private: + + bool done() const + { + return reader_->done() || reader_->current().event_type() == staj_event_type::end_object; + } + + void next(); + + void next(std::error_code& ec); +}; + +template +basic_staj_object_iterator begin(basic_staj_object_iterator iter) noexcept +{ + return iter; +} + +template +basic_staj_object_iterator end(const basic_staj_object_iterator&) noexcept +{ + return basic_staj_object_iterator(); +} + +template +using staj_array_iterator = basic_staj_array_iterator; + +template +using wstaj_array_iterator = basic_staj_array_iterator; + +template +using staj_object_iterator = basic_staj_object_iterator; + +template +using wstaj_object_iterator = basic_staj_object_iterator; + +} + +#include + +namespace jsoncons { + +template +void basic_staj_array_iterator::next() +{ + if (!done()) + { + reader_->next(); + if (!done()) + { + read_from(Json(), *reader_, value_); + } + } +} + +template +void basic_staj_array_iterator::next(std::error_code& ec) +{ + if (!done()) + { + reader_->next(ec); + if (ec) + { + return; + } + if (!done()) + { + read_from(Json(), *reader_, value_, ec); + } + } +} + +template +void basic_staj_object_iterator::next() +{ + reader_->next(); + if (!done()) + { + JSONCONS_ASSERT(reader_->current().event_type() == staj_event_type::name); + kv_.first =reader_->current(). template as(); + reader_->next(); + if (!done()) + { + read_from(Json(), *reader_, kv_.second); + } + } +} + +template +void basic_staj_object_iterator::next(std::error_code& ec) +{ + reader_->next(ec); + if (ec) + { + return; + } + if (!done()) + { + JSONCONS_ASSERT(reader_->current().event_type() == staj_event_type::name); + kv_.first =reader_->current(). template as(); + reader_->next(ec); + if (ec) + { + return; + } + if (!done()) + { + read_from(Json(), *reader_, kv_.second, ec); + } + } +} + +} + +#endif + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/staj_reader.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/staj_reader.hpp new file mode 100644 index 0000000000..269437361f --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/staj_reader.hpp @@ -0,0 +1,434 @@ +// Copyright 2018 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_STAJ_READER_HPP +#define JSONCONS_STAJ_READER_HPP + +#include // std::allocator +#include +#include +#include +#include +#include // std::enable_if +#include // std::array +#include +#include +#include +#include +#include +#include +#include + +namespace jsoncons { + +enum class staj_event_type +{ + begin_array, + end_array, + begin_object, + end_object, + name, + string_value, + byte_string_value, + null_value, + bool_value, + int64_value, + uint64_value, + double_value +}; + +JSONCONS_STRING_LITERAL(null,'n','u','l','l') +JSONCONS_STRING_LITERAL(true,'t','r','u','e') +JSONCONS_STRING_LITERAL(false,'f','a','l','s','e') + +template +class basic_staj_event +{ + staj_event_type event_type_; + semantic_tag semantic_tag_; + union + { + bool bool_value_; + int64_t int64_value_; + uint64_t uint64_value_; + double double_value_; + const CharT* string_data_; + const uint8_t* byte_string_data_; + } value_; + size_t length_; +public: + basic_staj_event(staj_event_type event_type, semantic_tag semantic_tag = semantic_tag::none) + : event_type_(event_type), semantic_tag_(semantic_tag), length_(0) + { + } + + basic_staj_event(null_type) + : event_type_(staj_event_type::null_value), semantic_tag_(semantic_tag::none), length_(0) + { + } + + basic_staj_event(bool value) + : event_type_(staj_event_type::bool_value), semantic_tag_(semantic_tag::none), length_(0) + { + value_.bool_value_ = value; + } + + basic_staj_event(int64_t value, semantic_tag semantic_tag) + : event_type_(staj_event_type::int64_value), semantic_tag_(semantic_tag), length_(0) + { + value_.int64_value_ = value; + } + + basic_staj_event(uint64_t value, semantic_tag semantic_tag) + : event_type_(staj_event_type::uint64_value), semantic_tag_(semantic_tag), length_(0) + { + value_.uint64_value_ = value; + } + + basic_staj_event(double value, semantic_tag semantic_tag) + : event_type_(staj_event_type::double_value), semantic_tag_(semantic_tag), length_(0) + { + value_.double_value_ = value; + } + + basic_staj_event(const CharT* data, size_t length, + staj_event_type event_type, + semantic_tag semantic_tag = semantic_tag::none) + : event_type_(event_type), semantic_tag_(semantic_tag), length_(length) + { + value_.string_data_ = data; + } + + template + typename std::enable_if::value && std::is_same::value, T>::type + as() const + { + T s; + switch (event_type_) + { + case staj_event_type::name: + case staj_event_type::string_value: + s = T(value_.string_data_, length_); + break; + case staj_event_type::int64_value: + { + jsoncons::string_result result(s); + jsoncons::detail::print_integer(value_.int64_value_, result); + break; + } + case staj_event_type::uint64_value: + { + jsoncons::string_result result(s); + jsoncons::detail::print_uinteger(value_.uint64_value_, result); + break; + } + case staj_event_type::double_value: + { + jsoncons::string_result result(s); + jsoncons::detail::print_double f{ floating_point_options() }; + f(value_.double_value_, result); + break; + } + case staj_event_type::bool_value: + { + jsoncons::string_result result(s); + if (value_.bool_value_) + { + result.append(true_literal().data(),true_literal().size()); + } + else + { + result.append(false_literal().data(),false_literal().size()); + } + break; + } + case staj_event_type::null_value: + { + jsoncons::string_result result(s); + result.append(null_literal().data(),null_literal().size()); + break; + } + default: + JSONCONS_THROW(json_runtime_error("Not a string")); + } + return s; + } + + template + typename std::enable_if::value && std::is_same::value, T>::type + as() const + { + T s; + switch (event_type_) + { + case staj_event_type::name: + case staj_event_type::string_value: + s = T(value_.string_data_, length_); + break; + default: + JSONCONS_THROW(json_runtime_error("Not a string")); + } + return s; + } + + template + typename std::enable_if::value, T>::type + as() const + { + return static_cast(as_int64()); + } + + template + typename std::enable_if::value, T>::type + as() const + { + return static_cast(as_uint64()); + } + + template + typename std::enable_if::value, T>::type + as() const + { + return static_cast(as_double()); + } + + template> + typename std::enable_if>::value, T>::type + as() const + { + return as_bignum(); + } + + template + typename std::enable_if::value, T>::type + as() const + { + return as_bool(); + } + + staj_event_type event_type() const noexcept { return event_type_; } + + semantic_tag get_semantic_tag() const noexcept { return semantic_tag_; } +private: + + int64_t as_int64() const + { + int64_t value = 0; + switch (event_type_) + { + case staj_event_type::name: + case staj_event_type::string_value: + { + auto result = jsoncons::detail::to_integer(value_.string_data_, length_); + if (result.ec != jsoncons::detail::to_integer_errc()) + { + JSONCONS_THROW(json_runtime_error(make_error_code(result.ec).message())); + } + value = result.value; + break; + } + case staj_event_type::double_value: + value = static_cast(value_.double_value_); + break; + case staj_event_type::int64_value: + value = value_.int64_value_; + break; + case staj_event_type::uint64_value: + value = static_cast(value_.uint64_value_); + break; + case staj_event_type::bool_value: + value = value_.bool_value_ ? 1 : 0; + break; + default: + JSONCONS_THROW(json_runtime_error("Not an integer")); + } + return value; + } + + uint64_t as_uint64() const + { + uint64_t value = 0; + switch (event_type_) + { + case staj_event_type::name: + case staj_event_type::string_value: + { + auto result = jsoncons::detail::to_integer(value_.string_data_, length_); + if (result.ec != jsoncons::detail::to_integer_errc()) + { + JSONCONS_THROW(json_runtime_error(make_error_code(result.ec).message())); + } + value = result.value; + break; + } + case staj_event_type::double_value: + value = static_cast(value_.double_value_); + break; + case staj_event_type::int64_value: + value = static_cast(value_.int64_value_); + break; + case staj_event_type::uint64_value: + value = value_.uint64_value_; + break; + case staj_event_type::bool_value: + value = value_.bool_value_ ? 1 : 0; + break; + default: + JSONCONS_THROW(json_runtime_error("Not an unsigned integer")); + } + return value; + } + + double as_double() const + { + switch (event_type_) + { + case staj_event_type::name: + case staj_event_type::string_value: + { + std::string target; + auto result = unicons::convert( + value_.string_data_, value_.string_data_ + length_, std::back_inserter(target), unicons::conv_flags::strict); + if (result.ec != unicons::conv_errc()) + { + JSONCONS_THROW(json_runtime_error("Not a double")); + } + jsoncons::detail::string_to_double f; + return f(target.data(), target.length()); + } + case staj_event_type::double_value: + return value_.double_value_; + case staj_event_type::int64_value: + return static_cast(value_.int64_value_); + case staj_event_type::uint64_value: + return static_cast(value_.uint64_value_); + default: + JSONCONS_THROW(json_runtime_error("Not a double")); + } + } + + bool as_bool() const + { + switch (event_type_) + { + case staj_event_type::bool_value: + return value_.bool_value_; + case staj_event_type::double_value: + return value_.double_value_ != 0.0; + case staj_event_type::int64_value: + return value_.int64_value_ != 0; + case staj_event_type::uint64_value: + return value_.uint64_value_ != 0; + default: + JSONCONS_THROW(json_runtime_error("Not a bool")); + } + } + + template > + basic_bignum as_bignum() const + { + switch (event_type_) + { + case staj_event_type::string_value: + if (!jsoncons::detail::is_integer(value_.string_data_, length_)) + { + JSONCONS_THROW(json_runtime_error("Not a bignum")); + } + return basic_bignum(value_.string_data_, length_); + case staj_event_type::double_value: + return basic_bignum(value_.double_value_); + case staj_event_type::int64_value: + return basic_bignum(value_.int64_value_); + case staj_event_type::uint64_value: + return basic_bignum(value_.uint64_value_); + case staj_event_type::bool_value: + return basic_bignum(value_.bool_value_ ? 1 : 0); + default: + JSONCONS_THROW(json_runtime_error("Not a bignum")); + } + } + +}; + +template +class basic_staj_reader +{ +public: + virtual ~basic_staj_reader() = default; + + virtual bool done() const = 0; + + virtual const basic_staj_event& current() const = 0; + + virtual void accept(basic_json_content_handler& handler) = 0; + + virtual void accept(basic_json_content_handler& handler, + std::error_code& ec) = 0; + + virtual void next() = 0; + + virtual void next(std::error_code& ec) = 0; + + virtual const ser_context& context() const = 0; +}; + +template +class basic_staj_filter +{ +public: + + virtual ~basic_staj_filter() = default; + + virtual bool accept(const basic_staj_event& event, const ser_context& context) = 0; +}; + +template +class default_basic_staj_filter : public basic_staj_filter +{ +public: + bool accept(const basic_staj_event&, const ser_context&) override + { + return true; + } +}; + +typedef basic_staj_event staj_event; +typedef basic_staj_event wstaj_event; + +typedef basic_staj_reader staj_reader; +typedef basic_staj_reader wstaj_reader; + +typedef basic_staj_filter staj_filter; +typedef basic_staj_filter wstaj_filter; + +#if !defined(JSONCONS_NO_DEPRECATED) + +typedef staj_event_type stream_event_type; + +template +using basic_stream_event = basic_staj_event; + +template +using basic_stream_reader = basic_staj_reader; + +template +using basic_stream_filter = basic_staj_filter; + +typedef basic_staj_event stream_event; +typedef basic_staj_event wstream_event; + +typedef basic_staj_reader stream_reader; +typedef basic_staj_reader wstream_reader; + +typedef basic_staj_filter stream_filter; +typedef basic_staj_filter wstream_filter; + +#endif + +} + +#endif + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/unicode_traits.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/unicode_traits.hpp new file mode 100644 index 0000000000..56bc9e7aa6 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons/unicode_traits.hpp @@ -0,0 +1,1492 @@ +// Copyright 2016 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/unicode_traits for latest version + +/* + * Includes code derived from Unicode, Inc decomposition code in ConvertUTF.h and ConvertUTF.c + * http://www.unicode.org/ + * + * "Unicode, Inc. hereby grants the right to freely use the information + * supplied in this file in the creation of products supporting the + * Unicode Standard." +*/ + +#ifndef JSONCONS_UNICONS_UNICODE_TRAITS_HPP +#define JSONCONS_UNICONS_UNICODE_TRAITS_HPP + +#if defined(__clang__) +# define UNICONS_FALLTHROUGH [[clang::fallthrough]] +#elif defined(__GNUC__) && ((__GNUC__ >= 7)) +# define UNICONS_FALLTHROUGH __attribute__((fallthrough)) +#elif defined (__GNUC__) +# define UNICONS_FALLTHROUGH // FALLTHRU +#else +# define UNICONS_FALLTHROUGH +#endif + +#if defined (__clang__) +#if defined(_GLIBCXX_USE_NOEXCEPT) +#define UNICONS_NOEXCEPT _GLIBCXX_USE_NOEXCEPT +#else +#define UNICONS_NOEXCEPT noexcept +#endif +#elif defined(__GNUC__) +#define UNICONS_NOEXCEPT _GLIBCXX_USE_NOEXCEPT +#elif defined(_MSC_VER) +#if _MSC_VER >= 1900 +#define UNICONS_NOEXCEPT noexcept +#else +#define UNICONS_NOEXCEPT +#endif +#else +#define UNICONS_NOEXCEPT +#endif + +#include +#include +#include +#include + +namespace jsoncons { namespace unicons { + +/* + * Magic values subtracted from a buffer value during UTF8 conversion. + * This table contains as many values as there might be trailing bytes + * in a UTF-8 sequence. Source: ConvertUTF.c + */ +const uint32_t offsets_from_utf8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, + 0x03C82080UL, 0xFA082080UL, 0x82082080UL }; + +/* + * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed + * into the first byte, depending on how many bytes follow. There are + * as many entries in this table as there are UTF-8 sequence types. + * (I.e., one byte sequence, two byte... etc.). Remember that sequencs + * for *legal* UTF-8 will be 4 or fewer bytes total. Source: ConvertUTF.c + */ +const uint8_t first_byte_mark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + +/* + * Index into the table below with the first byte of a UTF-8 sequence to + * get the number of trailing bytes that are supposed to follow it. + * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is + * left as-is for anyone who may want to do such conversion, which was + * allowed in earlier algorithms. Source: ConvertUTF.c + */ +const uint8_t trailing_bytes_for_utf8[256] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 +}; + +// Some fundamental constants. Source: ConvertUTF.h +const uint32_t replacement_char = 0x0000FFFD; +const uint32_t max_bmp = 0x0000FFFF; +const uint32_t max_utf16 = 0x0010FFFF; +const uint32_t max_utf32 = 0x7FFFFFFF; +const uint32_t max_legal_utf32 = 0x0010FFFF; + +const int half_shift = 10; // used for shifting by 10 bits +const uint32_t half_base = 0x0010000UL; +const uint32_t half_mask = 0x3FFUL; + +const uint16_t sur_high_start = 0xD800; +const uint16_t sur_high_end = 0xDBFF; +const uint16_t sur_low_start = 0xDC00; +const uint16_t sur_low_end = 0xDFFF; + +inline +static bool is_continuation_byte(unsigned char ch) +{ + return (ch & 0xC0) == 0x80; +} + +inline +bool is_high_surrogate(uint32_t ch) UNICONS_NOEXCEPT +{ + return (ch >= sur_high_start && ch <= sur_high_end); +} + +inline +bool is_low_surrogate(uint32_t ch) UNICONS_NOEXCEPT +{ + return (ch >= sur_low_start && ch <= sur_low_end); +} + +inline +bool is_surrogate(uint32_t ch) UNICONS_NOEXCEPT +{ + return (ch >= sur_high_start && ch <= sur_low_end); +} + +enum class conv_flags +{ + strict = 0, + lenient +}; + +// conv_errc + +enum class conv_errc +{ + ok = 0, + over_long_utf8_sequence = 1, // over long utf8 sequence + expected_continuation_byte, // expected continuation byte + unpaired_high_surrogate, // unpaired high surrogate UTF-16 + illegal_surrogate_value, // UTF-16 surrogate values are illegal in UTF-32 + source_exhausted, // partial character in source, but hit end + source_illegal // source sequence is illegal/malformed +}; + +class Unicode_traits_error_category_impl_ + : public std::error_category +{ +public: + virtual const char* name() const UNICONS_NOEXCEPT + { + return "unicons conversion error"; + } + virtual std::string message(int ev) const + { + switch (static_cast(ev)) + { + case conv_errc::over_long_utf8_sequence: + return "Over long utf8 sequence"; + case conv_errc::expected_continuation_byte: + return "Expected continuation byte"; + case conv_errc::unpaired_high_surrogate: + return "Unpaired high surrogate UTF-16"; + case conv_errc::illegal_surrogate_value: + return "UTF-16 surrogate values are illegal in UTF-32"; + case conv_errc::source_exhausted: + return "Partial character in source, but hit end"; + case conv_errc::source_illegal: + return "Source sequence is illegal/malformed"; + default: + return ""; + break; + } + } +}; + +inline +const std::error_category& unicode_traits_error_category() +{ + static Unicode_traits_error_category_impl_ instance; + return instance; +} + +inline +std::error_code make_error_code(conv_errc result) +{ + return std::error_code(static_cast(result),unicode_traits_error_category()); +} + +// encoding_errc + +enum class encoding_errc +{ + ok = 0, + expected_u8_found_u16 = 1, + expected_u8_found_u32, + expected_u16_found_fffe, + expected_u32_found_fffe +}; + +class Encoding_errc_impl_ + : public std::error_category +{ +public: + virtual const char* name() const UNICONS_NOEXCEPT + { + return "unicons encoding error"; + } + virtual std::string message(int ev) const + { + switch (static_cast(ev)) + { + case encoding_errc::expected_u8_found_u16: + return "Expected UTF-8, found UTF-16"; + case encoding_errc::expected_u8_found_u32: + return "Expected UTF-8, found UTF-32"; + case encoding_errc::expected_u16_found_fffe: + return "Expected UTF-16, found non character"; + case encoding_errc::expected_u32_found_fffe: + return "Expected UTF-32, found non character"; + default: + return ""; + break; + } + } +}; + +inline +const std::error_category& encoding_error_category() +{ + static Encoding_errc_impl_ instance; + return instance; +} + +inline +std::error_code make_error_code(encoding_errc result) +{ + return std::error_code(static_cast(result),encoding_error_category()); +} + +// utf8 + +template +typename std::enable_if::value_type>::value + && sizeof(typename std::iterator_traits::value_type) == sizeof(uint8_t), + conv_errc >::type +is_legal_utf8(Iterator first, size_t length) +{ + uint8_t a; + Iterator srcptr = first+length; + switch (length) { + default: + return conv_errc::over_long_utf8_sequence; + case 4: + if (((a = (*--srcptr))& 0xC0) != 0x80) + return conv_errc::expected_continuation_byte; + UNICONS_FALLTHROUGH; + case 3: + if (((a = (*--srcptr))& 0xC0) != 0x80) + return conv_errc::expected_continuation_byte; + UNICONS_FALLTHROUGH; + case 2: + if (((a = (*--srcptr))& 0xC0) != 0x80) + return conv_errc::expected_continuation_byte; + + switch (static_cast(*first)) + { + /* no fall-through in this inner switch */ + case 0xE0: if (a < 0xA0) return conv_errc::source_illegal; break; + case 0xED: if (a > 0x9F) return conv_errc::source_illegal; break; + case 0xF0: if (a < 0x90) return conv_errc::source_illegal; break; + case 0xF4: if (a > 0x8F) return conv_errc::source_illegal; break; + default: if (a < 0x80) return conv_errc::source_illegal; + } + + UNICONS_FALLTHROUGH; + case 1: + if (static_cast(*first) >= 0x80 && static_cast(*first) < 0xC2) + return conv_errc::source_illegal; + break; + } + if (static_cast(*first) > 0xF4) + return conv_errc::source_illegal; + + return conv_errc(); +} + +template using void_t = void; + +template +struct is_output_iterator : std::false_type {}; + +template +struct is_output_iterator::iterator_category, + decltype(*std::declval() = std::declval())>> : std::true_type {}; + +// is_same_size fixes issue with vs2013 + +// primary template +template +struct is_same_size : std::false_type +{ +}; + +// specialization for non void types +template +struct is_same_size::value && !std::is_void::value>::type> +{ + static const bool value = (sizeof(T1) == sizeof(T2)); +}; + +template +struct is_compatible_output_iterator : std::false_type {}; + +template +struct is_compatible_output_iterator::value + && std::is_void::value_type>::value + && std::is_integral::value + && !std::is_void::value + && is_same_size::value>::type +> : std::true_type {}; + +template +struct is_compatible_output_iterator::value + && std::is_integral::value_type>::value + && is_same_size::value_type,CharT>::value>::type +> : std::true_type {}; + +template +struct is_compatible_output_iterator::value + && std::is_void::value_type>::value + && is_same_size::value>::type +> : std::true_type {}; + +// convert + +template +struct convert_result +{ + Iterator it; + conv_errc ec; +}; + +template +typename std::enable_if::value_type>::value && sizeof(typename std::iterator_traits::value_type) == sizeof(uint8_t) + && is_compatible_output_iterator::value,convert_result>::type +convert(InputIt first, InputIt last, OutputIt target, conv_flags flags=conv_flags::strict) +{ + (void)flags; + + conv_errc result = conv_errc(); + while (first != last) + { + size_t length = trailing_bytes_for_utf8[static_cast(*first)] + 1; + if (length > (size_t)(last - first)) + { + return convert_result{first, conv_errc::source_exhausted}; + } + if ((result=is_legal_utf8(first, length)) != conv_errc()) + { + return convert_result{first,result}; + } + + switch (length) { + case 4: *target++ = (static_cast(*first++)); + UNICONS_FALLTHROUGH; + case 3: *target++ = (static_cast(*first++)); + UNICONS_FALLTHROUGH; + case 2: *target++ = (static_cast(*first++)); + UNICONS_FALLTHROUGH; + case 1: *target++ = (static_cast(*first++)); + } + } + return convert_result{first,result} ; +} + +template +typename std::enable_if::value_type>::value && sizeof(typename std::iterator_traits::value_type) == sizeof(uint8_t) + && is_compatible_output_iterator::value,convert_result>::type +convert(InputIt first, InputIt last, + OutputIt target, + conv_flags flags = conv_flags::strict) +{ + conv_errc result = conv_errc(); + + while (first != last) + { + uint32_t ch = 0; + unsigned short extra_bytes_to_read = trailing_bytes_for_utf8[static_cast(*first)]; + if (extra_bytes_to_read >= last - first) + { + result = conv_errc::source_exhausted; + break; + } + /* Do this check whether lenient or strict */ + if ((result=is_legal_utf8(first, extra_bytes_to_read+1)) != conv_errc()) + { + break; + } + /* + * The cases all fall through. See "Note A" below. + */ + switch (extra_bytes_to_read) { + case 5: ch += static_cast(*first++); ch <<= 6; /* remember, illegal UTF-8 */ + case 4: ch += static_cast(*first++); ch <<= 6; /* remember, illegal UTF-8 */ + case 3: ch += static_cast(*first++); ch <<= 6; + case 2: ch += static_cast(*first++); ch <<= 6; + case 1: ch += static_cast(*first++); ch <<= 6; + case 0: ch += static_cast(*first++); + } + ch -= offsets_from_utf8[extra_bytes_to_read]; + + if (ch <= max_bmp) { /* Target is a character <= 0xFFFF */ + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (is_surrogate(ch) ) { + if (flags == conv_flags::strict) { + first -= (extra_bytes_to_read+1); /* return to the illegal value itself */ + result = conv_errc::source_illegal; + break; + } else { + *target++ = (replacement_char); + } + } else { + *target++ = ((uint16_t)ch); /* normal case */ + } + } else if (ch > max_utf16) { + if (flags == conv_flags::strict) { + result = conv_errc::source_illegal; + first -= (extra_bytes_to_read+1); /* return to the start */ + break; /* Bail out; shouldn't continue */ + } else { + *target++ = (replacement_char); + } + } else { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + ch -= half_base; + *target++ = ((uint16_t)((ch >> half_shift) + sur_high_start)); + *target++ = ((uint16_t)((ch & half_mask) + sur_low_start)); + } + } + return convert_result{first,result} ; +} + +template +typename std::enable_if::value_type>::value && sizeof(typename std::iterator_traits::value_type) == sizeof(uint8_t) + && is_compatible_output_iterator::value,convert_result>::type +convert(InputIt first, InputIt last, + OutputIt target, + conv_flags flags = conv_flags::strict) +{ + conv_errc result = conv_errc(); + + while (first < last) + { + uint32_t ch = 0; + unsigned short extra_bytes_to_read = trailing_bytes_for_utf8[static_cast(*first)]; + if (extra_bytes_to_read >= last - first) + { + result = conv_errc::source_exhausted; + break; + } + /* Do this check whether lenient or strict */ + if ((result=is_legal_utf8(first, extra_bytes_to_read+1)) != conv_errc()) { + break; + } + /* + * The cases all fall through. See "Note A" below. + */ + switch (extra_bytes_to_read) + { + case 5: + ch += static_cast(*first++); + ch <<= 6; + UNICONS_FALLTHROUGH; + case 4: + ch += static_cast(*first++); + ch <<= 6; + UNICONS_FALLTHROUGH; + case 3: + ch += static_cast(*first++); + ch <<= 6; + UNICONS_FALLTHROUGH; + case 2: + ch += static_cast(*first++); + ch <<= 6; + UNICONS_FALLTHROUGH; + case 1: + ch += static_cast(*first++); + ch <<= 6; + UNICONS_FALLTHROUGH; + case 0: + ch += static_cast(*first++); + break; + } + ch -= offsets_from_utf8[extra_bytes_to_read]; + + if (ch <= max_legal_utf32) { + /* + * UTF-16 surrogate values are illegal in UTF-32, and anything + * over Plane 17 (> 0x10FFFF) is illegal. + */ + if (is_surrogate(ch) ) { + if (flags == conv_flags::strict) { + first -= (extra_bytes_to_read+1); /* return to the illegal value itself */ + result = conv_errc::source_illegal; + break; + } else { + *target++ = (replacement_char); + } + } else { + *target++ = (ch); + } + } else { /* i.e., ch > max_legal_utf32 */ + result = conv_errc::source_illegal; + *target++ = (replacement_char); + } + } + return convert_result{first,result} ; +} + +// utf16 + +template +typename std::enable_if::value_type>::value && sizeof(typename std::iterator_traits::value_type) == sizeof(uint16_t) + && is_compatible_output_iterator::value,convert_result>::type +convert(InputIt first, InputIt last, + OutputIt target, + conv_flags flags = conv_flags::strict) { + conv_errc result = conv_errc(); + while (first < last) { + unsigned short bytes_to_write = 0; + const uint32_t byteMask = 0xBF; + const uint32_t byteMark = 0x80; + uint32_t ch = *first++; + /* If we have a surrogate pair, convert to uint32_t first. */ + if (is_high_surrogate(ch)) { + /* If the 16 bits following the high surrogate are in the first buffer... */ + if (first < last) { + uint32_t ch2 = *first; + /* If it's a low surrogate, convert to uint32_t. */ + if (ch2 >= sur_low_start && ch2 <= sur_low_end) { + ch = ((ch - sur_high_start) << half_shift) + + (ch2 - sur_low_start) + half_base; + ++first; + } else if (flags == conv_flags::strict) { /* it's an unpaired high surrogate */ + --first; /* return to the illegal value itself */ + result = conv_errc::unpaired_high_surrogate; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --first; /* return to the high surrogate */ + result = conv_errc::source_exhausted; + break; + } + } else if (flags == conv_flags::strict) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (is_low_surrogate(ch)) { + --first; /* return to the illegal value itself */ + result = conv_errc::source_illegal; + break; + } + } + /* Figure out how many bytes the result will require */ + if (ch < (uint32_t)0x80) { + bytes_to_write = 1; + } else if (ch < (uint32_t)0x800) { + bytes_to_write = 2; + } else if (ch < (uint32_t)0x10000) { + bytes_to_write = 3; + } else if (ch < (uint32_t)0x110000) { + bytes_to_write = 4; + } else { + bytes_to_write = 3; + ch = replacement_char; + } + + uint8_t byte1 = 0; + uint8_t byte2 = 0; + uint8_t byte3 = 0; + uint8_t byte4 = 0; + + switch (bytes_to_write) { // note: everything falls through + case 4: byte4 = (uint8_t)((ch | byteMark) & byteMask); ch >>= 6; + case 3: byte3 = (uint8_t)((ch | byteMark) & byteMask); ch >>= 6; + case 2: byte2 = (uint8_t)((ch | byteMark) & byteMask); ch >>= 6; + case 1: byte1 = (uint8_t)(ch | first_byte_mark[bytes_to_write]); + } + switch (bytes_to_write) + { + case 4: + *target++ = (byte1); + *target++ = (byte2); + *target++ = (byte3); + *target++ = (byte4); + break; + case 3: + *target++ = (byte1); + *target++ = (byte2); + *target++ = (byte3); + break; + case 2: + *target++ = (byte1); + *target++ = (byte2); + break; + case 1: + *target++ = (byte1); + break; + } + } + return convert_result{first,result} ; +} + +template +typename std::enable_if::value_type>::value && sizeof(typename std::iterator_traits::value_type) == sizeof(uint16_t) + && is_compatible_output_iterator::value,convert_result>::type +convert(InputIt first, InputIt last, + OutputIt target, + conv_flags flags = conv_flags::strict) +{ + conv_errc result = conv_errc(); + + while (first != last) + { + uint32_t ch = *first++; + /* If we have a surrogate pair, convert to uint32_t first. */ + if (is_high_surrogate(ch)) + { + /* If the 16 bits following the high surrogate are in the first buffer... */ + if (first < last) { + uint32_t ch2 = *first; + /* If it's a low surrogate, */ + if (ch2 >= sur_low_start && ch2 <= sur_low_end) { + *target++ = ((uint16_t)ch); + *target++ = ((uint16_t)ch2); + ++first; + } else if (flags == conv_flags::strict) { /* it's an unpaired high surrogate */ + --first; /* return to the illegal value itself */ + result = conv_errc::unpaired_high_surrogate; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --first; /* return to the high surrogate */ + result = conv_errc::source_exhausted; + break; + } + } else if (is_low_surrogate(ch)) + { + // illegal leading low surrogate + if (flags == conv_flags::strict) { + --first; /* return to the illegal value itself */ + result = conv_errc::source_illegal; + break; + } + else + { + *target++ = ((uint16_t)ch); + } + } + else + { + *target++ = ((uint16_t)ch); + } + } + return convert_result{first,result} ; +} + +template +typename std::enable_if::value_type>::value && sizeof(typename std::iterator_traits::value_type) == sizeof(uint16_t) + && is_compatible_output_iterator::value,convert_result>::type +convert(InputIt first, InputIt last, + OutputIt target, + conv_flags flags = conv_flags::strict) +{ + conv_errc result = conv_errc(); + + while (first != last) + { + uint32_t ch = *first++; + /* If we have a surrogate pair, convert to UTF32 first. */ + if (is_high_surrogate(ch)) { + /* If the 16 bits following the high surrogate are in the first buffer... */ + if (first < last) { + uint32_t ch2 = *first; + /* If it's a low surrogate, convert to UTF32. */ + if (ch2 >= sur_low_start && ch2 <= sur_low_end ) { + ch = ((ch - sur_high_start) << half_shift) + + (ch2 - sur_low_start) + half_base; + ++first; + } else if (flags == conv_flags::strict) { /* it's an unpaired high surrogate */ + --first; /* return to the illegal value itself */ + result = conv_errc::source_illegal; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --first; /* return to the high surrogate */ + result = conv_errc::source_exhausted; + break; + } + } else if (flags == conv_flags::strict) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (is_low_surrogate(ch) ) { + --first; /* return to the illegal value itself */ + result = conv_errc::source_illegal; + break; + } + } + *target++ = (ch); + } + return convert_result{first,result} ; +} + +// utf32 + +template +typename std::enable_if::value_type>::value && sizeof(typename std::iterator_traits::value_type) == sizeof(uint32_t) + && is_compatible_output_iterator::value,convert_result>::type +convert(InputIt first, InputIt last, + OutputIt target, + conv_flags flags = conv_flags::strict) +{ + conv_errc result = conv_errc(); + while (first < last) { + unsigned short bytes_to_write = 0; + const uint32_t byteMask = 0xBF; + const uint32_t byteMark = 0x80; + uint32_t ch = *first++; + if (flags == conv_flags::strict ) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (is_surrogate(ch)) { + --first; /* return to the illegal value itself */ + result = conv_errc::illegal_surrogate_value; + break; + } + } + /* + * Figure out how many bytes the result will require. Turn any + * illegally large UTF32 things (> Plane 17) into replacement chars. + */ + if (ch < (uint32_t)0x80) { bytes_to_write = 1; + } else if (ch < (uint32_t)0x800) { bytes_to_write = 2; + } else if (ch < (uint32_t)0x10000) { bytes_to_write = 3; + } else if (ch <= max_legal_utf32) { bytes_to_write = 4; + } else { + bytes_to_write = 3; + ch = replacement_char; + result = conv_errc::source_illegal; + } + + uint8_t byte1 = 0; + uint8_t byte2 = 0; + uint8_t byte3 = 0; + uint8_t byte4 = 0; + + switch (bytes_to_write) { + case 4: + byte4 = (uint8_t)((ch | byteMark) & byteMask); ch >>= 6; + UNICONS_FALLTHROUGH; + case 3: + byte3 = (uint8_t)((ch | byteMark) & byteMask); ch >>= 6; + UNICONS_FALLTHROUGH; + case 2: + byte2 = (uint8_t)((ch | byteMark) & byteMask); ch >>= 6; + UNICONS_FALLTHROUGH; + case 1: + byte1 = (uint8_t) (ch | first_byte_mark[bytes_to_write]); + } + + switch (bytes_to_write) + { + case 4: + *target++ = (byte1); + *target++ = (byte2); + *target++ = (byte3); + *target++ = (byte4); + break; + case 3: + *target++ = (byte1); + *target++ = (byte2); + *target++ = (byte3); + break; + case 2: + *target++ = (byte1); + *target++ = (byte2); + break; + case 1: + *target++ = (byte1); + break; + } + } + return convert_result{first,result} ; +} + +template +typename std::enable_if::value_type>::value && sizeof(typename std::iterator_traits::value_type) == sizeof(uint32_t) + && is_compatible_output_iterator::value,convert_result>::type +convert(InputIt first, InputIt last, + OutputIt target, + conv_flags flags = conv_flags::strict) +{ + conv_errc result = conv_errc(); + + while (first != last) + { + uint32_t ch = *first++; + if (ch <= max_bmp) { /* Target is a character <= 0xFFFF */ + /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */ + if (is_surrogate(ch) ) { + if (flags == conv_flags::strict) { + --first; /* return to the illegal value itself */ + result = conv_errc::source_illegal; + break; + } else { + *target++ = (replacement_char); + } + } else { + *target++ = ((uint16_t)ch); /* normal case */ + } + } else if (ch > max_legal_utf32) { + if (flags == conv_flags::strict) { + result = conv_errc::source_illegal; + } else { + *target++ = (replacement_char); + } + } else { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + ch -= half_base; + *target++ = ((uint16_t)((ch >> half_shift) + sur_high_start)); + *target++ = ((uint16_t)((ch & half_mask) + sur_low_start)); + } + } + return convert_result{first,result} ; +} + +template +typename std::enable_if::value_type>::value && sizeof(typename std::iterator_traits::value_type) == sizeof(uint32_t) + && is_compatible_output_iterator::value,convert_result>::type +convert(InputIt first, InputIt last, + OutputIt target, + conv_flags flags = conv_flags::strict) +{ + conv_errc result = conv_errc(); + + while (first != last) + { + uint32_t ch = *first++; + if (flags == conv_flags::strict ) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (is_surrogate(ch)) { + --first; /* return to the illegal value itself */ + result = conv_errc::illegal_surrogate_value; + break; + } + } + if (ch <= max_legal_utf32) + { + *target++ = (ch); + } + else + { + *target++ = (replacement_char); + result = conv_errc::source_illegal; + } + } + return convert_result{first,result} ; +} + +// validate + +template +typename std::enable_if::value_type>::value && sizeof(typename std::iterator_traits::value_type) == sizeof(uint8_t) + ,convert_result>::type +validate(InputIt first, InputIt last) UNICONS_NOEXCEPT +{ + conv_errc result = conv_errc(); + while (first != last) + { + size_t length = trailing_bytes_for_utf8[static_cast(*first)] + 1; + if (length > (size_t)(last - first)) + { + return convert_result{first, conv_errc::source_exhausted}; + } + if ((result=is_legal_utf8(first, length)) != conv_errc()) + { + return convert_result{first,result} ; + } + first += length; + } + return convert_result{first,result} ; +} + +// utf16 + +template +typename std::enable_if::value_type>::value && sizeof(typename std::iterator_traits::value_type) == sizeof(uint16_t) + ,convert_result>::type +validate(InputIt first, InputIt last) UNICONS_NOEXCEPT +{ + conv_errc result = conv_errc(); + + while (first != last) + { + uint32_t ch = *first++; + /* If we have a surrogate pair, validate to uint32_t first. */ + if (is_high_surrogate(ch)) + { + /* If the 16 bits following the high surrogate are in the first buffer... */ + if (first < last) { + uint32_t ch2 = *first; + /* If it's a low surrogate, */ + if (ch2 >= sur_low_start && ch2 <= sur_low_end) { + ++first; + } else { + --first; /* return to the illegal value itself */ + result = conv_errc::unpaired_high_surrogate; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --first; /* return to the high surrogate */ + result = conv_errc::source_exhausted; + break; + } + } else if (is_low_surrogate(ch)) + { + /* UTF-16 surrogate values are illegal in UTF-32 */ + --first; /* return to the illegal value itself */ + result = conv_errc::source_illegal; + break; + } + } + return convert_result{first,result} ; +} + + +// utf32 + + +template +typename std::enable_if::value_type>::value && sizeof(typename std::iterator_traits::value_type) == sizeof(uint32_t) + ,convert_result>::type +validate(InputIt first, InputIt last) UNICONS_NOEXCEPT +{ + conv_errc result = conv_errc(); + + while (first != last) + { + uint32_t ch = *first++; + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (is_surrogate(ch)) { + --first; /* return to the illegal value itself */ + result = conv_errc::illegal_surrogate_value; + break; + } + if (!(ch <= max_legal_utf32)) + { + result = conv_errc::source_illegal; + } + } + return convert_result{first,result} ; +} + +// sequence + +template +class sequence +{ + Iterator first_; + size_t length_; +public: + sequence(Iterator first, size_t length) + : first_(first), length_(length) + { + } + + Iterator begin() const + { + return first_; + } + + size_t length() const + { + return length_; + } + + template ::value_type> + typename std::enable_if::type + codepoint() const UNICONS_NOEXCEPT + { + uint32_t ch = 0; + Iterator it = first_; + switch (length_) + { + default: + return replacement_char; + break; + case 4: + ch += static_cast(*it++); ch <<= 6; + UNICONS_FALLTHROUGH; + case 3: + ch += static_cast(*it++); ch <<= 6; + UNICONS_FALLTHROUGH; + case 2: + ch += static_cast(*it++); ch <<= 6; + UNICONS_FALLTHROUGH; + case 1: + ch += static_cast(*it++); + ch -= offsets_from_utf8[length_ - 1]; + break; + } + if (ch <= max_legal_utf32) + { + if (is_surrogate(ch)) + { + ch = replacement_char; + } + } + else // ch > max_legal_utf32 + { + ch = replacement_char; + } + return ch; + } + + template ::value_type> + typename std::enable_if::type + codepoint() const UNICONS_NOEXCEPT + { + if (length_ == 0) + { + return replacement_char; + } + if (length_ == 2) + { + uint32_t ch = *first_; + uint32_t ch2 = *(first_+ 1); + ch = ((ch - sur_high_start) << half_shift) + + (ch2 - sur_low_start) + half_base; + return ch; + } + else + { + return *first_; + } + } + + template ::value_type> + typename std::enable_if::type + codepoint() const UNICONS_NOEXCEPT + { + if (length_ == 0) + { + return replacement_char; + } + return *(first_); + } +}; + +// sequence_generator + +template +class sequence_generator +{ + Iterator begin_; + Iterator last_; + conv_flags flags_; + size_t length_; + conv_errc err_cd_; +public: + typedef sequence sequence_type; + + sequence_generator(Iterator first, Iterator last, + conv_flags flags = conv_flags::strict) UNICONS_NOEXCEPT + : begin_(first), last_(last), flags_(flags), + length_(0), err_cd_(conv_errc()) + { + next(); + } + + bool done() const UNICONS_NOEXCEPT + { + return err_cd_ != conv_errc() || begin_ == last_; + } + + conv_errc status() const UNICONS_NOEXCEPT + { + return err_cd_; + } + + sequence_type get() const UNICONS_NOEXCEPT + { + return sequence(begin_,length_); + } + + template ::value_type> + typename std::enable_if::type + next() UNICONS_NOEXCEPT + { + begin_ += length_; + if (begin_ != last_) + { + size_t length = trailing_bytes_for_utf8[static_cast(*begin_)] + 1; + if (length > (size_t)(last_ - begin_)) + { + err_cd_ = conv_errc::source_exhausted; + } + else if ((err_cd_ = is_legal_utf8(begin_, length)) != conv_errc()) + { + } + else + { + length_ = length; + } + } + } + + template ::value_type> + typename std::enable_if::type + next() UNICONS_NOEXCEPT + { + begin_ += length_; + if (begin_ != last_) + { + if (begin_ != last_) + { + + Iterator it = begin_; + + uint32_t ch = *it++; + /* If we have a surrogate pair, validate to uint32_t it. */ + if (is_high_surrogate(ch)) + { + /* If the 16 bits following the high surrogate are in the it buffer... */ + if (it < last_) { + uint32_t ch2 = *it; + /* If it's a low surrogate, */ + if (ch2 >= sur_low_start && ch2 <= sur_low_end) + { + ++it; + length_ = 2; + } + else + { + err_cd_ = conv_errc::unpaired_high_surrogate; + } + } + else + { + // We don't have the 16 bits following the high surrogate. + err_cd_ = conv_errc::source_exhausted; + } + } + else if (is_low_surrogate(ch)) + { + /* leading low surrogate */ + err_cd_ = conv_errc::source_illegal; + } + else + { + length_ = 1; + } + } + } + } + + template ::value_type> + typename std::enable_if::type + next() UNICONS_NOEXCEPT + { + begin_ += length_; + length_ = 1; + } +}; + +template +sequence_generator make_sequence_generator(Iterator first, Iterator last, + conv_flags flags = conv_flags::strict) +{ + return sequence_generator(first, last, flags); +} + +template +typename std::enable_if::value_type>::value + && (sizeof(typename std::iterator_traits::value_type) == sizeof(uint8_t) || sizeof(typename std::iterator_traits::value_type) == sizeof(uint16_t)), + sequence>::type +sequence_at(InputIt first, InputIt last, size_t index) +{ + sequence_generator g(first, last, unicons::conv_flags::strict); + + size_t count = 0; + while (!g.done() && count < index) + { + g.next(); + ++count; + } + return (!g.done() && count == index) ? g.get() : sequence(last,0); +} + +template +typename std::enable_if::value_type>::value && sizeof(typename std::iterator_traits::value_type) == sizeof(uint32_t), + sequence>::type +sequence_at(InputIt first, InputIt last, size_t index) +{ + size_t size = std::distance(first,last); + return index < size ? sequence(first+index,1) : sequence(last,0); +} + +// u8_length + +template +typename std::enable_if::value_type>::value && sizeof(typename std::iterator_traits::value_type) == sizeof(uint8_t),size_t>::type +u8_length(InputIt first, InputIt last) UNICONS_NOEXCEPT +{ + return std::distance(first,last); +} + +// utf16 + +template +typename std::enable_if::value_type>::value && sizeof(typename std::iterator_traits::value_type) == sizeof(uint16_t),size_t>::type +u8_length(InputIt first, InputIt last) UNICONS_NOEXCEPT +{ + conv_flags flags = conv_flags::strict; + size_t count = 0; + for (InputIt p = first; p != last; ++p) + { + uint32_t ch = *p; + if (is_high_surrogate(ch)) { + /* If the 16 bits following the high surrogate are in the p buffer... */ + if (p < last) { + uint32_t ch2 = *(++p); + /* If it's a low surrogate, convert to uint32_t. */ + if (ch2 >= sur_low_start && ch2 <= sur_low_end) { + ch = ((ch - sur_high_start) << half_shift) + + (ch2 - sur_low_start) + half_base; + + } else if (flags == conv_flags::strict) { /* it's an unpaired high surrogate */ + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + break; + } + } else if (flags == conv_flags::strict) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (is_low_surrogate(ch)) { + break; + } + } + if (ch < (uint32_t)0x80) { + ++count; + } else if (ch < (uint32_t)0x800) { + count += 2; + } else if (ch < (uint32_t)0x10000) { + count += 3; + } else if (ch < (uint32_t)0x110000) { + count += 4; + } else { + count += 3; + } + } + return count; +} + + +// utf32 + +template +typename std::enable_if::value_type>::value && sizeof(typename std::iterator_traits::value_type) == sizeof(uint32_t),size_t>::type +u8_length(InputIt first, InputIt last) UNICONS_NOEXCEPT +{ + size_t count = 0; + for (InputIt p = first; p < last; ++p) + { + uint32_t ch = *p; + if (ch < (uint32_t)0x80) { + ++count; + } else if (ch < (uint32_t)0x800) { + count += 2; + } else if (ch < (uint32_t)0x10000) { + count += 3; + } else if (ch <= max_legal_utf32) { + count += 4; + } else { + count += 3; + } + } + return count; +} + +// u32_length + +template +typename std::enable_if::value_type>::value + && (sizeof(typename std::iterator_traits::value_type) == sizeof(uint8_t) || sizeof(typename std::iterator_traits::value_type) == sizeof(uint16_t)), + size_t>::type +u32_length(InputIt first, InputIt last) UNICONS_NOEXCEPT +{ + sequence_generator g(first, last, unicons::conv_flags::strict); + + size_t count = 0; + while (!g.done()) + { + g.next(); + ++count; + } + return count; +} + +template +typename std::enable_if::value_type>::value && sizeof(typename std::iterator_traits::value_type) == sizeof(uint32_t), + size_t>::type +u32_length(InputIt first, InputIt last) UNICONS_NOEXCEPT +{ + return std::distance(first,last); +} + +enum class encoding {u8,u16le,u16be,u32le,u32be,undetected}; + +template +struct detect_encoding_result +{ + Iterator it; + encoding ec; +}; + +template +typename std::enable_if::value_type>::value && sizeof(typename std::iterator_traits::value_type) == sizeof(uint8_t), + detect_encoding_result>::type +detect_encoding(Iterator first, Iterator last) UNICONS_NOEXCEPT +{ + Iterator it1 = first; + if (std::distance(first,last) < 4) + { + if (std::distance(first,last) == 3) + { + Iterator it2 = ++first; + Iterator it3 = ++first; + if (static_cast(*it1) == 0xEF && static_cast(*it2) == 0xBB && static_cast(*it3) == 0xBF) + { + return detect_encoding_result{last,encoding::u8}; + } + } + return detect_encoding_result{it1,encoding::undetected}; + } + else + { + Iterator it2 = ++first; + Iterator it3 = ++first; + Iterator it4 = ++first; + + uint32_t bom = static_cast(*it1) | (static_cast(*it2) << 8) | (static_cast(*it3) << 16) | (static_cast(*it4) << 24); + if (bom == 0xFFFE0000) + { + return detect_encoding_result{it4++,encoding::u32be}; + } + else if (bom == 0x0000FEFF) + { + return detect_encoding_result{first,encoding::u32le}; + } + else if ((bom & 0xFFFF) == 0xFFFE) + { + return detect_encoding_result{it3,encoding::u16be}; + } + else if ((bom & 0xFFFF) == 0xFEFF) + { + return detect_encoding_result{it3,encoding::u16le}; + } + else if ((bom & 0xFFFFFF) == 0xBFBBEF) + { + return detect_encoding_result{it4,encoding::u8}; + } + else + { + uint32_t pattern = (static_cast(*it1) ? 1 : 0) | (static_cast(*it2) ? 2 : 0) | (static_cast(*it3) ? 4 : 0) | (static_cast(*it4) ? 8 : 0); + switch (pattern) { + case 0x08: + return detect_encoding_result{it1,encoding::u32be}; + case 0x0A: + return detect_encoding_result{it1,encoding::u16be}; + case 0x01: + return detect_encoding_result{it1,encoding::u32le}; + case 0x05: + return detect_encoding_result{it1,encoding::u16le}; + case 0x0F: + return detect_encoding_result{it1,encoding::u8}; + default: + return detect_encoding_result{it1,encoding::undetected}; + } + } + } +} + +template +struct skip_bom_result +{ + Iterator it; + encoding_errc ec; +}; + +template +typename std::enable_if::value_type>::value && sizeof(typename std::iterator_traits::value_type) == sizeof(uint8_t), + skip_bom_result>::type +skip_bom(Iterator first, Iterator last) UNICONS_NOEXCEPT +{ + auto result = unicons::detect_encoding(first,last); + switch (result.ec) + { + case unicons::encoding::u8: + return skip_bom_result{result.it,encoding_errc()}; + break; + case unicons::encoding::u16le: + case unicons::encoding::u16be: + return skip_bom_result{result.it,encoding_errc::expected_u8_found_u16}; + break; + case unicons::encoding::u32le: + case unicons::encoding::u32be: + return skip_bom_result{result.it,encoding_errc::expected_u8_found_u32}; + break; + default: + return skip_bom_result{result.it,encoding_errc()}; + break; + } +} + +template +typename std::enable_if::value_type>::value && sizeof(typename std::iterator_traits::value_type) == sizeof(uint16_t), + skip_bom_result>::type +skip_bom(Iterator first, Iterator last) UNICONS_NOEXCEPT +{ + if (first == last) + { + return skip_bom_result{first,encoding_errc()}; + } + uint16_t bom = static_cast(*first); + if (bom == 0xFEFF) + { + return skip_bom_result{++first,encoding_errc()}; + } + else if (bom == 0xFFFE) + { + return skip_bom_result{last,encoding_errc::expected_u16_found_fffe}; + } + else + { + return skip_bom_result{first,encoding_errc()}; + } +} + +template +typename std::enable_if::value_type>::value && sizeof(typename std::iterator_traits::value_type) == sizeof(uint32_t), + skip_bom_result>::type +skip_bom(Iterator first, Iterator last) UNICONS_NOEXCEPT +{ + if (first == last) + { + return skip_bom_result{first,encoding_errc()}; + } + uint32_t bom = static_cast(*first); + if (bom == 0xFEFF0000) + { + return skip_bom_result{++first,encoding_errc()}; + } + else if (bom == 0xFFFE0000) + { + return skip_bom_result{last,encoding_errc::expected_u32_found_fffe}; + } + else + { + return skip_bom_result{first,encoding_errc()}; + } +} + +} // unicons +} // jsoncons + +namespace std { + template<> + struct is_error_code_enum : public true_type + { + }; + template<> + struct is_error_code_enum : public true_type + { + }; +} + +#endif + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/bson/bson.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/bson/bson.hpp new file mode 100644 index 0000000000..7d14eda0c4 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/bson/bson.hpp @@ -0,0 +1,106 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_BSON_BSON_HPP +#define JSONCONS_BSON_BSON_HPP + +#include +#include +#include +#include // std::enable_if +#include // std::basic_istream +#include +#include +#include +#include + +namespace jsoncons { namespace bson { + +// encode_bson + +template +typename std::enable_if::value,void>::type +encode_bson(const T& j, std::vector& v) +{ + typedef typename T::char_type char_type; + bson_bytes_encoder encoder(v); + auto adaptor = make_json_content_handler_adaptor>(encoder); + j.dump(adaptor); +} + +template +typename std::enable_if::value,void>::type +encode_bson(const T& val, std::vector& v) +{ + bson_bytes_encoder encoder(v); + write_to(json(), val, encoder); +} + +template +typename std::enable_if::value,void>::type +encode_bson(const T& j, std::ostream& os) +{ + typedef typename T::char_type char_type; + bson_encoder encoder(os); + auto adaptor = make_json_content_handler_adaptor>(encoder); + j.dump(adaptor); +} + +template +typename std::enable_if::value,void>::type +encode_bson(const T& val, std::ostream& os) +{ + bson_encoder encoder(os); + write_to(json(), val, encoder); +} + +// decode_bson + +template +typename std::enable_if::value,T>::type +decode_bson(const std::vector& v) +{ + jsoncons::json_decoder decoder; + auto adaptor = make_json_content_handler_adaptor(decoder); + basic_bson_reader reader(v, adaptor); + reader.read(); + return decoder.get_result(); +} + +template +typename std::enable_if::value,T>::type +decode_bson(const std::vector& v) +{ + jsoncons::json_decoder decoder; + basic_bson_reader reader(v, decoder); + reader.read(); + return decoder.get_result().template as(); +} + +template +typename std::enable_if::value,T>::type +decode_bson(std::istream& is) +{ + jsoncons::json_decoder decoder; + auto adaptor = make_json_content_handler_adaptor(decoder); + bson_reader reader(is, adaptor); + reader.read(); + return decoder.get_result(); +} + +template +typename std::enable_if::value,T>::type +decode_bson(std::istream& is) +{ + jsoncons::json_decoder decoder; + bson_reader reader(is, decoder); + reader.read(); + return decoder.get_result(); +} + +}} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/bson/bson_detail.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/bson/bson_detail.hpp new file mode 100644 index 0000000000..a1b50025eb --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/bson/bson_detail.hpp @@ -0,0 +1,42 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_BSON_BSON_DETAIL_HPP +#define JSONCONS_BSON_BSON_DETAIL_HPP + +#include +#include +#include + +namespace jsoncons { namespace bson { namespace detail { + +namespace bson_format +{ + const uint8_t double_cd = 0x01; + const uint8_t string_cd = 0x02; // UTF-8 string + const uint8_t document_cd = 0x03; + const uint8_t array_cd = 0x04; + const uint8_t binary_cd = 0x05; + const uint8_t object_id_cd = 0x07; + const uint8_t bool_cd = 0x08; + const uint8_t datetime_cd = 0x09; + const uint8_t null_cd = 0x0a; + const uint8_t regex_cd = 0x0b; + const uint8_t javascript_cd = 0x0d; + const uint8_t javascript_with_scope_cd = 0x0f; + const uint8_t int32_cd = 0x10; + const uint8_t timestamp_cd = 0x11; // MongoDB internal Timestamp, uint64 + const uint8_t int64_cd = 0x12; + const uint8_t decimal128_cd = 0x13; + const uint8_t min_key_cd = 0xff; + const uint8_t max_key_cd = 0x7f; +} + +enum class bson_container_type {document, array}; + +}}} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/bson/bson_encoder.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/bson/bson_encoder.hpp new file mode 100644 index 0000000000..4161bb2505 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/bson/bson_encoder.hpp @@ -0,0 +1,342 @@ +// Copyright 2018 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_BSON_BSON_ENCODER_HPP +#define JSONCONS_BSON_BSON_ENCODER_HPP + +#include +#include +#include // std::numeric_limits +#include +#include // std::move +#include +#include +#include +#include +#include +#include + +namespace jsoncons { namespace bson { + +template +class basic_bson_encoder final : public basic_json_content_handler +{ + enum class decimal_parse_state { start, integer, exp1, exp2, fraction1 }; +public: + typedef char char_type; + using typename basic_json_content_handler::string_view_type; + typedef Result result_type; + +private: + struct stack_item + { + jsoncons::bson::detail::bson_container_type type_; + size_t offset_; + size_t name_offset_; + size_t index_; + + stack_item(jsoncons::bson::detail::bson_container_type type, size_t offset) + : type_(type), offset_(offset), name_offset_(0), index_(0) + { + } + + size_t offset() const + { + return offset_; + } + + size_t member_offset() const + { + return name_offset_; + } + + void member_offset(size_t offset) + { + name_offset_ = offset; + } + + size_t next_index() + { + return index_++; + } + + bool is_object() const + { + return type_ == jsoncons::bson::detail::bson_container_type::document; + } + + + }; + + std::vector stack_; + std::vector buffer_; + result_type result_; + + // Noncopyable and nonmoveable + basic_bson_encoder(const basic_bson_encoder&) = delete; + basic_bson_encoder& operator=(const basic_bson_encoder&) = delete; +public: + explicit basic_bson_encoder(result_type result) + : result_(std::move(result)) + { + } + + ~basic_bson_encoder() + { + try + { + result_.flush(); + } + catch (...) + { + } + } + +private: + // Implementing methods + + void do_flush() override + { + result_.flush(); + } + + bool do_begin_object(semantic_tag, const ser_context&) override + { + if (buffer_.size() > 0) + { + before_value(jsoncons::bson::detail::bson_format::document_cd); + } + stack_.emplace_back(jsoncons::bson::detail::bson_container_type::document, buffer_.size()); + buffer_.insert(buffer_.end(), sizeof(int32_t), 0); + + return true; + } + + bool do_end_object(const ser_context&) override + { + JSONCONS_ASSERT(!stack_.empty()); + + buffer_.push_back(0x00); + + size_t length = buffer_.size() - stack_.back().offset(); + jsoncons::detail::to_little_endian(static_cast(length), buffer_.begin()+stack_.back().offset()); + + stack_.pop_back(); + if (stack_.empty()) + { + for (auto c : buffer_) + { + result_.push_back(c); + } + } + return true; + } + + bool do_begin_array(semantic_tag, const ser_context&) override + { + if (buffer_.size() > 0) + { + before_value(jsoncons::bson::detail::bson_format::array_cd); + } + stack_.emplace_back(jsoncons::bson::detail::bson_container_type::array, buffer_.size()); + buffer_.insert(buffer_.end(), sizeof(int32_t), 0); + return true; + } + + bool do_end_array(const ser_context&) override + { + JSONCONS_ASSERT(!stack_.empty()); + + buffer_.push_back(0x00); + + size_t length = buffer_.size() - stack_.back().offset(); + jsoncons::detail::to_little_endian(static_cast(length), buffer_.begin()+stack_.back().offset()); + + stack_.pop_back(); + if (stack_.empty()) + { + for (auto c : buffer_) + { + result_.push_back(c); + } + } + return true; + } + + bool do_name(const string_view_type& name, const ser_context&) override + { + stack_.back().member_offset(buffer_.size()); + buffer_.push_back(0x00); // reserve space for code + for (auto c : name) + { + buffer_.push_back(c); + } + buffer_.push_back(0x00); + return true; + } + + bool do_null_value(semantic_tag, const ser_context&) override + { + before_value(jsoncons::bson::detail::bson_format::null_cd); + return true; + } + + bool do_bool_value(bool val, semantic_tag, const ser_context&) override + { + before_value(jsoncons::bson::detail::bson_format::bool_cd); + if (val) + { + buffer_.push_back(0x01); + } + else + { + buffer_.push_back(0x00); + } + + return true; + } + + bool do_string_value(const string_view_type& sv, semantic_tag, const ser_context&) override + { + before_value(jsoncons::bson::detail::bson_format::string_cd); + + size_t offset = buffer_.size(); + buffer_.insert(buffer_.end(), sizeof(int32_t), 0); + size_t string_offset = buffer_.size(); + + auto result = unicons::validate(sv.begin(), sv.end()); + if (result.ec != unicons::conv_errc()) + { + JSONCONS_THROW(json_runtime_error("Illegal unicode")); + } + for (auto c : sv) + { + buffer_.push_back(c); + } + buffer_.push_back(0x00); + size_t length = buffer_.size() - string_offset; + jsoncons::detail::to_little_endian(static_cast(length), buffer_.begin()+offset); + + return true; + } + + bool do_byte_string_value(const byte_string_view& b, + semantic_tag, + const ser_context&) override + { + before_value(jsoncons::bson::detail::bson_format::binary_cd); + + size_t offset = buffer_.size(); + buffer_.insert(buffer_.end(), sizeof(int32_t), 0); + size_t string_offset = buffer_.size(); + + for (auto c : b) + { + buffer_.push_back(c); + } + size_t length = buffer_.size() - string_offset; + jsoncons::detail::to_little_endian(static_cast(length), buffer_.begin()+offset); + + return true; + } + + bool do_int64_value(int64_t val, + semantic_tag tag, + const ser_context&) override + { + if (tag == semantic_tag::timestamp) + { + before_value(jsoncons::bson::detail::bson_format::datetime_cd); + } + else + { + before_value(jsoncons::bson::detail::bson_format::int64_cd); + } + if (val >= (std::numeric_limits::lowest)() && val <= (std::numeric_limits::max)()) + { + jsoncons::detail::to_little_endian(static_cast(val),std::back_inserter(buffer_)); + } + else if (val >= (std::numeric_limits::lowest)() && val <= (std::numeric_limits::max)()) + { + jsoncons::detail::to_little_endian(static_cast(val),std::back_inserter(buffer_)); + } + else + { + // error + } + + return true; + } + + bool do_uint64_value(uint64_t val, + semantic_tag tag, + const ser_context&) override + { + if (tag == semantic_tag::timestamp) + { + before_value(jsoncons::bson::detail::bson_format::datetime_cd); + } + else + { + before_value(jsoncons::bson::detail::bson_format::int64_cd); + } + if (val <= (std::numeric_limits::max)()) + { + jsoncons::detail::to_little_endian(static_cast(val),std::back_inserter(buffer_)); + } + else if (val <= (uint64_t)(std::numeric_limits::max)()) + { + jsoncons::detail::to_little_endian(static_cast(val),std::back_inserter(buffer_)); + } + else + { + // error + } + + return true; + } + + bool do_double_value(double val, + semantic_tag, + const ser_context&) override + { + before_value(jsoncons::bson::detail::bson_format::double_cd); + + jsoncons::detail::to_little_endian(val,std::back_inserter(buffer_)); + + return true; + } + + void before_value(uint8_t code) + { + if (stack_.back().is_object()) + { + buffer_[stack_.back().member_offset()] = code; + } + else + { + buffer_.push_back(code); + std::string name = std::to_string(stack_.back().next_index()); + buffer_.insert(buffer_.end(), name.begin(), name.end()); + buffer_.push_back(0x00); + } + } +}; + +typedef basic_bson_encoder bson_encoder; +typedef basic_bson_encoder bson_bytes_encoder; + +#if !defined(JSONCONS_NO_DEPRECATED) +template +using basic_bson_serializer = basic_bson_encoder; + +typedef basic_bson_encoder bson_serializer; +typedef basic_bson_encoder bson_buffer_serializer; + +#endif + +}} +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/bson/bson_error.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/bson/bson_error.hpp new file mode 100644 index 0000000000..47204f67e9 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/bson/bson_error.hpp @@ -0,0 +1,70 @@ +/// Copyright 2018 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_BSON_BSON_ERROR_HPP +#define JSONCONS_BSON_BSON_ERROR_HPP + +#include +#include + +namespace jsoncons { namespace bson { + +enum class bson_errc +{ + ok = 0, + unexpected_eof = 1, + source_error, + invalid_utf8_text_string +}; + +class bson_error_category_impl + : public std::error_category +{ +public: + const char* name() const noexcept override + { + return "jsoncons/bson"; + } + std::string message(int ev) const override + { + switch (static_cast(ev)) + { + case bson_errc::unexpected_eof: + return "Unexpected end of file"; + case bson_errc::source_error: + return "Source error"; + case bson_errc::invalid_utf8_text_string: + return "Illegal UTF-8 encoding in text string"; + default: + return "Unknown BSON parser error"; + } + } +}; + +inline +const std::error_category& bson_error_category() +{ + static bson_error_category_impl instance; + return instance; +} + +inline +std::error_code make_error_code(bson_errc result) +{ + return std::error_code(static_cast(result),bson_error_category()); +} + + +}} + +namespace std { + template<> + struct is_error_code_enum : public true_type + { + }; +} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/bson/bson_reader.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/bson/bson_reader.hpp new file mode 100644 index 0000000000..f0d3d1b458 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/bson/bson_reader.hpp @@ -0,0 +1,297 @@ +// Copyright 2017 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_BSON_BSON_READER_HPP +#define JSONCONS_BSON_BSON_READER_HPP + +#include +#include +#include +#include // std::move +#include +#include +#include +#include +#include +#include + +namespace jsoncons { namespace bson { + +template +class basic_bson_reader : public ser_context +{ + Src source_; + json_content_handler& handler_; + size_t nesting_depth_; +public: + template + basic_bson_reader(Source&& source, json_content_handler& handler) + : source_(std::forward(source)), + handler_(handler), + nesting_depth_(0) + { + } + + void read() + { + std::error_code ec; + read(ec); + if (ec) + { + throw ser_error(ec,line(),column()); + } + } + + void read(std::error_code& ec) + { + try + { + if (source_.is_error()) + { + ec = bson_errc::source_error; + return; + } + uint8_t buf[sizeof(int32_t)]; + if (source_.read(buf, sizeof(int32_t)) != sizeof(int32_t)) + { + ec = bson_errc::unexpected_eof; + return; + } + const uint8_t* endp; + /* auto len = */jsoncons::detail::from_little_endian(buf, buf+sizeof(int32_t),&endp); + + handler_.begin_object(semantic_tag::none, *this); + ++nesting_depth_; + read_e_list(jsoncons::bson::detail::bson_container_type::document, ec); + handler_.end_object(*this); + --nesting_depth_; + } + catch (const ser_error& e) + { + ec = e.code(); + } + } + + size_t line() const override + { + return 0; + } + + size_t column() const override + { + return source_.position(); + } +private: + + void read_e_list(jsoncons::bson::detail::bson_container_type type, std::error_code& ec) + { + uint8_t t{}; + while (source_.get(t) > 0 && t != 0x00) + { + std::basic_string s; + uint8_t c{}; + while (source_.get(c) > 0 && c != 0) + { + s.push_back(c); + } + + if (type == jsoncons::bson::detail::bson_container_type::document) + { + auto result = unicons::validate(s.begin(),s.end()); + if (result.ec != unicons::conv_errc()) + { + ec = bson_errc::invalid_utf8_text_string; + return; + } + handler_.name(basic_string_view(s.data(),s.length()), *this); + } + read_internal(t, ec); + } + } + + void read_internal(uint8_t type, std::error_code& ec) + { + switch (type) + { + case jsoncons::bson::detail::bson_format::double_cd: + { + uint8_t buf[sizeof(double)]; + if (source_.read(buf, sizeof(double)) != sizeof(double)) + { + ec = bson_errc::unexpected_eof; + return; + } + const uint8_t* endp; + double res = jsoncons::detail::from_little_endian(buf,buf+sizeof(buf),&endp); + handler_.double_value(res, semantic_tag::none, *this); + break; + } + case jsoncons::bson::detail::bson_format::string_cd: + { + uint8_t buf[sizeof(int32_t)]; + if (source_.read(buf, sizeof(int32_t)) != sizeof(int32_t)) + { + ec = bson_errc::unexpected_eof; + return; + } + const uint8_t* endp; + auto len = jsoncons::detail::from_little_endian(buf, buf+sizeof(buf),&endp); + + std::basic_string s; + s.reserve(len - 1); + if ((int32_t)source_.read(std::back_inserter(s), len-1) != len-1) + { + ec = bson_errc::unexpected_eof; + return; + } + uint8_t c{}; + source_.get(c); // discard 0 + auto result = unicons::validate(s.begin(),s.end()); + if (result.ec != unicons::conv_errc()) + { + ec = bson_errc::invalid_utf8_text_string; + return; + } + handler_.string_value(basic_string_view(s.data(),s.length()), semantic_tag::none, *this); + break; + } + case jsoncons::bson::detail::bson_format::document_cd: + { + read(ec); + if (ec) + { + return; + } + break; + } + + case jsoncons::bson::detail::bson_format::array_cd: + { + uint8_t buf[sizeof(int32_t)]; + if (source_.read(buf, sizeof(int32_t)) != sizeof(int32_t)) + { + ec = bson_errc::unexpected_eof; + return; + } + const uint8_t* endp; + /* auto len = */ jsoncons::detail::from_little_endian(buf, buf+sizeof(int32_t),&endp); + + handler_.begin_array(semantic_tag::none, *this); + ++nesting_depth_; + read_e_list(jsoncons::bson::detail::bson_container_type::document, ec); + handler_.end_array(*this); + --nesting_depth_; + break; + } + case jsoncons::bson::detail::bson_format::null_cd: + { + handler_.null_value(semantic_tag::none, *this); + break; + } + case jsoncons::bson::detail::bson_format::bool_cd: + { + uint8_t val{}; + if (source_.get(val) == 0) + { + ec = bson_errc::unexpected_eof; + return; + } + handler_.bool_value(val != 0, semantic_tag::none, *this); + break; + } + case jsoncons::bson::detail::bson_format::int32_cd: + { + uint8_t buf[sizeof(int32_t)]; + if (source_.read(buf, sizeof(int32_t)) != sizeof(int32_t)) + { + ec = bson_errc::unexpected_eof; + return; + } + const uint8_t* endp; + auto val = jsoncons::detail::from_little_endian(buf, buf+sizeof(int32_t),&endp); + handler_.int64_value(val, semantic_tag::none, *this); + break; + } + + case jsoncons::bson::detail::bson_format::timestamp_cd: + { + uint8_t buf[sizeof(uint64_t)]; + if (source_.read(buf, sizeof(uint64_t)) != sizeof(uint64_t)) + { + ec = bson_errc::unexpected_eof; + return; + } + const uint8_t* endp; + auto val = jsoncons::detail::from_little_endian(buf, buf+sizeof(uint64_t),&endp); + handler_.uint64_value(val, semantic_tag::timestamp, *this); + break; + } + + case jsoncons::bson::detail::bson_format::int64_cd: + { + uint8_t buf[sizeof(int64_t)]; + if (source_.read(buf, sizeof(int64_t)) != sizeof(int64_t)) + { + ec = bson_errc::unexpected_eof; + return; + } + const uint8_t* endp; + auto val = jsoncons::detail::from_little_endian(buf, buf+sizeof(int64_t),&endp); + handler_.int64_value(val, semantic_tag::none, *this); + break; + } + + case jsoncons::bson::detail::bson_format::datetime_cd: + { + uint8_t buf[sizeof(int64_t)]; + if (source_.read(buf, sizeof(int64_t)) != sizeof(int64_t)) + { + ec = bson_errc::unexpected_eof; + return; + } + const uint8_t* endp; + auto val = jsoncons::detail::from_little_endian(buf, buf+sizeof(int64_t),&endp); + handler_.int64_value(val, semantic_tag::timestamp, *this); + break; + } + case jsoncons::bson::detail::bson_format::binary_cd: + { + uint8_t buf[sizeof(int32_t)]; + if (source_.read(buf, sizeof(int32_t)) != sizeof(int32_t)) + { + ec = bson_errc::unexpected_eof; + return; + } + const uint8_t* endp; + const auto len = jsoncons::detail::from_little_endian(buf, buf+sizeof(int32_t),&endp); + + std::vector v(len, 0); + if (source_.read(v.data(), v.size()) != v.size()) + { + ec = bson_errc::unexpected_eof; + return; + } + + handler_.byte_string_value(byte_string_view(v.data(),v.size()), + semantic_tag::none, + *this); + break; + } + } + + } +}; + +typedef basic_bson_reader bson_reader; +typedef basic_bson_reader bson_bytes_reader; + +#if !defined(JSONCONS_NO_DEPRECATED) +typedef bson_bytes_reader bson_buffer_reader; +#endif + +}} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/cbor/cbor.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/cbor/cbor.hpp new file mode 100644 index 0000000000..c05b3c2439 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/cbor/cbor.hpp @@ -0,0 +1,130 @@ +// Copyright 2017 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_CBOR_CBOR_HPP +#define JSONCONS_CBOR_CBOR_HPP + +#include +#include +#include +#include // std::enable_if +#include // std::basic_istream +#include +#include +#include +#include +#include + +namespace jsoncons { namespace cbor { + +// encode_cbor + +template +void encode_cbor(const T& j, std::vector& v) +{ + encode_cbor(j,v,cbor_options::default_options()); +} + +template +void encode_cbor(const T& j, std::ostream& os) +{ + encode_cbor(j,os,cbor_options::default_options()); +} + +template +typename std::enable_if::value,void>::type +encode_cbor(const T& j, std::vector& v, const cbor_encode_options& options) +{ + typedef typename T::char_type char_type; + cbor_bytes_encoder encoder(v, options); + auto adaptor = make_json_content_handler_adaptor>(encoder); + j.dump(adaptor); +} + +template +typename std::enable_if::value,void>::type +encode_cbor(const T& val, std::vector& v, const cbor_encode_options& options) +{ + cbor_bytes_encoder encoder(v, options); + write_to(json(), val, encoder); +} + +template +typename std::enable_if::value,void>::type +encode_cbor(const T& j, std::ostream& os, const cbor_encode_options& options) +{ + typedef typename T::char_type char_type; + cbor_encoder encoder(os, options); + auto adaptor = make_json_content_handler_adaptor>(encoder); + j.dump(adaptor); +} + +template +typename std::enable_if::value,void>::type +encode_cbor(const T& val, std::ostream& os, const cbor_encode_options& options) +{ + cbor_encoder encoder(os, options); + write_to(json(), val, encoder); +} + +// decode_cbor + +template +typename std::enable_if::value,T>::type +decode_cbor(const std::vector& v) +{ + jsoncons::json_decoder decoder; + auto adaptor = make_json_content_handler_adaptor(decoder); + basic_cbor_reader reader(v, adaptor); + reader.read(); + return decoder.get_result(); +} + +template +typename std::enable_if::value,T>::type +decode_cbor(const std::vector& v) +{ + jsoncons::json_decoder decoder; + basic_cbor_reader reader(v, decoder); + reader.read(); + return decoder.get_result().template as(); +} + +template +typename std::enable_if::value,T>::type +decode_cbor(std::istream& is) +{ + jsoncons::json_decoder decoder; + auto adaptor = make_json_content_handler_adaptor(decoder); + cbor_reader reader(is, adaptor); + reader.read(); + return decoder.get_result(); +} + +template +typename std::enable_if::value,T>::type +decode_cbor(std::istream& is) +{ + jsoncons::json_decoder decoder; + cbor_reader reader(is, decoder); + reader.read(); + return decoder.get_result().template as(); +} + + +#if !defined(JSONCONS_NO_DEPRECATED) +template +std::vector encode_cbor(const Json& j) +{ + std::vector v; + encode_cbor(j, v); + return v; +} +#endif + +}} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/cbor/cbor_detail.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/cbor/cbor_detail.hpp new file mode 100644 index 0000000000..d59397bd27 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/cbor/cbor_detail.hpp @@ -0,0 +1,72 @@ +// Copyright 2017 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_CBOR_CBOR_DETAIL_HPP +#define JSONCONS_CBOR_CBOR_DETAIL_HPP + +#include +#include +#include +#include // std::forward_iterator_tag +#include // std::numeric_limits +#include // std::move +#include +#include +#include + +namespace jsoncons { namespace cbor { namespace detail { + +// 0x00..0x17 (0..23) +#define JSONCONS_CBOR_0x00_0x17 \ + 0x00:case 0x01:case 0x02:case 0x03:case 0x04:case 0x05:case 0x06:case 0x07:case 0x08:case 0x09:case 0x0a:case 0x0b:case 0x0c:case 0x0d:case 0x0e:case 0x0f:case 0x10:case 0x11:case 0x12:case 0x13:case 0x14:case 0x15:case 0x16:case 0x17 + +enum class cbor_major_type : uint8_t +{ + unsigned_integer = 0x00, + negative_integer = 0x01, + byte_string = 0x02, + text_string = 0x03, + array = 0x04, + map = 0x05, + semantic_tag = 0x06, + simple = 0x7 +}; + +namespace additional_info +{ + const uint8_t indefinite_length = 0x1f; +} + +inline +size_t min_length_for_stringref(uint64_t index) +{ + size_t n; + if (index <= 23) + { + n = 3; + } + else if (index <= 255) + { + n = 4; + } + else if (index <= 65535) + { + n = 5; + } + else if (index <= 4294967295) + { + n = 7; + } + else + { + n = 11; + } + return n; +} + +}}} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/cbor/cbor_encoder.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/cbor/cbor_encoder.hpp new file mode 100644 index 0000000000..6fb3ad185a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/cbor/cbor_encoder.hpp @@ -0,0 +1,1062 @@ +// Copyright 2018 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_CBOR_CBOR_ENCODER_HPP +#define JSONCONS_CBOR_CBOR_ENCODER_HPP + +#include +#include +#include // std::numeric_limits +#include +#include // std::move +#include // jsoncons::ser_error +#include +#include +#include +#include +#include +#include + +namespace jsoncons { namespace cbor { + +enum class cbor_container_type {object, indefinite_length_object, array, indefinite_length_array}; + +template +class basic_cbor_encoder final : public basic_json_content_handler +{ + enum class decimal_parse_state { start, integer, exp1, exp2, fraction1 }; + enum class hexfloat_parse_state { start, expect_0, expect_x, integer, exp1, exp2, fraction1 }; + +public: + typedef char char_type; + typedef Result result_type; + using typename basic_json_content_handler::string_view_type; + +private: + struct stack_item + { + cbor_container_type type_; + size_t length_; + size_t count_; + + stack_item(cbor_container_type type, size_t length = 0) + : type_(type), length_(length), count_(0) + { + } + + size_t length() const + { + return length_; + } + + size_t count() const + { + return count_; + } + + bool is_object() const + { + return type_ == cbor_container_type::object || type_ == cbor_container_type::indefinite_length_object; + } + + bool is_indefinite_length() const + { + return type_ == cbor_container_type::indefinite_length_array || type_ == cbor_container_type::indefinite_length_object; + } + + }; + std::vector stack_; + Result result_; + const cbor_encode_options& options_; + + // Noncopyable and nonmoveable + basic_cbor_encoder(const basic_cbor_encoder&) = delete; + basic_cbor_encoder& operator=(const basic_cbor_encoder&) = delete; + + std::map stringref_map_; + std::map bytestringref_map_; + size_t next_stringref_ = 0; +public: + explicit basic_cbor_encoder(result_type result) + : result_(std::move(result)), options_(cbor_options::default_options()) + { + } + basic_cbor_encoder(result_type result, const cbor_encode_options& options) + : result_(std::move(result)), options_(options) + { + if (options.pack_strings()) + { + // tag(256) + result_.push_back(0xd9); + result_.push_back(0x01); + result_.push_back(0x00); + } + } + + ~basic_cbor_encoder() + { + try + { + result_.flush(); + } + catch (...) + { + } + } + +private: + // Implementing methods + + void do_flush() override + { + result_.flush(); + } + + bool do_begin_object(semantic_tag, const ser_context&) override + { + stack_.push_back(stack_item(cbor_container_type::indefinite_length_object)); + + result_.push_back(0xbf); + return true; + } + + bool do_begin_object(size_t length, semantic_tag, const ser_context&) override + { + stack_.push_back(stack_item(cbor_container_type::object, length)); + + if (length <= 0x17) + { + jsoncons::detail::to_big_endian(static_cast(0xa0 + length), + std::back_inserter(result_)); + } + else if (length <= 0xff) + { + jsoncons::detail::to_big_endian(static_cast(0xb8), + std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(length), + std::back_inserter(result_)); + } + else if (length <= 0xffff) + { + jsoncons::detail::to_big_endian(static_cast(0xb9), + std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(length), + std::back_inserter(result_)); + } + else if (length <= 0xffffffff) + { + jsoncons::detail::to_big_endian(static_cast(0xba), + std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(length), + std::back_inserter(result_)); + } + else if (length <= 0xffffffffffffffff) + { + jsoncons::detail::to_big_endian(static_cast(0xbb), + std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(length), + std::back_inserter(result_)); + } + + return true; + } + + bool do_end_object(const ser_context&) override + { + JSONCONS_ASSERT(!stack_.empty()); + if (stack_.back().is_indefinite_length()) + { + result_.push_back(0xff); + } + else + { + if (stack_.back().count() < stack_.back().length()) + { + throw ser_error(cbor_errc::too_few_items); + } + if (stack_.back().count() > stack_.back().length()) + { + throw ser_error(cbor_errc::too_many_items); + } + } + + stack_.pop_back(); + end_value(); + + return true; + } + + bool do_begin_array(semantic_tag, const ser_context&) override + { + stack_.push_back(stack_item(cbor_container_type::indefinite_length_array)); + result_.push_back(0x9f); + return true; + } + + bool do_begin_array(size_t length, semantic_tag tag, const ser_context&) override + { +#if !defined(JSONCONS_NO_DEPRECATED) + if (length == 2 && tag == semantic_tag::bigfloat) + { + result_.push_back(0xc5); + } +#endif + stack_.push_back(stack_item(cbor_container_type::array, length)); + if (length <= 0x17) + { + jsoncons::detail::to_big_endian(static_cast(0x80 + length), + std::back_inserter(result_)); + } + else if (length <= 0xff) + { + jsoncons::detail::to_big_endian(static_cast(0x98), + std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(length), + std::back_inserter(result_)); + } + else if (length <= 0xffff) + { + jsoncons::detail::to_big_endian(static_cast(0x99), + std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(length), + std::back_inserter(result_)); + } + else if (length <= 0xffffffff) + { + jsoncons::detail::to_big_endian(static_cast(0x9a), + std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(length), + std::back_inserter(result_)); + } + else if (length <= 0xffffffffffffffff) + { + jsoncons::detail::to_big_endian(static_cast(0x9b), + std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(length), + std::back_inserter(result_)); + } + return true; + } + + bool do_end_array(const ser_context&) override + { + JSONCONS_ASSERT(!stack_.empty()); + + if (stack_.back().is_indefinite_length()) + { + result_.push_back(0xff); + } + else + { + if (stack_.back().count() < stack_.back().length()) + { + throw ser_error(cbor_errc::too_few_items); + } + if (stack_.back().count() > stack_.back().length()) + { + throw ser_error(cbor_errc::too_many_items); + } + } + + stack_.pop_back(); + end_value(); + + return true; + } + + bool do_name(const string_view_type& name, const ser_context&) override + { + write_string(name); + return true; + } + + bool do_null_value(semantic_tag tag, const ser_context&) override + { + if (tag == semantic_tag::undefined) + { + result_.push_back(0xf7); + } + else + { + result_.push_back(0xf6); + } + + end_value(); + return true; + } + + void write_string(const string_view& sv) + { + auto result = unicons::validate(sv.begin(), sv.end()); + if (result.ec != unicons::conv_errc()) + { + JSONCONS_THROW(json_runtime_error("Illegal unicode")); + } + + if (options_.pack_strings() && sv.size() >= jsoncons::cbor::detail::min_length_for_stringref(next_stringref_)) + { + std::string s(sv); + auto it = stringref_map_.find(s); + if (it == stringref_map_.end()) + { + stringref_map_.insert(std::make_pair(std::move(s), next_stringref_++)); + write_utf8_string(sv); + } + else + { + // tag(25) + result_.push_back(0xd8); + result_.push_back(0x19); + write_uint64_value(it->second); + } + } + else + { + write_utf8_string(sv); + } + } + + void write_utf8_string(const string_view& sv) + { + const size_t length = sv.size(); + + if (length <= 0x17) + { + // fixstr stores a byte array whose length is upto 31 bytes + jsoncons::detail::to_big_endian(static_cast(0x60 + length), + std::back_inserter(result_)); + } + else if (length <= 0xff) + { + jsoncons::detail::to_big_endian(static_cast(0x78), + std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(length), + std::back_inserter(result_)); + } + else if (length <= 0xffff) + { + jsoncons::detail::to_big_endian(static_cast(0x79), + std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(length), + std::back_inserter(result_)); + } + else if (length <= 0xffffffff) + { + jsoncons::detail::to_big_endian(static_cast(0x7a), + std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(length), + std::back_inserter(result_)); + } + else if (length <= 0xffffffffffffffff) + { + jsoncons::detail::to_big_endian(static_cast(0x7b), + std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(length), + std::back_inserter(result_)); + } + + for (auto c : sv) + { + result_.push_back(c); + } + } + + void write_bignum(const bignum& n) + { + int signum; + std::vector data; + n.dump(signum, data); + size_t length = data.size(); + + if (signum == -1) + { + result_.push_back(0xc3); + } + else + { + result_.push_back(0xc2); + } + + if (length <= 0x17) + { + // fixstr stores a byte array whose length is upto 31 bytes + jsoncons::detail::to_big_endian(static_cast(0x40 + length), + std::back_inserter(result_)); + } + else if (length <= 0xff) + { + jsoncons::detail::to_big_endian(static_cast(0x58), + std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(length), + std::back_inserter(result_)); + } + else if (length <= 0xffff) + { + jsoncons::detail::to_big_endian(static_cast(0x59), + std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(length), + std::back_inserter(result_)); + } + else if (length <= 0xffffffff) + { + jsoncons::detail::to_big_endian(static_cast(0x5a), + std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(length), + std::back_inserter(result_)); + } + else if (length <= 0xffffffffffffffff) + { + jsoncons::detail::to_big_endian(static_cast(0x5b), + std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(length), + std::back_inserter(result_)); + } + + for (auto c : data) + { + result_.push_back(c); + } + } + + void write_decimal_value(const string_view_type& sv, const ser_context& context) + { + decimal_parse_state state = decimal_parse_state::start; + std::basic_string s; + std::basic_string exponent; + int64_t scale = 0; + for (auto c : sv) + { + switch (state) + { + case decimal_parse_state::start: + { + switch (c) + { + case '-': + s.push_back(c); + state = decimal_parse_state::integer; + break; + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + s.push_back(c); + state = decimal_parse_state::integer; + break; + default: + throw std::invalid_argument("Invalid decimal string"); + } + break; + } + case decimal_parse_state::integer: + { + switch (c) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + s.push_back(c); + state = decimal_parse_state::integer; + break; + case 'e': case 'E': + state = decimal_parse_state::exp1; + break; + case '.': + state = decimal_parse_state::fraction1; + break; + default: + throw std::invalid_argument("Invalid decimal string"); + } + break; + } + case decimal_parse_state::exp1: + { + switch (c) + { + case '+': + state = decimal_parse_state::exp2; + break; + case '-': + exponent.push_back(c); + state = decimal_parse_state::exp2; + break; + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + exponent.push_back(c); + state = decimal_parse_state::exp2; + break; + default: + throw std::invalid_argument("Invalid decimal string"); + } + break; + } + case decimal_parse_state::exp2: + { + switch (c) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + exponent.push_back(c); + break; + default: + throw std::invalid_argument("Invalid decimal string"); + } + break; + } + case decimal_parse_state::fraction1: + { + switch (c) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + s.push_back(c); + --scale; + break; + default: + throw std::invalid_argument("Invalid decimal string"); + } + break; + } + } + } + + result_.push_back(0xc4); + do_begin_array((size_t)2, semantic_tag::none, context); + if (exponent.length() > 0) + { + auto result = jsoncons::detail::to_integer(exponent.data(), exponent.length()); + if (result.ec != jsoncons::detail::to_integer_errc()) + { + JSONCONS_THROW(json_runtime_error(make_error_code(result.ec).message())); + } + scale += result.value; + } + do_int64_value(scale, semantic_tag::none, context); + + auto result = jsoncons::detail::to_integer(s.data(),s.length()); + if (result.ec == jsoncons::detail::to_integer_errc()) + { + do_int64_value(result.value, semantic_tag::none, context); + } + else if (result.ec == jsoncons::detail::to_integer_errc::overflow) + { + bignum n(s.data(), s.length()); + write_bignum(n); + end_value(); + } + else + { + JSONCONS_THROW(json_runtime_error(make_error_code(result.ec).message())); + } + do_end_array(context); + } + + void write_hexfloat_value(const string_view_type& sv, const ser_context& context) + { + hexfloat_parse_state state = hexfloat_parse_state::start; + std::basic_string s; + std::basic_string exponent; + int64_t scale = 0; + + for (auto c : sv) + { + switch (state) + { + case hexfloat_parse_state::start: + { + switch (c) + { + case '-': + s.push_back(c); + state = hexfloat_parse_state::expect_0; + break; + case '0': + state = hexfloat_parse_state::expect_x; + break; + default: + throw std::invalid_argument("Invalid hexfloat string"); + } + break; + } + case hexfloat_parse_state::expect_0: + { + switch (c) + { + case '0': + state = hexfloat_parse_state::expect_x; + break; + default: + throw std::invalid_argument("Invalid hexfloat string"); + } + break; + } + case hexfloat_parse_state::expect_x: + { + switch (c) + { + case 'x': + case 'X': + state = hexfloat_parse_state::integer; + break; + default: + throw std::invalid_argument("Invalid hexfloat string"); + } + break; + } + case hexfloat_parse_state::integer: + { + switch (c) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9':case 'a':case 'b':case 'c':case 'd':case 'e':case 'f':case 'A':case 'B':case 'C':case 'D':case 'E':case 'F': + s.push_back(c); + state = hexfloat_parse_state::integer; + break; + case 'p': case 'P': + state = hexfloat_parse_state::exp1; + break; + case '.': + state = hexfloat_parse_state::fraction1; + break; + default: + throw std::invalid_argument("Invalid hexfloat string"); + } + break; + } + case hexfloat_parse_state::exp1: + { + switch (c) + { + case '+': + state = hexfloat_parse_state::exp2; + break; + case '-': + exponent.push_back(c); + state = hexfloat_parse_state::exp2; + break; + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9':case 'a':case 'b':case 'c':case 'd':case 'e':case 'f':case 'A':case 'B':case 'C':case 'D':case 'E':case 'F': + exponent.push_back(c); + state = hexfloat_parse_state::exp2; + break; + default: + throw std::invalid_argument("Invalid hexfloat string"); + } + break; + } + case hexfloat_parse_state::exp2: + { + switch (c) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9':case 'a':case 'b':case 'c':case 'd':case 'e':case 'f':case 'A':case 'B':case 'C':case 'D':case 'E':case 'F': + exponent.push_back(c); + break; + default: + throw std::invalid_argument("Invalid hexfloat string"); + } + break; + } + case hexfloat_parse_state::fraction1: + { + switch (c) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9':case 'a':case 'b':case 'c':case 'd':case 'e':case 'f':case 'A':case 'B':case 'C':case 'D':case 'E':case 'F': + s.push_back(c); + scale -= 4; + break; + default: + throw std::invalid_argument("Invalid hexfloat string"); + } + break; + } + } + } + + result_.push_back(0xc5); + do_begin_array((size_t)2, semantic_tag::none, context); + if (exponent.length() > 0) + { + auto result = jsoncons::detail::base16_to_integer(exponent.data(), exponent.length()); + if (result.ec != jsoncons::detail::to_integer_errc()) + { + JSONCONS_THROW(json_runtime_error(make_error_code(result.ec).message())); + } + scale += result.value; + } + do_int64_value(scale, semantic_tag::none, context); + + auto result = jsoncons::detail::base16_to_integer(s.data(),s.length()); + if (result.ec == jsoncons::detail::to_integer_errc()) + { + do_int64_value(result.value, semantic_tag::none, context); + } + else if (result.ec == jsoncons::detail::to_integer_errc::overflow) + { + bignum n(s.data(), s.length(), 16); + write_bignum(n); + end_value(); + } + else + { + JSONCONS_THROW(json_runtime_error(make_error_code(result.ec).message())); + } + do_end_array(context); + } + + bool do_string_value(const string_view_type& sv, semantic_tag tag, const ser_context& context) override + { + switch (tag) + { + case semantic_tag::bigint: + { + bignum n(sv.data(), sv.length()); + write_bignum(n); + end_value(); + break; + } + case semantic_tag::bigdec: + { + write_decimal_value(sv, context); + break; + } + case semantic_tag::bigfloat: + { + write_hexfloat_value(sv, context); + break; + } + case semantic_tag::datetime: + { + result_.push_back(0xc0); + write_string(sv); + end_value(); + break; + } + case semantic_tag::uri: + { + result_.push_back(32); + write_string(sv); + end_value(); + break; + } + case semantic_tag::base64url: + { + result_.push_back(33); + write_string(sv); + end_value(); + break; + } + case semantic_tag::base64: + { + result_.push_back(34); + write_string(sv); + end_value(); + break; + } + default: + { + write_string(sv); + end_value(); + break; + } + } + return true; + } + + bool do_byte_string_value(const byte_string_view& b, + semantic_tag tag, + const ser_context&) override + { + byte_string_chars_format encoding_hint; + switch (tag) + { + case semantic_tag::base16: + encoding_hint = byte_string_chars_format::base16; + break; + case semantic_tag::base64: + encoding_hint = byte_string_chars_format::base64; + break; + case semantic_tag::base64url: + encoding_hint = byte_string_chars_format::base64url; + break; + default: + encoding_hint = byte_string_chars_format::none; + break; + } + switch (encoding_hint) + { + case byte_string_chars_format::base64url: + result_.push_back(0xd5); + break; + case byte_string_chars_format::base64: + result_.push_back(0xd6); + break; + case byte_string_chars_format::base16: + result_.push_back(0xd7); + break; + default: + break; + } + if (options_.pack_strings() && b.length() >= jsoncons::cbor::detail::min_length_for_stringref(next_stringref_)) + { + auto it = bytestringref_map_.find(byte_string(b)); + if (it == bytestringref_map_.end()) + { + bytestringref_map_.insert(std::make_pair(byte_string(b), next_stringref_++)); + write_byte_string_value(b); + } + else + { + // tag(25) + result_.push_back(0xd8); + result_.push_back(0x19); + write_uint64_value(it->second); + } + } + else + { + write_byte_string_value(b); + } + + end_value(); + return true; + } + + void write_byte_string_value(const byte_string_view& b) + { + if (b.length() <= 0x17) + { + // fixstr stores a byte array whose length is upto 31 bytes + jsoncons::detail::to_big_endian(static_cast(0x40 + b.length()), + std::back_inserter(result_)); + } + else if (b.length() <= 0xff) + { + jsoncons::detail::to_big_endian(static_cast(0x58), + std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(b.length()), + std::back_inserter(result_)); + } + else if (b.length() <= 0xffff) + { + jsoncons::detail::to_big_endian(static_cast(0x59), + std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(b.length()), + std::back_inserter(result_)); + } + else if (b.length() <= 0xffffffff) + { + jsoncons::detail::to_big_endian(static_cast(0x5a), + std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(b.length()), + std::back_inserter(result_)); + } + else if (b.length() <= 0xffffffffffffffff) + { + jsoncons::detail::to_big_endian(static_cast(0x5b), + std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(b.length()), + std::back_inserter(result_)); + } + + for (auto c : b) + { + result_.push_back(c); + } + } + + bool do_double_value(double val, + semantic_tag tag, + const ser_context&) override + { + if (tag == semantic_tag::timestamp) + { + result_.push_back(0xc1); + } + + float valf = (float)val; + if ((double)valf == val) + { + jsoncons::detail::to_big_endian(static_cast(0xfa), + std::back_inserter(result_)); + jsoncons::detail::to_big_endian(valf, std::back_inserter(result_)); + } + else + { + jsoncons::detail::to_big_endian(static_cast(0xfb), + std::back_inserter(result_)); + jsoncons::detail::to_big_endian(val, std::back_inserter(result_)); + } + + // write double + + end_value(); + return true; + } + + bool do_int64_value(int64_t value, + semantic_tag tag, + const ser_context&) override + { + if (tag == semantic_tag::timestamp) + { + result_.push_back(0xc1); + } + if (value >= 0) + { + if (value <= 0x17) + { + jsoncons::detail::to_big_endian(static_cast(value), + std::back_inserter(result_)); + } + else if (value <= (std::numeric_limits::max)()) + { + jsoncons::detail::to_big_endian(static_cast(0x18), + std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(value), + std::back_inserter(result_)); + } + else if (value <= (std::numeric_limits::max)()) + { + jsoncons::detail::to_big_endian(static_cast(0x19), + std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(value), + std::back_inserter(result_)); + } + else if (value <= (std::numeric_limits::max)()) + { + jsoncons::detail::to_big_endian(static_cast(0x1a), + std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(value), + std::back_inserter(result_)); + } + else if (value <= (std::numeric_limits::max)()) + { + jsoncons::detail::to_big_endian(static_cast(0x1b), + std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(value), + std::back_inserter(result_)); + } + } else + { + const auto posnum = -1 - value; + if (value >= -24) + { + jsoncons::detail::to_big_endian(static_cast(0x20 + posnum), + std::back_inserter(result_)); + } + else if (posnum <= (std::numeric_limits::max)()) + { + jsoncons::detail::to_big_endian(static_cast(0x38), + std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(posnum), + std::back_inserter(result_)); + } + else if (posnum <= (std::numeric_limits::max)()) + { + jsoncons::detail::to_big_endian(static_cast(0x39), + std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(posnum), + std::back_inserter(result_)); + } + else if (posnum <= (std::numeric_limits::max)()) + { + jsoncons::detail::to_big_endian(static_cast(0x3a), + std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(posnum), + std::back_inserter(result_)); + } + else if (posnum <= (std::numeric_limits::max)()) + { + jsoncons::detail::to_big_endian(static_cast(0x3b), + std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(posnum), + std::back_inserter(result_)); + } + } + end_value(); + return true; + } + + bool do_uint64_value(uint64_t value, + semantic_tag tag, + const ser_context&) override + { + if (tag == semantic_tag::timestamp) + { + result_.push_back(0xc1); + } + + write_uint64_value(value); + end_value(); + return true; + } + + void write_uint64_value(uint64_t value) + { + if (value <= 0x17) + { + jsoncons::detail::to_big_endian(static_cast(value), + std::back_inserter(result_)); + } + else if (value <=(std::numeric_limits::max)()) + { + jsoncons::detail::to_big_endian(static_cast(0x18), + std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(value), + std::back_inserter(result_)); + } + else if (value <=(std::numeric_limits::max)()) + { + jsoncons::detail::to_big_endian(static_cast(0x19), + std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(value), + std::back_inserter(result_)); + } + else if (value <=(std::numeric_limits::max)()) + { + jsoncons::detail::to_big_endian(static_cast(0x1a), + std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(value), + std::back_inserter(result_)); + } + else if (value <=(std::numeric_limits::max)()) + { + jsoncons::detail::to_big_endian(static_cast(0x1b), + std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(value), + std::back_inserter(result_)); + } + } + + bool do_bool_value(bool value, semantic_tag, const ser_context&) override + { + if (value) + { + result_.push_back(0xf5); + } + else + { + result_.push_back(0xf4); + } + + end_value(); + return true; + } + + void end_value() + { + if (!stack_.empty()) + { + ++stack_.back().count_; + } + } +}; + +typedef basic_cbor_encoder cbor_encoder; +typedef basic_cbor_encoder cbor_bytes_encoder; + +#if !defined(JSONCONS_NO_DEPRECATED) +typedef basic_cbor_encoder cbor_bytes_serializer; + +template +using basic_cbor_serializer = basic_cbor_encoder; + +typedef basic_cbor_encoder cbor_serializer; +typedef basic_cbor_encoder cbor_buffer_serializer; +#endif + +}} +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/cbor/cbor_error.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/cbor/cbor_error.hpp new file mode 100644 index 0000000000..79c3de976f --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/cbor/cbor_error.hpp @@ -0,0 +1,96 @@ +/// Copyright 2018 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_CBOR_CBOR_ERROR_HPP +#define JSONCONS_CBOR_CBOR_ERROR_HPP + +#include +#include +#include // jsoncons::ser_error + +namespace jsoncons { namespace cbor { + +enum class cbor_errc +{ + ok = 0, + unexpected_eof, + source_error, + invalid_decimal, + invalid_bigfloat, + invalid_utf8_text_string, + too_many_items, + too_few_items, + number_too_large, + stringref_too_large +}; + +class cbor_error_category_impl + : public std::error_category +{ +public: + const char* name() const noexcept override + { + return "jsoncons/cbor"; + } + std::string message(int ev) const override + { + switch (static_cast(ev)) + { + case cbor_errc::unexpected_eof: + return "Unexpected end of file"; + case cbor_errc::source_error: + return "Source error"; + case cbor_errc::invalid_decimal: + return "Invalid decimal"; + case cbor_errc::invalid_bigfloat: + return "Invalid bigfloat"; + case cbor_errc::invalid_utf8_text_string: + return "Illegal UTF-8 encoding in text string"; + case cbor_errc::too_many_items: + return "Too many items were added to a CBOR map or array of known length"; + case cbor_errc::too_few_items: + return "Too few items were added to a CBOR map or array of known length"; + case cbor_errc::number_too_large: + return "Number exceeds implementation limits"; + case cbor_errc::stringref_too_large: + return "stringref exceeds stringref map size"; + default: + return "Unknown CBOR parser error"; + } + } +}; + +inline +const std::error_category& cbor_error_category() +{ + static cbor_error_category_impl instance; + return instance; +} + +inline +std::error_code make_error_code(cbor_errc e) +{ + return std::error_code(static_cast(e),cbor_error_category()); +} + + +#if !defined(JSONCONS_NO_DEPRECATED) + +typedef ser_error cbor_error; +typedef ser_error cbor_decode_error; +typedef cbor_errc cbor_reader_errc; +#endif + +}} + +namespace std { + template<> + struct is_error_code_enum : public true_type + { + }; +} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/cbor/cbor_options.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/cbor/cbor_options.hpp new file mode 100644 index 0000000000..cc780ca80a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/cbor/cbor_options.hpp @@ -0,0 +1,66 @@ +// Copyright 2019 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_CBOR_CBOR_OPTIONS_HPP +#define JSONCONS_CBOR_CBOR_OPTIONS_HPP + +#include +#include // std::numeric_limits +#include +#include +#include + +namespace jsoncons { namespace cbor { + +class cbor_decode_options +{ +public: + virtual ~cbor_decode_options() = default; +}; + +class cbor_encode_options +{ +public: + virtual ~cbor_encode_options() = default; + + virtual bool pack_strings() const = 0; +}; + +class cbor_options : public virtual cbor_decode_options, + public virtual cbor_encode_options +{ +private: + bool pack_strings_; +public: + + static const cbor_options& default_options() + { + static cbor_options options{}; + return options; + } + + +// Constructors + + cbor_options() + : pack_strings_(false) + { + } + + bool pack_strings() const override + { + return pack_strings_; + } + + cbor_options& pack_strings(bool value) + { + pack_strings_ = value; + return *this; + } +}; + +}} +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/cbor/cbor_reader.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/cbor/cbor_reader.hpp new file mode 100644 index 0000000000..cb63bcafd1 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/cbor/cbor_reader.hpp @@ -0,0 +1,1491 @@ +// Copyright 2017 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_CBOR_CBOR_READER_HPP +#define JSONCONS_CBOR_CBOR_READER_HPP + +#include +#include +#include +#include // std::move +#include +#include +#include +#include +#include +#include +#include + +namespace jsoncons { namespace cbor { + +enum class parse_mode {root,array,indefinite_array,map,indefinite_map}; + +struct mapped_string +{ + jsoncons::cbor::detail::cbor_major_type type; + std::string s; + std::vector bs; + + mapped_string(const std::string& s) + : type(jsoncons::cbor::detail::cbor_major_type::text_string), s(s) + { + } + + mapped_string(std::string&& s) + : type(jsoncons::cbor::detail::cbor_major_type::text_string), s(std::move(s)) + { + } + + mapped_string(const std::vector& bs) + : type(jsoncons::cbor::detail::cbor_major_type::byte_string), bs(bs) + { + } + + mapped_string(std::vector&& bs) + : type(jsoncons::cbor::detail::cbor_major_type::byte_string), bs(std::move(bs)) + { + } + + mapped_string(const mapped_string&) = default; + + mapped_string(mapped_string&&) = default; + + mapped_string& operator=(const mapped_string&) = default; + + mapped_string& operator=(mapped_string&&) = default; +}; + +typedef std::vector stringref_map_type; + +struct parse_state +{ + parse_mode mode; + size_t length; + size_t index; + std::shared_ptr stringref_map; + + parse_state(parse_mode mode, size_t length) + : mode(mode), length(length), index(0) + { + } + + parse_state(parse_mode mode, size_t length, std::shared_ptr stringref_map) + : mode(mode), length(length), index(0), stringref_map(stringref_map) + { + } + + parse_state(const parse_state&) = default; + parse_state(parse_state&&) = default; +}; + +template +class basic_cbor_reader : public ser_context +{ + Src source_; + json_content_handler& handler_; + std::string buffer_; + std::vector tags_; + std::vector state_stack_; +public: + template + basic_cbor_reader(Source&& source, json_content_handler& handler) + : source_(std::forward(source)), + handler_(handler) + { + } + + void read() + { + std::error_code ec; + read(ec); + if (ec) + { + throw ser_error(ec,line(),column()); + } + } + + void read(std::error_code& ec) + { + if (source_.is_error()) + { + ec = cbor_errc::source_error; + return; + } + try + { + state_stack_.emplace_back(parse_mode::root,0); + read_internal(ec); + if (ec) + { + return; + } + } + catch (const ser_error& e) + { + ec = e.code(); + } + } + + size_t line() const override + { + return 0; + } + + size_t column() const override + { + return source_.position(); + } +private: + + void read_internal(std::error_code& ec) + { + while (!state_stack_.empty()) + { + switch (state_stack_.back().mode) + { + case parse_mode::array: + { + if (state_stack_.back().index < state_stack_.back().length) + { + ++state_stack_.back().index; + read_item(ec); + if (ec) + { + return; + } + } + else + { + end_array(ec); + } + break; + } + case parse_mode::indefinite_array: + { + int c = source_.peek(); + switch (c) + { + case Src::traits_type::eof(): + ec = cbor_errc::unexpected_eof; + return; + case 0xff: + end_array(ec); + if (ec) + { + return; + } + break; + default: + read_item(ec); + if (ec) + { + return; + } + break; + } + break; + } + case parse_mode::map: + { + if (state_stack_.back().index < state_stack_.back().length) + { + ++state_stack_.back().index; + read_name(ec); + if (ec) + { + return; + } + read_item(ec); + if (ec) + { + return; + } + } + else + { + end_map(ec); + } + break; + } + case parse_mode::indefinite_map: + { + int c = source_.peek(); + switch (c) + { + case Src::traits_type::eof(): + ec = cbor_errc::unexpected_eof; + return; + case 0xff: + end_map(ec); + if (ec) + { + return; + } + break; + default: + read_name(ec); + if (ec) + { + return; + } + read_item(ec); + if (ec) + { + return; + } + break; + } + break; + } + case parse_mode::root: + { + read_item(ec); + if (ec) + { + return; + } + } + break; + } + + JSONCONS_ASSERT(!state_stack_.empty()); + if (state_stack_.back().mode == parse_mode::root) + { + state_stack_.pop_back(); + handler_.flush(); + } + } + } + + void read_item(std::error_code& ec) + { + read_tags(ec); + if (ec) + { + return; + } + int c = source_.peek(); + if (c == Src::traits_type::eof()) + { + ec = cbor_errc::unexpected_eof; + return; + } + jsoncons::cbor::detail::cbor_major_type major_type = get_major_type((uint8_t)c); + + uint8_t info = get_additional_information_value((uint8_t)c); + switch (major_type) + { + case jsoncons::cbor::detail::cbor_major_type::unsigned_integer: + { + uint64_t val = get_uint64_value(source_, ec); + if (ec) + { + return; + } + if (state_stack_.back().stringref_map && !tags_.empty() && tags_.back() == 25) + { + tags_.pop_back(); + if (val >= state_stack_.back().stringref_map->size()) + { + ec = cbor_errc::stringref_too_large; + return; + } + stringref_map_type::size_type index = (stringref_map_type::size_type)val; + if (index != val) + { + ec = cbor_errc::number_too_large; + return; + } + auto& str = state_stack_.back().stringref_map->at(index); + switch (str.type) + { + case jsoncons::cbor::detail::cbor_major_type::text_string: + { + handle_string(basic_string_view(str.s.data(),str.s.length()),ec); + if (ec) + { + return; + } + break; + } + case jsoncons::cbor::detail::cbor_major_type::byte_string: + { + handle_byte_string(byte_string_view(str.bs.data(),str.bs.size()), ec); + if (ec) + { + return; + } + break; + } + default: + JSONCONS_UNREACHABLE(); + break; + } + } + else + { + semantic_tag tag = semantic_tag::none; + if (!tags_.empty()) + { + if (tags_.back() == 1) + { + tag = semantic_tag::timestamp; + } + tags_.clear(); + } + handler_.uint64_value(val, tag, *this); + } + break; + } + case jsoncons::cbor::detail::cbor_major_type::negative_integer: + { + int64_t val = get_int64_value(source_, ec); + if (ec) + { + return; + } + semantic_tag tag = semantic_tag::none; + if (!tags_.empty()) + { + if (tags_.back() == 1) + { + tag = semantic_tag::timestamp; + } + tags_.clear(); + } + handler_.int64_value(val, tag, *this); + break; + } + case jsoncons::cbor::detail::cbor_major_type::byte_string: + { + std::vector v = get_byte_string(ec); + if (ec) + { + return; + } + handle_byte_string(byte_string_view(v.data(), v.size()), ec); + if (ec) + { + return; + } + break; + } + case jsoncons::cbor::detail::cbor_major_type::text_string: + { + std::string s = get_text_string(ec); + auto result = unicons::validate(s.begin(),s.end()); + if (result.ec != unicons::conv_errc()) + { + ec = cbor_errc::invalid_utf8_text_string; + return; + } + handle_string(basic_string_view(s.data(),s.length()),ec); + if (ec) + { + return; + } + break; + } + case jsoncons::cbor::detail::cbor_major_type::semantic_tag: + { + JSONCONS_UNREACHABLE(); + break; + } + case jsoncons::cbor::detail::cbor_major_type::simple: + { + switch (info) + { + case 0x14: + handler_.bool_value(false, semantic_tag::none, *this); + source_.ignore(1); + break; + case 0x15: + handler_.bool_value(true, semantic_tag::none, *this); + source_.ignore(1); + break; + case 0x16: + handler_.null_value(semantic_tag::none, *this); + source_.ignore(1); + break; + case 0x17: + handler_.null_value(semantic_tag::undefined, *this); + source_.ignore(1); + break; + case 0x19: // Half-Precision Float (two-byte IEEE 754) + case 0x1a: // Single-Precision Float (four-byte IEEE 754) + case 0x1b: // Double-Precision Float (eight-byte IEEE 754) + double val = get_double(source_, ec); + if (ec) + { + return; + } + semantic_tag tag = semantic_tag::none; + if (!tags_.empty()) + { + if (tags_.back() == 1) + { + tag = semantic_tag::timestamp; + } + tags_.clear(); + } + handler_.double_value(val, tag, *this); + break; + } + break; + } + case jsoncons::cbor::detail::cbor_major_type::array: + { + if (!tags_.empty() && tags_.back() == 0x04) + { + std::string s = get_array_as_decimal_string(ec); + if (ec) + { + return; + } + handler_.string_value(s, semantic_tag::bigdec); + tags_.pop_back(); + } + else if (!tags_.empty() && tags_.back() == 0x05) + { + std::string s = get_array_as_hexfloat_string(ec); + if (ec) + { + return; + } + handler_.string_value(s, semantic_tag::bigfloat); + tags_.pop_back(); + } + else + { + begin_array(info, ec); + } + break; + } + case jsoncons::cbor::detail::cbor_major_type::map: + { + begin_map(info,ec); + break; + } + default: + break; + } + tags_.clear(); + } + + void begin_array(uint8_t info, std::error_code& ec) + { + semantic_tag tag = semantic_tag::none; + auto stringref_map = state_stack_.back().stringref_map; + for (auto t : tags_) + { + switch (t) + { + case 0x05: + tag = semantic_tag::bigfloat; + break; + case 0x100: // 256 (stringref-namespace) + stringref_map = std::make_shared(); + break; + default: + break; + } + } + tags_.clear(); + switch (info) + { + case jsoncons::cbor::detail::additional_info::indefinite_length: + { + state_stack_.push_back(parse_state(parse_mode::indefinite_array,0,stringref_map)); + handler_.begin_array(tag, *this); + source_.ignore(1); + break; + } + default: // definite length + { + size_t len = get_definite_length(source_,ec); + if (ec) + { + return; + } + state_stack_.push_back(parse_state(parse_mode::array,len,stringref_map)); + handler_.begin_array(len, tag, *this); + break; + } + } + } + + void end_array(std::error_code&) + { + switch (state_stack_.back().mode) + { + case parse_mode::indefinite_array: + { + source_.ignore(1); + break; + } + default: + break; + } + handler_.end_array(*this); + state_stack_.pop_back(); + } + + void begin_map(uint8_t info, std::error_code& ec) + { + auto stringref_map = state_stack_.back().stringref_map; + for (auto t : tags_) + { + switch (t) + { + case 0x100: // 256 (stringref-namespace) + stringref_map = std::make_shared(); + break; + default: + break; + } + } + tags_.clear(); + switch (info) + { + case jsoncons::cbor::detail::additional_info::indefinite_length: + { + state_stack_.push_back(parse_state(parse_mode::indefinite_map,0,stringref_map)); + handler_.begin_object(semantic_tag::none, *this); + source_.ignore(1); + break; + } + default: // definite_length + { + size_t len = get_definite_length(source_, ec); + if (ec) + { + return; + } + state_stack_.push_back(parse_state(parse_mode::map,len,stringref_map)); + handler_.begin_object(len, semantic_tag::none, *this); + break; + } + } + } + + void end_map(std::error_code&) + { + switch (state_stack_.back().mode) + { + case parse_mode::indefinite_map: + { + source_.ignore(1); + break; + } + default: + break; + } + handler_.end_object(*this); + state_stack_.pop_back(); + } + + void read_name(std::error_code& ec) + { + read_tags(ec); + if (ec) + { + return; + } + jsoncons::cbor::detail::cbor_major_type major_type; + int c = source_.peek(); + switch (c) + { + case Src::traits_type::eof(): + ec = cbor_errc::unexpected_eof; + return; + default: + major_type = get_major_type((uint8_t)c); + break; + } + switch (major_type) + { + case jsoncons::cbor::detail::cbor_major_type::text_string: + { + std::string s = get_text_string(ec); + if (ec) + { + return; + } + auto result = unicons::validate(s.begin(),s.end()); + if (result.ec != unicons::conv_errc()) + { + ec = cbor_errc::invalid_utf8_text_string; + return; + } + handler_.name(basic_string_view(s.data(),s.length()), *this); + break; + } + case jsoncons::cbor::detail::cbor_major_type::byte_string: + { + std::vector v = get_byte_string(ec); + if (ec) + { + return; + } + std::string s; + encode_base64url(v.begin(),v.end(),s); + handler_.name(basic_string_view(s.data(),s.length()), *this); + break; + } + case jsoncons::cbor::detail::cbor_major_type::unsigned_integer: + { + if (state_stack_.back().stringref_map && !tags_.empty() && tags_.back() == 25) + { + uint64_t ref = get_uint64_value(source_, ec); + if (ec) + { + return; + } + if (ref >= state_stack_.back().stringref_map->size()) + { + ec = cbor_errc::stringref_too_large; + return; + } + + stringref_map_type::size_type index = (stringref_map_type::size_type)ref; + if (index != ref) + { + ec = cbor_errc::number_too_large; + return; + } + auto& val = state_stack_.back().stringref_map->at(index); + switch (val.type) + { + case jsoncons::cbor::detail::cbor_major_type::text_string: + { + handler_.name(basic_string_view(val.s.data(),val.s.length()), *this); + break; + } + case jsoncons::cbor::detail::cbor_major_type::byte_string: + { + std::string s; + encode_base64url(val.bs.begin(),val.bs.end(),s); + handler_.name(basic_string_view(s.data(),s.length()), *this); + break; + } + default: + JSONCONS_UNREACHABLE(); + break; + } + tags_.pop_back(); + break; + } + } + JSONCONS_FALLTHROUGH; + default: + { + std::string s; + json_string_encoder encoder(s); + basic_cbor_reader reader(std::move(source_), encoder); + reader.read(ec); + source_ = std::move(reader.source_); + auto result = unicons::validate(s.begin(),s.end()); + if (result.ec != unicons::conv_errc()) + { + ec = cbor_errc::invalid_utf8_text_string; + return; + } + handler_.name(basic_string_view(s.data(),s.length()), *this); + } + } + } + + std::string get_text_string(std::error_code& ec) + { + std::string s; + + jsoncons::cbor::detail::cbor_major_type major_type; + uint8_t info; + int c = source_.peek(); + switch (c) + { + case Src::traits_type::eof(): + ec = cbor_errc::unexpected_eof; + return s; + default: + major_type = get_major_type((uint8_t)c); + info = get_additional_information_value((uint8_t)c); + break; + } + JSONCONS_ASSERT(major_type == jsoncons::cbor::detail::cbor_major_type::text_string); + auto func = [&s](Src& source_, size_t length, std::error_code& ec) + { + s.reserve(s.size()+length); + source_.read(std::back_inserter(s), length); + if (source_.eof()) + { + ec = cbor_errc::unexpected_eof; + return; + } + }; + iterate_string_chunks(source_, func, ec); + if (state_stack_.back().stringref_map && + info != jsoncons::cbor::detail::additional_info::indefinite_length && + s.length() >= jsoncons::cbor::detail::min_length_for_stringref(state_stack_.back().stringref_map->size())) + { + state_stack_.back().stringref_map->emplace_back(s); + } + + return s; + } + + static size_t get_definite_length(Src& source, std::error_code& ec) + { + if (JSONCONS_UNLIKELY(source.eof())) + { + ec = cbor_errc::unexpected_eof; + return 0; + } + switch (get_major_type((uint8_t)source.peek())) + { + case jsoncons::cbor::detail::cbor_major_type::byte_string: + case jsoncons::cbor::detail::cbor_major_type::text_string: + case jsoncons::cbor::detail::cbor_major_type::array: + case jsoncons::cbor::detail::cbor_major_type::map: + break; + default: + return 0; + } + + uint64_t u = get_uint64_value(source, ec); + size_t len = (size_t)u; + if (len != u) + { + ec = cbor_errc::number_too_large; + } + return len; + } + + std::vector get_byte_string(std::error_code& ec) + { + std::vector v; + + jsoncons::cbor::detail::cbor_major_type major_type; + uint8_t info; + int c = source_.peek(); + switch (c) + { + case Src::traits_type::eof(): + ec = cbor_errc::unexpected_eof; + return v; + default: + major_type = get_major_type((uint8_t)c); + info = get_additional_information_value((uint8_t)c); + break; + } + JSONCONS_ASSERT(major_type == jsoncons::cbor::detail::cbor_major_type::byte_string); + auto func = [&v](Src& source_, size_t length, std::error_code& ec) + { + v.reserve(v.size()+length); + source_.read(std::back_inserter(v), length); + if (source_.eof()) + { + ec = cbor_errc::unexpected_eof; + return; + } + }; + iterate_string_chunks(source_, func, ec); + if (state_stack_.back().stringref_map && + info != jsoncons::cbor::detail::additional_info::indefinite_length && + v.size() >= jsoncons::cbor::detail::min_length_for_stringref(state_stack_.back().stringref_map->size())) + { + state_stack_.back().stringref_map->emplace_back(v); + } + return v; + } + + template + static void iterate_string_chunks(Src& source, + Function func, + std::error_code& ec) + { + int c = source.peek(); + if (c == Src::traits_type::eof()) + { + ec = cbor_errc::unexpected_eof; + return; + } + + jsoncons::cbor::detail::cbor_major_type major_type = get_major_type((uint8_t)c); + JSONCONS_ASSERT(major_type == jsoncons::cbor::detail::cbor_major_type::text_string || major_type == jsoncons::cbor::detail::cbor_major_type::byte_string); + uint8_t info = get_additional_information_value((uint8_t)c); + + switch (info) + { + case jsoncons::cbor::detail::additional_info::indefinite_length: + { + source.ignore(1); + bool done = false; + while (!done) + { + int test = source.peek(); + switch (test) + { + case Src::traits_type::eof(): + ec = cbor_errc::unexpected_eof; + return; + case 0xff: + done = true; + break; + default: + iterate_string_chunks(source, func, ec); + if (ec) + { + return; + } + break; + } + } + source.ignore(1); + break; + } + default: // definite length + { + size_t length = get_definite_length(source, ec); + if (ec) + { + return; + } + func(source, length, ec); + if (ec) + { + return; + } + break; + } + } + } + + static uint64_t get_uint64_value(Src& source, std::error_code& ec) + { + uint64_t val = 0; + if (JSONCONS_UNLIKELY(source.eof())) + { + ec = cbor_errc::unexpected_eof; + return val; + } + const uint8_t* endp = nullptr; + + uint8_t type{}; + if (source.get(type) == 0) + { + ec = cbor_errc::unexpected_eof; + return 0; + } + uint8_t info = get_additional_information_value(type); + switch (info) + { + case JSONCONS_CBOR_0x00_0x17: // Integer 0x00..0x17 (0..23) + { + val = info; + break; + } + + case 0x18: // Unsigned integer (one-byte uint8_t follows) + { + uint8_t c{}; + source.get(c); + if (source.eof()) + { + ec = cbor_errc::unexpected_eof; + return val; + } + val = c; + break; + } + + case 0x19: // Unsigned integer (two-byte uint16_t follows) + { + uint8_t buf[sizeof(uint16_t)]; + source.read(buf, sizeof(uint16_t)); + val = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + break; + } + + case 0x1a: // Unsigned integer (four-byte uint32_t follows) + { + uint8_t buf[sizeof(uint32_t)]; + source.read(buf, sizeof(uint32_t)); + val = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + break; + } + + case 0x1b: // Unsigned integer (eight-byte uint64_t follows) + { + uint8_t buf[sizeof(uint64_t)]; + source.read(buf, sizeof(uint64_t)); + val = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + break; + } + default: + break; + } + return val; + } + + static int64_t get_int64_value(Src& source, std::error_code& ec) + { + int64_t val = 0; + if (JSONCONS_UNLIKELY(source.eof())) + { + ec = cbor_errc::unexpected_eof; + return val; + } + const uint8_t* endp = nullptr; + + uint8_t info = get_additional_information_value((uint8_t)source.peek()); + switch (get_major_type((uint8_t)source.peek())) + { + case jsoncons::cbor::detail::cbor_major_type::negative_integer: + source.ignore(1); + switch (info) + { + case JSONCONS_CBOR_0x00_0x17: // 0x00..0x17 (0..23) + { + val = static_cast(- 1 - info); + break; + } + case 0x18: // Negative integer (one-byte uint8_t follows) + { + uint8_t c{}; + source.get(c); + if (source.eof()) + { + ec = cbor_errc::unexpected_eof; + return val; + } + val = static_cast(-1)- c; + break; + } + + case 0x19: // Negative integer -1-n (two-byte uint16_t follows) + { + uint8_t buf[sizeof(uint16_t)]; + if (source.read(buf, sizeof(uint16_t)) != sizeof(uint16_t)) + { + return val; + } + auto x = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + val = static_cast(-1)- x; + break; + } + + case 0x1a: // Negative integer -1-n (four-byte uint32_t follows) + { + uint8_t buf[sizeof(uint32_t)]; + if (source.read(buf, sizeof(uint32_t)) != sizeof(uint32_t)) + { + return val; + } + auto x = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + val = static_cast(-1)- x; + break; + } + + case 0x1b: // Negative integer -1-n (eight-byte uint64_t follows) + { + uint8_t buf[sizeof(uint64_t)]; + if (source.read(buf, sizeof(uint64_t)) != sizeof(uint64_t)) + { + return val; + } + auto x = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + val = static_cast(-1)- static_cast(x); + break; + } + } + break; + + case jsoncons::cbor::detail::cbor_major_type::unsigned_integer: + { + uint64_t x = get_uint64_value(source, ec); + if (ec) + { + return 0; + } + if (x <= static_cast((std::numeric_limits::max)())) + { + val = x; + } + else + { + // error; + } + + break; + } + break; + default: + break; + } + + return val; + } + + static double get_double(Src& source, std::error_code& ec) + { + double val = 0; + if (JSONCONS_UNLIKELY(source.eof())) + { + ec = cbor_errc::unexpected_eof; + return val; + } + const uint8_t* endp = nullptr; + + uint8_t type{}; + if (source.get(type) == 0) + { + ec = cbor_errc::unexpected_eof; + return 0; + } + uint8_t info = get_additional_information_value(type); + switch (info) + { + case 0x19: // Half-Precision Float (two-byte IEEE 754) + { + uint8_t buf[sizeof(uint16_t)]; + source.read(buf, sizeof(uint16_t)); + if (source.eof()) + { + ec = cbor_errc::unexpected_eof; + return 0; + } + uint16_t x = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + val = jsoncons::detail::decode_half(x); + break; + } + + + case 0x1a: // Single-Precision Float (four-byte IEEE 754) + { + uint8_t buf[sizeof(float)]; + source.read(buf, sizeof(float)); + if (source.eof()) + { + ec = cbor_errc::unexpected_eof; + return 0; + } + val = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + break; + } + + case 0x1b: // Double-Precision Float (eight-byte IEEE 754) + { + uint8_t buf[sizeof(double)]; + source.read(buf, sizeof(double)); + if (source.eof()) + { + ec = cbor_errc::unexpected_eof; + return 0; + } + val = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + break; + } + default: + break; + } + + return val; + } + + std::string get_array_as_decimal_string(std::error_code& ec) + { + std::string s; + + int c; + if ((c=source_.get()) == Src::traits_type::eof()) + { + ec = cbor_errc::unexpected_eof; + return s; + } + jsoncons::cbor::detail::cbor_major_type major_type = get_major_type((uint8_t)c); + uint8_t info = get_additional_information_value((uint8_t)c); + JSONCONS_ASSERT(major_type == jsoncons::cbor::detail::cbor_major_type::array); + JSONCONS_ASSERT(info == 2); + + if ((c=source_.peek()) == Src::traits_type::eof()) + { + ec = cbor_errc::unexpected_eof; + return s; + } + int64_t exponent = 0; + switch (get_major_type((uint8_t)c)) + { + case jsoncons::cbor::detail::cbor_major_type::unsigned_integer: + { + exponent = get_uint64_value(source_,ec); + if (ec) + { + return s; + } + break; + } + case jsoncons::cbor::detail::cbor_major_type::negative_integer: + { + exponent = get_int64_value(source_,ec); + if (ec) + { + return s; + } + break; + } + default: + { + ec = cbor_errc::invalid_decimal; + return s; + } + } + + switch (get_major_type((uint8_t)source_.peek())) + { + case jsoncons::cbor::detail::cbor_major_type::unsigned_integer: + { + uint64_t val = get_uint64_value(source_,ec); + if (ec) + { + return s; + } + jsoncons::detail::print_uinteger(val, s); + break; + } + case jsoncons::cbor::detail::cbor_major_type::negative_integer: + { + int64_t val = get_int64_value(source_,ec); + if (ec) + { + return s; + } + jsoncons::detail::print_integer(val, s); + break; + } + case jsoncons::cbor::detail::cbor_major_type::semantic_tag: + { + if ((c=source_.get()) == Src::traits_type::eof()) + { + ec = cbor_errc::unexpected_eof; + return s; + } + uint8_t tag = get_additional_information_value((uint8_t)c); + if ((c=source_.peek()) == Src::traits_type::eof()) + { + ec = cbor_errc::unexpected_eof; + return s; + } + + if (get_major_type((uint8_t)c) == jsoncons::cbor::detail::cbor_major_type::byte_string) + { + std::vector v = get_byte_string(ec); + if (ec) + { + return s; + } + if (tag == 2) + { + bignum n(1, v.data(), v.size()); + n.dump(s); + } + else if (tag == 3) + { + bignum n(-1, v.data(), v.size()); + n.dump(s); + } + } + break; + } + default: + { + ec = cbor_errc::invalid_decimal; + return s; + } + } + + std::string result; + if (s.size() > 0) + { + if (s[0] == '-') + { + result.push_back('-'); + jsoncons::detail::prettify_string(s.c_str()+1, s.size()-1, (int)exponent, -4, 17, result); + } + else + { + jsoncons::detail::prettify_string(s.c_str(), s.size(), (int)exponent, -4, 17, result); + } + } + //std::cout << "s: " << s << ", exponent: " << std::dec << exponent << ", result: " << result << "\n"; + return result; + } + + std::string get_array_as_hexfloat_string(std::error_code& ec) + { + std::string s; + + int c; + if ((c=source_.get()) == Src::traits_type::eof()) + { + ec = cbor_errc::unexpected_eof; + return s; + } + jsoncons::cbor::detail::cbor_major_type major_type = get_major_type((uint8_t)c); + uint8_t info = get_additional_information_value((uint8_t)c); + JSONCONS_ASSERT(major_type == jsoncons::cbor::detail::cbor_major_type::array); + JSONCONS_ASSERT(info == 2); + + if ((c=source_.peek()) == Src::traits_type::eof()) + { + ec = cbor_errc::unexpected_eof; + return s; + } + int64_t exponent = 0; + switch (get_major_type((uint8_t)c)) + { + case jsoncons::cbor::detail::cbor_major_type::unsigned_integer: + { + exponent = get_uint64_value(source_,ec); + if (ec) + { + return s; + } + break; + } + case jsoncons::cbor::detail::cbor_major_type::negative_integer: + { + exponent = get_int64_value(source_,ec); + if (ec) + { + return s; + } + break; + } + default: + { + ec = cbor_errc::invalid_bigfloat; + return s; + } + } + + switch (get_major_type((uint8_t)source_.peek())) + { + case jsoncons::cbor::detail::cbor_major_type::unsigned_integer: + { + uint64_t val = get_uint64_value(source_,ec); + if (ec) + { + return s; + } + s.push_back('0'); + s.push_back('x'); + jsoncons::detail::uinteger_to_hex_string(val, s); + break; + } + case jsoncons::cbor::detail::cbor_major_type::negative_integer: + { + int64_t val = get_int64_value(source_,ec); + if (ec) + { + return s; + } + s.push_back('-'); + s.push_back('0'); + s.push_back('x'); + jsoncons::detail::uinteger_to_hex_string(static_cast(-val), s); + break; + } + case jsoncons::cbor::detail::cbor_major_type::semantic_tag: + { + if ((c=source_.get()) == Src::traits_type::eof()) + { + ec = cbor_errc::unexpected_eof; + return s; + } + uint8_t tag = get_additional_information_value((uint8_t)c); + if ((c=source_.peek()) == Src::traits_type::eof()) + { + ec = cbor_errc::unexpected_eof; + return s; + } + + if (get_major_type((uint8_t)c) == jsoncons::cbor::detail::cbor_major_type::byte_string) + { + std::vector v = get_byte_string(ec); + if (ec) + { + return s; + } + if (tag == 2) + { + s.push_back('-'); + s.push_back('0'); + s.push_back('x'); + bignum n(1, v.data(), v.size()); + n.dump_hex_string(s); + } + else if (tag == 3) + { + s.push_back('-'); + s.push_back('0'); + bignum n(-1, v.data(), v.size()); + n.dump_hex_string(s); + s[2] = 'x'; + } + } + break; + } + default: + { + ec = cbor_errc::invalid_bigfloat; + return s; + } + } + + s.push_back('p'); + if (exponent >=0) + { + jsoncons::detail::uinteger_to_hex_string(static_cast(exponent), s); + } + else + { + s.push_back('-'); + jsoncons::detail::uinteger_to_hex_string(static_cast(-exponent), s); + } + return s; + } + + static jsoncons::cbor::detail::cbor_major_type get_major_type(uint8_t type) + { + static const uint8_t major_type_shift = 0x05; + uint8_t value = type >> major_type_shift; + return static_cast(value); + } + + static uint8_t get_additional_information_value(uint8_t type) + { + static const uint8_t additional_information_mask = (1U << 5) - 1; + uint8_t value = type & additional_information_mask; + return value; + } + + void read_tags(std::error_code& ec) + { + int c = source_.peek(); + if (c == Src::traits_type::eof()) + { + ec = cbor_errc::unexpected_eof; + return; + } + jsoncons::cbor::detail::cbor_major_type major_type = get_major_type((uint8_t)c); + while (major_type == jsoncons::cbor::detail::cbor_major_type::semantic_tag) + { + uint64_t val = get_uint64_value(source_, ec); + if (ec) + { + return; + } + tags_.push_back(val); + c = source_.peek(); + if (c == Src::traits_type::eof()) + { + ec = cbor_errc::unexpected_eof; + return; + } + major_type = get_major_type((uint8_t)c); + } + } + + void handle_string(const basic_string_view& v, std::error_code&) + { + semantic_tag tag = semantic_tag::none; + if (!tags_.empty()) + { + switch (tags_.back()) + { + case 0: + tag = semantic_tag::datetime; + break; + case 32: + tag = semantic_tag::uri; + break; + case 33: + tag = semantic_tag::base64url; + break; + case 34: + tag = semantic_tag::base64; + break; + default: + break; + } + tags_.clear(); + } + handler_.string_value(v, tag, *this); + } + + void handle_byte_string(const byte_string_view& v, std::error_code&) + { + if (!tags_.empty()) + { + switch (tags_.back()) + { + case 0x2: + { + bignum n(1, v.data(), v.size()); + buffer_.clear(); + n.dump(buffer_); + handler_.string_value(buffer_, semantic_tag::bigint, *this); + break; + } + case 0x3: + { + bignum n(-1, v.data(), v.size()); + buffer_.clear(); + n.dump(buffer_); + handler_.string_value(buffer_, semantic_tag::bigint, *this); + break; + } + case 0x15: + { + handler_.byte_string_value(byte_string_view(v.data(), v.size()), semantic_tag::base64url, *this); + break; + } + case 0x16: + { + handler_.byte_string_value(byte_string_view(v.data(), v.size()), semantic_tag::base64, *this); + break; + } + case 0x17: + { + handler_.byte_string_value(byte_string_view(v.data(), v.size()), semantic_tag::base16, *this); + break; + } + default: + handler_.byte_string_value(byte_string_view(v.data(), v.size()), semantic_tag::none, *this); + break; + } + tags_.clear(); + } + else + { + handler_.byte_string_value(byte_string_view(v.data(), v.size()), semantic_tag::none, *this); + } + } + +}; + +typedef basic_cbor_reader cbor_reader; + +typedef basic_cbor_reader cbor_bytes_reader; + +#if !defined(JSONCONS_NO_DEPRECATED) +typedef cbor_bytes_reader cbor_buffer_reader; +#endif + +}} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/csv/csv.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/csv/csv.hpp new file mode 100644 index 0000000000..d0d5597c98 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/csv/csv.hpp @@ -0,0 +1,14 @@ +/// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_CSV_CSV_HPP +#define JSONCONS_CSV_CSV_HPP + +#include +#include +#include + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/csv/csv_encoder.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/csv/csv_encoder.hpp new file mode 100644 index 0000000000..1bc98d9830 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/csv/csv_encoder.hpp @@ -0,0 +1,619 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_CSV_CSV_ENCODER_HPP +#define JSONCONS_CSV_CSV_ENCODER_HPP + +#include // std::array +#include +#include +#include +#include +#include // std::move +#include // std::unordered_map +#include // std::allocator +#include // std::numeric_limits +#include +#include +#include +#include +#include + +namespace jsoncons { namespace csv { + +template,class Allocator=std::allocator> +class basic_csv_encoder final : public basic_json_content_handler +{ + static const std::array& null_k() + { + static constexpr std::array k{'n','u','l','l'}; + return k; + } + static const std::array& true_k() + { + static constexpr std::array k{'t','r','u','e'}; + return k; + } + static const std::array& false_k() + { + static constexpr std::array k{'f','a','l','s','e'}; + return k; + } + +public: + typedef CharT char_type; + using typename basic_json_content_handler::string_view_type; + typedef Result result_type; + + typedef Allocator allocator_type; + typedef typename std::allocator_traits:: template rebind_alloc char_allocator_type; + typedef std::basic_string, char_allocator_type> string_type; + typedef typename std::allocator_traits:: template rebind_alloc string_allocator_type; + +private: + struct stack_item + { + stack_item(bool is_object) + : is_object_(is_object), count_(0) + { + } + bool is_object() const + { + return is_object_; + } + + bool is_object_; + size_t count_; + string_type name_; + }; + Result result_; + const basic_csv_encode_options& options_; + std::vector stack_; + jsoncons::detail::print_double fp_; + std::vector column_names_; + + typedef typename std::allocator_traits:: template rebind_alloc> string_string_allocator_type; + std::unordered_map,std::equal_to,string_string_allocator_type> buffered_line_; + + // Noncopyable and nonmoveable + basic_csv_encoder(const basic_csv_encoder&) = delete; + basic_csv_encoder& operator=(const basic_csv_encoder&) = delete; +public: + basic_csv_encoder(result_type result) + : basic_csv_encoder(std::move(result), basic_csv_options::default_options()) + { + } + + basic_csv_encoder(result_type result, + const basic_csv_encode_options& options) + : + result_(std::move(result)), + options_(options), + stack_(), + fp_(floating_point_options(options.floating_point_format(), + options.precision(), + 0)), + column_names_(options_.column_names()) + { + } + + ~basic_csv_encoder() + { + try + { + result_.flush(); + } + catch (...) + { + } + } + +private: + + template + void escape_string(const CharT* s, + size_t length, + CharT quote_char, CharT quote_escape_char, + AnyWriter& result) + { + const CharT* begin = s; + const CharT* end = s + length; + for (const CharT* it = begin; it != end; ++it) + { + CharT c = *it; + if (c == quote_char) + { + result.push_back(quote_escape_char); + result.push_back(quote_char); + } + else + { + result.push_back(c); + } + } + } + + void do_flush() override + { + result_.flush(); + } + + bool do_begin_object(semantic_tag, const ser_context&) override + { + stack_.push_back(stack_item(true)); + return true; + } + + bool do_end_object(const ser_context&) override + { + if (stack_.size() == 2) + { + if (stack_[0].count_ == 0) + { + for (size_t i = 0; i < column_names_.size(); ++i) + { + if (i > 0) + { + result_.push_back(options_.field_delimiter()); + } + result_.append(column_names_[i].data(), + column_names_[i].length()); + } + result_.append(options_.line_delimiter().data(), + options_.line_delimiter().length()); + } + for (size_t i = 0; i < column_names_.size(); ++i) + { + if (i > 0) + { + result_.push_back(options_.field_delimiter()); + } + auto it = buffered_line_.find(column_names_[i]); + if (it != buffered_line_.end()) + { + result_.append(it->second.data(),it->second.length()); + it->second.clear(); + } + } + result_.append(options_.line_delimiter().data(), options_.line_delimiter().length()); + } + stack_.pop_back(); + + end_value(); + return true; + } + + bool do_begin_array(semantic_tag, const ser_context&) override + { + stack_.push_back(stack_item(false)); + if (stack_.size() == 2) + { + if (stack_[0].count_ == 0) + { + for (size_t i = 0; i < column_names_.size(); ++i) + { + if (i > 0) + { + result_.push_back(options_.field_delimiter()); + } + result_.append(column_names_[i].data(),column_names_[i].length()); + } + if (column_names_.size() > 0) + { + result_.append(options_.line_delimiter().data(), + options_.line_delimiter().length()); + } + } + } + return true; + } + + bool do_end_array(const ser_context&) override + { + if (stack_.size() == 2) + { + result_.append(options_.line_delimiter().data(), + options_.line_delimiter().length()); + } + stack_.pop_back(); + + end_value(); + return true; + } + + bool do_name(const string_view_type& name, const ser_context&) override + { + if (stack_.size() == 2) + { + stack_.back().name_ = string_type(name); + buffered_line_[string_type(name)] = std::basic_string(); + if (stack_[0].count_ == 0 && options_.column_names().size() == 0) + { + column_names_.push_back(string_type(name)); + } + } + return true; + } + + template + bool string_value(const CharT* s, size_t length, AnyWriter& result) + { + bool quote = false; + if (options_.quote_style() == quote_style_type::all || options_.quote_style() == quote_style_type::nonnumeric || + (options_.quote_style() == quote_style_type::minimal && + (std::char_traits::find(s, length, options_.field_delimiter()) != nullptr || std::char_traits::find(s, length, options_.quote_char()) != nullptr))) + { + quote = true; + result.push_back(options_.quote_char()); + } + escape_string(s, length, options_.quote_char(), options_.quote_escape_char(), result); + if (quote) + { + result.push_back(options_.quote_char()); + } + + return true; + } + + bool do_null_value(semantic_tag, const ser_context&) override + { + if (stack_.size() == 2) + { + if (stack_.back().is_object()) + { + auto it = buffered_line_.find(stack_.back().name_); + if (it != buffered_line_.end()) + { + std::basic_string s; + jsoncons::string_result> bo(s); + accept_null_value(bo); + bo.flush(); + it->second = s; + } + } + else + { + accept_null_value(result_); + } + } + return true; + } + + bool do_string_value(const string_view_type& sv, semantic_tag, const ser_context&) override + { + if (stack_.size() == 2) + { + if (stack_.back().is_object()) + { + auto it = buffered_line_.find(stack_.back().name_); + if (it != buffered_line_.end()) + { + std::basic_string s; + jsoncons::string_result> bo(s); + value(sv,bo); + bo.flush(); + it->second = s; + } + } + else + { + value(sv,result_); + } + } + return true; + } + + bool do_byte_string_value(const byte_string_view& b, + semantic_tag tag, + const ser_context& context) override + { + byte_string_chars_format encoding_hint; + switch (tag) + { + case semantic_tag::base16: + encoding_hint = byte_string_chars_format::base16; + break; + case semantic_tag::base64: + encoding_hint = byte_string_chars_format::base64; + break; + case semantic_tag::base64url: + encoding_hint = byte_string_chars_format::base64url; + break; + default: + encoding_hint = byte_string_chars_format::none; + break; + } + byte_string_chars_format format = jsoncons::detail::resolve_byte_string_chars_format(encoding_hint,byte_string_chars_format::none,byte_string_chars_format::base64url); + + std::basic_string s; + switch (format) + { + case byte_string_chars_format::base16: + { + encode_base16(b.begin(),b.end(),s); + do_string_value(s, semantic_tag::none, context); + break; + } + case byte_string_chars_format::base64: + { + encode_base64(b.begin(),b.end(),s); + do_string_value(s, semantic_tag::none, context); + break; + } + case byte_string_chars_format::base64url: + { + encode_base64url(b.begin(),b.end(),s); + do_string_value(s, semantic_tag::none, context); + break; + } + default: + { + JSONCONS_UNREACHABLE(); + } + } + + return true; + } + + bool do_double_value(double val, + semantic_tag, + const ser_context&) override + { + if (stack_.size() == 2) + { + if (stack_.back().is_object()) + { + auto it = buffered_line_.find(stack_.back().name_); + if (it != buffered_line_.end()) + { + std::basic_string s; + jsoncons::string_result> bo(s); + value(val, bo); + bo.flush(); + it->second = s; + } + } + else + { + value(val, result_); + } + } + return true; + } + + bool do_int64_value(int64_t val, + semantic_tag, + const ser_context&) override + { + if (stack_.size() == 2) + { + if (stack_.back().is_object()) + { + auto it = buffered_line_.find(stack_.back().name_); + if (it != buffered_line_.end()) + { + std::basic_string s; + jsoncons::string_result> bo(s); + value(val,bo); + bo.flush(); + it->second = s; + } + } + else + { + value(val,result_); + } + } + return true; + } + + bool do_uint64_value(uint64_t val, + semantic_tag, + const ser_context&) override + { + if (stack_.size() == 2) + { + if (stack_.back().is_object()) + { + auto it = buffered_line_.find(stack_.back().name_); + if (it != buffered_line_.end()) + { + std::basic_string s; + jsoncons::string_result> bo(s); + value(val,bo); + bo.flush(); + it->second = s; + } + } + else + { + value(val,result_); + } + } + return true; + } + + bool do_bool_value(bool val, semantic_tag, const ser_context&) override + { + if (stack_.size() == 2) + { + if (stack_.back().is_object()) + { + auto it = buffered_line_.find(stack_.back().name_); + if (it != buffered_line_.end()) + { + std::basic_string s; + jsoncons::string_result> bo(s); + value(val,bo); + bo.flush(); + it->second = s; + } + } + else + { + value(val,result_); + } + } + return true; + } + + template + void value(const string_view_type& value, AnyWriter& result) + { + begin_value(result); + string_value(value.data(),value.length(),result); + end_value(); + } + + template + void value(double val, AnyWriter& result) + { + begin_value(result); + + if ((std::isnan)(val)) + { + result.append(null_k().data(), null_k().size()); + } + else if (val == std::numeric_limits::infinity()) + { + result.append(null_k().data(), null_k().size()); + } + else if (!(std::isfinite)(val)) + { + result.append(null_k().data(), null_k().size()); + } + else + { + fp_(val, result); + } + + end_value(); + + } + + template + void value(int64_t val, AnyWriter& result) + { + begin_value(result); + + std::basic_ostringstream ss; + ss << val; + result.append(ss.str().data(),ss.str().length()); + + end_value(); + } + + template + void value(uint64_t val, AnyWriter& result) + { + begin_value(result); + + std::basic_ostringstream ss; + ss << val; + result.append(ss.str().data(),ss.str().length()); + + end_value(); + } + + template + void value(bool val, AnyWriter& result) + { + begin_value(result); + + if (val) + { + result.append(true_k().data(), true_k().size()); + } + else + { + result.append(false_k().data(), false_k().size()); + } + + end_value(); + } + + template + bool accept_null_value(AnyWriter& result) + { + begin_value(result); + result.append(null_k().data(), null_k().size()); + end_value(); + return true; + } + + template + void begin_value(AnyWriter& result) + { + if (!stack_.empty()) + { + if (!stack_.back().is_object_ && stack_.back().count_ > 0) + { + result.push_back(options_.field_delimiter()); + } + } + } + + void end_value() + { + if (!stack_.empty()) + { + ++stack_.back().count_; + } + } +}; + +// encode_csv + +template +typename std::enable_if::value,void>::type +encode_csv(const T& j, std::basic_string& s, const basic_csv_options& options = basic_csv_options::default_options()) +{ + typedef CharT char_type; + basic_csv_encoder>> encoder(s,options); + j.dump(encoder); +} + +template +typename std::enable_if::value,void>::type +encode_csv(const T& val, std::basic_string& s, const basic_csv_options& options = basic_csv_options::default_options()) +{ + typedef CharT char_type; + basic_csv_encoder>> encoder(s,options); + write_to(basic_json(), val, encoder); +} + +template +typename std::enable_if::value,void>::type +encode_csv(const T& j, std::basic_ostream& os, const basic_csv_options& options = basic_csv_options::default_options()) +{ + typedef CharT char_type; + basic_csv_encoder> encoder(os,options); + j.dump(encoder); +} + +template +typename std::enable_if::value,void>::type +encode_csv(const T& val, std::basic_ostream& os, const basic_csv_options& options = basic_csv_options::default_options()) +{ + typedef CharT char_type; + basic_csv_encoder> encoder(os,options); + write_to(basic_json(), val, encoder); +} + +typedef basic_csv_encoder csv_encoder; +typedef basic_csv_encoder> csv_string_encoder; + +#if !defined(JSONCONS_NO_DEPRECATED) +template, class Allocator = std::allocator> +using basic_csv_serializer = basic_csv_encoder; + +typedef basic_csv_serializer csv_serializer; +typedef basic_csv_serializer> csv_string_serializer; +#endif + +}} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/csv/csv_error.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/csv/csv_error.hpp new file mode 100644 index 0000000000..49a09a0d6d --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/csv/csv_error.hpp @@ -0,0 +1,77 @@ +/// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_CSV_CSV_ERROR_HPP +#define JSONCONS_CSV_CSV_ERROR_HPP + +#include +#include + +namespace jsoncons { namespace csv { + + enum class csv_errc : int + { + ok = 0, + unexpected_eof = 1, + source_error, + expected_quote, + invalid_csv_text, + invalid_state + }; + +#if !defined(JSONCONS_NO_DEPRECATED) +typedef csv_errc csv_parser_errc; +#endif + +class csv_error_category_impl + : public std::error_category +{ +public: + const char* name() const noexcept override + { + return "jsoncons/csv"; + } + std::string message(int ev) const override + { + switch (static_cast(ev)) + { + case csv_errc::unexpected_eof: + return "Unexpected end of file"; + case csv_errc::source_error: + return "Source error"; + case csv_errc::expected_quote: + return "Expected quote character"; + case csv_errc::invalid_csv_text: + return "Invalid CSV text"; + default: + return "Unknown JSON parser error"; + } + } +}; + +inline +const std::error_category& csv_error_category() +{ + static csv_error_category_impl instance; + return instance; +} + +inline +std::error_code make_error_code(csv_errc result) +{ + return std::error_code(static_cast(result),csv_error_category()); +} + +}} + +namespace std { + template<> + struct is_error_code_enum : public true_type + { + }; +} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/csv/csv_options.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/csv/csv_options.hpp new file mode 100644 index 0000000000..5cae9e1610 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/csv/csv_options.hpp @@ -0,0 +1,771 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_CSV_CSV_OPTIONS_HPP +#define JSONCONS_CSV_CSV_OPTIONS_HPP + +#include +#include +#include // std::pair +#include // std::unordered_map +#include // std::numeric_limits +#include + +namespace jsoncons { namespace csv { + +namespace detail { + JSONCONS_STRING_LITERAL(string,'s','t','r','i','n','g') + JSONCONS_STRING_LITERAL(integer,'i','n','t','e','g','e','r') + JSONCONS_STRING_LITERAL(float,'f','l','o','a','t') + JSONCONS_STRING_LITERAL(boolean,'b','o','o','l','e','a','n') +} + +enum class csv_column_type +{ + string_t,integer_t,float_t,boolean_t,repeat_t +}; + +enum class quote_style_type +{ + all,minimal,none,nonnumeric +}; + +typedef quote_style_type quote_styles; + +enum class mapping_type +{ + n_rows, + n_objects, + m_columns +}; + +enum class column_state {sequence,label}; + +struct csv_type_info +{ + csv_type_info() = default; + csv_type_info(const csv_type_info&) = default; + csv_type_info(csv_type_info&&) = default; + + csv_type_info(csv_column_type ctype, size_t lev, size_t repcount = 0) + { + col_type = ctype; + level = lev; + rep_count = repcount; + } + + csv_column_type col_type; + size_t level; + size_t rep_count; +}; + +template +class basic_csv_decode_options +{ +public: + typedef std::basic_string string_type; + + virtual size_t header_lines() const = 0; + + virtual bool assume_header() const = 0; + + virtual bool ignore_empty_values() const = 0; + + virtual bool ignore_empty_lines() const = 0; + + virtual bool trim_leading() const = 0; + + virtual bool trim_trailing() const = 0; + + virtual bool trim_leading_inside_quotes() const = 0; + + virtual bool trim_trailing_inside_quotes() const = 0; + + virtual bool trim() const = 0; + + virtual bool trim_inside_quotes() const = 0; + + virtual bool unquoted_empty_value_is_null() const = 0; + + virtual std::vector column_names() const = 0; + + virtual std::vector column_types() const = 0; + + virtual std::vector column_defaults() const = 0; + + virtual CharT field_delimiter() const = 0; + + virtual const std::pair& subfield_delimiter() const = 0; + + virtual string_type line_delimiter() const = 0; + + virtual CharT quote_char() const = 0; + + virtual bool infer_types() const = 0; + + virtual bool lossless_number() const = 0; + + virtual CharT quote_escape_char() const = 0; + + virtual CharT comment_starter() const = 0; + + virtual mapping_type mapping() const = 0; + + virtual unsigned long max_lines() const = 0; +}; + +template +class basic_csv_encode_options +{ +public: + typedef std::basic_string string_type; + + virtual chars_format floating_point_format() const = 0; + + virtual int precision() const = 0; + + virtual std::vector column_names() const = 0; + + virtual CharT field_delimiter() const = 0; + + virtual const std::pair& subfield_delimiter() const = 0; + + virtual string_type line_delimiter() const = 0; + + virtual CharT quote_char() const = 0; + + virtual CharT quote_escape_char() const = 0; + + virtual quote_style_type quote_style() const = 0; +}; + +template +class basic_csv_options : public virtual basic_csv_decode_options, + public virtual basic_csv_encode_options +{ + typedef CharT char_type; + typedef std::basic_string string_type; + + chars_format floating_point_format_; + int precision_; + bool assume_header_; + bool ignore_empty_values_; + bool ignore_empty_lines_; + bool trim_leading_; + bool trim_trailing_; + bool trim_leading_inside_quotes_; + bool trim_trailing_inside_quotes_; + bool unquoted_empty_value_is_null_; + CharT field_delimiter_; + std::pair subfield_delimiter_; + CharT quote_char_; + CharT quote_escape_char_; + CharT comment_starter_; + quote_style_type quote_style_; + std::pair mapping_; + unsigned long max_lines_; + size_t header_lines_; + string_type line_delimiter_; + bool infer_types_; + bool lossless_number_; + + std::vector column_names_; + std::vector column_types_; + std::vector column_defaults_; +public: + static const size_t default_indent = 4; + + static const basic_csv_options& default_options() + { + static basic_csv_options options{}; + return options; + } + +// Constructors + + basic_csv_options() : + floating_point_format_(chars_format()), + precision_(0), + assume_header_(false), + ignore_empty_values_(false), + ignore_empty_lines_(true), + trim_leading_(false), + trim_trailing_(false), + trim_leading_inside_quotes_(false), + trim_trailing_inside_quotes_(false), + unquoted_empty_value_is_null_(false), + field_delimiter_(','), + subfield_delimiter_(std::make_pair(',',false)), + quote_char_('\"'), + quote_escape_char_('\"'), + comment_starter_('\0'), + quote_style_(quote_style_type::minimal), + mapping_({mapping_type::n_rows,false}), + max_lines_((std::numeric_limits::max)()), + header_lines_(0), + infer_types_(true), + lossless_number_(false) + { + line_delimiter_.push_back('\n'); + } + +// Properties + + chars_format floating_point_format() const override + { + return floating_point_format_; + } + + basic_csv_options& floating_point_format(chars_format value) + { + floating_point_format_ = value; + return *this; + } + + int precision() const override + { + return precision_; + } + + basic_csv_options& precision(int value) + { + precision_ = value; + return *this; + } + + size_t header_lines() const override + { + return (assume_header_ && header_lines_ <= 1) ? 1 : header_lines_; + } + + basic_csv_options& header_lines(size_t value) + { + header_lines_ = value; + return *this; + } + + bool assume_header() const override + { + return assume_header_; + } + + basic_csv_options& assume_header(bool value) + { + assume_header_ = value; + return *this; + } + + bool ignore_empty_values() const override + { + return ignore_empty_values_; + } + + basic_csv_options& ignore_empty_values(bool value) + { + ignore_empty_values_ = value; + return *this; + } + + bool ignore_empty_lines() const override + { + return ignore_empty_lines_; + } + + basic_csv_options& ignore_empty_lines(bool value) + { + ignore_empty_lines_ = value; + return *this; + } + + bool trim_leading() const override + { + return trim_leading_; + } + + basic_csv_options& trim_leading(bool value) + { + trim_leading_ = value; + return *this; + } + + bool trim_trailing() const override + { + return trim_trailing_; + } + + basic_csv_options& trim_trailing(bool value) + { + trim_trailing_ = value; + return *this; + } + + bool trim_leading_inside_quotes() const override + { + return trim_leading_inside_quotes_; + } + + basic_csv_options& trim_leading_inside_quotes(bool value) + { + trim_leading_inside_quotes_ = value; + return *this; + } + + bool trim_trailing_inside_quotes() const override + { + return trim_trailing_inside_quotes_; + } + + basic_csv_options& trim_trailing_inside_quotes(bool value) + { + trim_trailing_inside_quotes_ = value; + return *this; + } + + bool trim() const override + { + return trim_leading_ && trim_trailing_; + } + + basic_csv_options& trim(bool value) + { + trim_leading_ = value; + trim_trailing_ = value; + return *this; + } + + bool trim_inside_quotes() const override + { + return trim_leading_inside_quotes_ && trim_trailing_inside_quotes_; + } + + basic_csv_options& trim_inside_quotes(bool value) + { + trim_leading_inside_quotes_ = value; + trim_trailing_inside_quotes_ = value; + return *this; + } + + bool unquoted_empty_value_is_null() const override + { + return unquoted_empty_value_is_null_; + } + + basic_csv_options& unquoted_empty_value_is_null(bool value) + { + unquoted_empty_value_is_null_ = value; + return *this; + } + + std::vector column_names() const override + { + return column_names_; + } + +#if !defined(JSONCONS_NO_DEPRECATED) + basic_csv_options& column_names(const std::vector& value) + { + column_names_ = value; + return *this; + } + + basic_csv_options& column_defaults(const std::vector& value) + { + column_defaults_ = value; + return *this; + } + + basic_csv_options& column_types(const std::vector& value) + { + if (value.size() > 0) + { + column_types_.reserve(value.size()); + for (size_t i = 0; i < value.size(); ++i) + { + if (value[i] == jsoncons::csv::detail::string_literal()()) + { + column_types_.emplace_back(csv_column_type::string_t,0); + } + else if (value[i] == jsoncons::csv::detail::integer_literal()()) + { + column_types_.emplace_back(csv_column_type::integer_t,0); + } + else if (value[i] == jsoncons::csv::detail::float_literal()()) + { + column_types_.emplace_back(csv_column_type::float_t,0); + } + else if (value[i] == jsoncons::csv::detail::boolean_literal()()) + { + column_types_.emplace_back(csv_column_type::boolean_t,0); + } + } + } + return *this; + } +#endif + basic_csv_options& column_names(const string_type& names) + { + column_names_ = parse_column_names(names); + return *this; + } + + std::vector column_types() const override + { + return column_types_; + } + + basic_csv_options& column_types(const string_type& types) + { + column_types_ = parse_column_types(types); + return *this; + } + + std::vector column_defaults() const override + { + return column_defaults_; + } + + basic_csv_options& column_defaults(const string_type& defaults) + { + column_defaults_ = parse_column_names(defaults); + return *this; + } + + CharT field_delimiter() const override + { + return field_delimiter_; + } + + const std::pair& subfield_delimiter() const override + { + return subfield_delimiter_; + } + + basic_csv_options& field_delimiter(CharT value) + { + field_delimiter_ = value; + return *this; + } + + basic_csv_options& subfield_delimiter(CharT value) + { + subfield_delimiter_ = std::make_pair(value,true); + return *this; + } + + string_type line_delimiter() const override + { + return line_delimiter_; + } + + basic_csv_options& line_delimiter(string_type value) + { + line_delimiter_ = value; + return *this; + } + + CharT quote_char() const override + { + return quote_char_; + } + + basic_csv_options& quote_char(CharT value) + { + quote_char_ = value; + return *this; + } + + bool infer_types() const override + { + return infer_types_; + } + + basic_csv_options& infer_types(bool value) + { + infer_types_ = value; + return *this; + } + + bool lossless_number() const override + { + return lossless_number_; + } + + basic_csv_options& lossless_number(bool value) + { + lossless_number_ = value; + return *this; + } + + CharT quote_escape_char() const override + { + return quote_escape_char_; + } + + basic_csv_options& quote_escape_char(CharT value) + { + quote_escape_char_ = value; + return *this; + } + + CharT comment_starter() const override + { + return comment_starter_; + } + + basic_csv_options& comment_starter(CharT value) + { + comment_starter_ = value; + return *this; + } + + quote_style_type quote_style() const override + { + return quote_style_; + } + + mapping_type mapping() const override + { + return mapping_.second ? (mapping_.first) : (assume_header() || column_names_.size() > 0 ? mapping_type::n_objects : mapping_type::n_rows); + } + + basic_csv_options& quote_style(quote_style_type value) + { + quote_style_ = value; + return *this; + } + + basic_csv_options& mapping(mapping_type value) + { + mapping_ = {value,true}; + return *this; + } + + unsigned long max_lines() const override + { + return max_lines_; + } + + basic_csv_options& max_lines(unsigned long value) + { + max_lines_ = value; + return *this; + } + + static std::vector parse_column_names(const string_type& names) + { + std::vector column_names; + + column_state state = column_state::sequence; + string_type buffer; + + auto p = names.begin(); + while (p != names.end()) + { + switch (state) + { + case column_state::sequence: + { + switch (*p) + { + case ' ': case '\t':case '\r': case '\n': + ++p; + break; + default: + buffer.clear(); + state = column_state::label; + break; + } + break; + } + case column_state::label: + { + switch (*p) + { + case ',': + column_names.push_back(buffer); + buffer.clear(); + ++p; + state = column_state::sequence; + break; + default: + buffer.push_back(*p); + ++p; + break; + } + break; + } + } + } + if (state == column_state::label) + { + column_names.push_back(buffer); + buffer.clear(); + } + return column_names; + } + + static std::vector parse_column_types(const string_type& types) + { + const std::unordered_map,std::equal_to> type_dictionary = + { + + {detail::string_literal(),csv_column_type::string_t}, + {detail::integer_literal(),csv_column_type::integer_t}, + {detail::float_literal(),csv_column_type::float_t}, + {detail::boolean_literal(),csv_column_type::boolean_t} + }; + + std::vector column_types; + + column_state state = column_state::sequence; + int depth = 0; + string_type buffer; + + auto p = types.begin(); + while (p != types.end()) + { + switch (state) + { + case column_state::sequence: + { + switch (*p) + { + case ' ': case '\t':case '\r': case '\n': + ++p; + break; + case '[': + ++depth; + ++p; + break; + case ']': + JSONCONS_ASSERT(depth > 0); + --depth; + ++p; + break; + case '*': + { + JSONCONS_ASSERT(column_types.size() != 0); + size_t offset = 0; + size_t level = column_types.size() > 0 ? column_types.back().level: 0; + if (level > 0) + { + for (auto it = column_types.rbegin(); + it != column_types.rend() && level == it->level; + ++it) + { + ++offset; + } + } + else + { + offset = 1; + } + column_types.emplace_back(csv_column_type::repeat_t,depth,offset); + ++p; + break; + } + default: + buffer.clear(); + state = column_state::label; + break; + } + break; + } + case column_state::label: + { + switch (*p) + { + case '*': + { + auto it = type_dictionary.find(buffer); + if (it != type_dictionary.end()) + { + column_types.emplace_back(it->second,depth); + buffer.clear(); + } + else + { + JSONCONS_ASSERT(false); + } + state = column_state::sequence; + break; + } + case ',': + { + auto it = type_dictionary.find(buffer); + if (it != type_dictionary.end()) + { + column_types.emplace_back(it->second,depth); + buffer.clear(); + } + else + { + JSONCONS_ASSERT(false); + } + ++p; + state = column_state::sequence; + break; + } + case ']': + { + JSONCONS_ASSERT(depth > 0); + auto it = type_dictionary.find(buffer); + if (it != type_dictionary.end()) + { + column_types.emplace_back(it->second,depth); + buffer.clear(); + } + else + { + JSONCONS_ASSERT(false); + } + --depth; + ++p; + state = column_state::sequence; + break; + } + default: + { + buffer.push_back(*p); + ++p; + break; + } + } + break; + } + } + } + if (state == column_state::label) + { + auto it = type_dictionary.find(buffer); + if (it != type_dictionary.end()) + { + column_types.emplace_back(it->second,depth); + buffer.clear(); + } + else + { + JSONCONS_ASSERT(false); + } + } + return column_types; + } + +}; + +typedef basic_csv_options csv_options; +typedef basic_csv_options wcsv_options; + +#if !defined(JSONCONS_NO_DEPRECATED) +typedef basic_csv_options csv_parameters; +typedef basic_csv_options wcsv_parameters; +typedef basic_csv_options csv_serializing_options; +typedef basic_csv_options wcsv_serializing_options; +#endif + + +}} +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/csv/csv_parser.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/csv/csv_parser.hpp new file mode 100644 index 0000000000..51d131d9c1 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/csv/csv_parser.hpp @@ -0,0 +1,1357 @@ +// Copyright 2015 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_CSV_CSV_PARSER_HPP +#define JSONCONS_CSV_CSV_PARSER_HPP + +#include // std::allocator +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace jsoncons { namespace csv { + +enum class csv_mode_type +{ + initial, + header, + data, + subfields +}; + +enum class csv_state_type +{ + start, + comment, + expect_value, + between_fields, + quoted_string, + unquoted_string, + escaped_value, + minus, + zero, + integer, + fraction, + exp1, + exp2, + exp3, + done +}; + +template> +class basic_csv_parser : public ser_context +{ + typedef basic_string_view string_view_type; + typedef CharT char_type; + typedef Allocator allocator_type; + typedef typename std::allocator_traits:: template rebind_alloc char_allocator_type; + typedef std::basic_string,char_allocator_type> string_type; + typedef typename std::allocator_traits:: template rebind_alloc string_allocator_type; + typedef typename std::allocator_traits:: template rebind_alloc csv_mode_allocator_type; + typedef typename std::allocator_traits:: template rebind_alloc csv_type_info_allocator_type; + typedef typename std::allocator_traits:: template rebind_alloc> string_vector_allocator_type; + typedef basic_json json_type; + + static const int default_depth = 3; + + default_parse_error_handler default_err_handler_; + csv_state_type state_; + int top_; + std::vector stack_; + basic_json_content_handler& handler_; + parse_error_handler& err_handler_; + unsigned long column_; + unsigned long line_; + CharT prev_char_; + string_type value_buffer_; + int depth_; + const basic_csv_decode_options& options_; + std::vector column_names_; + std::vector,string_vector_allocator_type> column_values_; + std::vector column_types_; + std::vector column_defaults_; + size_t column_index_; + basic_json_fragment_filter filter_; + size_t level_; + size_t offset_; + jsoncons::detail::string_to_double to_double_; + std::vector> decoders_; + const CharT* begin_input_; + const CharT* input_end_; + const CharT* input_ptr_; + bool continue_; + +public: + basic_csv_parser(basic_json_content_handler& handler) + : basic_csv_parser(handler, basic_csv_options::default_options(), default_err_handler_) + { + } + + basic_csv_parser(basic_json_content_handler& handler, + const basic_csv_decode_options& options) + : basic_csv_parser(handler, options, default_err_handler_) + { + } + + basic_csv_parser(basic_json_content_handler& handler, + parse_error_handler& err_handler) + : basic_csv_parser(handler, basic_csv_options::default_options(), err_handler) + { + } + + basic_csv_parser(basic_json_content_handler& handler, + const basic_csv_decode_options& options, + parse_error_handler& err_handler) + : top_(-1), + stack_(default_depth), + handler_(handler), + err_handler_(err_handler), + options_(options), + filter_(handler), + level_(0), + offset_(0), + begin_input_(nullptr), + input_end_(nullptr), + input_ptr_(nullptr), + continue_(true) + { + depth_ = default_depth; + state_ = csv_state_type::start; + top_ = -1; + line_ = 1; + column_ = 0; + column_index_ = 0; + } + + ~basic_csv_parser() + { + } + + bool done() const + { + return state_ == csv_state_type::done; + } + + bool stopped() const + { + return !continue_; + } + + bool source_exhausted() const + { + return input_ptr_ == input_end_; + } + + const std::vector>& column_labels() const + { + return column_names_; + } + + void before_field() + { + switch (stack_[top_]) + { + case csv_mode_type::header: + if (options_.assume_header() && line_ == 1) + { + column_names_.push_back(value_buffer_); + } + break; + case csv_mode_type::data: + case csv_mode_type::subfields: + switch (options_.mapping()) + { + case mapping_type::n_objects: + if (!(options_.ignore_empty_values() && value_buffer_.size() == 0)) + { + if (column_index_ < column_names_.size() + offset_) + { + continue_ = handler_.name(column_names_[column_index_ - offset_], *this); + } + } + break; + default: + break; + } + break; + default: + break; + } + } + + void before_multi_valued_field() + { + push_mode(csv_mode_type::subfields); + switch (options_.mapping()) + { + case mapping_type::n_rows: + case mapping_type::n_objects: + continue_ = handler_.begin_array(semantic_tag::none, *this); + break; + case mapping_type::m_columns: + decoders_[column_index_].begin_array(semantic_tag::none, *this); + break; + default: + break; + } + } + + void after_field() + { + if (stack_[top_] == csv_mode_type::subfields) + { + pop_mode(csv_mode_type::subfields); + switch (options_.mapping()) + { + case mapping_type::n_rows: + case mapping_type::n_objects: + continue_ = handler_.end_array(*this); + break; + case mapping_type::m_columns: + decoders_[column_index_].end_array(*this); + break; + default: + break; + } + } + ++column_index_; + } + + void before_record() + { + offset_ = 0; + if (stack_[top_] == csv_mode_type::data) + { + switch (options_.mapping()) + { + case mapping_type::n_rows: + continue_ = handler_.begin_array(semantic_tag::none, *this); + break; + case mapping_type::n_objects: + continue_ = handler_.begin_object(semantic_tag::none, *this); + break; + case mapping_type::m_columns: + break; + default: + break; + } + } + } + + void after_record() + { + if (column_types_.size() > 0) + { + if (level_ > 0) + { + continue_ = handler_.end_array(*this); + level_ = 0; + } + } + if (stack_[top_] == csv_mode_type::header) + { + if (line_ >= options_.header_lines()) + { + flip(csv_mode_type::header, csv_mode_type::data); + } + column_values_.resize(column_names_.size()); + switch (options_.mapping()) + { + case mapping_type::n_rows: + if (column_names_.size() > 0) + { + continue_ = handler_.begin_array(semantic_tag::none, *this); + for (const auto& name : column_names_) + { + continue_ = handler_.string_value(name, semantic_tag::none, *this); + } + continue_ = handler_.end_array(*this); + } + break; + case mapping_type::m_columns: + for (size_t i = 0; i < column_names_.size(); ++i) + { + decoders_.push_back(json_decoder()); + decoders_.back().begin_array(semantic_tag::none, *this); + } + break; + default: + break; + } + } + else if (stack_[top_] == csv_mode_type::data || stack_[top_] == csv_mode_type::subfields) + { + switch (options_.mapping()) + { + case mapping_type::n_rows: + continue_ = handler_.end_array(*this); + break; + case mapping_type::n_objects: + continue_ = handler_.end_object(*this); + break; + default: + break; + } + } + column_index_ = 0; + } + + void reset() + { + push_mode(csv_mode_type::initial); + + for (auto name : options_.column_names()) + { + column_names_.emplace_back(name.data(),name.size()); + } + for (auto name : options_.column_types()) + { + column_types_.push_back(name); + } + for (auto name : options_.column_defaults()) + { + column_defaults_.emplace_back(name.data(), name.size()); + } + if (options_.header_lines() > 0) + { + push_mode(csv_mode_type::header); + } + else + { + push_mode(csv_mode_type::data); + } + if (options_.mapping() != mapping_type::m_columns) + { + continue_ = handler_.begin_array(semantic_tag::none, *this); + } + state_ = csv_state_type::expect_value; + column_index_ = 0; + prev_char_ = 0; + column_ = 1; + level_ = 0; + } + + void parse_some() + { + std::error_code ec; + parse_some(ec); + if (ec) + { + throw ser_error(ec,line_,column_); + } + } + + void parse_some(std::error_code& ec) + { + const CharT* local_input_end = input_end_; + + if (input_ptr_ == local_input_end && continue_) + { + switch (state_) + { + case csv_state_type::unquoted_string: + if (options_.trim_leading() || options_.trim_trailing()) + { + trim_string_buffer(options_.trim_leading(),options_.trim_trailing()); + } + if (!options_.ignore_empty_lines() || (column_index_ > 0 || value_buffer_.length() > 0)) + { + if (column_index_ == 0) + { + before_record(); + } + if (stack_[top_] != csv_mode_type::subfields) + { + before_field(); + } + end_unquoted_string_value(); + after_field(); + } + break; + case csv_state_type::escaped_value: + if (options_.quote_escape_char() == options_.quote_char()) + { + if (column_index_ == 0) + { + before_record(); + } + if (stack_[top_] != csv_mode_type::subfields) + { + before_field(); + } + end_quoted_string_value(ec); + if (ec) return; + after_field(); + } + break; + default: + break; + } + if (column_index_ > 0) + { + after_record(); + } + switch (stack_[top_]) + { + case csv_mode_type::header: + pop_mode(csv_mode_type::header); + break; + case csv_mode_type::data: + pop_mode(csv_mode_type::data); + break; + default: + break; + } + if (options_.mapping() == mapping_type::m_columns) + { + basic_json_fragment_filter fragment_filter(handler_); + continue_ = handler_.begin_object(semantic_tag::none, *this); + for (size_t i = 0; i < column_names_.size(); ++i) + { + continue_ = handler_.name(column_names_[i],*this); + decoders_[i].end_array(*this); + decoders_[i].flush(); + decoders_[i].get_result().dump(fragment_filter); + } + continue_ = handler_.end_object(*this); + } + else + { + continue_ = handler_.end_array(*this); + } + if (!pop_mode(csv_mode_type::initial)) + { + err_handler_.fatal_error(csv_errc::unexpected_eof, *this); + ec = csv_errc::unexpected_eof; + continue_ = false; + return; + } + handler_.flush(); + continue_ = false; + } + + for (; (input_ptr_ < local_input_end) && continue_; ++input_ptr_) + { + CharT curr_char = *input_ptr_; +all_csv_states: + switch (state_) + { + case csv_state_type::comment: + if (curr_char == '\n') + { + state_ = csv_state_type::expect_value; + } + else if (prev_char_ == '\r') + { + state_ = csv_state_type::expect_value; + goto all_csv_states; + } + break; + case csv_state_type::expect_value: + if (column_ == 1 && curr_char == options_.comment_starter()) + { + state_ = csv_state_type::comment; + } + else + { + state_ = csv_state_type::unquoted_string; + goto all_csv_states; + } + break; + case csv_state_type::escaped_value: + { + if (curr_char == options_.quote_char()) + { + value_buffer_.push_back(static_cast(curr_char)); + state_ = csv_state_type::quoted_string; + } + else if (options_.quote_escape_char() == options_.quote_char()) + { + state_ = csv_state_type::between_fields; + goto all_csv_states; + } + } + break; + case csv_state_type::quoted_string: + { + if (curr_char == options_.quote_escape_char()) + { + state_ = csv_state_type::escaped_value; + } + else if (curr_char == options_.quote_char()) + { + state_ = csv_state_type::between_fields; + } + else + { + value_buffer_.push_back(static_cast(curr_char)); + } + } + break; + case csv_state_type::between_fields: + if (prev_char_ == '\r' && curr_char == '\n') + { + } + else if (curr_char == '\r' || curr_char == '\n') + { + if (options_.trim_leading() || options_.trim_trailing()) + { + trim_string_buffer(options_.trim_leading(),options_.trim_trailing()); + } + if (!options_.ignore_empty_lines() || (column_index_ > 0 || value_buffer_.length() > 0)) + { + if (column_index_ == 0) + { + before_record(); + } + if (stack_[top_] != csv_mode_type::subfields) + { + before_field(); + } + end_quoted_string_value(ec); + if (ec) return; + after_field(); + after_record(); + } + state_ = csv_state_type::expect_value; + } + else if (curr_char == options_.field_delimiter() || (options_.subfield_delimiter().second && curr_char == options_.subfield_delimiter().first)) + { + if (column_index_ == 0 && stack_[top_] != csv_mode_type::subfields) + { + before_record(); + } + if (options_.trim_leading() || options_.trim_trailing()) + { + trim_string_buffer(options_.trim_leading(),options_.trim_trailing()); + } + if (stack_[top_] != csv_mode_type::subfields) + { + before_field(); + if (options_.subfield_delimiter().second && curr_char == options_.subfield_delimiter().first) + { + before_multi_valued_field(); + } + } + end_quoted_string_value(ec); + if (ec) return; + if (curr_char == options_.field_delimiter()) + { + after_field(); + } + state_ = csv_state_type::unquoted_string; + } + break; + case csv_state_type::unquoted_string: + { + if (prev_char_ == '\r' && curr_char == '\n') + { + } + else if (curr_char == '\r' || curr_char == '\n') + { + if (options_.trim_leading() || options_.trim_trailing()) + { + trim_string_buffer(options_.trim_leading(),options_.trim_trailing()); + } + if (!options_.ignore_empty_lines() || (column_index_ > 0 || value_buffer_.length() > 0)) + { + if (column_index_ == 0) + { + before_record(); + } + if (stack_[top_] != csv_mode_type::subfields) + { + before_field(); + } + end_unquoted_string_value(); + after_field(); + after_record(); + } + state_ = csv_state_type::expect_value; + } + else if (curr_char == options_.field_delimiter() || (options_.subfield_delimiter().second && curr_char == options_.subfield_delimiter().first)) + { + if (column_index_ == 0 && stack_[top_] != csv_mode_type::subfields) + { + before_record(); + } + if (options_.trim_leading() || options_.trim_trailing()) + { + trim_string_buffer(options_.trim_leading(),options_.trim_trailing()); + } + if (stack_[top_] != csv_mode_type::subfields) + { + before_field(); + if (options_.subfield_delimiter().second && curr_char == options_.subfield_delimiter().first) + { + before_multi_valued_field(); + } + } + end_unquoted_string_value(); + if (curr_char == options_.field_delimiter()) + { + after_field(); + } + state_ = csv_state_type::unquoted_string; + } + else if (curr_char == options_.quote_char()) + { + value_buffer_.clear(); + state_ = csv_state_type::quoted_string; + } + else + { + value_buffer_.push_back(static_cast(curr_char)); + } + } + break; + default: + err_handler_.fatal_error(csv_errc::invalid_state, *this); + ec = csv_errc::invalid_state; + continue_ = false; + return; + } + if (line_ > options_.max_lines()) + { + state_ = csv_state_type::done; + continue_ = false; + } + switch (curr_char) + { + case '\r': + ++line_; + column_ = 1; + break; + case '\n': + if (prev_char_ != '\r') + { + ++line_; + } + column_ = 1; + break; + default: + ++column_; + break; + } + prev_char_ = curr_char; + } + } + + void finish_parse() + { + std::error_code ec; + finish_parse(ec); + if (ec) + { + throw ser_error(ec,line_,column_); + } + } + + void finish_parse(std::error_code& ec) + { + while (continue_) + { + parse_some(ec); + } + } + + csv_state_type state() const + { + return state_; + } + + void update(const string_view_type sv) + { + update(sv.data(),sv.length()); + } + + void update(const CharT* data, size_t length) + { + begin_input_ = data; + input_end_ = data + length; + input_ptr_ = begin_input_; + } + + size_t line() const override + { + return line_; + } + + size_t column() const override + { + return column_; + } +private: + + void trim_string_buffer(bool trim_leading, bool trim_trailing) + { + size_t start = 0; + size_t length = value_buffer_.length(); + if (trim_leading) + { + bool done = false; + while (!done && start < value_buffer_.length()) + { + if ((value_buffer_[start] < 256) && std::isspace(value_buffer_[start])) + { + ++start; + } + else + { + done = true; + } + } + } + if (trim_trailing) + { + bool done = false; + while (!done && length > 0) + { + if ((value_buffer_[length-1] < 256) && std::isspace(value_buffer_[length-1])) + { + --length; + } + else + { + done = true; + } + } + } + if (start != 0 || length != value_buffer_.size()) + { + value_buffer_ = value_buffer_.substr(start,length-start); + } + } + + void end_unquoted_string_value() + { + switch (stack_[top_]) + { + case csv_mode_type::data: + case csv_mode_type::subfields: + switch (options_.mapping()) + { + case mapping_type::n_rows: + if (options_.unquoted_empty_value_is_null() && value_buffer_.length() == 0) + { + continue_ = handler_.null_value(semantic_tag::none, *this); + } + else + { + end_value(value_buffer_,column_index_,options_.infer_types(),handler_); + } + break; + case mapping_type::n_objects: + if (!(options_.ignore_empty_values() && value_buffer_.size() == 0)) + { + if (column_index_ < column_names_.size() + offset_) + { + if (options_.unquoted_empty_value_is_null() && value_buffer_.length() == 0) + { + continue_ = handler_.null_value(semantic_tag::none, *this); + } + else + { + end_value(value_buffer_,column_index_,options_.infer_types(),handler_); + } + } + else if (level_ > 0) + { + if (options_.unquoted_empty_value_is_null() && value_buffer_.length() == 0) + { + continue_ = handler_.null_value(semantic_tag::none, *this); + } + else + { + end_value(value_buffer_,column_index_,options_.infer_types(),handler_); + } + } + } + break; + case mapping_type::m_columns: + if (column_index_ < decoders_.size()) + { + if (!(options_.ignore_empty_values() && value_buffer_.size() == 0)) + { + end_value(value_buffer_,column_index_,options_.infer_types(),decoders_[column_index_]); + } + } + break; + } + break; + default: + break; + } + state_ = csv_state_type::expect_value; + value_buffer_.clear(); + } + + void end_quoted_string_value(std::error_code& ec) + { + if (options_.trim_leading_inside_quotes() | options_.trim_trailing_inside_quotes()) + { + trim_string_buffer(options_.trim_leading_inside_quotes(),options_.trim_trailing_inside_quotes()); + } + switch (stack_[top_]) + { + case csv_mode_type::header: + break; + case csv_mode_type::data: + case csv_mode_type::subfields: + switch (options_.mapping()) + { + case mapping_type::n_rows: + end_value(value_buffer_,column_index_,false,handler_); + break; + case mapping_type::n_objects: + if (!(options_.ignore_empty_values() && value_buffer_.size() == 0)) + { + if (column_index_ < column_names_.size() + offset_) + { + if (options_.unquoted_empty_value_is_null() && value_buffer_.length() == 0) + { + continue_ = handler_.null_value(semantic_tag::none, *this); + } + else + { + end_value(value_buffer_,column_index_,false,handler_); + } + } + else if (level_ > 0) + { + if (options_.unquoted_empty_value_is_null() && value_buffer_.length() == 0) + { + continue_ = handler_.null_value(semantic_tag::none, *this); + } + else + { + end_value(value_buffer_,column_index_,false,handler_); + } + } + } + break; + case mapping_type::m_columns: + if (column_index_ < decoders_.size()) + { + end_value(value_buffer_,column_index_,options_.infer_types(),decoders_[column_index_]); + } + break; + } + break; + default: + err_handler_.fatal_error(csv_errc::invalid_csv_text, *this); + ec = csv_errc::invalid_csv_text; + continue_ = false; + return; + } + state_ = csv_state_type::expect_value; + value_buffer_.clear(); + } + + void end_value(const string_view_type& value, + size_t column_index, + bool infer_types, + basic_json_content_handler& handler) + { + if (column_index < column_types_.size() + offset_) + { + if (column_types_[column_index - offset_].col_type == csv_column_type::repeat_t) + { + offset_ = offset_ + column_types_[column_index - offset_].rep_count; + if (column_index - offset_ + 1 < column_types_.size()) + { + if (column_index == offset_ || level_ > column_types_[column_index-offset_].level) + { + handler.end_array(*this); + } + level_ = column_index == offset_ ? 0 : column_types_[column_index - offset_].level; + } + } + if (level_ < column_types_[column_index - offset_].level) + { + handler.begin_array(semantic_tag::none, *this); + level_ = column_types_[column_index - offset_].level; + } + else if (level_ > column_types_[column_index - offset_].level) + { + handler.end_array(*this); + level_ = column_types_[column_index - offset_].level; + } + switch (column_types_[column_index - offset_].col_type) + { + case csv_column_type::integer_t: + { + std::istringstream iss{ std::string(value) }; + int64_t val; + iss >> val; + if (!iss.fail()) + { + handler.int64_value(val, semantic_tag::none, *this); + } + else + { + if (column_index - offset_ < column_defaults_.size() && column_defaults_[column_index - offset_].length() > 0) + { + basic_json_parser parser(err_handler_); + parser.update(column_defaults_[column_index - offset_].data(),column_defaults_[column_index - offset_].length()); + parser.parse_some(filter_); + parser.finish_parse(filter_); + } + else + { + handler.null_value(semantic_tag::none, *this); + } + } + } + break; + case csv_column_type::float_t: + { + if (options_.lossless_number()) + { + handler.string_value(value,semantic_tag::bigdec, *this); + } + else + { + std::istringstream iss{ std::string(value) }; + double val; + iss >> val; + if (!iss.fail()) + { + handler.double_value(val, semantic_tag::none, *this); + } + else + { + if (column_index - offset_ < column_defaults_.size() && column_defaults_[column_index - offset_].length() > 0) + { + basic_json_parser parser(err_handler_); + parser.update(column_defaults_[column_index - offset_].data(),column_defaults_[column_index - offset_].length()); + parser.parse_some(filter_); + parser.finish_parse(filter_); + } + else + { + handler.null_value(semantic_tag::none, *this); + } + } + } + } + break; + case csv_column_type::boolean_t: + { + if (value.length() == 1 && value[0] == '0') + { + handler.bool_value(false, semantic_tag::none, *this); + } + else if (value.length() == 1 && value[0] == '1') + { + handler.bool_value(true, semantic_tag::none, *this); + } + else if (value.length() == 5 && ((value[0] == 'f' || value[0] == 'F') && (value[1] == 'a' || value[1] == 'A') && (value[2] == 'l' || value[2] == 'L') && (value[3] == 's' || value[3] == 'S') && (value[4] == 'e' || value[4] == 'E'))) + { + handler.bool_value(false, semantic_tag::none, *this); + } + else if (value.length() == 4 && ((value[0] == 't' || value[0] == 'T') && (value[1] == 'r' || value[1] == 'R') && (value[2] == 'u' || value[2] == 'U') && (value[3] == 'e' || value[3] == 'E'))) + { + handler.bool_value(true, semantic_tag::none, *this); + } + else + { + if (column_index - offset_ < column_defaults_.size() && column_defaults_[column_index - offset_].length() > 0) + { + basic_json_parser parser(err_handler_); + parser.update(column_defaults_[column_index - offset_].data(),column_defaults_[column_index - offset_].length()); + parser.parse_some(filter_); + parser.finish_parse(filter_); + } + else + { + handler.null_value(semantic_tag::none, *this); + } + } + } + break; + default: + if (value.length() > 0) + { + handler.string_value(value, semantic_tag::none, *this); + } + else + { + if (column_index < column_defaults_.size() + offset_ && column_defaults_[column_index - offset_].length() > 0) + { + basic_json_parser parser(err_handler_); + parser.update(column_defaults_[column_index - offset_].data(),column_defaults_[column_index - offset_].length()); + parser.parse_some(filter_); + parser.finish_parse(filter_); + } + else + { + handler.string_value(string_view_type(), semantic_tag::none, *this); + } + } + break; + } + } + else + { + if (infer_types) + { + end_value_with_numeric_check(value, handler); + } + else + { + handler.string_value(value, semantic_tag::none, *this); + } + } + } + + enum class numeric_check_state + { + initial, + null, + boolean_true, + boolean_false, + minus, + zero, + integer, + fraction1, + fraction, + exp1, + exp, + done + }; + + void end_value_with_numeric_check(const string_view_type& value, basic_json_content_handler& handler) + { + numeric_check_state state = numeric_check_state::initial; + bool is_negative = false; + int precision = 0; + uint8_t decimal_places = 0; + + auto last = value.end(); + + std::string buffer; + for (auto p = value.begin(); state != numeric_check_state::done && p != last; ++p) + { + switch (state) + { + case numeric_check_state::initial: + { + switch (*p) + { + case 'n':case 'N': + if ((last-p) == 4 && (p[1] == 'u' || p[1] == 'U') && (p[2] == 'l' || p[2] == 'L') && (p[3] == 'l' || p[3] == 'L')) + { + state = numeric_check_state::null; + } + else + { + state = numeric_check_state::done; + } + break; + case 't':case 'T': + if ((last-p) == 4 && (p[1] == 'r' || p[1] == 'R') && (p[2] == 'u' || p[2] == 'U') && (p[3] == 'e' || p[3] == 'U')) + { + state = numeric_check_state::boolean_true; + } + else + { + state = numeric_check_state::done; + } + break; + case 'f':case 'F': + if ((last-p) == 5 && (p[1] == 'a' || p[1] == 'A') && (p[2] == 'l' || p[2] == 'L') && (p[3] == 's' || p[3] == 'S') && (p[4] == 'e' || p[4] == 'E')) + { + state = numeric_check_state::boolean_false; + } + else + { + state = numeric_check_state::done; + } + break; + case '-': + is_negative = true; + buffer.push_back(*p); + state = numeric_check_state::minus; + break; + case '0': + ++precision; + buffer.push_back(*p); + state = numeric_check_state::zero; + break; + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + ++precision; + buffer.push_back(*p); + state = numeric_check_state::integer; + break; + default: + state = numeric_check_state::done; + break; + } + break; + } + case numeric_check_state::zero: + { + switch (*p) + { + case '.': + buffer.push_back(to_double_.get_decimal_point()); + state = numeric_check_state::fraction1; + break; + case 'e':case 'E': + buffer.push_back(*p); + state = numeric_check_state::exp1; + break; + default: + state = numeric_check_state::done; + break; + } + break; + } + case numeric_check_state::integer: + { + switch (*p) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + ++precision; + buffer.push_back(*p); + break; + case '.': + buffer.push_back(to_double_.get_decimal_point()); + state = numeric_check_state::fraction1; + break; + case 'e':case 'E': + buffer.push_back(*p); + state = numeric_check_state::exp1; + break; + default: + state = numeric_check_state::done; + break; + } + break; + } + case numeric_check_state::minus: + { + switch (*p) + { + case '0': + ++precision; + buffer.push_back(*p); + state = numeric_check_state::zero; + break; + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + ++precision; + buffer.push_back(*p); + state = numeric_check_state::integer; + break; + case 'e':case 'E': + buffer.push_back(*p); + state = numeric_check_state::exp1; + break; + default: + state = numeric_check_state::done; + break; + } + break; + } + case numeric_check_state::fraction1: + { + switch (*p) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + ++precision; + ++decimal_places; + buffer.push_back(*p); + state = numeric_check_state::fraction; + break; + default: + state = numeric_check_state::done; + break; + } + break; + } + case numeric_check_state::fraction: + { + switch (*p) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + ++precision; + ++decimal_places; + buffer.push_back(*p); + break; + case 'e':case 'E': + buffer.push_back(*p); + state = numeric_check_state::exp1; + break; + default: + state = numeric_check_state::done; + break; + } + break; + } + case numeric_check_state::exp1: + { + switch (*p) + { + case '-': + buffer.push_back(*p); + state = numeric_check_state::exp; + break; + case '+': + state = numeric_check_state::exp; + break; + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + buffer.push_back(*p); + state = numeric_check_state::integer; + break; + default: + state = numeric_check_state::done; + break; + } + break; + } + case numeric_check_state::exp: + { + switch (*p) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + buffer.push_back(*p); + break; + default: + state = numeric_check_state::done; + break; + } + break; + } + default: + break; + } + } + + switch (state) + { + case numeric_check_state::null: + handler.null_value(semantic_tag::none, *this); + break; + case numeric_check_state::boolean_true: + handler.bool_value(true, semantic_tag::none, *this); + break; + case numeric_check_state::boolean_false: + handler.bool_value(false, semantic_tag::none, *this); + break; + case numeric_check_state::zero: + case numeric_check_state::integer: + { + if (is_negative) + { + auto result = jsoncons::detail::to_integer(value.data(), value.length()); + if (result.ec == jsoncons::detail::to_integer_errc()) + { + handler.int64_value(result.value, semantic_tag::none, *this); + } + else // Must be overflow + { + handler.string_value(value, semantic_tag::bigint, *this); + } + } + else + { + auto result = jsoncons::detail::to_integer(value.data(), value.length()); + if (result.ec == jsoncons::detail::to_integer_errc()) + { + handler.uint64_value(result.value, semantic_tag::none, *this); + } + else if (result.ec == jsoncons::detail::to_integer_errc::overflow) + { + handler.string_value(value, semantic_tag::bigint, *this); + } + else + { + JSONCONS_THROW(json_runtime_error(make_error_code(result.ec).message())); + } + } + break; + } + case numeric_check_state::fraction: + case numeric_check_state::exp: + { + if (options_.lossless_number()) + { + handler.string_value(value,semantic_tag::bigdec, *this); + } + else + { + double d = to_double_(buffer.c_str(), buffer.length()); + handler.double_value(d, semantic_tag::none, *this); + } + break; + } + default: + handler.string_value(value, semantic_tag::none, *this); + } + } + + void push_mode(csv_mode_type mode) + { + ++top_; + if (top_ >= depth_) + { + depth_ *= 2; + stack_.resize(depth_); + } + stack_[top_] = mode; + } + + int peek() + { + return stack_[top_]; + } + + bool peek(csv_mode_type mode) + { + return stack_[top_] == mode; + } + + bool flip(csv_mode_type mode1, csv_mode_type mode2) + { + if (top_ < 0 || stack_[top_] != mode1) + { + return false; + } + stack_[top_] = mode2; + return true; + } + + bool pop_mode(csv_mode_type mode) + { + if (top_ < 0 || stack_[top_] != mode) + { + return false; + } + --top_; + return true; + } +}; + +typedef basic_csv_parser csv_parser; +typedef basic_csv_parser wcsv_parser; + +}} + +#endif + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/csv/csv_reader.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/csv/csv_reader.hpp new file mode 100644 index 0000000000..46d94a50b1 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/csv/csv_reader.hpp @@ -0,0 +1,328 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_CSV_CSV_READER_HPP +#define JSONCONS_CSV_CSV_READER_HPP + +#include +#include +#include +#include // std::allocator +#include // std::move +#include // std::basic_istream +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace jsoncons { namespace csv { + +template,class Allocator=std::allocator> +class basic_csv_reader +{ + struct stack_item + { + stack_item() + : array_begun_(false) + { + } + + bool array_begun_; + }; + typedef CharT char_type; + typedef Allocator allocator_type; + typedef typename std::allocator_traits:: template rebind_alloc char_allocator_type; + + basic_csv_reader(const basic_csv_reader&) = delete; + basic_csv_reader& operator = (const basic_csv_reader&) = delete; + + default_parse_error_handler default_err_handler_; + + basic_csv_parser parser_; + Src source_; + std::vector buffer_; + size_t buffer_length_; + bool eof_; + bool begin_; +public: + // Structural characters + static const size_t default_max_buffer_length = 16384; + //! Parse an input stream of CSV text into a json object + /*! + \param is The input stream to read from + */ + + template + basic_csv_reader(Source&& source, + basic_json_content_handler& handler) + + : basic_csv_reader(std::forward(source), + handler, + basic_csv_options::default_options(), + default_err_handler_) + { + } + + template + basic_csv_reader(Source&& source, + basic_json_content_handler& handler, + const basic_csv_options& options) + + : basic_csv_reader(std::forward(source), + handler, + options, + default_err_handler_) + { + } + + template + basic_csv_reader(Source&& source, + basic_json_content_handler& handler, + parse_error_handler& err_handler) + : basic_csv_reader(std::forward(source), + handler, + basic_csv_options::default_options(), + err_handler) + { + } + + template + basic_csv_reader(Source&& source, + basic_json_content_handler& handler, + const basic_csv_decode_options& options, + parse_error_handler& err_handler, + typename std::enable_if,Source>::value>::type* = 0) + : + parser_(handler, options, err_handler), + source_(std::forward(source)), + buffer_length_(default_max_buffer_length), + eof_(false), + begin_(true) + { + buffer_.reserve(buffer_length_); + } + + template + basic_csv_reader(Source&& source, + basic_json_content_handler& handler, + const basic_csv_decode_options& options, + parse_error_handler& err_handler, + typename std::enable_if,Source>::value>::type* = 0) + : + parser_(handler, options, err_handler), + buffer_length_(0), + eof_(false), + begin_(false) + { + basic_string_view sv(std::forward(source)); + auto result = unicons::skip_bom(sv.begin(), sv.end()); + if (result.ec != unicons::encoding_errc()) + { + throw ser_error(result.ec,parser_.line(),parser_.column()); + } + size_t offset = result.it - sv.begin(); + parser_.update(sv.data()+offset,sv.size()-offset); + } + + ~basic_csv_reader() + { + } + + void read() + { + std::error_code ec; + read(ec); + if (ec) + { + throw ser_error(ec,parser_.line(),parser_.column()); + } + } + + void read(std::error_code& ec) + { + try + { + read_internal(ec); + } + catch (const ser_error& e) + { + ec = e.code(); + } + } + + bool eof() const + { + return eof_; + } + + size_t buffer_length() const + { + return buffer_length_; + } + + void buffer_length(size_t length) + { + buffer_length_ = length; + buffer_.reserve(buffer_length_); + } + +#if !defined(JSONCONS_NO_DEPRECATED) + + size_t buffer_capacity() const + { + return buffer_length_; + } + + void buffer_capacity(size_t length) + { + buffer_length_ = length; + buffer_.reserve(buffer_length_); + } +#endif +private: + + void read_internal(std::error_code& ec) + { + if (source_.is_error()) + { + ec = csv_errc::source_error; + return; + } + parser_.reset(); + if (ec) + { + return; + } + while (!parser_.stopped()) + { + if (parser_.source_exhausted()) + { + if (!source_.eof()) + { + read_buffer(ec); + if (ec) + { + return; + } + /* buffer_.clear(); + buffer_.resize(buffer_length_); + size_t count = source_.read(buffer_.data(), buffer_length_); + buffer_.resize(count); + if (buffer_.size() == 0) + { + eof_ = true; + } + parser_.update(buffer_.data(),buffer_.size());*/ + } + else + { + parser_.update(buffer_.data(),0); + eof_ = true; + } + } + parser_.parse_some(ec); + if (ec) return; + } + } + void read_buffer(std::error_code& ec) + { + buffer_.clear(); + buffer_.resize(buffer_length_); + size_t count = source_.read(buffer_.data(), buffer_length_); + buffer_.resize(static_cast(count)); + if (buffer_.size() == 0) + { + eof_ = true; + } + else if (begin_) + { + auto result = unicons::skip_bom(buffer_.begin(), buffer_.end()); + if (result.ec != unicons::encoding_errc()) + { + ec = result.ec; + return; + } + size_t offset = result.it - buffer_.begin(); + parser_.update(buffer_.data()+offset,buffer_.size()-offset); + begin_ = false; + } + else + { + parser_.update(buffer_.data(),buffer_.size()); + } + } + +}; + +template +typename std::enable_if::value,T>::type +decode_csv(const std::basic_string& s, const basic_csv_options& options = basic_csv_options::default_options()) +{ + typedef CharT char_type; + + json_decoder decoder; + + basic_csv_reader> reader(s,decoder,options); + reader.read(); + return decoder.get_result(); +} + +template +typename std::enable_if::value,T>::type +decode_csv(const std::basic_string& s, const basic_csv_options& options = basic_csv_options::default_options()) +{ + typedef CharT char_type; + + json_decoder> decoder; + + basic_csv_reader> reader(s,decoder,options); + reader.read(); + return decoder.get_result().template as(); +} + +template +typename std::enable_if::value,T>::type +decode_csv(std::basic_istream& is, const basic_csv_options& options = basic_csv_options::default_options()) +{ + typedef CharT char_type; + + json_decoder decoder; + + basic_csv_reader> reader(is,decoder,options); + reader.read(); + return decoder.get_result(); +} + +template +typename std::enable_if::value,T>::type +decode_csv(std::basic_istream& is, const basic_csv_options& options = basic_csv_options::default_options()) +{ + typedef CharT char_type; + + json_decoder> decoder; + + basic_csv_reader> reader(is,decoder,options); + reader.read(); + return decoder.get_result().template as(); +} + +typedef basic_csv_reader csv_reader; +typedef basic_csv_reader wcsv_reader; + +#if !defined(JSONCONS_NO_DEPRECATED) +typedef basic_csv_reader> csv_string_reader; +typedef basic_csv_reader> wcsv_string_reader; +#endif + +}} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/csv/csv_serializer.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/csv/csv_serializer.hpp new file mode 100644 index 0000000000..ec73510bf7 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/csv/csv_serializer.hpp @@ -0,0 +1,12 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_CSV_CSV_SERIALIZER_HPP +#define JSONCONS_CSV_CSV_SERIALIZER_HPP + +#include + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/jsonpatch/jsonpatch.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/jsonpatch/jsonpatch.hpp new file mode 100644 index 0000000000..600dd9cffb --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/jsonpatch/jsonpatch.hpp @@ -0,0 +1,492 @@ +// Copyright 2017 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSONPOINTER_JSONPATCH_HPP +#define JSONCONS_JSONPOINTER_JSONPATCH_HPP + +#include +#include +#include +#include +#include // std::min +#include // std::move +#include +#include +#include + +namespace jsoncons { namespace jsonpatch { + +namespace detail { + + JSONCONS_STRING_LITERAL(test,'t','e','s','t') + JSONCONS_STRING_LITERAL(add,'a','d','d') + JSONCONS_STRING_LITERAL(remove,'r','e','m','o','v','e') + JSONCONS_STRING_LITERAL(replace,'r','e','p','l','a','c','e') + JSONCONS_STRING_LITERAL(move,'m','o','v','e') + JSONCONS_STRING_LITERAL(copy,'c','o','p','y') + JSONCONS_STRING_LITERAL(op,'o','p') + JSONCONS_STRING_LITERAL(path,'p','a','t','h') + JSONCONS_STRING_LITERAL(from,'f','r','o','m') + JSONCONS_STRING_LITERAL(value,'v','a','l','u','e') + + enum class op_type {add,remove,replace}; + enum class state_type {begin,abort,commit}; + + template + struct operation_unwinder + { + typedef typename Json::string_type string_type; + typedef typename Json::string_view_type string_view_type; + + struct entry + { + op_type op; + string_type path; + Json value; + }; + + Json& target; + state_type state; + std::vector stack; + + operation_unwinder(Json& j) + : target(j), state(state_type::begin) + { + } + + ~operation_unwinder() + { + std::error_code ec; + //std::cout << "state: " << std::boolalpha << (state == state_type::commit) << ", stack size: " << stack.size() << std::endl; + if (state != state_type::commit) + { + for (auto it = stack.rbegin(); it != stack.rend(); ++it) + { + if (it->op == op_type::add) + { + jsonpointer::insert_or_assign(target,it->path,it->value,ec); + if (ec) + { + //std::cout << "add: " << it->path << std::endl; + break; + } + } + else if (it->op == op_type::remove) + { + jsonpointer::remove(target,it->path,ec); + if (ec) + { + //std::cout << "remove: " << it->path << std::endl; + break; + } + } + else if (it->op == op_type::replace) + { + jsonpointer::replace(target,it->path,it->value,ec); + if (ec) + { + //std::cout << "replace: " << it->path << std::endl; + break; + } + } + } + } + } + }; + + template + Json from_diff(const Json& source, const Json& target, const typename Json::string_type& path) + { + typedef typename Json::char_type char_type; + + Json result = typename Json::array(); + + if (source == target) + { + return result; + } + + if (source.is_array() && target.is_array()) + { + size_t common = (std::min)(source.size(),target.size()); + for (size_t i = 0; i < common; ++i) + { + std::basic_ostringstream ss; + ss << path << '/' << i; + auto temp_diff = from_diff(source[i],target[i],ss.str()); + result.insert(result.array_range().end(),temp_diff.array_range().begin(),temp_diff.array_range().end()); + } + // Element in source, not in target - remove + for (size_t i = target.size(); i < source.size(); ++i) + { + std::basic_ostringstream ss; + ss << path << '/' << i; + Json val = typename Json::object(); + val.insert_or_assign(op_literal(), remove_literal()); + val.insert_or_assign(path_literal(), ss.str()); + result.push_back(std::move(val)); + } + // Element in target, not in source - add, + // Fix contributed by Alexander rog13 + for (size_t i = source.size(); i < target.size(); ++i) + { + const auto& a = target[i]; + std::basic_ostringstream ss; + ss << path << '/' << i; + Json val = typename Json::object(); + val.insert_or_assign(op_literal(), add_literal()); + val.insert_or_assign(path_literal(), ss.str()); + val.insert_or_assign(value_literal(), a); + result.push_back(std::move(val)); + } + } + else if (source.is_object() && target.is_object()) + { + for (const auto& a : source.object_range()) + { + std::basic_ostringstream ss; + ss << path << '/'; + jsonpointer::escape(a.key(),ss); + auto it = target.find(a.key()); + if (it != target.object_range().end()) + { + auto temp_diff = from_diff(a.value(),it->value(),ss.str()); + result.insert(result.array_range().end(),temp_diff.array_range().begin(),temp_diff.array_range().end()); + } + else + { + Json val = typename Json::object(); + val.insert_or_assign(op_literal(), remove_literal()); + val.insert_or_assign(path_literal(), ss.str()); + result.push_back(std::move(val)); + } + } + for (const auto& a : target.object_range()) + { + auto it = source.find(a.key()); + if (it == source.object_range().end()) + { + std::basic_ostringstream ss; + ss << path << '/'; + jsonpointer::escape(a.key(),ss); + Json val = typename Json::object(); + val.insert_or_assign(op_literal(), add_literal()); + val.insert_or_assign(path_literal(), ss.str()); + val.insert_or_assign(value_literal(), a.value()); + result.push_back(std::move(val)); + } + } + } + else + { + Json val = typename Json::object(); + val.insert_or_assign(op_literal(), replace_literal()); + val.insert_or_assign(path_literal(), path); + val.insert_or_assign(value_literal(), target); + result.push_back(std::move(val)); + } + + return result; + } +} + +template +void apply_patch(Json& target, const Json& patch, std::error_code& patch_ec) +{ + typedef typename Json::char_type char_type; + typedef typename Json::string_type string_type; + typedef typename Json::string_view_type string_view_type; + + jsoncons::jsonpatch::detail::operation_unwinder unwinder(target); + + // Validate + + string_type bad_path; + for (const auto& operation : patch.array_range()) + { + unwinder.state =jsoncons::jsonpatch::detail::state_type::begin; + + if (operation.count(detail::op_literal()) != 1 || operation.count(detail::path_literal()) != 1) + { + patch_ec = jsonpatch_errc::invalid_patch; + unwinder.state =jsoncons::jsonpatch::detail::state_type::abort; + } + else + { + string_view_type op = operation.at(detail::op_literal()).as_string_view(); + string_view_type path = operation.at(detail::path_literal()).as_string_view(); + + if (op ==jsoncons::jsonpatch::detail::test_literal()) + { + std::error_code ec; + Json val = jsonpointer::get(target,path,ec); + if (ec) + { + patch_ec = jsonpatch_errc::test_failed; + unwinder.state =jsoncons::jsonpatch::detail::state_type::abort; + } + else if (operation.count(detail::value_literal()) != 1) + { + patch_ec = jsonpatch_errc::invalid_patch; + unwinder.state =jsoncons::jsonpatch::detail::state_type::abort; + } + else if (val != operation.at(detail::value_literal())) + { + patch_ec = jsonpatch_errc::test_failed; + unwinder.state =jsoncons::jsonpatch::detail::state_type::abort; + } + } + else if (op ==jsoncons::jsonpatch::detail::add_literal()) + { + if (operation.count(detail::value_literal()) != 1) + { + patch_ec = jsonpatch_errc::invalid_patch; + unwinder.state =jsoncons::jsonpatch::detail::state_type::abort; + } + else + { + std::error_code insert_ec; + Json val = operation.at(detail::value_literal()); + auto npath = jsonpointer::normalized_path(target,path); + jsonpointer::insert(target,npath,val,insert_ec); // try insert without replace + if (insert_ec) // try a replace + { + std::error_code select_ec; + Json orig_val = jsonpointer::get(target,npath,select_ec); + if (select_ec) // shouldn't happen + { + patch_ec = jsonpatch_errc::add_failed; + unwinder.state =jsoncons::jsonpatch::detail::state_type::abort; + } + else + { + std::error_code replace_ec; + jsonpointer::replace(target,npath,val,replace_ec); + if (replace_ec) + { + patch_ec = jsonpatch_errc::add_failed; + unwinder.state =jsoncons::jsonpatch::detail::state_type::abort; + } + else + { + unwinder.stack.push_back({detail::op_type::replace,npath,orig_val}); + } + } + } + else // insert without replace succeeded + { + unwinder.stack.push_back({detail::op_type::remove,npath,Json::null()}); + } + } + } + else if (op ==jsoncons::jsonpatch::detail::remove_literal()) + { + std::error_code ec; + Json val = jsonpointer::get(target,path,ec); + if (ec) + { + patch_ec = jsonpatch_errc::remove_failed; + unwinder.state =jsoncons::jsonpatch::detail::state_type::abort; + } + else + { + jsonpointer::remove(target,path,ec); + if (ec) + { + patch_ec = jsonpatch_errc::remove_failed; + unwinder.state =jsoncons::jsonpatch::detail::state_type::abort; + } + else + { + unwinder.stack.push_back({detail::op_type::add,string_type(path),val}); + } + } + } + else if (op ==jsoncons::jsonpatch::detail::replace_literal()) + { + std::error_code ec; + Json val = jsonpointer::get(target,path,ec); + if (ec) + { + patch_ec = jsonpatch_errc::replace_failed; + unwinder.state =jsoncons::jsonpatch::detail::state_type::abort; + } + else if (operation.count(detail::value_literal()) != 1) + { + patch_ec = jsonpatch_errc::invalid_patch; + unwinder.state =jsoncons::jsonpatch::detail::state_type::abort; + } + else + { + jsonpointer::replace(target,path,operation.at(detail::value_literal()),ec); + if (ec) + { + patch_ec = jsonpatch_errc::replace_failed; + unwinder.state =jsoncons::jsonpatch::detail::state_type::abort; + } + else + { + unwinder.stack.push_back({detail::op_type::replace,string_type(path),val}); + } + } + } + else if (op ==jsoncons::jsonpatch::detail::move_literal()) + { + if (operation.count(detail::from_literal()) != 1) + { + patch_ec = jsonpatch_errc::invalid_patch; + unwinder.state =jsoncons::jsonpatch::detail::state_type::abort; + } + else + { + string_view_type from = operation.at(detail::from_literal()).as_string_view(); + std::error_code ec; + Json val = jsonpointer::get(target,from,ec); + if (ec) + { + patch_ec = jsonpatch_errc::move_failed; + unwinder.state =jsoncons::jsonpatch::detail::state_type::abort; + } + else + { + jsonpointer::remove(target,from,ec); + if (ec) + { + patch_ec = jsonpatch_errc::move_failed; + unwinder.state =jsoncons::jsonpatch::detail::state_type::abort; + } + else + { + unwinder.stack.push_back({detail::op_type::add,string_type(from),val}); + // add + std::error_code insert_ec; + auto npath = jsonpointer::normalized_path(target,path); + jsonpointer::insert(target,npath,val,insert_ec); // try insert without replace + if (insert_ec) // try a replace + { + std::error_code select_ec; + Json orig_val = jsonpointer::get(target,npath,select_ec); + if (select_ec) // shouldn't happen + { + patch_ec = jsonpatch_errc::copy_failed; + unwinder.state =jsoncons::jsonpatch::detail::state_type::abort; + } + else + { + std::error_code replace_ec; + jsonpointer::replace(target, npath, val, replace_ec); + if (replace_ec) + { + patch_ec = jsonpatch_errc::copy_failed; + unwinder.state =jsoncons::jsonpatch::detail::state_type::abort; + + } + else + { + unwinder.stack.push_back({jsoncons::jsonpatch::detail::op_type::replace,npath,orig_val }); + } + + } + } + else + { + unwinder.stack.push_back({detail::op_type::remove,npath,Json::null()}); + } + } + } + } + } + else if (op ==jsoncons::jsonpatch::detail::copy_literal()) + { + if (operation.count(detail::from_literal()) != 1) + { + patch_ec = jsonpatch_errc::invalid_patch; + unwinder.state =jsoncons::jsonpatch::detail::state_type::abort; + } + else + { + std::error_code ec; + string_view_type from = operation.at(detail::from_literal()).as_string_view(); + Json val = jsonpointer::get(target,from,ec); + if (ec) + { + patch_ec = jsonpatch_errc::copy_failed; + unwinder.state =jsoncons::jsonpatch::detail::state_type::abort; + } + else + { + // add + auto npath = jsonpointer::normalized_path(target,path); + std::error_code insert_ec; + jsonpointer::insert(target,npath,val,insert_ec); // try insert without replace + if (insert_ec) // Failed, try a replace + { + std::error_code select_ec; + Json orig_val = jsonpointer::get(target,npath, select_ec); + if (select_ec) // shouldn't happen + { + patch_ec = jsonpatch_errc::copy_failed; + unwinder.state =jsoncons::jsonpatch::detail::state_type::abort; + } + else + { + std::error_code replace_ec; + jsonpointer::replace(target, npath, val,replace_ec); + if (replace_ec) + { + patch_ec = jsonpatch_errc::copy_failed; + unwinder.state =jsoncons::jsonpatch::detail::state_type::abort; + } + else + { + unwinder.stack.push_back({jsoncons::jsonpatch::detail::op_type::replace,npath,orig_val }); + } + } + } + else + { + unwinder.stack.push_back({detail::op_type::remove,npath,Json::null()}); + } + } + } + } + if (unwinder.state !=jsoncons::jsonpatch::detail::state_type::begin) + { + bad_path = string_type(path); + } + } + if (unwinder.state !=jsoncons::jsonpatch::detail::state_type::begin) + { + break; + } + } + if (unwinder.state ==jsoncons::jsonpatch::detail::state_type::begin) + { + unwinder.state =jsoncons::jsonpatch::detail::state_type::commit; + } +} + +template +Json from_diff(const Json& source, const Json& target) +{ + typename Json::string_type path; + return jsoncons::jsonpatch::detail::from_diff(source, target, path); +} + +template +void apply_patch(Json& target, const Json& patch) +{ + std::error_code ec; + apply_patch(target, patch, ec); + if (ec) + { + JSONCONS_THROW(jsonpatch_error(ec)); + } +} + +}} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/jsonpatch/jsonpatch_error.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/jsonpatch/jsonpatch_error.hpp new file mode 100644 index 0000000000..731b25f816 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/jsonpatch/jsonpatch_error.hpp @@ -0,0 +1,114 @@ +/// Copyright 2017 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSONPATCH_JSONPATCH_ERROR_HPP +#define JSONCONS_JSONPATCH_JSONPATCH_ERROR_HPP + +#include +#include + +namespace jsoncons { namespace jsonpatch { + +class jsonpatch_error : public std::system_error, public virtual json_exception +{ +public: + jsonpatch_error(const std::error_code& ec) + : std::system_error(ec) + { + } + + jsonpatch_error(const std::error_code& ec, const std::string& what_arg) + : std::system_error(ec, what_arg) + { + } + + jsonpatch_error(const std::error_code& ec, const char* what_arg) + : std::system_error(ec, what_arg) + { + } + + jsonpatch_error(const jsonpatch_error& other) = default; + + jsonpatch_error(jsonpatch_error&& other) = default; + + const char* what() const noexcept override + { + return std::system_error::what(); + } + + jsonpatch_error& operator=(const jsonpatch_error& e) = default; + jsonpatch_error& operator=(jsonpatch_error&& e) = default; +private: +}; + +enum class jsonpatch_errc +{ + ok = 0, + invalid_patch = 1, + test_failed, + add_failed, + remove_failed, + replace_failed, + move_failed, + copy_failed + +}; + +class jsonpatch_error_category_impl + : public std::error_category +{ +public: + const char* name() const noexcept override + { + return "jsoncons/jsonpatch"; + } + std::string message(int ev) const override + { + switch (static_cast(ev)) + { + case jsonpatch_errc::invalid_patch: + return "Invalid JSON Patch document"; + case jsonpatch_errc::test_failed: + return "JSON Patch test operation failed"; + case jsonpatch_errc::add_failed: + return "JSON Patch add operation failed"; + case jsonpatch_errc::remove_failed: + return "JSON Patch remove operation failed"; + case jsonpatch_errc::replace_failed: + return "JSON Patch replace operation failed"; + case jsonpatch_errc::move_failed: + return "JSON Patch move operation failed"; + case jsonpatch_errc::copy_failed: + return "JSON Patch copy operation failed"; + default: + return "Unknown JSON Patch error"; + } + } +}; + +inline +const std::error_category& jsonpatch_error_category() +{ + static jsonpatch_error_category_impl instance; + return instance; +} + +inline +std::error_code make_error_code(jsonpatch_errc result) +{ + return std::error_code(static_cast(result),jsonpatch_error_category()); +} + +}} + +namespace std { + template<> + struct is_error_code_enum : public true_type + { + }; +} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/jsonpath/json_query.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/jsonpath/json_query.hpp new file mode 100644 index 0000000000..0c97f3371b --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/jsonpath/json_query.hpp @@ -0,0 +1,1808 @@ +// Copyright 2013 Daniel Parkerpath_single_quoted +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSONPATH_JSON_QUERY_HPP +#define JSONCONS_JSONPATH_JSON_QUERY_HPP + +#include // std::array +#include +#include +#include +#include // std::is_const +#include // std::numeric_limits +#include // std::move +#include +#include // std::set +#include // std::make_move_iterator +#include +#include +#include +#include + +namespace jsoncons { namespace jsonpath { + +struct array_slice +{ + size_t start_; + bool is_start_positive; + size_t end_; + bool is_end_positive; + bool is_end_defined; + size_t step_; + bool is_step_positive; + + array_slice() + : start_(0), is_start_positive(true), + end_(0), is_end_positive(true), is_end_defined(false), + step_(1), is_step_positive(true) + { + } + + array_slice(size_t start, bool is_start_positive, + size_t end, bool is_end_positive, bool is_end_defined, + size_t step, bool is_step_positive) + : start_(start), is_start_positive(is_start_positive), + end_(end), is_end_positive(is_end_positive), is_end_defined(is_end_defined), + step_(step), is_step_positive(is_step_positive) + { + } + + size_t get_start(size_t size) const + { + return is_start_positive ? start_ : size - start_; + } + + size_t get_end(size_t size) const + { + if (is_end_defined) + { + return is_end_positive ? end_ : size - end_; + } + else + { + return size; + } + } + + size_t step() const + { + return step_; + } + + array_slice(const array_slice&) = default; + + array_slice& operator=(const array_slice&) = default; +}; + +// work around for std::make_unique not being available until C++14 +template +std::unique_ptr make_unique_ptr(Args&&... args) +{ + return std::unique_ptr(new T(std::forward(args)...)); +} + +enum class result_type {value,path}; + +template +Json json_query(const Json& root, const typename Json::string_view_type& path, result_type result_t = result_type::value) +{ + if (result_t == result_type::value) + { + jsoncons::jsonpath::detail::jsonpath_evaluator> evaluator; + evaluator.evaluate(root, path); + return evaluator.get_values(); + } + else + { + jsoncons::jsonpath::detail::jsonpath_evaluator> evaluator; + evaluator.evaluate(root, path); + return evaluator.get_normalized_paths(); + } +} + +template +void json_replace(Json& root, const typename Json::string_view_type& path, T&& new_value) +{ + jsoncons::jsonpath::detail::jsonpath_evaluator> evaluator; + evaluator.evaluate(root, path); + evaluator.replace(std::forward(new_value)); +} + +namespace detail { + +template +bool try_string_to_index(const CharT *s, size_t length, size_t* value, bool* positive) +{ + static const size_t max_value = (std::numeric_limits::max)(); + static const size_t max_value_div_10 = max_value / 10; + + size_t start = 0; + size_t n = 0; + if (length > 0) + { + if (s[start] == '-') + { + *positive = false; + ++start; + } + else + { + *positive = true; + } + } + if (length > start) + { + for (size_t i = start; i < length; ++i) + { + CharT c = s[i]; + switch (c) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + { + size_t x = c - '0'; + if (n > max_value_div_10) + { + return false; + } + n = n * 10; + if (n > max_value - x) + { + return false; + } + + n += x; + break; + } + default: + return false; + break; + } + } + *value = n; + return true; + } + else + { + return false; + } +} + +enum class path_state +{ + start, + dot_or_left_bracket, + name_or_left_bracket, + name, + unquoted_name, + unquoted_name2, + single_quoted_name, + double_quoted_name, + bracketed_unquoted_name, + bracketed_single_quoted_name, + bracketed_double_quoted_name, + bracketed_name_or_path, + bracketed_wildcard_or_path, + wildcard_or_rpath_or_slice_or_filter, + slice_end_or_end_step, + slice_end, + slice_step, + slice_step2, + comma_or_right_bracket, + path_or_function_name, + function, + arg_or_right_paren, + path_argument, + unquoted_arg, + single_quoted_arg, + double_quoted_arg, + more_args_or_right_paren, + dot, + path, + path2, + path_single_quoted, + path_double_quoted +}; + +struct state_item +{ + path_state state; + bool is_recursive_descent; + bool is_union; + + state_item() + : state(path_state::start), is_recursive_descent(false), is_union(false) + { + } + + explicit state_item(path_state state) + : state(state), is_recursive_descent(false), is_union(false) + { + } + + state_item(path_state state, const state_item& parent) + : state(state), + is_recursive_descent(parent.is_recursive_descent), + is_union(parent.is_union) + { + } + + state_item(const state_item&) = default; + state_item& operator=(const state_item&) = default; +}; + +JSONCONS_STRING_LITERAL(length, 'l', 'e', 'n', 'g', 't', 'h') + +template +class jsonpath_evaluator : public ser_context +{ + typedef typename Json::char_type char_type; + typedef typename Json::char_traits_type char_traits_type; + typedef std::basic_string string_type; + typedef typename Json::string_view_type string_view_type; + typedef JsonReference reference; + using pointer = typename std::conditional::type>::value,typename Json::const_pointer,typename Json::pointer>::type; + typedef typename Json::const_pointer const_pointer; + + struct node_type + { + string_type path; + pointer val_ptr; + + node_type() = default; + node_type(const string_type& p, const pointer& valp) + : path(p),val_ptr(valp) + { + } + node_type(string_type&& p, pointer&& valp) + : path(std::move(p)),val_ptr(valp) + { + } + node_type(const node_type&) = default; + node_type(node_type&& other) + : path(std::move(other.path)), val_ptr(other.val_ptr) + { + + } + node_type& operator=(const node_type&) = default; + node_type& operator=(node_type&& other) + { + path.swap(other.path); + val_ptr = other.val_ptr; + } + + }; + typedef std::vector node_set; + + struct node_less + { + bool operator()(const node_type& a, const node_type& b) const + { + return *(a.val_ptr) < *(b.val_ptr); + } + }; + + class selector_base + { + public: + virtual ~selector_base() + { + } + virtual void select(jsonpath_evaluator& evaluator, + const string_type& path, reference val, node_set& nodes) = 0; + + virtual bool is_filter() const + { + return false; + } + }; + + class path_selector final : public selector_base + { + private: + std::basic_string path_; + public: + path_selector(const std::basic_string& path) + : path_(path) + { + } + + void select(jsonpath_evaluator&, + const string_type& path, reference val, + node_set& nodes) override + { + std::error_code ec; + jsonpath_evaluator e; + e.evaluate(val, path_, ec); + if (!ec) + { + for (auto ptr : e.get_pointers()) + { + nodes.emplace_back(PathCons()(path,path_),ptr); + } + } + } + }; + + class expr_selector final : public selector_base + { + private: + jsonpath_filter_expr result_; + public: + expr_selector(const jsonpath_filter_expr& result) + : result_(result) + { + } + + void select(jsonpath_evaluator& evaluator, + const string_type& path, reference val, + node_set& nodes) override + { + auto index = result_.eval(val); + if (index.template is()) + { + size_t start = index.template as(); + if (val.is_array() && start < val.size()) + { + nodes.emplace_back(PathCons()(path,start),std::addressof(val[start])); + } + } + else if (index.is_string()) + { + name_selector selector(index.as_string_view()); + selector.select(evaluator, path, val, nodes); + } + } + }; + + class filter_selector final : public selector_base + { + private: + jsonpath_filter_expr result_; + public: + filter_selector(const jsonpath_filter_expr& result) + : result_(result) + { + } + + bool is_filter() const override + { + return true; + } + + void select(jsonpath_evaluator&, + const string_type& path, reference val, + node_set& nodes) override + { + //std::cout << "filter_selector select "; + if (val.is_array()) + { + //std::cout << "from array \n"; + for (size_t i = 0; i < val.size(); ++i) + { + if (result_.exists(val[i])) + { + nodes.emplace_back(PathCons()(path,i),std::addressof(val[i])); + } + } + } + else if (val.is_object()) + { + //std::cout << "from object \n"; + if (result_.exists(val)) + { + nodes.emplace_back(path, std::addressof(val)); + } + } + } + }; + + class name_selector final : public selector_base + { + private: + string_type name_; + public: + name_selector(const string_view_type& name) + : name_(name) + { + } + + void select(jsonpath_evaluator& evaluator, + const string_type& path, reference val, + node_set& nodes) override + { + bool is_start_positive = true; + + if (val.is_object() && val.contains(name_)) + { + nodes.emplace_back(PathCons()(path,name_),std::addressof(val.at(name_))); + } + else if (val.is_array()) + { + size_t pos = 0; + if (try_string_to_index(name_.data(), name_.size(), &pos, &is_start_positive)) + { + size_t index = is_start_positive ? pos : val.size() - pos; + if (index < val.size()) + { + nodes.emplace_back(PathCons()(path,index),std::addressof(val[index])); + } + } + else if (name_ == length_literal() && val.size() > 0) + { + pointer ptr = evaluator.create_temp(val.size()); + nodes.emplace_back(PathCons()(path, name_), ptr); + } + } + else if (val.is_string()) + { + size_t pos = 0; + string_view_type sv = val.as_string_view(); + if (try_string_to_index(name_.data(), name_.size(), &pos, &is_start_positive)) + { + size_t index = is_start_positive ? pos : sv.size() - pos; + auto sequence = unicons::sequence_at(sv.data(), sv.data() + sv.size(), index); + if (sequence.length() > 0) + { + pointer ptr = evaluator.create_temp(sequence.begin(),sequence.length()); + nodes.emplace_back(PathCons()(path, index), ptr); + } + } + else if (name_ == length_literal() && sv.size() > 0) + { + size_t count = unicons::u32_length(sv.begin(),sv.end()); + pointer ptr = evaluator.create_temp(count); + nodes.emplace_back(PathCons()(path, name_), ptr); + } + } + } + }; + + class array_slice_selector final : public selector_base + { + private: + array_slice slice_; + public: + array_slice_selector(const array_slice& slice) + : slice_(slice) + { + } + + void select(jsonpath_evaluator&, + const string_type& path, reference val, + node_set& nodes) override + { + if (slice_.is_step_positive) + { + end_array_slice1(path, val, nodes); + } + else + { + end_array_slice2(path, val, nodes); + } + } + + void end_array_slice1(const string_type& path, reference val, node_set& nodes) + { + if (val.is_array()) + { + size_t start = slice_.get_start(val.size()); + size_t end = slice_.get_end(val.size()); + for (size_t j = start; j < end; j += slice_.step()) + { + if (j < val.size()) + { + nodes.emplace_back(PathCons()(path,j),std::addressof(val[j])); + } + } + } + } + + void end_array_slice2(const string_type& path, reference val, node_set& nodes) + { + if (val.is_array()) + { + size_t start = slice_.get_start(val.size()); + size_t end = slice_.get_end(val.size()); + + size_t j = end + slice_.step() - 1; + while (j > (start+slice_.step()-1)) + { + j -= slice_.step(); + if (j < val.size()) + { + nodes.emplace_back(PathCons()(path,j),std::addressof(val[j])); + } + } + } + } + }; + + function_table functions_; + + default_parse_error_handler default_err_handler_; + node_set nodes_; + std::vector stack_; + size_t line_; + size_t column_; + const char_type* begin_input_; + const char_type* end_input_; + const char_type* p_; + std::vector> selectors_; + std::vector> temp_json_values_; + + typedef std::vector argument_type; + std::vector function_stack_; + std::vector state_stack_; + +public: + jsonpath_evaluator() + : line_(1), column_(1), + begin_input_(nullptr), end_input_(nullptr), + p_(nullptr) + { + } + + jsonpath_evaluator(size_t line, size_t column) + : line_(line), column_(column), + begin_input_(nullptr), end_input_(nullptr), + p_(nullptr) + { + } + + size_t line() const + { + return line_; + } + + size_t column() const + { + return column_; + } + + Json get_values() const + { + Json result = typename Json::array(); + + if (stack_.size() > 0) + { + result.reserve(stack_.back().size()); + for (const auto& p : stack_.back()) + { + result.push_back(*(p.val_ptr)); + } + } + return result; + } + + std::vector get_pointers() const + { + std::vector result; + + if (stack_.size() > 0) + { + result.reserve(stack_.back().size()); + for (const auto& p : stack_.back()) + { + result.push_back(p.val_ptr); + } + } + return result; + } + + void call_function(const string_type& function_name, std::error_code& ec) + { + auto f = functions_.get(function_name, ec); + if (ec) + { + return; + } + auto result = f(function_stack_, ec); + if (ec) + { + return; + } + + string_type s = {'$'}; + node_set v; + pointer ptr = create_temp(std::move(result)); + v.emplace_back(s,ptr); + stack_.push_back(v); + } + + template + pointer create_temp(Args&& ... args) + { + auto temp = make_unique_ptr(std::forward(args)...); + pointer ptr = temp.get(); + temp_json_values_.emplace_back(std::move(temp)); + return ptr; + } + + Json get_normalized_paths() const + { + Json result = typename Json::array(); + if (stack_.size() > 0) + { + result.reserve(stack_.back().size()); + for (const auto& p : stack_.back()) + { + result.push_back(p.path); + } + } + return result; + } + + template + void replace(T&& new_value) + { + if (stack_.size() > 0) + { + for (size_t i = 0; i < stack_.back().size(); ++i) + { + *(stack_.back()[i].val_ptr) = new_value; + } + } + } + + void evaluate(reference root, const string_view_type& path) + { + std::error_code ec; + evaluate(root, path.data(), path.length(), ec); + if (ec) + { + throw jsonpath_error(ec, line_, column_); + } + } + + void evaluate(reference root, const string_view_type& path, std::error_code& ec) + { + try + { + evaluate(root, path.data(), path.length(), ec); + } + catch (...) + { + ec = jsonpath_errc::unidentified_error; + } + } + + void evaluate(reference root, + const char_type* path, + size_t length, + std::error_code& ec) + { + state_stack_.emplace_back(path_state::start); + + string_type function_name; + string_type buffer; + + begin_input_ = path; + end_input_ = path + length; + p_ = begin_input_; + + string_type s = {'$'}; + node_set v; + v.emplace_back(std::move(s),std::addressof(root)); + stack_.push_back(v); + + array_slice slice; + + while (p_ < end_input_) + { + switch (state_stack_.back().state) + { + case path_state::start: + { + switch (*p_) + { + case ' ':case '\t':case '\r':case '\n': + advance_past_space_character(); + break; + case '$': + { + state_stack_.emplace_back(path_state::dot_or_left_bracket, state_stack_.back()); + ++p_; + ++column_; + break; + } + default: + { + switch (*p_) + { + case '.': + case '[': + ec = jsonpath_errc::expected_root; + return; + default: // might be function, validate name later + state_stack_.emplace_back(path_state::dot_or_left_bracket, state_stack_.back()); + state_stack_.emplace_back(path_state::path_or_function_name, state_stack_.back()); + break; + } + break; + } + + return; + }; + break; + } + case path_state::path_or_function_name: + switch (*p_) + { + case ' ':case '\t':case '\r':case '\n': + { + selectors_.push_back(make_unique_ptr(buffer)); + apply_selectors(); + buffer.clear(); + state_stack_.pop_back(); + advance_past_space_character(); + break; + } + case '(': + state_stack_.back().state = path_state::arg_or_right_paren; + function_name = std::move(buffer); + buffer.clear(); + ++p_; + ++column_; + break; + case '[': + { + if (buffer.size() > 0) + { + selectors_.push_back(make_unique_ptr(buffer)); + apply_selectors(); + buffer.clear(); + } + slice.start_ = 0; + + state_stack_.back().state = path_state::wildcard_or_rpath_or_slice_or_filter; + ++p_; + ++column_; + break; + } + case '.': + { + if (buffer.size() > 0) + { + selectors_.push_back(make_unique_ptr(buffer)); + apply_selectors(); + buffer.clear(); + } + state_stack_.back().state = path_state::dot; + ++p_; + ++column_; + break; + } + case '*': + { + end_all(); + transfer_nodes(); + state_stack_.back().state = path_state::dot; + ++p_; + ++column_; + break; + } + case '\'': + { + buffer.clear(); + state_stack_.back().state = path_state::single_quoted_name; + ++p_; + ++column_; + break; + } + case '\"': + { + buffer.clear(); + state_stack_.back().state = path_state::double_quoted_name; + ++p_; + ++column_; + break; + } + default: + buffer.push_back(*p_); + ++p_; + ++column_; + break; + } + break; + case path_state::arg_or_right_paren: + switch (*p_) + { + case ' ':case '\t':case '\r':case '\n': + advance_past_space_character(); + break; + case '$': + buffer.clear(); + buffer.push_back(*p_); + state_stack_.emplace_back(path_state::path_argument, state_stack_.back()); + ++p_; + ++column_; + break; + case '\'': + buffer.clear(); + buffer.push_back('\"'); + state_stack_.back().state = path_state::more_args_or_right_paren; + state_stack_.emplace_back(path_state::single_quoted_arg, state_stack_.back()); + ++p_; + ++column_; + break; + case '\"': + buffer.clear(); + buffer.push_back('\"'); + state_stack_.back().state = path_state::more_args_or_right_paren; + state_stack_.emplace_back(path_state::double_quoted_arg, state_stack_.back()); + ++p_; + ++column_; + break; + case ')': + { + jsonpath_evaluator evaluator; + evaluator.evaluate(root, buffer, ec); + if (ec) + { + return; + } + function_stack_.push_back(evaluator.get_pointers()); + + call_function(function_name, ec); + if (ec) + { + return; + } + state_stack_.pop_back(); + ++p_; + ++column_; + break; + } + default: + buffer.clear(); + state_stack_.back().state = path_state::more_args_or_right_paren; + state_stack_.emplace_back(path_state::unquoted_arg, state_stack_.back()); + ++p_; + ++column_; + break; + } + break; + case path_state::path_argument: + switch (*p_) + { + case ',': + { + jsonpath_evaluator evaluator; + evaluator.evaluate(root, buffer, ec); + if (ec) + { + return; + } + function_stack_.push_back(evaluator.get_pointers()); + state_stack_.pop_back(); + ++p_; + ++column_; + break; + } + case ')': + { + state_stack_.pop_back(); + break; + } + default: + buffer.push_back(*p_); // path_argument + ++p_; + ++column_; + break; + } + break; + case path_state::unquoted_arg: + switch (*p_) + { + case ',': + try + { + auto val = Json::parse(buffer); + auto temp = create_temp(val); + function_stack_.push_back(std::vector{temp}); + } + catch (const ser_error&) + { + ec = jsonpath_errc::argument_parse_error; + return; + } + buffer.clear(); + //state_ = path_state::arg_or_right_paren; + state_stack_.pop_back(); + break; + case ')': + { + try + { + auto val = Json::parse(buffer); + auto temp = create_temp(val); + function_stack_.push_back(std::vector{temp}); + } + catch (const ser_error&) + { + ec = jsonpath_errc::argument_parse_error; + return; + } + call_function(function_name, ec); + if (ec) + { + return; + } + state_stack_.pop_back(); + break; + } + default: + buffer.push_back(*p_); + break; + } + ++p_; + ++column_; + break; + case path_state::single_quoted_arg: + switch (*p_) + { + case '\'': + buffer.push_back('\"'); + state_stack_.pop_back(); + break; + case '\"': + buffer.push_back('\\'); + buffer.push_back('\"'); + state_stack_.pop_back(); + break; + default: + buffer.push_back(*p_); + break; + } + ++p_; + ++column_; + break; + case path_state::double_quoted_arg: + switch (*p_) + { + case '\"': + buffer.push_back('\"'); + state_stack_.pop_back(); + break; + default: + buffer.push_back(*p_); + break; + } + ++p_; + ++column_; + break; + case path_state::more_args_or_right_paren: + switch (*p_) + { + case ' ':case '\t':case '\r':case '\n': + advance_past_space_character(); + break; + case ',': + try + { + auto val = Json::parse(buffer); + auto temp = create_temp(val); + function_stack_.push_back(std::vector{temp}); + } + catch (const ser_error&) + { + ec = jsonpath_errc::argument_parse_error; + return; + } + buffer.clear(); + //state_ = path_state::arg_or_right_paren; + state_stack_.pop_back(); + ++p_; + ++column_; + break; + case ')': + { + try + { + auto val = Json::parse(buffer); + auto temp = create_temp(val); + function_stack_.push_back(std::vector{temp}); + } + catch (const ser_error&) + { + ec = jsonpath_errc::argument_parse_error; + return; + } + call_function(function_name, ec); + if (ec) + { + return; + } + state_stack_.pop_back(); + ++p_; + ++column_; + break; + } + default: + ec = jsonpath_errc::invalid_filter_unsupported_operator; + return; + } + break; + case path_state::dot: + switch (*p_) + { + case '.': + state_stack_.back().is_recursive_descent = true; + ++p_; + ++column_; + state_stack_.back().state = path_state::name_or_left_bracket; + break; + default: + state_stack_.back().state = path_state::name; + break; + } + break; + case path_state::name_or_left_bracket: + switch (*p_) + { + case ' ':case '\t':case '\r':case '\n': + advance_past_space_character(); + break; + case '[': // [ can follow .. + state_stack_.back().state = path_state::wildcard_or_rpath_or_slice_or_filter; + ++p_; + ++column_; + break; + default: + buffer.clear(); + state_stack_.back().state = path_state::name; + break; + } + break; + case path_state::name: + switch (*p_) + { + case ' ':case '\t':case '\r':case '\n': + advance_past_space_character(); + break; + case '*': + end_all(); + transfer_nodes(); + state_stack_.pop_back(); + ++p_; + ++column_; + break; + case '\'': + state_stack_.back().state = path_state::single_quoted_name; + ++p_; + ++column_; + break; + case '\"': + state_stack_.back().state = path_state::double_quoted_name; + ++p_; + ++column_; + break; + case '[': + case '.': + ec = jsonpath_errc::expected_name; + return; + default: + buffer.clear(); + state_stack_.back().state = path_state::unquoted_name; + break; + } + break; + case path_state::dot_or_left_bracket: + switch (*p_) + { + case ' ':case '\t':case '\r':case '\n': + advance_past_space_character(); + break; + case '.': + state_stack_.emplace_back(path_state::dot, state_stack_.back()); + ++p_; + ++column_; + break; + case '[': + state_stack_.emplace_back(path_state::wildcard_or_rpath_or_slice_or_filter, state_stack_.back()); + ++p_; + ++column_; + break; + default: + ec = jsonpath_errc::expected_separator; + return; + }; + break; + case path_state::unquoted_name: + switch (*p_) + { + case '[': + case '.': + case ' ':case '\t': + case '\r': + case '\n': + state_stack_.back().state = path_state::unquoted_name2; + break; + default: + buffer.push_back(*p_); + ++p_; + ++column_; + break; + }; + break; + case path_state::unquoted_name2: + switch (*p_) + { + case ' ':case '\t':case '\r':case '\n': + advance_past_space_character(); + break; + case '[': + selectors_.push_back(make_unique_ptr(buffer)); + apply_selectors(); + buffer.clear(); + slice.start_ = 0; + state_stack_.pop_back(); + break; + case '.': + selectors_.push_back(make_unique_ptr(buffer)); + apply_selectors(); + buffer.clear(); + state_stack_.pop_back(); + break; + default: + ec = jsonpath_errc::expected_name; + return; + }; + break; + case path_state::single_quoted_name: + switch (*p_) + { + case '\'': + selectors_.push_back(make_unique_ptr(buffer)); + apply_selectors(); + buffer.clear(); + state_stack_.pop_back(); + break; + case '\\': + if (p_+1 < end_input_) + { + ++p_; + ++column_; + buffer.push_back(*p_); + } + else + { + ec = jsonpath_errc::unexpected_end_of_input; + return; + } + break; + default: + buffer.push_back(*p_); + break; + }; + ++p_; + ++column_; + break; + case path_state::double_quoted_name: + switch (*p_) + { + case '\"': + selectors_.push_back(make_unique_ptr(buffer)); + apply_selectors(); + buffer.clear(); + state_stack_.pop_back(); + break; + case '\\': + if (p_+1 < end_input_) + { + ++p_; + ++column_; + buffer.push_back(*p_); + } + else + { + ec = jsonpath_errc::unexpected_end_of_input; + return; + } + break; + default: + buffer.push_back(*p_); + break; + }; + ++p_; + ++column_; + break; + case path_state::comma_or_right_bracket: + switch (*p_) + { + case ' ':case '\t':case '\r':case '\n': + advance_past_space_character(); + break; + case ',': + state_stack_.back().is_union = true; + state_stack_.back().state = path_state::wildcard_or_rpath_or_slice_or_filter; + ++p_; + ++column_; + break; + case ']': + apply_selectors(); + state_stack_.pop_back(); + ++p_; + ++column_; + break; + default: + ec = jsonpath_errc::expected_right_bracket; + return; + } + break; + case path_state::wildcard_or_rpath_or_slice_or_filter: + switch (*p_) + { + case ' ':case '\t':case '\r':case '\n': + advance_past_space_character(); + break; + case '(': + { + jsonpath_filter_parser parser(line_,column_); + auto result = parser.parse(root, p_,end_input_,&p_); + line_ = parser.line(); + column_ = parser.column(); + selectors_.push_back(make_unique_ptr(result)); + state_stack_.back().state = path_state::comma_or_right_bracket; + break; + } + case '?': + { + jsonpath_filter_parser parser(line_,column_); + auto result = parser.parse(root,p_,end_input_,&p_); + line_ = parser.line(); + column_ = parser.column(); + selectors_.push_back(make_unique_ptr(result)); + state_stack_.back().state = path_state::comma_or_right_bracket; + break; + } + case ':': + slice = array_slice(); + buffer.clear(); + state_stack_.back().state = path_state::comma_or_right_bracket; + state_stack_.emplace_back(path_state::slice_end_or_end_step, state_stack_.back()); + ++p_; + ++column_; + break; + case '*': + state_stack_.back().state = path_state::comma_or_right_bracket; + state_stack_.emplace_back(path_state::bracketed_wildcard_or_path, state_stack_.back()); + ++p_; + ++column_; + break; + case '\'': + state_stack_.back().state = path_state::comma_or_right_bracket; + state_stack_.emplace_back(path_state::bracketed_single_quoted_name, state_stack_.back()); + ++p_; + ++column_; + break; + case '\"': + state_stack_.back().state = path_state::comma_or_right_bracket; + state_stack_.emplace_back(path_state::bracketed_double_quoted_name, state_stack_.back()); + ++p_; + ++column_; + break; + default: + slice = array_slice(); + buffer.clear(); + buffer.push_back(*p_); + state_stack_.back().state = path_state::comma_or_right_bracket; + state_stack_.emplace_back(path_state::bracketed_unquoted_name, state_stack_.back()); + ++p_; + ++column_; + break; + } + break; + case path_state::bracketed_unquoted_name: + switch (*p_) + { + case ':': + if (!try_string_to_index(buffer.data(), buffer.size(), &slice.start_, &slice.is_start_positive)) + { + ec = jsonpath_errc::expected_slice_start; + return; + } + state_stack_.back().state = path_state::slice_end_or_end_step; + ++p_; + ++column_; + break; + case '.': + case '[': + case ',': + case ']': + state_stack_.back().state = path_state::bracketed_name_or_path; + break; + default: + buffer.push_back(*p_); + ++p_; + ++column_; + break; + } + break; + case path_state::bracketed_name_or_path: + switch (*p_) + { + case ' ':case '\t':case '\r':case '\n': + advance_past_space_character(); + break; + case '.': + buffer.push_back(*p_); + state_stack_.back().state = path_state::path; + ++p_; + ++column_; + break; + case '[': + buffer.push_back(*p_); + state_stack_.back().state = path_state::path2; + ++p_; + ++column_; + break; + case ',': + case ']': + if (!buffer.empty()) + { + selectors_.push_back(make_unique_ptr(buffer)); + buffer.clear(); + } + state_stack_.pop_back(); + break; + default: + ec = jsonpath_errc::expected_right_bracket; + return; + } + break; + case path_state::bracketed_wildcard_or_path: + switch (*p_) + { + case ' ':case '\t':case '\r':case '\n': + advance_past_space_character(); + break; + case '.': + buffer.push_back('*'); + buffer.push_back(*p_); + state_stack_.back().state = path_state::path; + ++p_; + ++column_; + break; + case '[': + buffer.push_back('*'); + buffer.push_back(*p_); + state_stack_.back().state = path_state::path2; + ++p_; + ++column_; + break; + case ',': + case ']': + end_all(); + state_stack_.pop_back(); + break; + default: + ec = jsonpath_errc::expected_right_bracket; + return; + } + break; + case path_state::path: + switch (*p_) + { + case '\'': + buffer.push_back(*p_); + state_stack_.emplace_back(path_state::path_single_quoted, state_stack_.back()); + ++p_; + ++column_; + break; + case '\"': + buffer.push_back(*p_); + state_stack_.emplace_back(path_state::path_double_quoted, state_stack_.back()); + ++p_; + ++column_; + break; + case ',': + case ']': + if (!buffer.empty()) + { + selectors_.push_back(make_unique_ptr(buffer)); + buffer.clear(); + } + state_stack_.pop_back(); + break; + default: + buffer.push_back(*p_); + ++p_; + ++column_; + break; + } + break; + case path_state::path_double_quoted: + switch (*p_) + { + case '\"': + buffer.push_back(*p_); + state_stack_.pop_back(); + break; + case '\\': + if (p_+1 < end_input_) + { + ++p_; + ++column_; + buffer.push_back(*p_); + } + else + { + ec = jsonpath_errc::unexpected_end_of_input; + return; + } + break; + default: + buffer.push_back(*p_); + break; + } + ++p_; + ++column_; + break; + case path_state::path_single_quoted: + switch (*p_) + { + case '\'': + buffer.push_back(*p_); + state_stack_.pop_back(); + break; + case '\\': + if (p_+1 < end_input_) + { + ++p_; + ++column_; + buffer.push_back(*p_); + } + else + { + ec = jsonpath_errc::unexpected_end_of_input; + return; + } + break; + default: + buffer.push_back(*p_); + break; + } + ++p_; + ++column_; + break; + case path_state::path2: + switch (*p_) + { + case ']': + buffer.push_back(*p_); + state_stack_.back().state = path_state::path; + break; + default: + buffer.push_back(*p_); + break; + } + ++p_; + ++column_; + break; + case path_state::slice_end_or_end_step: + switch (*p_) + { + case '-': + slice.is_end_positive = false; + state_stack_.back().state = path_state::slice_end; + ++p_; + ++column_; + break; + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + slice.is_end_defined = true; + slice.end_ = static_cast(*p_-'0'); + state_stack_.back().state = path_state::slice_end; + ++p_; + ++column_; + break; + case ':': + slice.step_ = 0; + state_stack_.back().state = path_state::slice_step; + ++p_; + ++column_; + break; + case ',': + case ']': + selectors_.push_back(make_unique_ptr(slice)); + state_stack_.pop_back(); + break; + default: + ec = jsonpath_errc::expected_minus_or_digit_or_colon_or_comma_or_right_bracket; + return; + } + break; + case path_state::slice_end: + switch (*p_) + { + case ':': + slice.step_ = 0; + state_stack_.back().state = path_state::slice_step; + ++p_; + ++column_; + break; + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + slice.is_end_defined = true; + slice.end_ = slice.end_*10 + static_cast(*p_-'0'); + ++p_; + ++column_; + break; + case ',': + case ']': + if (!slice.is_end_defined) + { + ec = jsonpath_errc::expected_slice_end; + return; + } + selectors_.push_back(make_unique_ptr(slice)); + state_stack_.pop_back(); + break; + default: + ec = jsonpath_errc::expected_digit_or_colon_or_comma_or_right_bracket; + return; + } + break; + case path_state::slice_step: + switch (*p_) + { + case '-': + slice.is_step_positive = false; + slice.step_ = 0; + state_stack_.back().state = path_state::slice_step2; + ++p_; + ++column_; + break; + default: + slice.step_ = 0; + state_stack_.back().state = path_state::slice_step2; + break; + } + break; + case path_state::slice_step2: + switch (*p_) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + slice.step_ = slice.step_*10 + static_cast(*p_-'0'); + ++p_; + ++column_; + break; + case ',': + case ']': + if (slice.step_ == 0) + { + ec = jsonpath_errc::expected_slice_step; + return; + } + selectors_.push_back(make_unique_ptr(slice)); + state_stack_.pop_back(); + break; + default: + ec = jsonpath_errc::expected_minus_or_digit_or_comma_or_right_bracket; + return; + } + break; + case path_state::bracketed_single_quoted_name: + switch (*p_) + { + case '\'': + state_stack_.back().state = path_state::bracketed_name_or_path; + break; + case '\\': + if (p_+1 < end_input_) + { + ++p_; + ++column_; + buffer.push_back(*p_); + } + else + { + ec = jsonpath_errc::unexpected_end_of_input; + return; + } + break; + default: + buffer.push_back(*p_); + break; + }; + ++p_; + ++column_; + break; + case path_state::bracketed_double_quoted_name: + switch (*p_) + { + case '\"': + state_stack_.back().state = path_state::bracketed_name_or_path; + break; + case '\\': + if (p_+1 < end_input_) + { + ++p_; + ++column_; + buffer.push_back(*p_); + } + else + { + ec = jsonpath_errc::unexpected_end_of_input; + return; + } + break; + default: + buffer.push_back(*p_); + break; + }; + ++p_; + ++column_; + break; + default: + ++p_; + ++column_; + break; + } + } + + switch (state_stack_.back().state) + { + case path_state::unquoted_name: + case path_state::unquoted_name2: + { + selectors_.push_back(make_unique_ptr(buffer)); + apply_selectors(); + buffer.clear(); + state_stack_.pop_back(); // unquoted_name + break; + } + default: + break; + } + + if (state_stack_.size() > 2) + { + ec = jsonpath_errc::unexpected_end_of_input; + return; + } + + JSONCONS_ASSERT(state_stack_.size() == 2); + state_stack_.pop_back(); + + JSONCONS_ASSERT(state_stack_.back().state == path_state::start); + state_stack_.pop_back(); + } + + void end_all() + { + for (const auto& node : stack_.back()) + { + const auto& path = node.path; + pointer p = node.val_ptr; + + if (p->is_array()) + { + for (auto it = p->array_range().begin(); it != p->array_range().end(); ++it) + { + nodes_.emplace_back(PathCons()(path,it - p->array_range().begin()),std::addressof(*it)); + } + } + else if (p->is_object()) + { + for (auto it = p->object_range().begin(); it != p->object_range().end(); ++it) + { + nodes_.emplace_back(PathCons()(path,it->key()),std::addressof(it->value())); + } + } + + } + } + + void apply_selectors() + { + //std::cout << "apply_selectors count: " << selectors_.size() << "\n"; + if (selectors_.size() > 0) + { + for (auto& node : stack_.back()) + { + //std::cout << "apply selector to:\n" << pretty_print(*(node.val_ptr)) << "\n"; + for (auto& selector : selectors_) + { + apply_selector(node.path, *(node.val_ptr), *selector, true); + } + } + selectors_.clear(); + } + transfer_nodes(); + } + + void apply_selector(const string_type& path, reference val, selector_base& selector, bool process) + { + if (process) + { + selector.select(*this, path, val, nodes_); + } + //std::cout << "*it: " << val << "\n"; + //std::cout << "apply_selectors 1 done\n"; + if (state_stack_.back().is_recursive_descent) + { + //std::cout << "is_recursive_descent\n"; + if (val.is_object()) + { + //std::cout << "is_object\n"; + for (auto& nvp : val.object_range()) + { + if (nvp.value().is_array() || nvp.value().is_object()) + { + apply_selector(PathCons()(path,nvp.key()), nvp.value(), selector, true); + } + } + } + else if (val.is_array()) + { + //std::cout << "is_array\n"; + auto first = val.array_range().begin(); + auto last = val.array_range().end(); + for (auto it = first; it != last; ++it) + { + if (it->is_array()) + { + apply_selector(PathCons()(path,it - first), *it,selector, true); + //std::cout << "*it: " << *it << "\n"; + } + else if (it->is_object()) + { + apply_selector(PathCons()(path,it - first), *it, selector, !selector.is_filter()); + } + } + } + } + } + + void transfer_nodes() + { + if (state_stack_.back().is_union) + { + std::set temp(nodes_.begin(), nodes_.end()); + stack_.push_back(std::vector(temp.begin(),temp.end())); + } + else + { + stack_.push_back(std::move(nodes_)); + } + nodes_.clear(); + state_stack_.back().is_recursive_descent = false; + state_stack_.back().is_union = false; + } + + void advance_past_space_character() + { + switch (*p_) + { + case ' ':case '\t': + ++p_; + ++column_; + break; + case '\r': + if (p_+1 < end_input_ && *(p_+1) == '\n') + ++p_; + ++line_; + column_ = 1; + ++p_; + break; + case '\n': + ++line_; + column_ = 1; + ++p_; + break; + default: + break; + } + } +}; + +} + +}} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/jsonpath/jsonpath_error.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/jsonpath/jsonpath_error.hpp new file mode 100644 index 0000000000..54aa4f6ae8 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/jsonpath/jsonpath_error.hpp @@ -0,0 +1,206 @@ +/// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSONPATH_JSONPATH_ERROR_HPP +#define JSONCONS_JSONPATH_JSONPATH_ERROR_HPP + +#include +#include + +namespace jsoncons { namespace jsonpath { + +class jsonpath_error : public std::system_error, public virtual json_exception +{ + std::string buffer_; + size_t line_number_; + size_t column_number_; +public: + jsonpath_error(std::error_code ec) + : std::system_error(ec), line_number_(0), column_number_(0) + { + } + jsonpath_error(std::error_code ec, size_t position) + : std::system_error(ec), line_number_(0), column_number_(position) + { + } + jsonpath_error(std::error_code ec, size_t line, size_t column) + : std::system_error(ec), line_number_(line), column_number_(column) + { + } + jsonpath_error(const jsonpath_error& other) = default; + + jsonpath_error(jsonpath_error&& other) = default; + + const char* what() const noexcept override + { + try + { + std::ostringstream os; + os << std::system_error::what(); + if (line_number_ != 0 && column_number_ != 0) + { + os << " at line " << line_number_ << " and column " << column_number_; + } + else if (column_number_ != 0) + { + os << " at position " << column_number_; + } + const_cast(buffer_) = os.str(); + return buffer_.c_str(); + } + catch (...) + { + return std::system_error::what(); + } + } + + size_t line() const noexcept + { + return line_number_; + } + + size_t column() const noexcept + { + return column_number_; + } +#if !defined(JSONCONS_NO_DEPRECATED) + size_t line_number() const noexcept + { + return line(); + } + + size_t column_number() const noexcept + { + return column(); + } +#endif +}; + +enum class jsonpath_errc +{ + ok = 0, + expected_root, + expected_current_node, + expected_right_bracket, + expected_name, + expected_separator, + invalid_filter, + invalid_filter_expected_slash, + invalid_filter_unbalanced_paren, + invalid_filter_unsupported_operator, + invalid_filter_expected_right_brace, + invalid_filter_expected_primary, + expected_slice_start, + expected_slice_end, + expected_slice_step, + expected_left_bracket_token, + expected_minus_or_digit_or_colon_or_comma_or_right_bracket, + expected_digit_or_colon_or_comma_or_right_bracket, + expected_minus_or_digit_or_comma_or_right_bracket, + expected_digit_or_comma_or_right_bracket, + unexpected_operator, + invalid_function_name, + invalid_argument, + function_name_not_found, + parse_error_in_filter, + argument_parse_error, + unidentified_error, + unexpected_end_of_input +}; + +class jsonpath_error_category_impl + : public std::error_category +{ +public: + const char* name() const noexcept override + { + return "jsoncons/jsonpath"; + } + std::string message(int ev) const override + { + switch (static_cast(ev)) + { + case jsonpath_errc::expected_root: + return "Expected $"; + case jsonpath_errc::expected_current_node: + return "Expected @"; + case jsonpath_errc::expected_right_bracket: + return "Expected ]"; + case jsonpath_errc::expected_name: + return "Expected a name following a dot"; + case jsonpath_errc::expected_slice_start: + return "Expected slice start"; + case jsonpath_errc::expected_slice_end: + return "Expected slice end"; + case jsonpath_errc::expected_slice_step: + return "Expected slice step"; + case jsonpath_errc::expected_separator: + return "Expected dot or left bracket separator"; + case jsonpath_errc::invalid_filter: + return "Invalid path filter"; + case jsonpath_errc::invalid_filter_expected_slash: + return "Invalid path filter, expected '/'"; + case jsonpath_errc::invalid_filter_unbalanced_paren: + return "Invalid path filter, unbalanced parenthesis"; + case jsonpath_errc::invalid_filter_unsupported_operator: + return "Unsupported operator"; + case jsonpath_errc::invalid_filter_expected_right_brace: + return "Invalid path filter, expected right brace }"; + case jsonpath_errc::invalid_filter_expected_primary: + return "Invalid path filter, expected primary expression."; + case jsonpath_errc::expected_left_bracket_token: + return "Expected ?,',\",0-9,*"; + case jsonpath_errc::expected_minus_or_digit_or_colon_or_comma_or_right_bracket: + return "Expected - or 0-9 or : or , or ]"; + case jsonpath_errc::expected_minus_or_digit_or_comma_or_right_bracket: + return "Expected - or 0-9 or , or ]"; + case jsonpath_errc::expected_digit_or_comma_or_right_bracket: + return "Expected - or 0-9 or , or ]"; + case jsonpath_errc::expected_digit_or_colon_or_comma_or_right_bracket: + return "Expected 0-9 or : or , or ]"; + case jsonpath_errc::invalid_function_name: + return "Invalid function name"; + case jsonpath_errc::invalid_argument: + return "Invalid argument type"; + case jsonpath_errc::function_name_not_found: + return "Function name not found"; + case jsonpath_errc::parse_error_in_filter: + return "Could not parse JSON expression in a JSONPath filter"; + case jsonpath_errc::argument_parse_error: + return "Could not parse JSON expression passed to JSONPath function"; + case jsonpath_errc::unidentified_error: + return "Unidentified error"; + case jsonpath_errc::unexpected_end_of_input: + return "Unexpected end of jsonpath input"; + default: + return "Unknown jsonpath parser error"; + } + } +}; + +inline +const std::error_category& jsonpath_error_category() +{ + static jsonpath_error_category_impl instance; + return instance; +} + +inline +std::error_code make_error_code(jsonpath_errc result) +{ + return std::error_code(static_cast(result),jsonpath_error_category()); +} + +}} + +namespace std { + template<> + struct is_error_code_enum : public true_type + { + }; +} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/jsonpath/jsonpath_filter.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/jsonpath/jsonpath_filter.hpp new file mode 100644 index 0000000000..444ac17f77 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/jsonpath/jsonpath_filter.hpp @@ -0,0 +1,1953 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSONPATH_FILTER_HPP +#define JSONCONS_JSONPATH_FILTER_HPP + +#include +#include // std::map +#include +#include +#include +#include +#include +#include // std::numeric_limits +#include +#include + +namespace jsoncons { namespace jsonpath { namespace detail { + +JSONCONS_STRING_LITERAL(eqtilde,'=','~') +JSONCONS_STRING_LITERAL(star,'*') +JSONCONS_STRING_LITERAL(forwardslash,'/') +JSONCONS_STRING_LITERAL(plus,'+') +JSONCONS_STRING_LITERAL(minus,'-') +JSONCONS_STRING_LITERAL(lt,'<') +JSONCONS_STRING_LITERAL(lte,'<','=') +JSONCONS_STRING_LITERAL(gt,'>') +JSONCONS_STRING_LITERAL(gte,'>','=') +JSONCONS_STRING_LITERAL(eq,'=','=') +JSONCONS_STRING_LITERAL(ne,'!', '=') +JSONCONS_STRING_LITERAL(ampamp,'&','&') +JSONCONS_STRING_LITERAL(pipepipe,'|','|') + +template +struct PathConstructor +{ + typedef typename Json::char_type char_type; + typedef typename Json::string_view_type string_view_type; + typedef typename Json::string_type string_type; + + string_type operator()(const string_type& path, size_t index) const + { + char_type buf[255]; + char_type* p = buf; + do + { + *p++ = static_cast(48 + index % 10); + } while (index /= 10); + + string_type s; + s.append(path); + s.push_back('['); + while (--p >= buf) + { + s.push_back(*p); + } + s.push_back(']'); + return s; + } + + string_type operator()(const string_type& path, const string_view_type& sv) const + { + string_type s; + s.append(path); + s.push_back('['); + s.push_back('\''); + s.append(sv.data(),sv.length()); + s.push_back('\''); + s.push_back(']'); + return s; + } +}; + +template +struct VoidPathConstructor +{ + typedef typename Json::char_type char_type; + typedef typename Json::string_view_type string_view_type; + typedef typename Json::string_type string_type; + + string_type operator()(const string_type&, size_t) const + { + return string_type{}; + } + + string_type operator()(const string_type&, string_view_type) const + { + return string_type{}; + } +}; + +template +class jsonpath_evaluator; + +enum class filter_path_mode +{ + path, + root_path, + current_path +}; + +enum class filter_state +{ + start, + expect_right_round_bracket, + expect_oper_or_right_round_bracket, + expect_path_or_value_or_unary_op, + expect_regex, + regex, + single_quoted_text, + double_quoted_text, + unquoted_text, + path, + value, + oper, + expect_arg, + path_argument, + unquoted_argument, + single_quoted_argument, + double_quoted_argument, + expect_more_args_or_right_round_bracket, + done +}; + +enum class token_type +{ + operand, + unary_operator, + binary_operator, + lparen, + rparen +}; + +template +class term +{ +public: + typedef typename Json::string_type string_type; + typedef typename Json::char_type char_type; + + virtual ~term() {} + + virtual void initialize(const Json&) = 0; + + virtual bool accept_single_node() const + { + throw jsonpath_error(jsonpath_errc::invalid_filter_unsupported_operator); + } + virtual Json get_single_node() const + { + throw jsonpath_error(jsonpath_errc::invalid_filter_unsupported_operator); + } + virtual bool exclaim() const + { + throw jsonpath_error(jsonpath_errc::invalid_filter_unsupported_operator); + } + virtual bool eq_term(const term&) const + { + throw jsonpath_error(jsonpath_errc::invalid_filter_unsupported_operator); + } + virtual bool eq(const Json&) const + { + throw jsonpath_error(jsonpath_errc::invalid_filter_unsupported_operator); + } + virtual bool ne_term(const term&) const + { + throw jsonpath_error(jsonpath_errc::invalid_filter_unsupported_operator); + } + virtual bool ne(const Json&) const + { + throw jsonpath_error(jsonpath_errc::invalid_filter_unsupported_operator); + } + virtual bool regex_term(const term&) const + { + throw jsonpath_error(jsonpath_errc::invalid_filter_unsupported_operator); + } + virtual bool regex2(const string_type&) const + { + throw jsonpath_error(jsonpath_errc::invalid_filter_unsupported_operator); + } + virtual bool ampamp_term(const term&) const + { + throw jsonpath_error(jsonpath_errc::invalid_filter_unsupported_operator); + } + virtual bool ampamp(const Json&) const + { + throw jsonpath_error(jsonpath_errc::invalid_filter_unsupported_operator); + } + virtual bool pipepipe_term(const term&) const + { + throw jsonpath_error(jsonpath_errc::invalid_filter_unsupported_operator); + } + virtual bool pipepipe(const Json&) const + { + throw jsonpath_error(jsonpath_errc::invalid_filter_unsupported_operator); + } + virtual bool lt_term(const term&) const + { + throw jsonpath_error(jsonpath_errc::invalid_filter_unsupported_operator); + } + virtual bool lt(const Json&) const + { + throw jsonpath_error(jsonpath_errc::invalid_filter_unsupported_operator); + } + virtual bool gt_term(const term&) const + { + throw jsonpath_error(jsonpath_errc::invalid_filter_unsupported_operator); + } + virtual bool gt(const Json&) const + { + throw jsonpath_error(jsonpath_errc::invalid_filter_unsupported_operator); + } + + virtual Json minus_term(const term&) const + { + throw jsonpath_error(jsonpath_errc::invalid_filter_unsupported_operator); + } + virtual Json minus(const Json&) const + { + throw jsonpath_error(jsonpath_errc::invalid_filter_unsupported_operator); + } + + virtual Json left_minus(const Json&) const + { + throw jsonpath_error(jsonpath_errc::invalid_filter_unsupported_operator); + } + + virtual Json unary_minus() const + { + throw jsonpath_error(jsonpath_errc::invalid_filter_unsupported_operator); + } + virtual Json plus_term(const term&) const + { + throw jsonpath_error(jsonpath_errc::invalid_filter_unsupported_operator); + } + virtual Json plus(const Json&) const + { + throw jsonpath_error(jsonpath_errc::invalid_filter_unsupported_operator); + } + virtual Json mult_term(const term&) const + { + throw jsonpath_error(jsonpath_errc::invalid_filter_unsupported_operator); + } + virtual Json mult(const Json&) const + { + throw jsonpath_error(jsonpath_errc::invalid_filter_unsupported_operator); + } + + virtual Json div_term(const term&) const + { + throw jsonpath_error(jsonpath_errc::invalid_filter_unsupported_operator); + } + virtual Json div(const Json&) const + { + throw jsonpath_error(jsonpath_errc::invalid_filter_unsupported_operator); + } + + virtual Json left_div(const Json&) const + { + throw jsonpath_error(jsonpath_errc::invalid_filter_unsupported_operator); + } +}; + +template +struct operator_properties +{ + typedef std::function&, const term&)> operator_type; + + size_t precedence_level; + bool is_right_associative; + operator_type op; +}; + +template +class token +{ +public: + typedef std::function&)> unary_operator_type; + typedef std::function&, const term&)> operator_type; +private: + token_type type_; + size_t precedence_level_; + bool is_right_associative_; + std::shared_ptr> operand_ptr_; + unary_operator_type unary_operator_; + operator_type operator_; +public: + + token(token_type type) + : type_(type),precedence_level_(0),is_right_associative_(false) + { + } + token(token_type type, std::shared_ptr> term_ptr) + : type_(type),precedence_level_(0),is_right_associative_(false),operand_ptr_(term_ptr) + { + } + token(size_t precedence_level, + bool is_right_associative, + unary_operator_type unary_operator) + : type_(token_type::unary_operator), + precedence_level_(precedence_level), + is_right_associative_(is_right_associative), + unary_operator_(unary_operator) + { + } + token(const operator_properties& properties) + : type_(token_type::binary_operator), + precedence_level_(properties.precedence_level), + is_right_associative_(properties.is_right_associative), + operator_(properties.op) + { + } + + token(const token& t) = default; + + token_type type() const + { + return type_; + } + + Json operator()(const term& a) + { + return unary_operator_(a); + } + + Json operator()(const term& a, const term& b) + { + return operator_(a,b); + } + + token& operator=(const token& val) = default; + + bool is_operator() const + { + return is_unary_operator() || is_binary_operator(); + } + + bool is_unary_operator() const + { + return type_ == token_type::unary_operator; + } + + bool is_binary_operator() const + { + return type_ == token_type::binary_operator; + } + + bool is_operand() const + { + return type_ == token_type::operand; + } + + bool is_lparen() const + { + return type_ == token_type::lparen; + } + + bool is_rparen() const + { + return type_ == token_type::rparen; + } + + size_t precedence_level() const + { + return precedence_level_; + } + + bool is_right_associative() const + { + return is_right_associative_; + } + + const term& operand() + { + JSONCONS_ASSERT(type_ == token_type::operand && operand_ptr_ != nullptr); + return *operand_ptr_; + } + + void initialize(const Json& current_node) + { + if (operand_ptr_.get() != nullptr) + { + operand_ptr_->initialize(current_node); + } + } +}; + +template +bool ampamp(const Json& lhs, const Json& rhs) +{ + return lhs.as_bool() && rhs.as_bool(); +} + +template +bool pipepipe(const Json& lhs, const Json& rhs) +{ + return lhs.as_bool() || rhs.as_bool(); +} + +template +bool lt(const Json& lhs, const Json& rhs) +{ + bool result = false; + if (lhs.template is() && rhs.template is()) + { + result = lhs.template as() < rhs.template as(); + } + else if (lhs.template is() && rhs.template is()) + { + result = lhs.template as() < rhs.template as(); + } + else if (lhs.is_number() && rhs.is_number()) + { + result = lhs.as_double() < rhs.as_double(); + } + else if (lhs.is_string() && rhs.is_string()) + { + result = lhs.as_string_view() < rhs.as_string_view(); + } + return result; +} + +template +bool gt(const Json& lhs, const Json& rhs) +{ + return lt(rhs,lhs); +} + +template +Json plus(const Json& lhs, const Json& rhs) +{ + Json result = Json(jsoncons::null_type()); + if (lhs.is_int64() && rhs.is_int64()) + { + result = Json(((lhs.template as() + rhs.template as()))); + } + else if (lhs.is_uint64() && rhs.is_uint64()) + { + result = Json((lhs.template as() + rhs.template as())); + } + else if ((lhs.is_number() && rhs.is_number())) + { + result = Json((lhs.as_double() + rhs.as_double())); + } + return result; +} + +template +Json mult(const Json& lhs, const Json& rhs) +{ + Json result = Json(jsoncons::null_type()); + if (lhs.is_int64() && rhs.is_int64()) + { + result = Json(((lhs.template as() * rhs.template as()))); + } + else if (lhs.is_uint64() && rhs.is_uint64()) + { + result = Json((lhs.template as() * rhs.template as())); + } + else if ((lhs.is_number() && rhs.is_number())) + { + result = Json((lhs.as_double() * rhs.as_double())); + } + return result; +} + +template +Json div(const Json& lhs, const Json& rhs) +{ + Json result = Json(jsoncons::null_type()); + if (lhs.is_int64() && rhs.is_int64()) + { + result = Json((double)(lhs.template as() / (double)rhs.template as())); + } + else if (lhs.is_uint64() && rhs.is_uint64()) + { + result = Json((double)(lhs.template as() / (double)rhs.template as())); + } + else if ((lhs.is_number() && rhs.is_number())) + { + result = Json((lhs.as_double() / rhs.as_double())); + } + return result; +} + +template +Json unary_minus(const Json& lhs) +{ + Json result = Json::null(); + if (lhs.is_int64()) + { + result = -lhs.template as(); + } + else if (lhs.is_double()) + { + result = -lhs.as_double(); + } + return result; +} + +template +Json minus(const Json& lhs, const Json& rhs) +{ + Json result = Json::null(); + if (lhs.is_int64() && rhs.is_int64()) + { + result = ((lhs.template as() - rhs.template as())); + } + else if (lhs.is_uint64() && rhs.is_uint64() && lt(rhs,lhs)) + { + result = (lhs.template as() - rhs.template as()); + } + else if ((lhs.is_number() && rhs.is_number())) + { + result = (lhs.as_double() - rhs.as_double()); + } + return result; +} + +template +class value_term final : public term +{ + Json value_; +public: + value_term(const Json& val) + : value_(val) + { + } + value_term(Json&& val) + : value_(std::move(val)) + { + } + + void initialize(const Json&) override + { + } + + bool accept_single_node() const override + { + return value_.as_bool(); + } + + Json get_single_node() const override + { + return value_; + } + + bool exclaim() const override + { + return !value_.as_bool(); + } + + bool eq_term(const term& rhs) const override + { + return rhs.eq(value_); + } + + bool eq(const Json& rhs) const override + { + return value_ == rhs; + } + + bool ne_term(const term& rhs) const override + { + return rhs.ne(value_); + } + bool ne(const Json& rhs) const override + { + return value_ != rhs; + } + bool regex_term(const term& rhs) const override + { + return rhs.regex2(value_.as_string()); + } + bool ampamp_term(const term& rhs) const override + { + return rhs.ampamp(value_); + } + bool ampamp(const Json& rhs) const override + { + return jsoncons::jsonpath::detail::ampamp(value_,rhs); + } + bool pipepipe_term(const term& rhs) const override + { + return rhs.pipepipe(value_); + } + bool pipepipe(const Json& rhs) const override + { + return jsoncons::jsonpath::detail::pipepipe(value_,rhs); + } + + bool lt_term(const term& rhs) const override + { + return rhs.gt(value_); + } + bool lt(const Json& rhs) const override + { + return jsoncons::jsonpath::detail::lt(value_,rhs); + } + + bool gt_term(const term& rhs) const override + { + return rhs.lt(value_); + } + bool gt(const Json& rhs) const override + { + return jsoncons::jsonpath::detail::gt(value_,rhs); + } + + Json minus_term(const term& rhs) const override + { + return rhs.left_minus(value_); + } + Json minus(const Json& rhs) const override + { + return jsoncons::jsonpath::detail::minus(value_,rhs); + } + + Json left_minus(const Json& lhs) const override + { + return jsoncons::jsonpath::detail::minus(lhs,value_); + } + + Json unary_minus() const override + { + return jsoncons::jsonpath::detail::unary_minus(value_); + } + + Json plus_term(const term& rhs) const override + { + return rhs.plus(value_); + } + + Json plus(const Json& rhs) const override + { + return jsoncons::jsonpath::detail::plus(value_,rhs); + } + Json mult_term(const term& rhs) const override + { + return rhs.mult(value_); + } + + Json mult(const Json& rhs) const override + { + return jsoncons::jsonpath::detail::mult(value_,rhs); + } + + Json div_term(const term& rhs) const override + { + return rhs.left_div(value_); + } + Json div(const Json& rhs) const override + { + return jsoncons::jsonpath::detail::div(value_,rhs); + } + + Json left_div(const Json& lhs) const override + { + return jsoncons::jsonpath::detail::div(lhs,value_); + } +}; + +template +class regex_term final : public term +{ + typedef typename Json::char_type char_type; + typedef typename Json::string_type string_type; + const std::basic_regex pattern_; +public: + regex_term(const string_type& pattern, std::regex::flag_type flags) + : pattern_(pattern,flags) + { + } + + void initialize(const Json&) override + { + } + + bool regex2(const string_type& subject) const override + { + return std::regex_match(subject, pattern_); + } +}; + +template +class path_term final : public term +{ + typedef typename Json::string_type string_type; + + string_type path_; + size_t line_; + size_t column_; + Json nodes_; +public: + path_term(const string_type& path, size_t line, size_t column) + : path_(path), line_(line), column_(column) + { + } + + void initialize(const Json& current_node) override + { + jsonpath_evaluator> evaluator(line_,column_); + evaluator.evaluate(current_node, path_); + nodes_ = evaluator.get_values(); + } + + bool accept_single_node() const override + { + return nodes_.size() != 0; + } + + Json get_single_node() const override + { + return nodes_.size() == 1 ? nodes_[0] : nodes_; + } + + bool exclaim() const override + { + return nodes_.size() == 0; + } + + bool eq_term(const term& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = rhs.eq(nodes_[i]); + } + } + return result; + } + + bool eq(const Json& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = nodes_[i] == rhs; + } + } + return result; + } + + bool ne_term(const term& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = rhs.ne(nodes_[i]); + } + } + return result; + + } + bool ne(const Json& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = nodes_[i] != rhs; + } + } + return result; + } + bool regex_term(const term& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = rhs.regex2(nodes_[i].as_string()); + } + } + return result; + } + bool ampamp_term(const term& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = rhs.ampamp(nodes_[i]); + } + } + return result; + } + bool ampamp(const Json& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = jsoncons::jsonpath::detail::ampamp(nodes_[i],rhs); + } + } + return result; + } + bool pipepipe_term(const term& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = rhs.pipepipe(nodes_[i]); + } + } + return result; + } + bool pipepipe(const Json& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = jsoncons::jsonpath::detail::pipepipe(nodes_[i],rhs); + } + } + return result; + } + + bool lt(const Json& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = jsoncons::jsonpath::detail::lt(nodes_[i],rhs); + } + } + return result; + } + + bool lt_term(const term& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = rhs.gt(nodes_[i]); + } + } + return result; + } + + bool gt(const Json& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = jsoncons::jsonpath::detail::gt(nodes_[i],rhs); + } + } + return result; + } + + bool gt_term(const term& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = rhs.lt(nodes_[i]); + } + } + return result; + } + + Json minus_term(const term& rhs) const override + { + static auto a_null = Json(jsoncons::null_type()); + return nodes_.size() == 1 ? rhs.left_minus(nodes_[0]) : a_null; + } + Json minus(const Json& rhs) const override + { + return nodes_.size() == 1 ? jsoncons::jsonpath::detail::minus(nodes_[0],rhs) : Json(jsoncons::null_type()); + } + + Json left_minus(const Json& lhs) const override + { + static auto a_null = Json(jsoncons::null_type()); + return nodes_.size() == 1 ? jsoncons::jsonpath::detail::minus(lhs,nodes_[0]) : a_null; + } + + Json unary_minus() const override + { + return nodes_.size() == 1 ? jsoncons::jsonpath::detail::unary_minus(nodes_[0]) : Json::null(); + } + + Json plus_term(const term& rhs) const override + { + static auto a_null = Json(jsoncons::null_type()); + return nodes_.size() == 1 ? rhs.plus(nodes_[0]) : a_null; + } + Json plus(const Json& rhs) const override + { + static auto a_null = Json(jsoncons::null_type()); + return nodes_.size() == 1 ? jsoncons::jsonpath::detail::plus(nodes_[0],rhs) : a_null; + } + + Json mult_term(const term& rhs) const override + { + static auto a_null = Json(jsoncons::null_type()); + return nodes_.size() == 1 ? rhs.mult(nodes_[0]) : a_null; + } + Json mult(const Json& rhs) const override + { + static auto a_null = Json(jsoncons::null_type()); + return nodes_.size() == 1 ? jsoncons::jsonpath::detail::mult(nodes_[0],rhs) : a_null; + } + + Json div_term(const term& rhs) const override + { + static auto a_null = Json(jsoncons::null_type()); + return nodes_.size() == 1 ? rhs.left_div(nodes_[0]) : a_null; + } + Json div(const Json& rhs) const override + { + static auto a_null = Json(jsoncons::null_type()); + return nodes_.size() == 1 ? jsoncons::jsonpath::detail::div(nodes_[0],rhs) : a_null; + } + + Json left_div(const Json& lhs) const override + { + static auto a_null = Json(jsoncons::null_type()); + return nodes_.size() == 1 ? jsoncons::jsonpath::detail::div(lhs, nodes_[0]) : a_null; + } +}; + +template +token evaluate(const Json& context, std::vector>& tokens) +{ + for (auto it= tokens.begin(); it != tokens.end(); ++it) + { + it->initialize(context); + } + std::vector> stack; + for (auto t : tokens) + { + if (t.is_operand()) + { + stack.push_back(t); + } + else if (t.is_unary_operator()) + { + auto rhs = stack.back(); + stack.pop_back(); + Json val = t(rhs.operand()); + stack.push_back(token(token_type::operand,std::make_shared>(std::move(val)))); + } + else if (t.is_binary_operator()) + { + auto rhs = stack.back(); + stack.pop_back(); + auto lhs = stack.back(); + stack.pop_back(); + Json val = t(lhs.operand(), rhs.operand()); + stack.push_back(token(token_type::operand,std::make_shared>(std::move(val)))); + } + } + if (stack.size() != 1) + { + JSONCONS_THROW(json_runtime_error("Invalid state")); + } + + return stack.back(); +} + +template +class jsonpath_filter_expr +{ +public: + std::vector> tokens_; +public: + jsonpath_filter_expr() + { + } + + jsonpath_filter_expr(const std::vector>& tokens) + : tokens_(tokens) + { + } + + Json eval(const Json& current_node) + { + auto t = evaluate(current_node, tokens_); + return t.operand().get_single_node(); + } + + bool exists(const Json& current_node) + { + auto t = evaluate(current_node,tokens_); + return t.operand().accept_single_node(); + } +}; + +template +class jsonpath_filter_parser +{ + typedef typename Json::string_type string_type; + typedef typename Json::string_view_type string_view_type; + typedef typename Json::char_type char_type; + + std::vector> output_stack_; + std::vector> operator_stack_; + std::vector state_stack_; + std::vector path_mode_stack_; + + size_t line_; + size_t column_; + + static const operator_properties op_properties_[]; + + class binary_operator_table + { + typedef std::map> binary_operator_map; + + const binary_operator_map operators = + { + {eqtilde_literal(),{2,false,[](const term& a, const term& b) {return Json(a.regex_term(b)); }}}, + {star_literal(),{3,false,[](const term& a, const term& b) {return a.mult_term(b); }}}, + {forwardslash_literal(),{3,false,[](const term& a, const term& b) {return a.div_term(b); }}}, + {plus_literal(),{4,false,[](const term& a, const term& b) {return a.plus_term(b); }}}, + {minus_literal(),{4,false,[](const term& a, const term& b) {return a.minus_term(b); }}}, + {lt_literal(),{5,false,[](const term& a, const term& b) {return Json(a.lt_term(b)); }}}, + {lte_literal(),{5,false,[](const term& a, const term& b) {return Json(a.lt_term(b) || a.eq_term(b)); }}}, + {gt_literal(),{5,false,[](const term& a, const term& b) {return Json(a.gt_term(b)); }}}, + {gte_literal(),{5,false,[](const term& a, const term& b) {return Json(a.gt_term(b) || a.eq_term(b)); }}}, + {eq_literal(),{6,false,[](const term& a, const term& b) {return Json(a.eq_term(b)); }}}, + {ne_literal(),{6,false,[](const term& a, const term& b) {return Json(a.ne_term(b)); }}}, + {ampamp_literal(),{7,false,[](const term& a, const term& b) {return Json(a.ampamp_term(b)); }}}, + {pipepipe_literal(),{8,false,[](const term& a, const term& b) {return Json(a.pipepipe_term(b)); }}} + }; + + public: + typename binary_operator_map::const_iterator find(const string_type& key) const + { + return operators.find(key); + } + typename binary_operator_map::const_iterator end() const + { + return operators.end(); + } + }; + + binary_operator_table binary_operators_; + +public: + jsonpath_filter_parser() + : line_(1), column_(1) + { + } + jsonpath_filter_parser(size_t line, size_t column) + : line_(line), column_(column) + { + } + + size_t line() const + { + return line_; + } + + size_t column() const + { + return column_; + } + + void push_state(filter_state state) + { + state_stack_.push_back(state); + } + + filter_state pop_state() + { + JSONCONS_ASSERT(!state_stack_.empty()) + filter_state state = state_stack_.back(); + state_stack_.pop_back(); + return state; + } + + void push_token(token token) + { + switch (token.type()) + { + case token_type::operand: + output_stack_.push_back(token); + break; + case token_type::lparen: + operator_stack_.push_back(token); + break; + case token_type::rparen: + { + auto it = operator_stack_.rbegin(); + while (it != operator_stack_.rend() && !it->is_lparen()) + { + output_stack_.push_back(*it); + ++it; + } + if (it == operator_stack_.rend()) + { + JSONCONS_THROW(json_runtime_error("Unbalanced parenthesis")); + } + operator_stack_.erase(it.base(),operator_stack_.end()); + operator_stack_.pop_back(); + break; + } + case token_type::unary_operator: + case token_type::binary_operator: + { + if (operator_stack_.empty() || operator_stack_.back().is_lparen()) + { + operator_stack_.push_back(token); + } + else if (token.precedence_level() < operator_stack_.back().precedence_level() + || (token.precedence_level() == operator_stack_.back().precedence_level() && token.is_right_associative())) + { + operator_stack_.push_back(token); + } + else + { + auto it = operator_stack_.rbegin(); + while (it != operator_stack_.rend() && it->is_operator() + && (token.precedence_level() > it->precedence_level() + || (token.precedence_level() == it->precedence_level() && token.is_right_associative()))) + { + output_stack_.push_back(*it); + ++it; + } + + operator_stack_.erase(it.base(),operator_stack_.end()); + operator_stack_.push_back(token); + } + break; + } + default: + break; + } + } + + jsonpath_filter_expr parse(const Json& root, const char_type* p, const char_type* end_expr, const char_type** end_ptr) + { + output_stack_.clear(); + operator_stack_.clear(); + state_stack_.clear(); + + string_type buffer; + size_t buffer_line = 1; + size_t buffer_column = 1; + + int depth = 0; + filter_state state = filter_state::start; + while (p < end_expr && state != filter_state::done) + { + switch (state) + { + case filter_state::start: + switch (*p) + { + case '\r': + if (p+1 < end_expr && *(p+1) == '\n') + ++p; + ++line_; + column_ = 1; + ++p; + break; + case '\n': + ++line_; + column_ = 1; + ++p; + break; + case '(': + state = filter_state::expect_path_or_value_or_unary_op; + ++depth; + push_token(token(token_type::lparen)); + break; + case ')': + state = filter_state::expect_path_or_value_or_unary_op; + push_token(token(token_type::rparen)); + if (--depth == 0) + { + state = filter_state::done; + } + break; + } + ++p; + ++column_; + break; + + case filter_state::expect_arg: + { + switch (*p) + { + case ' ':case '\t': + break; + case '\r': + if (p+1 < end_expr && *(p+1) == '\n') + ++p; + ++line_; + column_ = 1; + ++p; + break; + case '\n': + ++line_; + column_ = 1; + ++p; + break; + case '$': + buffer.push_back(*p); + path_mode_stack_.back() = filter_path_mode::root_path; + state = filter_state::path_argument; + break; + case '@': + buffer.push_back('$'); + path_mode_stack_.back() = filter_path_mode::current_path; + state = filter_state::path_argument; + break; + // Maybe error from here down + case '\'': + buffer.push_back('\"'); + state = filter_state::single_quoted_argument; + break; + case '\"': + buffer.push_back('\"'); + state = filter_state::double_quoted_argument; + break; + default: + buffer.push_back(*p); + state = filter_state::unquoted_argument; + break; + } + ++p; + ++column_; + break; + } + + case filter_state::path_argument: + { + switch (*p) + { + case '\r': + if (p+1 < end_expr && *(p+1) == '\n') + ++p; + ++line_; + column_ = 1; + ++p; + break; + case '\n': + ++line_; + column_ = 1; + ++p; + break; + case ' ':case '\t': + break; + case ',': + buffer.push_back(*p); + state = filter_state::expect_arg; + break; + case ')': + { + buffer.push_back(*p); + state = filter_state::path; + break; + } + default: + buffer.push_back(*p); + break; + } + ++p; + ++column_; + break; + } + case filter_state::single_quoted_argument: + { + switch (*p) + { + case '\'': + buffer.push_back('\"'); + state = filter_state::expect_more_args_or_right_round_bracket; + break; + default: + buffer.push_back(*p); + break; + } + ++p; + ++column_; + break; + } + case filter_state::double_quoted_argument: + { + switch (*p) + { + case '\"': + buffer.push_back('\"'); + state = filter_state::expect_more_args_or_right_round_bracket; + break; + default: + buffer.push_back(*p); + break; + } + ++p; + ++column_; + break; + } + case filter_state::unquoted_argument: + { + switch (*p) + { + case ',': + buffer.push_back(*p); + state = filter_state::expect_arg; + break; + case ')': + { + buffer.push_back(*p); + state = filter_state::path; + break; + } + default: + buffer.push_back(*p); + break; + } + ++p; + ++column_; + break; + } + case filter_state::expect_more_args_or_right_round_bracket: + { + switch (*p) + { + case ' ': + case '\t': + break; + case ',': + buffer.push_back(*p); + state = filter_state::expect_arg; + break; + case ')': + { + buffer.push_back(*p); + state = filter_state::path; + break; + } + default: + throw jsonpath_error(jsonpath_errc::invalid_filter_unsupported_operator, line_, column_); + } + ++p; + ++column_; + break; + } + + case filter_state::oper: + switch (*p) + { + case '~': + { + buffer.push_back(*p); + ++p; + ++column_; + auto it = binary_operators_.find(buffer); + if (it == binary_operators_.end()) + { + throw jsonpath_error(jsonpath_errc::invalid_filter_unsupported_operator, line_, column_); + } + buffer.clear(); + buffer_line = buffer_column = 1; + push_token(token(it->second)); + state = filter_state::expect_regex; + break; + } + case '=': + case '&': + case '|': + { + buffer.push_back(*p); + ++p; + ++column_; + auto it = binary_operators_.find(buffer); + if (it == binary_operators_.end()) + { + throw jsonpath_error(jsonpath_errc::invalid_filter_unsupported_operator, line_, column_); + } + buffer.clear(); + buffer_line = buffer_column = 1; + push_token(token(it->second)); + state = filter_state::expect_path_or_value_or_unary_op; + break; + } + default: + { + auto it = binary_operators_.find(buffer); + if (it == binary_operators_.end()) + { + throw jsonpath_error(jsonpath_errc::invalid_filter_unsupported_operator, line_, column_); + } + buffer.clear(); + buffer_line = buffer_column = 1; + push_token(token(it->second)); + state = filter_state::expect_path_or_value_or_unary_op; + break; + } + } + break; + case filter_state::unquoted_text: + { + switch (*p) + { + case ' ':case '\t': + if (buffer.length() > 0) + { + try + { + auto val = Json::parse(buffer); + push_token(token(token_type::operand,std::make_shared>(std::move(val)))); + } + catch (const ser_error&) + { + throw jsonpath_error(jsonpath_errc::parse_error_in_filter,line_,column_); + } + buffer.clear(); + buffer_line = buffer_column = 1; + } + ++p; + ++column_; + break; + case '(': + { + buffer.push_back(*p); + path_mode_stack_.push_back(filter_path_mode::path); + state = filter_state::expect_arg; + ++p; + ++column_; + break; + } + case '<': + case '>': + case '!': + case '=': + case '&': + case '|': + case '+': + case '-': + case '*': + case '/': + { + if (buffer.length() > 0) + { + try + { + auto val = Json::parse(buffer); + push_token(token(token_type::operand,std::make_shared>(std::move(val)))); + } + catch (const ser_error&) + { + throw jsonpath_error(jsonpath_errc::parse_error_in_filter,line_,column_); + } + buffer.clear(); + buffer_line = buffer_column = 1; + } + buffer.push_back(*p); + state = filter_state::oper; + ++p; + ++column_; + } + break; + case ')': + if (buffer.length() > 0) + { + try + { + auto val = Json::parse(buffer); + push_token(token(token_type::operand,std::make_shared>(std::move(val)))); + } + catch (const ser_error&) + { + throw jsonpath_error(jsonpath_errc::parse_error_in_filter,line_,column_); + } + buffer.clear(); + buffer_line = buffer_column = 1; + } + push_token(token(token_type::rparen)); + if (--depth == 0) + { + state = filter_state::done; + } + else + { + state = filter_state::expect_path_or_value_or_unary_op; + } + ++p; + ++column_; + break; + default: + buffer.push_back(*p); + ++p; + ++column_; + break; + } + } + break; + case filter_state::single_quoted_text: + { + switch (*p) + { + case '\\': + buffer.push_back(*p); + if (p+1 < end_expr) + { + ++p; + ++column_; + buffer.push_back(*p); + } + break; + case '\'': + buffer.push_back('\"'); + //if (buffer.length() > 0) + { + try + { + auto val = Json::parse(buffer); + push_token(token(token_type::operand,std::make_shared>(std::move(val)))); + } + catch (const ser_error&) + { + throw jsonpath_error(jsonpath_errc::parse_error_in_filter,line_,column_); + } + buffer.clear(); + buffer_line = buffer_column = 1; + } + state = filter_state::expect_path_or_value_or_unary_op; + break; + + default: + buffer.push_back(*p); + break; + } + } + ++p; + ++column_; + break; + case filter_state::double_quoted_text: + { + switch (*p) + { + case '\\': + buffer.push_back(*p); + if (p+1 < end_expr) + { + ++p; + ++column_; + buffer.push_back(*p); + } + break; + case '\"': + buffer.push_back(*p); + try + { + auto val = Json::parse(buffer); + push_token(token(token_type::operand,std::make_shared>(std::move(val)))); + } + catch (const ser_error&) + { + throw jsonpath_error(jsonpath_errc::parse_error_in_filter,line_,column_); + } + buffer.clear(); + buffer_line = buffer_column = 1; + state = filter_state::expect_path_or_value_or_unary_op; + break; + + default: + buffer.push_back(*p); + break; + } + } + ++p; + ++column_; + break; + case filter_state::expect_path_or_value_or_unary_op: + switch (*p) + { + case '\r': + if (p+1 < end_expr && *(p+1) == '\n') + ++p; + ++line_; + column_ = 1; + ++p; + break; + case '\n': + ++line_; + column_ = 1; + ++p; + break; + case ' ':case '\t': + ++p; + ++column_; + break; + case '!': + { + std::function&)> f = [](const term& b) {return Json(b.exclaim());}; + push_token(token(1, true, f)); + ++p; + ++column_; + break; + } + case '-': + { + std::function&)> f = [](const term& b) {return b.unary_minus();}; + push_token(token(1, true, f)); + ++p; + ++column_; + break; + } + case '@': + buffer_line = line_; + buffer_column = column_; + buffer.push_back('$'); + state = filter_state::path; + ++p; + ++column_; + break; + case '\'': + buffer.push_back('\"'); + state = filter_state::single_quoted_text; + ++p; + ++column_; + break; + case '\"': + buffer.push_back(*p); + state = filter_state::double_quoted_text; + ++p; + ++column_; + break; + case '(': + ++depth; + push_token(token(token_type::lparen)); + ++p; + ++column_; + break; + case ')': + push_token(token(token_type::rparen)); + if (--depth == 0) + { + state = filter_state::done; + } + ++p; + ++column_; + break; + default: + // don't increment + state = filter_state::unquoted_text; + break; + }; + break; + case filter_state::expect_oper_or_right_round_bracket: + switch (*p) + { + case '\r': + if (p+1 < end_expr && *(p+1) == '\n') + ++p; + ++line_; + column_ = 1; + ++p; + break; + case '\n': + ++line_; + column_ = 1; + ++p; + break; + case ' ':case '\t': + ++p; + ++column_; + break; + case ')': + push_token(token(token_type::rparen)); + if (--depth == 0) + { + state = filter_state::done; + ++p; // fix + } + break; + case '<': + case '>': + case '!': + case '=': + case '&': + case '|': + case '+': + case '-': + case '*': + case '/': + { + buffer.push_back(*p); + state = filter_state::oper; + ++p; + ++column_; + } + break; + default: + throw jsonpath_error(jsonpath_errc::invalid_filter,line_,column_); + break; + }; + break; + case filter_state::expect_right_round_bracket: + switch (*p) + { + case '\r': + if (p+1 < end_expr && *(p+1) == '\n') + ++p; + ++line_; + column_ = 1; + ++p; + break; + case '\n': + ++line_; + column_ = 1; + ++p; + break; + case ' ':case '\t': + break; + case ')': + push_token(token(token_type::rparen)); + if (--depth == 0) + { + state = filter_state::done; + } + else + { + state = filter_state::expect_oper_or_right_round_bracket; + } + break; + default: + throw jsonpath_error(jsonpath_errc::invalid_filter,line_,column_); + break; + }; + ++p; + ++column_; + break; + case filter_state::path: + switch (*p) + { + case '<': + case '>': + case '!': + case '=': + case '&': + case '|': + case '+': + case '-': + case '*': + case '/': + { + if (!path_mode_stack_.empty()) + { + if (path_mode_stack_[0] == filter_path_mode::root_path) + { + jsonpath_evaluator> evaluator(buffer_line,buffer_column); + evaluator.evaluate(root, buffer); + auto result = evaluator.get_values(); + if (result.size() > 0) + { + push_token(token(token_type::operand,std::make_shared>(std::move(result[0])))); + } + } + else + { + push_token(token(token_type::operand,std::make_shared>(buffer, buffer_line, buffer_column))); + } + path_mode_stack_.pop_back(); + } + else + { + push_token(token(token_type::operand,std::make_shared>(buffer, buffer_line, buffer_column))); + } + buffer.clear(); + buffer_line = buffer_column = 1; + buffer.push_back(*p); + ++p; + ++column_; + state = filter_state::oper; + } + break; + case ')': + if (!path_mode_stack_.empty()) + { + if (path_mode_stack_[0] == filter_path_mode::root_path) + { + jsonpath_evaluator> evaluator(buffer_line,buffer_column); + evaluator.evaluate(root, buffer); + auto result = evaluator.get_values(); + if (result.size() > 0) + { + push_token(token(token_type::operand,std::make_shared>(std::move(result[0])))); + } + push_token(token(token_type::rparen)); + } + else + { + push_token(token(token_type::operand,std::make_shared>(buffer, buffer_line, buffer_column))); + } + path_mode_stack_.pop_back(); + } + else + { + push_token(token(token_type::operand,std::make_shared>(buffer, buffer_line, buffer_column))); + push_token(token(token_type::rparen)); + } + buffer.clear(); + buffer_line = buffer_column = 1; + if (--depth == 0) + { + state = filter_state::done; + } + else + { + state = filter_state::expect_path_or_value_or_unary_op; + } + ++p; + ++column_; + break; + default: + buffer.push_back(*p); + ++p; + ++column_; + break; + }; + break; + case filter_state::expect_regex: + switch (*p) + { + case '\r': + if (p+1 < end_expr && *(p+1) == '\n') + ++p; + ++line_; + column_ = 1; + ++p; + break; + case '\n': + ++line_; + column_ = 1; + ++p; + break; + case ' ':case '\t': + break; + case '/': + state = filter_state::regex; + break; + default: + throw jsonpath_error(jsonpath_errc::invalid_filter_expected_slash,line_,column_); + break; + }; + ++p; + ++column_; + break; + case filter_state::regex: + { + switch (*p) + { + case '/': + //if (buffer.length() > 0) + { + std::regex::flag_type flags = std::regex_constants::ECMAScript; + if (p+1 < end_expr && *(p+1) == 'i') + { + ++p; + ++column_; + flags |= std::regex_constants::icase; + } + push_token(token(token_type::operand,std::make_shared>(buffer,flags))); + buffer.clear(); + buffer_line = buffer_column = 1; + } + state = filter_state::expect_path_or_value_or_unary_op; + break; + + default: + buffer.push_back(*p); + break; + } + ++p; + ++column_; + break; + } + default: + ++p; + ++column_; + break; + } + } + if (depth != 0) + { + throw jsonpath_error(jsonpath_errc::invalid_filter_unbalanced_paren,line_,column_); + } + *end_ptr = p; + + return jsonpath_filter_expr(output_stack_); + } +}; + +template +const operator_properties jsonpath_filter_parser::op_properties_[] = +{ + {2,false,[](const term& a, const term& b) {return Json(a.regex_term(b));}}, + {3,false,[](const term& a, const term& b) {return a.mult_term(b);}}, + {3,false,[](const term& a, const term& b) {return a.div_term(b);}}, + {4,false,[](const term& a, const term& b) {return a.plus_term(b);}}, + {4,false,[](const term& a, const term& b) {return a.minus_term(b);}}, + {5,false,[](const term& a, const term& b) {return Json(a.lt_term(b));}}, + {5,false,[](const term& a, const term& b) {return Json(a.lt_term(b) || a.eq_term(b));}}, + {5,false,[](const term& a, const term& b) {return Json(a.gt_term(b));}}, + {5,false,[](const term& a, const term& b) {return Json(a.gt_term(b) || a.eq_term(b));}}, + {6,false,[](const term& a, const term& b) {return Json(a.eq_term(b)); }}, + {6,false,[](const term& a, const term& b) {return Json(a.ne_term(b)); }}, + {7,false,[](const term& a, const term& b) {return Json(a.ampamp_term(b));}}, + {8,false,[](const term& a, const term& b) {return Json(a.pipepipe_term(b));}} +}; + +}}} + +#endif \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/jsonpath/jsonpath_function.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/jsonpath/jsonpath_function.hpp new file mode 100644 index 0000000000..793ea2aa58 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/jsonpath/jsonpath_function.hpp @@ -0,0 +1,225 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSONPATH_JSONPATH_FUNCTION_HPP +#define JSONCONS_JSONPATH_JSONPATH_FUNCTION_HPP + +#include // std::basic_string +#include // std::vector +#include // std::unordered_map +#include // std::numeric_limits +#include // std::move +#include + +namespace jsoncons { namespace jsonpath { + +JSONCONS_STRING_LITERAL(keys,'k','e','y','s') +JSONCONS_STRING_LITERAL(avg,'a','v','g') +JSONCONS_STRING_LITERAL(max,'m','a','x') +JSONCONS_STRING_LITERAL(min,'m','i','n') +JSONCONS_STRING_LITERAL(sum,'s','u','m') +JSONCONS_STRING_LITERAL(prod,'p','r','o','d') +JSONCONS_STRING_LITERAL(count,'c','o','u','n','t') +JSONCONS_STRING_LITERAL(tokenize,'t','o','k','e','n','i','z','e') + +template +class function_table +{ +public: + typedef typename Json::char_type char_type; + typedef typename Json::char_traits_type char_traits_type; + typedef std::basic_string string_type; + typedef typename Json::string_view_type string_view_type; + typedef JsonPointer pointer; + typedef std::vector argument_type; + typedef std::function&, std::error_code&)> function_type; + typedef std::unordered_map function_dictionary; +private: + const function_dictionary functions_ = + { + { + keys_literal(),[](const std::vector& args, std::error_code& ec) + { + Json j = typename Json::array(); + if (args.size() != 1) + { + ec = jsonpath_errc::invalid_argument; + return j; + } + if (args[0].size() != 1 && !args[0][0]->is_object()) + { + return j; + } + pointer arg = args[0][0]; + for (const auto& kv : arg->object_range()) + { + j.emplace_back(kv.key()); + } + + return j; + } + }, + { + max_literal(),[](const std::vector& args, std::error_code& ec) + { + if (args.size() != 1) + { + ec = jsonpath_errc::invalid_argument; + return Json(); + } + const auto& arg = args[0]; + double v = std::numeric_limits::lowest(); + for (auto& node : arg) + { + double x = node->template as(); + if (x > v) + { + v = x; + } + } + return Json(v); + } + }, + { + min_literal(),[](const std::vector& args, std::error_code& ec) + { + if (args.size() != 1) + { + ec = jsonpath_errc::invalid_argument; + return Json(); + } + const auto& arg = args[0]; + double v = (std::numeric_limits::max)(); + for (const auto& node : arg) + { + double x = node->template as(); + if (x < v) + { + v = x; + } + } + return Json(v); + } + }, + { + avg_literal(),[](const std::vector& args, std::error_code& ec) + { + if (args.size() != 1) + { + ec = jsonpath_errc::invalid_argument; + return Json(); + } + const auto& arg = args[0]; + double v = 0.0; + for (const auto& node : arg) + { + v += node->template as(); + } + return arg.size() > 0 ? Json(v/arg.size()) : Json(null_type()); + } + }, + { + sum_literal(),[](const std::vector& args, std::error_code& ec) + { + if (args.size() != 1) + { + ec = jsonpath_errc::invalid_argument; + return Json(); + } + const auto& arg = args[0]; + double v = 0.0; + for (const auto& node : arg) + { + v += node->template as(); + } + return Json(v); + } + }, + { + count_literal(),[](const std::vector& args, std::error_code& ec) + { + if (args.size() != 1) + { + ec = jsonpath_errc::invalid_argument; + return Json(); + } + const auto& arg = args[0]; + size_t count = 0; + while (count < arg.size()) + { + ++count; + } + return Json(count); + } + }, + { + prod_literal(),[](const std::vector& args, std::error_code& ec) + { + if (args.size() != 1) + { + ec = jsonpath_errc::invalid_argument; + return Json(); + } + const auto& arg = args[0]; + double v = 0.0; + for (const auto& node : arg) + { + double x = node->template as(); + v == 0.0 && x != 0.0 + ? (v = x) + : (v *= x); + + } + return Json(v); + } + } +#if !(defined(__GNUC__) && (__GNUC__ == 4 && __GNUC_MINOR__ < 9)) +// GCC 4.8 has broken regex support: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53631 + ,{ + tokenize_literal(),[](const std::vector& args, std::error_code& ec) + { + if (args.size() != 2) + { + ec = jsonpath_errc::invalid_argument; + return Json(); + } + string_type arg1 = args[0][0]->as_string(); + string_type arg2 = args[1][0]->as_string(); + + std::regex::flag_type flags = std::regex_constants::ECMAScript; + std::basic_regex pieces_regex(arg2, flags); + + std::regex_token_iterator rit ( arg1.begin(), arg1.end(), pieces_regex, -1); + std::regex_token_iterator rend; + + Json j = typename Json::array(); + while (rit!=rend) + { + j.push_back(rit->str()); + ++rit; + } + return j; + } + } +#endif + }; +public: + function_type get(const string_type& name, std::error_code& ec) const + { + auto it = functions_.find(name); + if (it == functions_.end()) + { + //std::cout << "Function name " << name << " not found\n"; + ec = jsonpath_errc::function_name_not_found; + return nullptr; + } + return it->second; + } +}; + +}} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/jsonpointer/jsonpointer.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/jsonpointer/jsonpointer.hpp new file mode 100644 index 0000000000..ec1b00824d --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/jsonpointer/jsonpointer.hpp @@ -0,0 +1,959 @@ +// Copyright 2017 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSONPOINTER_JSONPOINTER_HPP +#define JSONCONS_JSONPOINTER_JSONPOINTER_HPP + +#include +#include +#include +#include +#include +#include +#include // std::move +#include // system_error +#include // std::enable_if, std::true_type +#include +#include +#include + +namespace jsoncons { namespace jsonpointer { + +// find_by_reference + +template +struct is_accessible_by_reference : std::false_type {}; + +template +struct is_accessible_by_reference().at(typename J::string_view_type()))>::value + && std::is_reference().at(0))>::value>::type> +: std::true_type {}; + +namespace detail { + +enum class pointer_state +{ + start, + escaped, + delim +}; + +} // detail + +// address_iterator +template +class address_iterator +{ + typedef typename std::iterator_traits::value_type char_type; + typedef std::basic_string string_type; + typedef InputIt base_iterator; + + base_iterator path_ptr_; + base_iterator end_input_; + base_iterator p_; + base_iterator q_; + jsonpointer::detail::pointer_state state_; + size_t line_; + size_t column_; + std::basic_string buffer_; +public: + typedef string_type value_type; + typedef std::ptrdiff_t difference_type; + typedef value_type* pointer; + typedef const value_type& reference; + typedef std::input_iterator_tag iterator_category; + + address_iterator(base_iterator first, base_iterator last) + : address_iterator(first, last, first) + { + std::error_code ec; + increment(ec); + } + + address_iterator(base_iterator first, base_iterator last, base_iterator current) + : path_ptr_(first), end_input_(last), p_(current), q_(current), state_(jsonpointer::detail::pointer_state::start) + { + } + + address_iterator(const address_iterator&) = default; + + address_iterator(address_iterator&&) = default; + + address_iterator& operator=(const address_iterator&) = default; + + address_iterator& operator=(address_iterator&&) = default; + + address_iterator& operator++() + { + std::error_code ec; + increment(ec); + if (ec) + { + throw jsonpointer_error(ec); + } + return *this; + } + + address_iterator& increment(std::error_code& ec) + { + q_ = p_; + buffer_.clear(); + + bool done = false; + while (p_ != end_input_ && !done) + { + switch (state_) + { + case jsonpointer::detail::pointer_state::start: + switch (*p_) + { + case '/': + state_ = jsonpointer::detail::pointer_state::delim; + break; + default: + ec = jsonpointer_errc::expected_slash; + done = true; + break; + }; + break; + case jsonpointer::detail::pointer_state::delim: + switch (*p_) + { + case '/': + state_ = jsonpointer::detail::pointer_state::delim; + done = true; + break; + case '~': + state_ = jsonpointer::detail::pointer_state::escaped; + break; + default: + buffer_.push_back(*p_); + break; + }; + break; + case jsonpointer::detail::pointer_state::escaped: + switch (*p_) + { + case '0': + buffer_.push_back('~'); + state_ = jsonpointer::detail::pointer_state::delim; + break; + case '1': + buffer_.push_back('/'); + state_ = jsonpointer::detail::pointer_state::delim; + break; + default: + ec = jsonpointer_errc::expected_0_or_1; + done = true; + break; + }; + break; + default: + JSONCONS_UNREACHABLE(); + break; + } + ++p_; + ++column_; + } + return *this; + } + + address_iterator operator++(int) // postfix increment + { + address_iterator temp(*this); + ++(*this); + return temp; + } + + reference operator*() const + { + return buffer_; + } + + friend bool operator==(const address_iterator& it1, const address_iterator& it2) + { + return it1.q_ == it2.q_; + } + friend bool operator!=(const address_iterator& it1, const address_iterator& it2) + { + return !(it1 == it2); + } + +private: +}; + +template +std::basic_string escape_string(const std::basic_string& s) +{ + std::basic_string result; + for (auto c : s) + { + switch (c) + { + case '~': + result.push_back('~'); + result.push_back('0'); + break; + case '/': + result.push_back('~'); + result.push_back('1'); + break; + default: + result.push_back(c); + break; + } + } + return result; +} + +// address + +template +class basic_address +{ +public: + std::basic_string path_; +public: + // Member types + typedef CharT char_type; + typedef std::basic_string string_type; + typedef basic_string_view string_view_type; + typedef address_iterator const_iterator; + typedef const_iterator iterator; + + // Constructors + basic_address() + { + } + explicit basic_address(const string_type& s) + : path_(s) + { + } + explicit basic_address(string_type&& s) + : path_(std::move(s)) + { + } + explicit basic_address(const CharT* s) + : path_(s) + { + } + + basic_address(const basic_address&) = default; + + basic_address(basic_address&&) = default; + + // operator= + basic_address& operator=(const basic_address&) = default; + + basic_address& operator=(basic_address&&) = default; + + // Modifiers + + void clear() + { + path_.clear(); + } + + basic_address& operator/=(const string_type& s) + { + path_.push_back('/'); + path_.append(escape_string(s)); + + return *this; + } + + basic_address& operator+=(const basic_address& p) + { + path_.append(p.path_); + return *this; + } + + // Accessors + bool empty() const + { + return path_.empty(); + } + + const string_type& string() const + { + return path_; + } + + operator string_view_type() const + { + return path_; + } + + // Iterators + iterator begin() const + { + return iterator(path_.begin(),path_.end()); + } + iterator end() const + { + return iterator(path_.begin(), path_.end(), path_.end()); + } + + // Non-member functions + friend basic_address operator/(const basic_address& lhs, const string_type& rhs) + { + basic_address p(lhs); + p /= rhs; + return p; + } + + friend basic_address operator+( const basic_address& lhs, const basic_address& rhs ) + { + basic_address p(lhs); + p += rhs; + return p; + } + + friend bool operator==( const basic_address& lhs, const basic_address& rhs ) + { + return lhs.path_ == rhs.path_; + } + + friend bool operator!=( const basic_address& lhs, const basic_address& rhs ) + { + return lhs.path_ != rhs.path_; + } + + friend std::basic_ostream& + operator<<( std::basic_ostream& os, const basic_address& p ) + { + os << p.path_; + return os; + } +}; + +typedef basic_address address; + +namespace detail { + +template +class handle_type +{ +public: + using value_type = typename J::value_type; + using type = value_type; + + handle_type(const value_type& val) noexcept + : val_(val) + { + } + + handle_type(value_type&& val) noexcept + : val_(std::move(val)) + { + } + + handle_type(const handle_type& w) noexcept + : val_(w.val_) + { + } + + handle_type& operator=(const handle_type&) noexcept = default; + + type get() const noexcept + { + return val_; + } +private: + value_type val_; +}; + +template +class handle_type::value>::type> +{ +public: + using reference = JReference; + using type = reference; + using pointer = typename std::conditional::type>::value,typename J::const_pointer,typename J::pointer>::type; + + handle_type(reference ref) noexcept + : ptr_(std::addressof(ref)) + { + } + + handle_type(const handle_type&) noexcept = default; + + handle_type& operator=(const handle_type&) noexcept = default; + + type get() const noexcept + { + return *ptr_; + } +private: + pointer ptr_; +}; + +template +class jsonpointer_evaluator : public ser_context +{ + typedef typename handle_type::type type; + typedef typename J::string_type string_type; + typedef typename string_type::value_type char_type; + typedef typename J::string_view_type string_view_type; + using reference = JReference; + using pointer = typename std::conditional::type>::value,typename J::const_pointer,typename J::pointer>::type; + + size_t line_; + size_t column_; + string_type buffer_; + std::vector> current_; +public: + type get_result() + { + return current_.back().get(); + } + + void get(reference root, const string_view_type& path, std::error_code& ec) + { + evaluate(root, path, ec); + if (ec) + { + return; + } + if (path.empty()) + { + return; + } + resolve(current_, buffer_, ec); + } + + string_type normalized_path(reference root, const string_view_type& path) + { + std::error_code ec; + evaluate(root, path, ec); + if (ec) + { + return string_type(path); + } + if (current_.back().get().is_array() && buffer_.size() == 1 && buffer_[0] == '-') + { + string_type p = string_type(path.substr(0,path.length()-1)); + std::string s = std::to_string(current_.back().get().size()); + for (auto c : s) + { + p.push_back(c); + } + return p; + } + else + { + return string_type(path); + } + } + + void insert_or_assign(reference root, const string_view_type& path, const J& value, std::error_code& ec) + { + evaluate(root, path, ec); + if (ec) + { + return; + } + if (current_.back().get().is_array()) + { + if (buffer_.size() == 1 && buffer_[0] == '-') + { + current_.back().get().push_back(value); + } + else + { + if (!jsoncons::detail::is_integer(buffer_.data(), buffer_.length())) + { + ec = jsonpointer_errc::invalid_index; + return; + } + auto result = jsoncons::detail::to_integer(buffer_.data(), buffer_.length()); + if (result.ec != jsoncons::detail::to_integer_errc()) + { + ec = jsonpointer_errc::invalid_index; + return; + } + size_t index = result.value; + if (index > current_.back().get().size()) + { + ec = jsonpointer_errc::index_exceeds_array_size; + return; + } + if (index == current_.back().get().size()) + { + current_.back().get().push_back(value); + } + else + { + current_.back().get().insert(current_.back().get().array_range().begin()+index,value); + } + } + } + else if (current_.back().get().is_object()) + { + current_.back().get().insert_or_assign(buffer_,value); + } + else + { + ec = jsonpointer_errc::expected_object_or_array; + return; + } + } + + void insert(reference root, const string_view_type& path, const J& value, std::error_code& ec) + { + evaluate(root, path, ec); + if (ec) + { + return; + } + if (current_.back().get().is_array()) + { + if (buffer_.size() == 1 && buffer_[0] == '-') + { + current_.back().get().push_back(value); + } + else + { + if (!jsoncons::detail::is_integer(buffer_.data(), buffer_.length())) + { + ec = jsonpointer_errc::invalid_index; + return; + } + auto result = jsoncons::detail::to_integer(buffer_.data(), buffer_.length()); + if (result.ec != jsoncons::detail::to_integer_errc()) + { + ec = jsonpointer_errc::invalid_index; + return; + } + size_t index = result.value; + if (index > current_.back().get().size()) + { + ec = jsonpointer_errc::index_exceeds_array_size; + return; + } + if (index == current_.back().get().size()) + { + current_.back().get().push_back(value); + } + else + { + current_.back().get().insert(current_.back().get().array_range().begin()+index,value); + } + } + } + else if (current_.back().get().is_object()) + { + if (current_.back().get().contains(buffer_)) + { + ec = jsonpointer_errc::key_already_exists; + return; + } + else + { + current_.back().get().insert_or_assign(buffer_,value); + } + } + else + { + ec = jsonpointer_errc::expected_object_or_array; + return; + } + } + + void remove(reference root, const string_view_type& path, std::error_code& ec) + { + evaluate(root, path, ec); + if (ec) + { + return; + } + if (current_.back().get().is_array()) + { + if (buffer_.size() == 1 && buffer_[0] == '-') + { + ec = jsonpointer_errc::index_exceeds_array_size; + return; + } + else + { + if (!jsoncons::detail::is_integer(buffer_.data(), buffer_.length())) + { + ec = jsonpointer_errc::invalid_index; + return; + } + auto result = jsoncons::detail::to_integer(buffer_.data(), buffer_.length()); + if (result.ec != jsoncons::detail::to_integer_errc()) + { + ec = jsonpointer_errc::invalid_index; + return; + } + size_t index = result.value; + if (index >= current_.back().get().size()) + { + ec = jsonpointer_errc::index_exceeds_array_size; + return; + } + current_.back().get().erase(current_.back().get().array_range().begin()+index); + } + } + else if (current_.back().get().is_object()) + { + if (!current_.back().get().contains(buffer_)) + { + ec = jsonpointer_errc::name_not_found; + return; + } + else + { + current_.back().get().erase(buffer_); + } + } + else + { + ec = jsonpointer_errc::expected_object_or_array; + return; + } + } + + void replace(reference root, const string_view_type& path, const J& value, std::error_code& ec) + { + evaluate(root, path, ec); + if (ec) + { + return; + } + if (current_.back().get().is_array()) + { + if (buffer_.size() == 1 && buffer_[0] == '-') + { + ec = jsonpointer_errc::index_exceeds_array_size; + return; + } + else + { + if (!jsoncons::detail::is_integer(buffer_.data(), buffer_.length())) + { + ec = jsonpointer_errc::invalid_index; + return; + } + auto result = jsoncons::detail::to_integer(buffer_.data(), buffer_.length()); + if (result.ec != jsoncons::detail::to_integer_errc()) + { + ec = jsonpointer_errc::invalid_index; + return; + } + size_t index = result.value; + if (index >= current_.back().get().size()) + { + ec = jsonpointer_errc::index_exceeds_array_size; + return; + } + (current_.back().get())[index] = value; + } + } + else if (current_.back().get().is_object()) + { + if (!current_.back().get().contains(buffer_)) + { + ec = jsonpointer_errc::key_already_exists; + return; + } + else + { + current_.back().get().insert_or_assign(buffer_,value); + } + } + else + { + ec = jsonpointer_errc::expected_object_or_array; + return; + } + } + + void evaluate(reference root, const string_view_type& path, std::error_code& ec) + { + current_.push_back(root); + + address_iterator it(path.begin(), path.end()); + address_iterator end(path.begin(), path.end(), path.end()); + while (it != end) + { + buffer_ = *it; + it.increment(ec); + if (ec) + return; + if (it == end) + { + return; + } + resolve(current_, buffer_, ec); + if (ec) + return; + } + } + + static void resolve(std::vector>& current, + const string_view_type& buffer, + std::error_code& ec) + { + if (current.back().get().is_array()) + { + if (buffer.size() == 1 && buffer[0] == '-') + { + ec = jsonpointer_errc::index_exceeds_array_size; + return; + } + else + { + if (!jsoncons::detail::is_integer(buffer.data(), buffer.length())) + { + ec = jsonpointer_errc::invalid_index; + return; + } + auto result = jsoncons::detail::to_integer(buffer.data(), buffer.length()); + if (result.ec != jsoncons::detail::to_integer_errc()) + { + ec = jsonpointer_errc::invalid_index; + return; + } + size_t index = result.value; + if (index >= current.back().get().size()) + { + ec = jsonpointer_errc::index_exceeds_array_size; + return; + } + current.push_back(current.back().get().at(index)); + } + } + else if (current.back().get().is_object()) + { + if (!current.back().get().contains(buffer)) + { + ec = jsonpointer_errc::name_not_found; + return; + } + current.push_back(current.back().get().at(buffer)); + } + else + { + ec = jsonpointer_errc::expected_object_or_array; + return; + } + } + + // ser_context + + size_t line() const override + { + return line_; + } + + size_t column() const override + { + return column_; + } +}; + +} + +template +typename J::string_type normalized_path(const J& root, const typename J::string_view_type& path) +{ + jsoncons::jsonpointer::detail::jsonpointer_evaluator evaluator; + return evaluator.normalized_path(root,path); +} + +template +typename std::enable_if::value,J&>::type +get(J& root, const typename J::string_view_type& path) +{ + jsoncons::jsonpointer::detail::jsonpointer_evaluator evaluator; + std::error_code ec; + evaluator.get(root, path, ec); + if (ec) + { + JSONCONS_THROW(jsonpointer_error(ec)); + } + return evaluator.get_result(); +} + +template +typename std::enable_if::value,const J&>::type +get(const J& root, const typename J::string_view_type& path) +{ + jsoncons::jsonpointer::detail::jsonpointer_evaluator evaluator; + + std::error_code ec; + evaluator.get(root, path, ec); + if (ec) + { + JSONCONS_THROW(jsonpointer_error(ec)); + } + return evaluator.get_result(); +} + +template +typename std::enable_if::value,J>::type +get(const J& root, const typename J::string_view_type& path) +{ + jsoncons::jsonpointer::detail::jsonpointer_evaluator evaluator; + + std::error_code ec; + evaluator.get(root, path, ec); + if (ec) + { + JSONCONS_THROW(jsonpointer_error(ec)); + } + return evaluator.get_result(); +} + +template +typename std::enable_if::value,J&>::type +get(J& root, const typename J::string_view_type& path, std::error_code& ec) +{ + jsoncons::jsonpointer::detail::jsonpointer_evaluator evaluator; + evaluator.get(root, path, ec); + return evaluator.get_result(); +} + +template +typename std::enable_if::value,const J&>::type +get(const J& root, const typename J::string_view_type& path, std::error_code& ec) +{ + jsoncons::jsonpointer::detail::jsonpointer_evaluator evaluator; + evaluator.get(root, path, ec); + return evaluator.get_result(); +} + +template +typename std::enable_if::value,J>::type +get(const J& root, const typename J::string_view_type& path, std::error_code& ec) +{ + jsoncons::jsonpointer::detail::jsonpointer_evaluator evaluator; + evaluator.get(root, path, ec); + return evaluator.get_result(); +} + +template +bool contains(const J& root, const typename J::string_view_type& path) +{ + jsoncons::jsonpointer::detail::jsonpointer_evaluator evaluator; + std::error_code ec; + evaluator.get(root, path, ec); + return !ec ? true : false; +} + +template +void insert_or_assign(J& root, const typename J::string_view_type& path, const J& value) +{ + jsoncons::jsonpointer::detail::jsonpointer_evaluator evaluator; + + std::error_code ec; + evaluator.insert_or_assign(root, path, value, ec); + if (ec) + { + JSONCONS_THROW(jsonpointer_error(ec)); + } +} + +template +void insert_or_assign(J& root, const typename J::string_view_type& path, const J& value, std::error_code& ec) +{ + jsoncons::jsonpointer::detail::jsonpointer_evaluator evaluator; + + evaluator.insert_or_assign(root, path, value, ec); +} + +template +void insert(J& root, const typename J::string_view_type& path, const J& value) +{ + jsoncons::jsonpointer::detail::jsonpointer_evaluator evaluator; + + std::error_code ec; + evaluator.insert(root, path, value, ec); + if (ec) + { + JSONCONS_THROW(jsonpointer_error(ec)); + } +} + +template +void insert(J& root, const typename J::string_view_type& path, const J& value, std::error_code& ec) +{ + jsoncons::jsonpointer::detail::jsonpointer_evaluator evaluator; + + evaluator.insert(root, path, value, ec); +} + +template +void remove(J& root, const typename J::string_view_type& path) +{ + jsoncons::jsonpointer::detail::jsonpointer_evaluator evaluator; + + std::error_code ec; + evaluator.remove(root, path, ec); + if (ec) + { + JSONCONS_THROW(jsonpointer_error(ec)); + } +} + +template +void remove(J& root, const typename J::string_view_type& path, std::error_code& ec) +{ + jsoncons::jsonpointer::detail::jsonpointer_evaluator evaluator; + + evaluator.remove(root, path, ec); +} + +template +void replace(J& root, const typename J::string_view_type& path, const J& value) +{ + jsoncons::jsonpointer::detail::jsonpointer_evaluator evaluator; + + std::error_code ec; + evaluator.replace(root, path, value, ec); + if (ec) + { + JSONCONS_THROW(jsonpointer_error(ec)); + } +} + +template +void replace(J& root, const typename J::string_view_type& path, const J& value, std::error_code& ec) +{ + jsoncons::jsonpointer::detail::jsonpointer_evaluator evaluator; + + evaluator.replace(root, path, value, ec); +} + +template +void escape(const String& s, std::basic_ostringstream& os) +{ + for (auto c : s) + { + if (c == '~') + { + os.put('~'); + os.put('0'); + } + else if (c == '/') + { + os.put('~'); + os.put('1'); + } + else + { + os.put(c); + } + } +} + +}} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/jsonpointer/jsonpointer.hpp.orig b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/jsonpointer/jsonpointer.hpp.orig new file mode 100644 index 0000000000..c18dd12aef --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/jsonpointer/jsonpointer.hpp.orig @@ -0,0 +1,1060 @@ +// Copyright 2017 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSONPOINTER_JSONPOINTER_HPP +#define JSONCONS_JSONPOINTER_JSONPOINTER_HPP + +#include +#include +#include +#include +#include +#include +#include // std::move +#include // std::enable_if, std::true_type +#include +#include +#include + +namespace jsoncons { namespace jsonpointer { + +class jsonpointer_error : public std::exception, public virtual json_exception +{ +public: + jsonpointer_error(const std::error_code& ec) + : error_code_(ec) + { + } + jsonpointer_error(const jsonpointer_error& other) = default; + + jsonpointer_error(jsonpointer_error&& other) = default; + + const char* what() const noexcept override + { + try + { + const_cast(buffer_) = error_code_.message(); + return buffer_.c_str(); + } + catch (...) + { + return ""; + } + } + + const std::error_code code() const + { + return error_code_; + } + + jsonpointer_error& operator=(const jsonpointer_error& e) = default; + jsonpointer_error& operator=(jsonpointer_error&& e) = default; +private: + std::string buffer_; + std::error_code error_code_; +}; + +// find_by_reference + +template +struct is_accessible_by_reference : std::false_type {}; + +template +struct is_accessible_by_reference().at(typename J::string_view_type()))>::value + && std::is_reference().at(0))>::value>::type> +: std::true_type {}; + +namespace detail { + +enum class pointer_state +{ + start, + escaped, + delim +}; + +} // detail + +// address_iterator +template +class address_iterator +{ + typedef typename std::iterator_traits::value_type char_type; + typedef std::basic_string string_type; + typedef InputIt base_iterator; + + base_iterator path_ptr_; + base_iterator end_input_; + base_iterator p_; + base_iterator q_; + jsonpointer::detail::pointer_state state_; + size_t line_; + size_t column_; + std::basic_string buffer_; +public: + typedef string_type value_type; + typedef std::ptrdiff_t difference_type; + typedef value_type* pointer; + typedef const value_type& reference; + typedef std::input_iterator_tag iterator_category; + + address_iterator(base_iterator first, base_iterator last) + : address_iterator(first, last, first) + { + std::error_code ec; + increment(ec); + } + + address_iterator(base_iterator first, base_iterator last, base_iterator current) + : path_ptr_(first), end_input_(last), p_(current), q_(current), state_(jsonpointer::detail::pointer_state::start) + { + } + + address_iterator(const address_iterator&) = default; + + address_iterator(address_iterator&&) = default; + + address_iterator& operator=(const address_iterator&) = default; + + address_iterator& operator=(address_iterator&&) = default; + + address_iterator& operator++() + { + std::error_code ec; + increment(ec); + if (ec) + { + throw jsonpointer_error(ec); + } + return *this; + } + + address_iterator& increment(std::error_code& ec) + { + q_ = p_; + buffer_.clear(); + + bool done = false; + while (p_ != end_input_ && !done) + { + switch (state_) + { + case jsonpointer::detail::pointer_state::start: + switch (*p_) + { + case '/': + state_ = jsonpointer::detail::pointer_state::delim; + break; + default: + ec = jsonpointer_errc::expected_slash; + done = true; + break; + }; + break; + case jsonpointer::detail::pointer_state::delim: + switch (*p_) + { + case '/': + state_ = jsonpointer::detail::pointer_state::delim; + done = true; + break; + case '~': + state_ = jsonpointer::detail::pointer_state::escaped; + break; + default: + buffer_.push_back(*p_); + break; + }; + break; + case jsonpointer::detail::pointer_state::escaped: + switch (*p_) + { + case '0': + buffer_.push_back('~'); + state_ = jsonpointer::detail::pointer_state::delim; + break; + case '1': + buffer_.push_back('/'); + state_ = jsonpointer::detail::pointer_state::delim; + break; + default: + ec = jsonpointer_errc::expected_0_or_1; + done = true; + break; + }; + break; + default: + JSONCONS_UNREACHABLE(); + break; + } + ++p_; + ++column_; + } + return *this; + } + + address_iterator operator++(int) // postfix increment + { + address_iterator temp(*this); + ++(*this); + return temp; + } + + reference operator*() const + { + return buffer_; + } + + friend bool operator==(const address_iterator& it1, const address_iterator& it2) + { + return it1.q_ == it2.q_; + } + friend bool operator!=(const address_iterator& it1, const address_iterator& it2) + { + return !(it1 == it2); + } + +private: +}; + +inline +std::basic_string escape_string(const std::basic_string& s) +{ + std::basic_string result; + for (auto c : s) + { + switch (c) + { + case '~': + result.push_back('~'); + result.push_back('0'); + break; + case '/': + result.push_back('~'); + result.push_back('1'); + break; + default: + result.push_back(c); + break; + } + } + return result; +} + +// address + +<<<<<<< HEAD +template +class basic_address +======= +class address +>>>>>>> efc18942efb17086d3de2d1d853d56a11666ebb0 +{ +public: + std::basic_string path_; +public: + // Member types + typedef char char_type; + typedef std::basic_string string_type; + typedef basic_string_view string_view_type; + typedef address_iterator const_iterator; + typedef const_iterator iterator; + + // Constructors +<<<<<<< HEAD + basic_address() + { + } + explicit basic_address(const string_type& s) + : path_(s) + { + } + explicit basic_address(string_type&& s) + : path_(std::move(s)) + { + } + explicit basic_address(const CharT* s) +======= + address() + { + } + explicit address(const string_type& s) + : path_(s) + { + } + explicit address(string_type&& s) + : path_(std::move(s)) + { + } + explicit address(const char_type* s) +>>>>>>> efc18942efb17086d3de2d1d853d56a11666ebb0 + : path_(s) + { + } + +<<<<<<< HEAD + basic_address(const basic_address&) = default; + + basic_address(basic_address&&) = default; + + // operator= + basic_address& operator=(const basic_address&) = default; + + basic_address& operator=(basic_address&&) = default; +======= + address(const address&) = default; + + address(address&&) = default; + + // operator= + address& operator=(const address&) = default; + + address& operator=(address&&) = default; +>>>>>>> efc18942efb17086d3de2d1d853d56a11666ebb0 + + // Modifiers + + void clear() + { + path_.clear(); + } + +<<<<<<< HEAD + basic_address& operator/=(const string_type& s) +======= + address& operator/=(const string_type& s) +>>>>>>> efc18942efb17086d3de2d1d853d56a11666ebb0 + { + path_.push_back('/'); + path_.append(escape_string(s)); + + return *this; + } + +<<<<<<< HEAD + basic_address& operator+=(const basic_address& p) +======= + address& operator+=(const address& p) +>>>>>>> efc18942efb17086d3de2d1d853d56a11666ebb0 + { + path_.append(p.path_); + return *this; + } + + // Accessors + bool empty() const + { + return path_.empty(); + } + + const string_type& string() const + { + return path_; + } + + operator string_view_type() const + { + return path_; + } + + // Iterators + iterator begin() const + { + return iterator(path_.begin(),path_.end()); + } + iterator end() const + { + return iterator(path_.begin(), path_.end(), path_.end()); + } + + // Non-member functions +<<<<<<< HEAD + friend basic_address operator/(const basic_address& lhs, const string_type& rhs) + { + basic_address p(lhs); +======= + friend address operator/(const address& lhs, const string_type& rhs) + { + address p(lhs); +>>>>>>> efc18942efb17086d3de2d1d853d56a11666ebb0 + p /= rhs; + return p; + } + +<<<<<<< HEAD + friend basic_address operator+( const basic_address& lhs, const basic_address& rhs ) + { + basic_address p(lhs); +======= + friend address operator+( const address& lhs, const address& rhs ) + { + address p(lhs); +>>>>>>> efc18942efb17086d3de2d1d853d56a11666ebb0 + p += rhs; + return p; + } + +<<<<<<< HEAD + friend bool operator==( const basic_address& lhs, const basic_address& rhs ) +======= + friend bool operator==( const address& lhs, const address& rhs ) +>>>>>>> efc18942efb17086d3de2d1d853d56a11666ebb0 + { + return lhs.path_ == rhs.path_; + } + +<<<<<<< HEAD + friend bool operator!=( const basic_address& lhs, const basic_address& rhs ) +======= + friend bool operator!=( const address& lhs, const address& rhs ) +>>>>>>> efc18942efb17086d3de2d1d853d56a11666ebb0 + { + return lhs.path_ != rhs.path_; + } + +<<<<<<< HEAD + friend std::basic_ostream& + operator<<( std::basic_ostream& os, const basic_address& p ) +======= + friend std::ostream& + operator<<( std::ostream& os, const address& p ) +>>>>>>> efc18942efb17086d3de2d1d853d56a11666ebb0 + { + os << p.path_; + return os; + } +}; + +<<<<<<< HEAD +typedef basic_address address; + +======= +>>>>>>> efc18942efb17086d3de2d1d853d56a11666ebb0 +namespace detail { + +template +class handle_type +{ +public: + using value_type = typename J::value_type; + using type = value_type; + + handle_type(const value_type& val) noexcept + : val_(val) + { + } + + handle_type(value_type&& val) noexcept + : val_(std::move(val)) + { + } + + handle_type(const handle_type& w) noexcept + : val_(w.val_) + { + } + + handle_type& operator=(const handle_type&) noexcept = default; + + type get() const noexcept + { + return val_; + } +private: + value_type val_; +}; + +template +class handle_type::value>::type> +{ +public: + using reference = JReference; + using type = reference; + using pointer = typename std::conditional::type>::value,typename J::const_pointer,typename J::pointer>::type; + + handle_type(reference ref) noexcept + : ptr_(std::addressof(ref)) + { + } + + handle_type(const handle_type&) noexcept = default; + + handle_type& operator=(const handle_type&) noexcept = default; + + type get() const noexcept + { + return *ptr_; + } +private: + pointer ptr_; +}; + +template +class jsonpointer_evaluator : private serializing_context +{ + typedef typename handle_type::type type; + typedef typename J::string_type string_type; + typedef typename string_type::value_type char_type; + typedef typename J::string_view_type string_view_type; + using reference = JReference; + using pointer = typename std::conditional::type>::value,typename J::const_pointer,typename J::pointer>::type; + + size_t line_; + size_t column_; + string_type buffer_; + std::vector> current_; +public: + type get_result() + { + return current_.back().get(); + } + + void get(reference root, const string_view_type& path, std::error_code& ec) + { + evaluate(root, path, ec); + if (ec) + { + return; + } + if (path.empty()) + { + return; + } + resolve(current_, buffer_, ec); + } + + string_type normalized_path(reference root, const string_view_type& path) + { + std::error_code ec; + evaluate(root, path, ec); + if (ec) + { + return string_type(path); + } + if (current_.back().get().is_array() && buffer_.size() == 1 && buffer_[0] == '-') + { + string_type p = string_type(path.substr(0,path.length()-1)); + std::string s = std::to_string(current_.back().get().size()); + for (auto c : s) + { + p.push_back(c); + } + return p; + } + else + { + return string_type(path); + } + } + + void insert_or_assign(reference root, const string_view_type& path, const J& value, std::error_code& ec) + { + evaluate(root, path, ec); + if (ec) + { + return; + } + if (current_.back().get().is_array()) + { + if (buffer_.size() == 1 && buffer_[0] == '-') + { + current_.back().get().push_back(value); + } + else + { + if (!jsoncons::detail::is_integer(buffer_.data(), buffer_.length())) + { + ec = jsonpointer_errc::invalid_index; + return; + } + auto result = jsoncons::detail::to_integer(buffer_.data(), buffer_.length()); + if (result.overflow) + { + ec = jsonpointer_errc::invalid_index; + return; + } + size_t index = result.value; + if (index > current_.back().get().size()) + { + ec = jsonpointer_errc::index_exceeds_array_size; + return; + } + if (index == current_.back().get().size()) + { + current_.back().get().push_back(value); + } + else + { + current_.back().get().insert(current_.back().get().array_range().begin()+index,value); + } + } + } + else if (current_.back().get().is_object()) + { + current_.back().get().insert_or_assign(buffer_,value); + } + else + { + ec = jsonpointer_errc::expected_object_or_array; + return; + } + } + + void insert(reference root, const string_view_type& path, const J& value, std::error_code& ec) + { + evaluate(root, path, ec); + if (ec) + { + return; + } + if (current_.back().get().is_array()) + { + if (buffer_.size() == 1 && buffer_[0] == '-') + { + current_.back().get().push_back(value); + } + else + { + if (!jsoncons::detail::is_integer(buffer_.data(), buffer_.length())) + { + ec = jsonpointer_errc::invalid_index; + return; + } + auto result = jsoncons::detail::to_integer(buffer_.data(), buffer_.length()); + if (result.overflow) + { + ec = jsonpointer_errc::invalid_index; + return; + } + size_t index = result.value; + if (index > current_.back().get().size()) + { + ec = jsonpointer_errc::index_exceeds_array_size; + return; + } + if (index == current_.back().get().size()) + { + current_.back().get().push_back(value); + } + else + { + current_.back().get().insert(current_.back().get().array_range().begin()+index,value); + } + } + } + else if (current_.back().get().is_object()) + { + if (current_.back().get().contains(buffer_)) + { + ec = jsonpointer_errc::key_already_exists; + return; + } + else + { + current_.back().get().insert_or_assign(buffer_,value); + } + } + else + { + ec = jsonpointer_errc::expected_object_or_array; + return; + } + } + + void remove(reference root, const string_view_type& path, std::error_code& ec) + { + evaluate(root, path, ec); + if (ec) + { + return; + } + if (current_.back().get().is_array()) + { + if (buffer_.size() == 1 && buffer_[0] == '-') + { + ec = jsonpointer_errc::index_exceeds_array_size; + return; + } + else + { + if (!jsoncons::detail::is_integer(buffer_.data(), buffer_.length())) + { + ec = jsonpointer_errc::invalid_index; + return; + } + auto result = jsoncons::detail::to_integer(buffer_.data(), buffer_.length()); + if (result.overflow) + { + ec = jsonpointer_errc::invalid_index; + return; + } + size_t index = result.value; + if (index >= current_.back().get().size()) + { + ec = jsonpointer_errc::index_exceeds_array_size; + return; + } + current_.back().get().erase(current_.back().get().array_range().begin()+index); + } + } + else if (current_.back().get().is_object()) + { + if (!current_.back().get().contains(buffer_)) + { + ec = jsonpointer_errc::name_not_found; + return; + } + else + { + current_.back().get().erase(buffer_); + } + } + else + { + ec = jsonpointer_errc::expected_object_or_array; + return; + } + } + + void replace(reference root, const string_view_type& path, const J& value, std::error_code& ec) + { + evaluate(root, path, ec); + if (ec) + { + return; + } + if (current_.back().get().is_array()) + { + if (buffer_.size() == 1 && buffer_[0] == '-') + { + ec = jsonpointer_errc::index_exceeds_array_size; + return; + } + else + { + if (!jsoncons::detail::is_integer(buffer_.data(), buffer_.length())) + { + ec = jsonpointer_errc::invalid_index; + return; + } + auto result = jsoncons::detail::to_integer(buffer_.data(), buffer_.length()); + if (result.overflow) + { + ec = jsonpointer_errc::invalid_index; + return; + } + size_t index = result.value; + if (index >= current_.back().get().size()) + { + ec = jsonpointer_errc::index_exceeds_array_size; + return; + } + (current_.back().get())[index] = value; + } + } + else if (current_.back().get().is_object()) + { + if (!current_.back().get().contains(buffer_)) + { + ec = jsonpointer_errc::key_already_exists; + return; + } + else + { + current_.back().get().insert_or_assign(buffer_,value); + } + } + else + { + ec = jsonpointer_errc::expected_object_or_array; + return; + } + } + + void evaluate(reference root, const string_view_type& path, std::error_code& ec) + { + current_.push_back(root); + + address_iterator it(path.begin(), path.end()); + address_iterator end(path.begin(), path.end(), path.end()); + while (it != end) + { + buffer_ = *it; + it.increment(ec); + if (ec) + return; + if (it == end) + { + return; + } + resolve(current_, buffer_, ec); + if (ec) + return; + } + } + + static void resolve(std::vector>& current, + const string_view_type& buffer, + std::error_code& ec) + { + if (current.back().get().is_array()) + { + if (buffer.size() == 1 && buffer[0] == '-') + { + ec = jsonpointer_errc::index_exceeds_array_size; + return; + } + else + { + if (!jsoncons::detail::is_integer(buffer.data(), buffer.length())) + { + ec = jsonpointer_errc::invalid_index; + return; + } + auto result = jsoncons::detail::to_integer(buffer.data(), buffer.length()); + if (result.overflow) + { + ec = jsonpointer_errc::invalid_index; + return; + } + size_t index = result.value; + if (index >= current.back().get().size()) + { + ec = jsonpointer_errc::index_exceeds_array_size; + return; + } + current.push_back(current.back().get().at(index)); + } + } + else if (current.back().get().is_object()) + { + if (!current.back().get().contains(buffer)) + { + ec = jsonpointer_errc::name_not_found; + return; + } + current.push_back(current.back().get().at(buffer)); + } + else + { + ec = jsonpointer_errc::expected_object_or_array; + return; + } + } + + // serializing_context + + size_t line_number() const override + { + return line_; + } + + size_t column_number() const override + { + return column_; + } +}; + +} + +template +typename J::string_type normalized_path(const J& root, const typename J::string_view_type& path) +{ + jsoncons::jsonpointer::detail::jsonpointer_evaluator evaluator; + return evaluator.normalized_path(root,path); +} + +template +typename std::enable_if::value,J&>::type +get(J& root, const typename J::string_view_type& path) +{ + jsoncons::jsonpointer::detail::jsonpointer_evaluator evaluator; + std::error_code ec; + evaluator.get(root, path, ec); + if (ec) + { + JSONCONS_THROW(jsonpointer_error(ec)); + } + return evaluator.get_result(); +} + +template +typename std::enable_if::value,const J&>::type +get(const J& root, const typename J::string_view_type& path) +{ + jsoncons::jsonpointer::detail::jsonpointer_evaluator evaluator; + + std::error_code ec; + evaluator.get(root, path, ec); + if (ec) + { + JSONCONS_THROW(jsonpointer_error(ec)); + } + return evaluator.get_result(); +} + +template +typename std::enable_if::value,J>::type +get(const J& root, const typename J::string_view_type& path) +{ + jsoncons::jsonpointer::detail::jsonpointer_evaluator evaluator; + + std::error_code ec; + evaluator.get(root, path, ec); + if (ec) + { + JSONCONS_THROW(jsonpointer_error(ec)); + } + return evaluator.get_result(); +} + +template +typename std::enable_if::value,J&>::type +get(J& root, const typename J::string_view_type& path, std::error_code& ec) +{ + jsoncons::jsonpointer::detail::jsonpointer_evaluator evaluator; + evaluator.get(root, path, ec); + return evaluator.get_result(); +} + +template +typename std::enable_if::value,const J&>::type +get(const J& root, const typename J::string_view_type& path, std::error_code& ec) +{ + jsoncons::jsonpointer::detail::jsonpointer_evaluator evaluator; + evaluator.get(root, path, ec); + return evaluator.get_result(); +} + +template +typename std::enable_if::value,J>::type +get(const J& root, const typename J::string_view_type& path, std::error_code& ec) +{ + jsoncons::jsonpointer::detail::jsonpointer_evaluator evaluator; + evaluator.get(root, path, ec); + return evaluator.get_result(); +} + +template +bool contains(const J& root, const typename J::string_view_type& path) +{ + jsoncons::jsonpointer::detail::jsonpointer_evaluator evaluator; + std::error_code ec; + evaluator.get(root, path, ec); + return !ec ? true : false; +} + +template +void insert_or_assign(J& root, const typename J::string_view_type& path, const J& value) +{ + jsoncons::jsonpointer::detail::jsonpointer_evaluator evaluator; + + std::error_code ec; + evaluator.insert_or_assign(root, path, value, ec); + if (ec) + { + JSONCONS_THROW(jsonpointer_error(ec)); + } +} + +template +void insert_or_assign(J& root, const typename J::string_view_type& path, const J& value, std::error_code& ec) +{ + jsoncons::jsonpointer::detail::jsonpointer_evaluator evaluator; + + evaluator.insert_or_assign(root, path, value, ec); +} + +template +void insert(J& root, const typename J::string_view_type& path, const J& value) +{ + jsoncons::jsonpointer::detail::jsonpointer_evaluator evaluator; + + std::error_code ec; + evaluator.insert(root, path, value, ec); + if (ec) + { + JSONCONS_THROW(jsonpointer_error(ec)); + } +} + +template +void insert(J& root, const typename J::string_view_type& path, const J& value, std::error_code& ec) +{ + jsoncons::jsonpointer::detail::jsonpointer_evaluator evaluator; + + evaluator.insert(root, path, value, ec); +} + +template +void remove(J& root, const typename J::string_view_type& path) +{ + jsoncons::jsonpointer::detail::jsonpointer_evaluator evaluator; + + std::error_code ec; + evaluator.remove(root, path, ec); + if (ec) + { + JSONCONS_THROW(jsonpointer_error(ec)); + } +} + +template +void remove(J& root, const typename J::string_view_type& path, std::error_code& ec) +{ + jsoncons::jsonpointer::detail::jsonpointer_evaluator evaluator; + + evaluator.remove(root, path, ec); +} + +template +void replace(J& root, const typename J::string_view_type& path, const J& value) +{ + jsoncons::jsonpointer::detail::jsonpointer_evaluator evaluator; + + std::error_code ec; + evaluator.replace(root, path, value, ec); + if (ec) + { + JSONCONS_THROW(jsonpointer_error(ec)); + } +} + +template +void replace(J& root, const typename J::string_view_type& path, const J& value, std::error_code& ec) +{ + jsoncons::jsonpointer::detail::jsonpointer_evaluator evaluator; + + evaluator.replace(root, path, value, ec); +} + +template +void escape(const String& s, std::basic_ostringstream& os) +{ + for (auto c : s) + { + if (c == '~') + { + os.put('~'); + os.put('0'); + } + else if (c == '/') + { + os.put('~'); + os.put('1'); + } + else + { + os.put(c); + } + } +} + +}} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/jsonpointer/jsonpointer_error.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/jsonpointer/jsonpointer_error.hpp new file mode 100644 index 0000000000..dfd26184c7 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/jsonpointer/jsonpointer_error.hpp @@ -0,0 +1,109 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSONPOINTER_JSONPOINTER_ERROR_HPP +#define JSONCONS_JSONPOINTER_JSONPOINTER_ERROR_HPP + +#include +#include + +namespace jsoncons { namespace jsonpointer { + +class jsonpointer_error : public std::system_error, public virtual json_exception +{ +public: + jsonpointer_error(const std::error_code& ec) + : std::system_error(ec) + { + } + jsonpointer_error(const std::error_code& ec, const std::string& what_arg) + : std::system_error(ec, what_arg) + { + } + jsonpointer_error(const std::error_code& ec, const char* what_arg) + : std::system_error(ec, what_arg) + { + } + jsonpointer_error(const jsonpointer_error& other) = default; + + jsonpointer_error(jsonpointer_error&& other) = default; + + const char* what() const noexcept override + { + return std::system_error::what(); + } +}; + +enum class jsonpointer_errc +{ + ok = 0, + expected_slash = 1, + index_exceeds_array_size, + expected_0_or_1, + invalid_index, + name_not_found, + key_already_exists, + expected_object_or_array, + end_of_input +}; + +class jsonpointer_error_category_impl + : public std::error_category +{ +public: + const char* name() const noexcept override + { + return "jsoncons/jsonpointer"; + } + std::string message(int ev) const override + { + switch (static_cast(ev)) + { + case jsonpointer_errc::expected_slash: + return "Expected /"; + case jsonpointer_errc::index_exceeds_array_size: + return "Index exceeds array size"; + case jsonpointer_errc::expected_0_or_1: + return "Expected '0' or '1' after escape character '~'"; + case jsonpointer_errc::name_not_found: + return "Name not found"; + case jsonpointer_errc::invalid_index: + return "Invalid array index"; + case jsonpointer_errc::key_already_exists: + return "Key already exists"; + case jsonpointer_errc::expected_object_or_array: + return "Expected object or array"; + case jsonpointer_errc::end_of_input: + return "Unexpected end of input"; + default: + return "Unknown jsonpointer error"; + } + } +}; + +inline +const std::error_category& jsonpointer_error_category() +{ + static jsonpointer_error_category_impl instance; + return instance; +} + +inline +std::error_code make_error_code(jsonpointer_errc result) +{ + return std::error_code(static_cast(result),jsonpointer_error_category()); +} + +}} + +namespace std { + template<> + struct is_error_code_enum : public true_type + { + }; +} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/msgpack/msgpack.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/msgpack/msgpack.hpp new file mode 100644 index 0000000000..d5c8360edb --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/msgpack/msgpack.hpp @@ -0,0 +1,126 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_MSGPACK_MSGPACK_HPP +#define JSONCONS_MSGPACK_MSGPACK_HPP + +#include +#include +#include +#include // std::enable_if +#include // std::basic_istream +#include +#include +#include +#include + +namespace jsoncons { namespace msgpack { + +// encode_msgpack + +template +typename std::enable_if::value,void>::type +encode_msgpack(const T& j, std::vector& v) +{ + typedef typename T::char_type char_type; + msgpack_bytes_encoder encoder(v); + auto adaptor = make_json_content_handler_adaptor>(encoder); + j.dump(adaptor); +} + +template +typename std::enable_if::value,void>::type +encode_msgpack(const T& val, std::vector& v) +{ + msgpack_bytes_encoder encoder(v); + write_to(json(), val, encoder); +} + +template +typename std::enable_if::value,void>::type +encode_msgpack(const T& j, std::ostream& os) +{ + typedef typename T::char_type char_type; + msgpack_encoder encoder(os); + auto adaptor = make_json_content_handler_adaptor>(encoder); + j.dump(adaptor); +} + +template +typename std::enable_if::value,void>::type +encode_msgpack(const T& val, std::ostream& os) +{ + msgpack_encoder encoder(os); + write_to(json(), val, encoder); +} + +// decode_msgpack + +template +typename std::enable_if::value,T>::type +decode_msgpack(const std::vector& v) +{ + jsoncons::json_decoder decoder; + auto adaptor = make_json_content_handler_adaptor(decoder); + basic_msgpack_reader reader(v, adaptor); + std::error_code ec; + reader.read(ec); + if (ec) + { + throw ser_error(ec,reader.line(),reader.column()); + } + return decoder.get_result(); +} + +template +typename std::enable_if::value,T>::type +decode_msgpack(const std::vector& v) +{ + jsoncons::json_decoder decoder; + basic_msgpack_reader reader(v, decoder); + reader.read(); + return decoder.get_result().template as(); +} + +template +typename std::enable_if::value,T>::type +decode_msgpack(std::istream& is) +{ + jsoncons::json_decoder decoder; + auto adaptor = make_json_content_handler_adaptor(decoder); + msgpack_reader reader(is, adaptor); + std::error_code ec; + reader.read(ec); + if (ec) + { + throw ser_error(ec,reader.line(),reader.column()); + } + return decoder.get_result(); +} + +template +typename std::enable_if::value,T>::type +decode_msgpack(std::istream& is) +{ + jsoncons::json_decoder decoder; + msgpack_reader reader(is, decoder); + reader.read(); + return decoder.get_result(); +} + +#if !defined(JSONCONS_NO_DEPRECATED) +template +std::vector encode_msgpack(const Json& j) +{ + std::vector v; + encode_msgpack(j, v); + return v; +} +#endif + +}} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/msgpack/msgpack_detail.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/msgpack/msgpack_detail.hpp new file mode 100644 index 0000000000..75f8ce0702 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/msgpack/msgpack_detail.hpp @@ -0,0 +1,50 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_MSGPACK_MSGPACK_DETAIL_HPP +#define JSONCONS_MSGPACK_MSGPACK_DETAIL_HPP + +#include +#include +#include + +namespace jsoncons { namespace msgpack { namespace detail { + +namespace msgpack_format +{ + const uint8_t positive_fixint_base_cd = 0x00; + const uint8_t nil_cd = 0xc0; + const uint8_t false_cd = 0xc2; + const uint8_t true_cd = 0xc3; + const uint8_t float32_cd = 0xca; + const uint8_t float64_cd = 0xcb; + const uint8_t uint8_cd = 0xcc; + const uint8_t uint16_cd = 0xcd; + const uint8_t uint32_cd = 0xce; + const uint8_t uint64_cd = 0xcf; + const uint8_t int8_cd = 0xd0; + const uint8_t int16_cd = 0xd1; + const uint8_t int32_cd = 0xd2; + const uint8_t int64_cd = 0xd3; + const uint8_t fixmap_base_cd = 0x80; + const uint8_t fixarray_base_cd = 0x90; + const uint8_t fixstr_base_cd = 0xa0; + const uint8_t str8_cd = 0xd9; + const uint8_t str16_cd = 0xda; + const uint8_t str32_cd = 0xdb; + const uint8_t bin8_cd = 0xc7; + const uint8_t bin16_cd = 0xc8; + const uint8_t bin32_cd = 0xc9; + const uint8_t array16_cd = 0xdc; + const uint8_t array32_cd = 0xdd; + const uint8_t map16_cd = 0xde; + const uint8_t map32_cd = 0xdf; + const uint8_t negative_fixint_base_cd = 0xe0; +} + +}}} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/msgpack/msgpack_encoder.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/msgpack/msgpack_encoder.hpp new file mode 100644 index 0000000000..6240156692 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/msgpack/msgpack_encoder.hpp @@ -0,0 +1,459 @@ +// Copyright 2018 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_MSGPACK_MSGPACK_ENCODER_HPP +#define JSONCONS_MSGPACK_MSGPACK_ENCODER_HPP + +#include +#include +#include // std::numeric_limits +#include +#include // std::move +#include +#include +#include +#include +#include +#include +#include + +namespace jsoncons { namespace msgpack { + +enum class msgpack_container_type {object, indefinite_length_object, array, indefinite_length_array}; + +template +class basic_msgpack_encoder final : public basic_json_content_handler +{ + enum class decimal_parse_state { start, integer, exp1, exp2, fraction1 }; +public: + typedef char char_type; + using typename basic_json_content_handler::string_view_type; + typedef Result result_type; + +private: + struct stack_item + { + msgpack_container_type type_; + size_t length_; + size_t count_; + + stack_item(msgpack_container_type type, size_t length = 0) + : type_(type), length_(length), count_(0) + { + } + + size_t length() const + { + return length_; + } + + size_t count() const + { + return count_; + } + + bool is_object() const + { + return type_ == msgpack_container_type::object || type_ == msgpack_container_type::indefinite_length_object; + } + + bool is_indefinite_length() const + { + return type_ == msgpack_container_type::indefinite_length_array || type_ == msgpack_container_type::indefinite_length_object; + } + + }; + std::vector stack_; + Result result_; + + // Noncopyable and nonmoveable + basic_msgpack_encoder(const basic_msgpack_encoder&) = delete; + basic_msgpack_encoder& operator=(const basic_msgpack_encoder&) = delete; +public: + explicit basic_msgpack_encoder(result_type result) + : result_(std::move(result)) + { + } + + ~basic_msgpack_encoder() + { + try + { + result_.flush(); + } + catch (...) + { + } + } + +private: + // Implementing methods + + void do_flush() override + { + result_.flush(); + } + + bool do_begin_object(semantic_tag, const ser_context&) override + { + throw ser_error(msgpack_errc::object_length_required); + } + + bool do_begin_object(size_t length, semantic_tag, const ser_context&) override + { + stack_.push_back(stack_item(msgpack_container_type::object, length)); + + if (length <= 15) + { + // fixmap + jsoncons::detail::to_big_endian(static_cast(jsoncons::msgpack::detail::msgpack_format ::fixmap_base_cd | (length & 0xf)), + std::back_inserter(result_)); + } + else if (length <= 65535) + { + // map 16 + jsoncons::detail::to_big_endian(static_cast(jsoncons::msgpack::detail::msgpack_format ::map16_cd), + std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(length), + std::back_inserter(result_)); + } + else if (length <= 4294967295) + { + // map 32 + jsoncons::detail::to_big_endian(static_cast(jsoncons::msgpack::detail::msgpack_format ::map32_cd), + std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(length), + std::back_inserter(result_)); + } + + return true; + } + + bool do_end_object(const ser_context&) override + { + JSONCONS_ASSERT(!stack_.empty()); + + if (stack_.back().count() < stack_.back().length()) + { + throw ser_error( msgpack_errc::too_few_items); + } + else if (stack_.back().count() > stack_.back().length()) + { + throw ser_error( msgpack_errc::too_many_items); + } + + stack_.pop_back(); + end_value(); + return true; + } + + bool do_begin_array(semantic_tag, const ser_context&) override + { + throw ser_error(msgpack_errc::array_length_required); + } + + bool do_begin_array(size_t length, semantic_tag, const ser_context&) override + { + stack_.push_back(stack_item(msgpack_container_type::array, length)); + if (length <= 15) + { + // fixarray + jsoncons::detail::to_big_endian(static_cast(jsoncons::msgpack::detail::msgpack_format ::fixarray_base_cd | (length & 0xf)), std::back_inserter(result_)); + } + else if (length <= (std::numeric_limits::max)()) + { + // array 16 + jsoncons::detail::to_big_endian(static_cast(jsoncons::msgpack::detail::msgpack_format ::array16_cd), std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(length),std::back_inserter(result_)); + } + else if (length <= (std::numeric_limits::max)()) + { + // array 32 + jsoncons::detail::to_big_endian(static_cast(jsoncons::msgpack::detail::msgpack_format ::array32_cd), std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(length),std::back_inserter(result_)); + } + return true; + } + + bool do_end_array(const ser_context&) override + { + JSONCONS_ASSERT(!stack_.empty()); + + if (stack_.back().count() < stack_.back().length()) + { + throw ser_error(msgpack_errc::too_few_items); + } + else if (stack_.back().count() > stack_.back().length()) + { + throw ser_error(msgpack_errc::too_many_items); + } + + stack_.pop_back(); + end_value(); + return true; + } + + bool do_name(const string_view_type& name, const ser_context&) override + { + write_string_value(name); + return true; + } + + bool do_null_value(semantic_tag, const ser_context&) override + { + // nil + jsoncons::detail::to_big_endian(static_cast(jsoncons::msgpack::detail::msgpack_format ::nil_cd), std::back_inserter(result_)); + end_value(); + return true; + } + + bool do_string_value(const string_view_type& sv, semantic_tag, const ser_context&) override + { + write_string_value(sv); + end_value(); + return true; + } + + void write_string_value(const string_view_type& sv) + { + auto result = unicons::validate(sv.begin(), sv.end()); + if (result.ec != unicons::conv_errc()) + { + throw ser_error(msgpack_errc::invalid_utf8_text_string); + } + + const size_t length = sv.length(); + if (length <= 31) + { + // fixstr stores a byte array whose length is upto 31 bytes + jsoncons::detail::to_big_endian(static_cast(jsoncons::msgpack::detail::msgpack_format ::fixstr_base_cd | length), std::back_inserter(result_)); + } + else if (length <= (std::numeric_limits::max)()) + { + // str 8 stores a byte array whose length is upto (2^8)-1 bytes + jsoncons::detail::to_big_endian(static_cast(jsoncons::msgpack::detail::msgpack_format ::str8_cd), std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(length), std::back_inserter(result_)); + } + else if (length <= (std::numeric_limits::max)()) + { + // str 16 stores a byte array whose length is upto (2^16)-1 bytes + jsoncons::detail::to_big_endian(static_cast(jsoncons::msgpack::detail::msgpack_format ::str16_cd), std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(length), std::back_inserter(result_)); + } + else if (length <= (std::numeric_limits::max)()) + { + // str 32 stores a byte array whose length is upto (2^32)-1 bytes + jsoncons::detail::to_big_endian(static_cast(jsoncons::msgpack::detail::msgpack_format ::str32_cd), std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(length),std::back_inserter(result_)); + } + + for (auto c : sv) + { + result_.push_back(c); + } + } + + bool do_byte_string_value(const byte_string_view& b, + semantic_tag, + const ser_context&) override + { + + const size_t length = b.length(); + if (length <= (std::numeric_limits::max)()) + { + // str 8 stores a byte array whose length is upto (2^8)-1 bytes + jsoncons::detail::to_big_endian(static_cast(jsoncons::msgpack::detail::msgpack_format ::bin8_cd), std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(length), std::back_inserter(result_)); + } + else if (length <= (std::numeric_limits::max)()) + { + // str 16 stores a byte array whose length is upto (2^16)-1 bytes + jsoncons::detail::to_big_endian(static_cast(jsoncons::msgpack::detail::msgpack_format ::bin16_cd), std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(length), std::back_inserter(result_)); + } + else if (length <= (std::numeric_limits::max)()) + { + // str 32 stores a byte array whose length is upto (2^32)-1 bytes + jsoncons::detail::to_big_endian(static_cast(jsoncons::msgpack::detail::msgpack_format ::bin32_cd), std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(length),std::back_inserter(result_)); + } + + for (auto c : b) + { + result_.push_back(c); + } + + end_value(); + return true; + } + + bool do_double_value(double val, + semantic_tag, + const ser_context&) override + { + float valf = (float)val; + if ((double)valf == val) + { + // float 32 + jsoncons::detail::to_big_endian(static_cast(jsoncons::msgpack::detail::msgpack_format ::float32_cd), std::back_inserter(result_)); + jsoncons::detail::to_big_endian(valf,std::back_inserter(result_)); + } + else + { + // float 64 + jsoncons::detail::to_big_endian(static_cast(jsoncons::msgpack::detail::msgpack_format ::float64_cd), std::back_inserter(result_)); + jsoncons::detail::to_big_endian(val,std::back_inserter(result_)); + } + + // write double + + end_value(); + return true; + } + + bool do_int64_value(int64_t val, + semantic_tag, + const ser_context&) override + { + if (val >= 0) + { + if (val <= 0x7f) + { + // positive fixnum stores 7-bit positive integer + jsoncons::detail::to_big_endian(static_cast(val),std::back_inserter(result_)); + } + else if (val <= (std::numeric_limits::max)()) + { + // uint 8 stores a 8-bit unsigned integer + jsoncons::detail::to_big_endian(static_cast(jsoncons::msgpack::detail::msgpack_format ::uint8_cd), std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(val),std::back_inserter(result_)); + } + else if (val <= (std::numeric_limits::max)()) + { + // uint 16 stores a 16-bit big-endian unsigned integer + jsoncons::detail::to_big_endian(static_cast(jsoncons::msgpack::detail::msgpack_format ::uint16_cd), std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(val),std::back_inserter(result_)); + } + else if (val <= (std::numeric_limits::max)()) + { + // uint 32 stores a 32-bit big-endian unsigned integer + jsoncons::detail::to_big_endian(static_cast(jsoncons::msgpack::detail::msgpack_format ::uint32_cd), std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(val),std::back_inserter(result_)); + } + else if (val <= (std::numeric_limits::max)()) + { + // int 64 stores a 64-bit big-endian signed integer + jsoncons::detail::to_big_endian(static_cast(jsoncons::msgpack::detail::msgpack_format ::uint64_cd), std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(val),std::back_inserter(result_)); + } + } + else + { + if (val >= -32) + { + // negative fixnum stores 5-bit negative integer + jsoncons::detail::to_big_endian(static_cast(val), std::back_inserter(result_)); + } + else if (val >= (std::numeric_limits::lowest)()) + { + // int 8 stores a 8-bit signed integer + jsoncons::detail::to_big_endian(static_cast(jsoncons::msgpack::detail::msgpack_format ::int8_cd), std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(val),std::back_inserter(result_)); + } + else if (val >= (std::numeric_limits::lowest)()) + { + // int 16 stores a 16-bit big-endian signed integer + jsoncons::detail::to_big_endian(static_cast(jsoncons::msgpack::detail::msgpack_format ::int16_cd), std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(val),std::back_inserter(result_)); + } + else if (val >= (std::numeric_limits::lowest)()) + { + // int 32 stores a 32-bit big-endian signed integer + jsoncons::detail::to_big_endian(static_cast(jsoncons::msgpack::detail::msgpack_format ::int32_cd), std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(val),std::back_inserter(result_)); + } + else if (val >= (std::numeric_limits::lowest)()) + { + // int 64 stores a 64-bit big-endian signed integer + jsoncons::detail::to_big_endian(static_cast(jsoncons::msgpack::detail::msgpack_format ::int64_cd), std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(val),std::back_inserter(result_)); + } + } + end_value(); + return true; + } + + bool do_uint64_value(uint64_t val, + semantic_tag, + const ser_context&) override + { + if (val <= (std::numeric_limits::max)()) + { + // positive fixnum stores 7-bit positive integer + jsoncons::detail::to_big_endian(static_cast(val), std::back_inserter(result_)); + } + else if (val <= (std::numeric_limits::max)()) + { + // uint 8 stores a 8-bit unsigned integer + jsoncons::detail::to_big_endian(static_cast(jsoncons::msgpack::detail::msgpack_format ::uint8_cd), std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(val), std::back_inserter(result_)); + } + else if (val <= (std::numeric_limits::max)()) + { + // uint 16 stores a 16-bit big-endian unsigned integer + jsoncons::detail::to_big_endian(static_cast(jsoncons::msgpack::detail::msgpack_format ::uint16_cd), std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(val),std::back_inserter(result_)); + } + else if (val <= (std::numeric_limits::max)()) + { + // uint 32 stores a 32-bit big-endian unsigned integer + jsoncons::detail::to_big_endian(static_cast(jsoncons::msgpack::detail::msgpack_format ::uint32_cd), std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(val),std::back_inserter(result_)); + } + else if (val <= (std::numeric_limits::max)()) + { + // uint 64 stores a 64-bit big-endian unsigned integer + jsoncons::detail::to_big_endian(static_cast(jsoncons::msgpack::detail::msgpack_format ::uint64_cd), std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(val),std::back_inserter(result_)); + } + end_value(); + return true; + } + + bool do_bool_value(bool val, semantic_tag, const ser_context&) override + { + // true and false + result_.push_back(static_cast(val ? jsoncons::msgpack::detail::msgpack_format ::true_cd : jsoncons::msgpack::detail::msgpack_format ::false_cd)); + //jsoncons::detail::to_big_endian(static_cast(val ? jsoncons::msgpack::detail::msgpack_format ::true_cd : jsoncons::msgpack::detail::msgpack_format ::false_cd), std::back_inserter(result_)); + + end_value(); + return true; + } + + void end_value() + { + if (!stack_.empty()) + { + ++stack_.back().count_; + } + } +}; + +typedef basic_msgpack_encoder msgpack_encoder; +typedef basic_msgpack_encoder msgpack_bytes_encoder; + +#if !defined(JSONCONS_NO_DEPRECATED) +typedef basic_msgpack_encoder msgpack_bytes_serializer; + +template +using basic_msgpack_serializer = basic_msgpack_encoder; + +typedef basic_msgpack_serializer msgpack_serializer; +typedef basic_msgpack_serializer msgpack_buffer_serializer; +#endif + +}} +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/msgpack/msgpack_error.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/msgpack/msgpack_error.hpp new file mode 100644 index 0000000000..3b2d1d7b05 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/msgpack/msgpack_error.hpp @@ -0,0 +1,82 @@ +/// Copyright 2018 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_MSGPACK_MSGPACK_ERROR_HPP +#define JSONCONS_MSGPACK_MSGPACK_ERROR_HPP + +#include +#include + +namespace jsoncons { namespace msgpack { + +enum class msgpack_errc +{ + ok = 0, + unexpected_eof = 1, + source_error, + invalid_utf8_text_string, + array_length_required, + object_length_required, + too_many_items, + too_few_items +}; + +class msgpack_error_category_impl + : public std::error_category +{ +public: + const char* name() const noexcept override + { + return "jsoncons/msgpack"; + } + std::string message(int ev) const override + { + switch (static_cast(ev)) + { + case msgpack_errc::unexpected_eof: + return "Unexpected end of file"; + case msgpack_errc::source_error: + return "Source error"; + case msgpack_errc::invalid_utf8_text_string: + return "Illegal UTF-8 encoding in text string"; + case msgpack_errc::array_length_required: + return "MessagePack encoder requires array length"; + case msgpack_errc::object_length_required: + return "MessagePack encoder requires object length"; + case msgpack_errc::too_many_items: + return "Too many items were added to a MessagePack object or array"; + case msgpack_errc::too_few_items: + return "Too few items were added to a MessagePack object or array"; + default: + return "Unknown MessagePack parser error"; + } + } +}; + +inline +const std::error_category& msgpack_error_category() +{ + static msgpack_error_category_impl instance; + return instance; +} + +inline +std::error_code make_error_code(msgpack_errc e) +{ + return std::error_code(static_cast(e),msgpack_error_category()); +} + + +}} + +namespace std { + template<> + struct is_error_code_enum : public true_type + { + }; +} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/msgpack/msgpack_reader.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/msgpack/msgpack_reader.hpp new file mode 100644 index 0000000000..8970675855 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/msgpack/msgpack_reader.hpp @@ -0,0 +1,757 @@ +// Copyright 2017 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_MSGPACK_MSGPACK_READER_HPP +#define JSONCONS_MSGPACK_MSGPACK_READER_HPP + +#include +#include +#include +#include // std::move +#include +#include +#include +#include +#include +#include + +namespace jsoncons { namespace msgpack { + +template +class basic_msgpack_reader : public ser_context +{ + Src source_; + json_content_handler& handler_; + size_t nesting_depth_; + std::string buffer_; +public: + template + basic_msgpack_reader(Source&& source, json_content_handler& handler) + : source_(std::forward(source)), + handler_(handler), + nesting_depth_(0) + { + } + + void read() + { + std::error_code ec; + read(ec); + if (ec) + { + throw ser_error(ec,line(),column()); + } + } + + void read(std::error_code& ec) + { + try + { + read_internal(ec); + } + catch (const ser_error& e) + { + ec = e.code(); + } + } + + size_t line() const override + { + return 0; + } + + size_t column() const override + { + return source_.position(); + } +private: + + void read_internal(std::error_code& ec) + { + if (source_.is_error()) + { + ec = msgpack_errc::source_error; + return; + } + //const uint8_t* pos = input_ptr_++; + + uint8_t type{}; + source_.get(type); + + if (type <= 0xbf) + { + if (type <= 0x7f) + { + // positive fixint + handler_.uint64_value(type, semantic_tag::none, *this); + } + else if (type <= 0x8f) + { + // fixmap + const size_t len = type & 0x0f; + handler_.begin_object(len, semantic_tag::none, *this); + ++nesting_depth_; + for (size_t i = 0; i < len; ++i) + { + parse_name(ec); + if (ec) + { + return; + } + read(ec); + if (ec) + { + return; + } + } + handler_.end_object(*this); + --nesting_depth_; + } + else if (type <= 0x9f) + { + // fixarray + const size_t len = type & 0x0f; + handler_.begin_array(len, semantic_tag::none, *this); + ++nesting_depth_; + for (size_t i = 0; i < len; ++i) + { + read(ec); + if (ec) + { + return; + } + } + handler_.end_array(*this); + --nesting_depth_; + } + else + { + // fixstr + const size_t len = type & 0x1f; + + std::basic_string s; + source_.read(std::back_inserter(s), len); + if (source_.eof()) + { + ec = msgpack_errc::unexpected_eof; + return; + } + + auto result = unicons::validate(s.begin(),s.end()); + if (result.ec != unicons::conv_errc()) + { + ec = msgpack_errc::invalid_utf8_text_string; + return; + } + handler_.string_value(basic_string_view(s.data(),s.length()), semantic_tag::none, *this); + } + } + else if (type >= 0xe0) + { + // negative fixint + handler_.int64_value(static_cast(type), semantic_tag::none, *this); + } + else + { + switch (type) + { + case jsoncons::msgpack::detail::msgpack_format ::nil_cd: + { + handler_.null_value(semantic_tag::none, *this); + break; + } + case jsoncons::msgpack::detail::msgpack_format ::true_cd: + { + handler_.bool_value(true, semantic_tag::none, *this); + break; + } + case jsoncons::msgpack::detail::msgpack_format ::false_cd: + { + handler_.bool_value(false, semantic_tag::none, *this); + break; + } + case jsoncons::msgpack::detail::msgpack_format ::float32_cd: + { + uint8_t buf[sizeof(float)]; + source_.read(buf, sizeof(float)); + if (source_.eof()) + { + ec = msgpack_errc::unexpected_eof; + return; + } + const uint8_t* endp; + float val = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + handler_.double_value(val, semantic_tag::none, *this); + break; + } + + case jsoncons::msgpack::detail::msgpack_format ::float64_cd: + { + uint8_t buf[sizeof(double)]; + source_.read(buf, sizeof(double)); + if (source_.eof()) + { + ec = msgpack_errc::unexpected_eof; + return; + } + const uint8_t* endp; + double val = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + handler_.double_value(val, semantic_tag::none, *this); + break; + } + + case jsoncons::msgpack::detail::msgpack_format ::uint8_cd: + { + uint8_t val{}; + source_.get(val); + handler_.uint64_value(val, semantic_tag::none, *this); + break; + } + + case jsoncons::msgpack::detail::msgpack_format ::uint16_cd: + { + uint8_t buf[sizeof(uint16_t)]; + source_.read(buf, sizeof(uint16_t)); + if (source_.eof()) + { + ec = msgpack_errc::unexpected_eof; + return; + } + const uint8_t* endp; + uint16_t val = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + handler_.uint64_value(val, semantic_tag::none, *this); + break; + } + + case jsoncons::msgpack::detail::msgpack_format ::uint32_cd: + { + uint8_t buf[sizeof(uint32_t)]; + source_.read(buf, sizeof(uint32_t)); + if (source_.eof()) + { + ec = msgpack_errc::unexpected_eof; + return; + } + const uint8_t* endp; + uint32_t val = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + handler_.uint64_value(val, semantic_tag::none, *this); + break; + } + + case jsoncons::msgpack::detail::msgpack_format ::uint64_cd: + { + uint8_t buf[sizeof(uint64_t)]; + source_.read(buf, sizeof(uint64_t)); + if (source_.eof()) + { + ec = msgpack_errc::unexpected_eof; + return; + } + const uint8_t* endp; + uint64_t val = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + handler_.uint64_value(val, semantic_tag::none, *this); + break; + } + + case jsoncons::msgpack::detail::msgpack_format ::int8_cd: + { + uint8_t buf[sizeof(int8_t)]; + source_.read(buf, sizeof(int8_t)); + if (source_.eof()) + { + ec = msgpack_errc::unexpected_eof; + return; + } + const uint8_t* endp; + int8_t val = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + handler_.int64_value(val, semantic_tag::none, *this); + break; + } + + case jsoncons::msgpack::detail::msgpack_format ::int16_cd: + { + uint8_t buf[sizeof(int16_t)]; + source_.read(buf, sizeof(int16_t)); + if (source_.eof()) + { + ec = msgpack_errc::unexpected_eof; + return; + } + const uint8_t* endp; + int16_t val = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + handler_.int64_value(val, semantic_tag::none, *this); + break; + } + + case jsoncons::msgpack::detail::msgpack_format ::int32_cd: + { + uint8_t buf[sizeof(int32_t)]; + source_.read(buf, sizeof(int32_t)); + if (source_.eof()) + { + ec = msgpack_errc::unexpected_eof; + return; + } + const uint8_t* endp; + int32_t val = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + handler_.int64_value(val, semantic_tag::none, *this); + break; + } + + case jsoncons::msgpack::detail::msgpack_format ::int64_cd: + { + uint8_t buf[sizeof(int64_t)]; + source_.read(buf, sizeof(int64_t)); + if (source_.eof()) + { + ec = msgpack_errc::unexpected_eof; + return; + } + const uint8_t* endp; + int64_t val = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + handler_.int64_value(val, semantic_tag::none, *this); + break; + } + + case jsoncons::msgpack::detail::msgpack_format ::str8_cd: + { + uint8_t buf[sizeof(int8_t)]; + source_.read(buf, sizeof(int8_t)); + if (source_.eof()) + { + ec = msgpack_errc::unexpected_eof; + return; + } + const uint8_t* endp; + int8_t len = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + + std::basic_string s; + source_.read(std::back_inserter(s), len); + if (source_.eof()) + { + ec = msgpack_errc::unexpected_eof; + return; + } + auto result = unicons::validate(s.begin(),s.end()); + if (result.ec != unicons::conv_errc()) + { + ec = msgpack_errc::invalid_utf8_text_string; + return; + } + handler_.string_value(basic_string_view(s.data(),s.length()), semantic_tag::none, *this); + break; + } + + case jsoncons::msgpack::detail::msgpack_format ::str16_cd: + { + uint8_t buf[sizeof(int16_t)]; + source_.read(buf, sizeof(int16_t)); + if (source_.eof()) + { + ec = msgpack_errc::unexpected_eof; + return; + } + const uint8_t* endp; + int16_t len = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + + std::basic_string s; + source_.read(std::back_inserter(s), len); + if (source_.eof()) + { + ec = msgpack_errc::unexpected_eof; + return; + } + + auto result = unicons::validate(s.begin(),s.end()); + if (result.ec != unicons::conv_errc()) + { + ec = msgpack_errc::invalid_utf8_text_string; + return; + } + handler_.string_value(basic_string_view(s.data(),s.length()), semantic_tag::none, *this); + break; + } + + case jsoncons::msgpack::detail::msgpack_format ::str32_cd: + { + uint8_t buf[sizeof(int32_t)]; + source_.read(buf, sizeof(int32_t)); + if (source_.eof()) + { + ec = msgpack_errc::unexpected_eof; + return; + } + const uint8_t* endp; + int32_t len = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + + std::basic_string s; + source_.read(std::back_inserter(s), len); + if (source_.eof()) + { + ec = msgpack_errc::unexpected_eof; + return; + } + + auto result = unicons::validate(s.begin(),s.end()); + if (result.ec != unicons::conv_errc()) + { + ec = msgpack_errc::invalid_utf8_text_string; + return; + } + handler_.string_value(basic_string_view(s.data(),s.length()), semantic_tag::none, *this); + break; + } + + case jsoncons::msgpack::detail::msgpack_format ::bin8_cd: + { + uint8_t buf[sizeof(int8_t)]; + source_.read(buf, sizeof(int8_t)); + if (source_.eof()) + { + ec = msgpack_errc::unexpected_eof; + return; + } + const uint8_t* endp; + int8_t len = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + + std::vector v; + v.reserve(len); + source_.read(std::back_inserter(v), len); + if (source_.eof()) + { + ec = msgpack_errc::unexpected_eof; + return; + } + + handler_.byte_string_value(byte_string_view(v.data(),v.size()), + semantic_tag::none, + *this); + break; + } + + case jsoncons::msgpack::detail::msgpack_format ::bin16_cd: + { + uint8_t buf[sizeof(int16_t)]; + source_.read(buf, sizeof(int16_t)); + if (source_.eof()) + { + ec = msgpack_errc::unexpected_eof; + return; + } + const uint8_t* endp; + int16_t len = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + + std::vector v; + v.reserve(len); + source_.read(std::back_inserter(v), len); + if (source_.eof()) + { + ec = msgpack_errc::unexpected_eof; + return; + } + + handler_.byte_string_value(byte_string_view(v.data(),v.size()), + semantic_tag::none, + *this); + break; + } + + case jsoncons::msgpack::detail::msgpack_format ::bin32_cd: + { + uint8_t buf[sizeof(int32_t)]; + source_.read(buf, sizeof(int32_t)); + if (source_.eof()) + { + ec = msgpack_errc::unexpected_eof; + return; + } + const uint8_t* endp; + int32_t len = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + + std::vector v; + v.reserve(len); + source_.read(std::back_inserter(v), len); + if (source_.eof()) + { + ec = msgpack_errc::unexpected_eof; + return; + } + + handler_.byte_string_value(byte_string_view(v.data(),v.size()), + semantic_tag::none, + *this); + break; + } + + case jsoncons::msgpack::detail::msgpack_format ::array16_cd: + { + uint8_t buf[sizeof(int16_t)]; + source_.read(buf, sizeof(int16_t)); + if (source_.eof()) + { + ec = msgpack_errc::unexpected_eof; + return; + } + const uint8_t* endp; + int16_t len = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + + handler_.begin_array(len, semantic_tag::none, *this); + ++nesting_depth_; + for (int16_t i = 0; i < len; ++i) + { + read(ec); + if (ec) + { + return; + } + } + handler_.end_array(*this); + --nesting_depth_; + break; + } + + case jsoncons::msgpack::detail::msgpack_format ::array32_cd: + { + uint8_t buf[sizeof(int32_t)]; + source_.read(buf, sizeof(int32_t)); + if (source_.eof()) + { + ec = msgpack_errc::unexpected_eof; + return; + } + const uint8_t* endp; + int32_t len = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + + handler_.begin_array(len, semantic_tag::none, *this); + ++nesting_depth_; + for (int32_t i = 0; i < len; ++i) + { + read(ec); + if (ec) + { + return; + } + } + handler_.end_array(*this); + --nesting_depth_; + break; + } + + case jsoncons::msgpack::detail::msgpack_format ::map16_cd : + { + uint8_t buf[sizeof(int16_t)]; + source_.read(buf, sizeof(int16_t)); + if (source_.eof()) + { + ec = msgpack_errc::unexpected_eof; + return; + } + const uint8_t* endp; + int16_t len = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + + handler_.begin_object(len, semantic_tag::none, *this); + ++nesting_depth_; + for (int16_t i = 0; i < len; ++i) + { + parse_name(ec); + if (ec) + { + return; + } + read(ec); + if (ec) + { + return; + } + } + handler_.end_object(*this); + --nesting_depth_; + break; + } + + case jsoncons::msgpack::detail::msgpack_format ::map32_cd : + { + uint8_t buf[sizeof(int32_t)]; + source_.read(buf, sizeof(int32_t)); + if (source_.eof()) + { + ec = msgpack_errc::unexpected_eof; + return; + } + const uint8_t* endp; + int32_t len = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + + handler_.begin_object(len, semantic_tag::none, *this); + ++nesting_depth_; + for (int32_t i = 0; i < len; ++i) + { + parse_name(ec); + if (ec) + { + return; + } + read(ec); + if (ec) + { + return; + } + } + handler_.end_object(*this); + --nesting_depth_; + break; + } + + default: + { + //error + } + } + } + } + + void parse_name(std::error_code& ec) + { + uint8_t type{}; + source_.get(type); + if (source_.eof()) + { + ec = msgpack_errc::unexpected_eof; + return; + } + + //const uint8_t* pos = input_ptr_++; + if (type >= 0xa0 && type <= 0xbf) + { + // fixstr + const size_t len = type & 0x1f; + + std::basic_string s; + source_.read(std::back_inserter(s), len); + if (source_.eof()) + { + ec = msgpack_errc::unexpected_eof; + return; + } + auto result = unicons::validate(s.begin(),s.end()); + if (result.ec != unicons::conv_errc()) + { + ec = msgpack_errc::invalid_utf8_text_string; + return; + } + handler_.name(basic_string_view(s.data(),s.length()), *this); + } + else + { + switch (type) + { + case jsoncons::msgpack::detail::msgpack_format ::str8_cd: + { + uint8_t buf[sizeof(int8_t)]; + source_.read(buf, sizeof(int8_t)); + if (source_.eof()) + { + ec = msgpack_errc::unexpected_eof; + return; + } + const uint8_t* endp; + int8_t len = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + + std::basic_string s; + source_.read(std::back_inserter(s), len); + if (source_.eof()) + { + ec = msgpack_errc::unexpected_eof; + return; + } + + auto result = unicons::validate(s.begin(),s.end()); + if (result.ec != unicons::conv_errc()) + { + ec = msgpack_errc::invalid_utf8_text_string; + return; + } + handler_.name(basic_string_view(s.data(),s.length()), *this); + break; + } + + case jsoncons::msgpack::detail::msgpack_format ::str16_cd: + { + uint8_t buf[sizeof(int16_t)]; + source_.read(buf, sizeof(int16_t)); + if (source_.eof()) + { + ec = msgpack_errc::unexpected_eof; + return; + } + const uint8_t* endp; + int16_t len = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + + std::basic_string s; + source_.read(std::back_inserter(s), len); + if (source_.eof()) + { + ec = msgpack_errc::unexpected_eof; + return; + } + + //std::basic_string s; + //auto result = unicons::convert( + // first, last,std::back_inserter(s),unicons::conv_flags::strict); + //if (result.ec != unicons::conv_errc()) + //{ + // JSONCONS_THROW(json_runtime_error("Illegal unicode")); + //} + handler_.name(basic_string_view(s.data(),s.length()), *this); + break; + } + + case jsoncons::msgpack::detail::msgpack_format ::str32_cd: + { + uint8_t buf[sizeof(int32_t)]; + source_.read(buf, sizeof(int32_t)); + if (source_.eof()) + { + ec = msgpack_errc::unexpected_eof; + return; + } + const uint8_t* endp; + int32_t len = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + + std::basic_string s; + source_.read(std::back_inserter(s), len); + if (source_.eof()) + { + ec = msgpack_errc::unexpected_eof; + return; + } + + //std::basic_string s; + //auto result = unicons::convert( + // first, last,std::back_inserter(s),unicons::conv_flags::strict); + //if (result.ec != unicons::conv_errc()) + //{ + // JSONCONS_THROW(json_runtime_error("Illegal unicode")); + //} + handler_.name(basic_string_view(s.data(),s.length()), *this); + break; + } + } + + } + } +}; + +typedef basic_msgpack_reader msgpack_reader; + +typedef basic_msgpack_reader msgpack_bytes_reader; + +#if !defined(JSONCONS_NO_DEPRECATED) +typedef msgpack_bytes_reader msgpack_buffer_reader; +#endif + +}} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/ubjson/ubjson.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/ubjson/ubjson.hpp new file mode 100644 index 0000000000..d30c562c41 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/ubjson/ubjson.hpp @@ -0,0 +1,106 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_UBJSON_UBJSON_HPP +#define JSONCONS_UBJSON_UBJSON_HPP + +#include +#include +#include +#include // std::enable_if +#include // std::basic_istream +#include +#include +#include +#include + +namespace jsoncons { namespace ubjson { + +// encode_ubjson + +template +typename std::enable_if::value,void>::type +encode_ubjson(const T& j, std::vector& v) +{ + typedef typename T::char_type char_type; + ubjson_bytes_encoder encoder(v); + auto adaptor = make_json_content_handler_adaptor>(encoder); + j.dump(adaptor); +} + +template +typename std::enable_if::value,void>::type +encode_ubjson(const T& val, std::vector& v) +{ + ubjson_bytes_encoder encoder(v); + write_to(json(), val, encoder); +} + +template +typename std::enable_if::value,void>::type +encode_ubjson(const T& j, std::ostream& os) +{ + typedef typename T::char_type char_type; + ubjson_encoder encoder(os); + auto adaptor = make_json_content_handler_adaptor>(encoder); + j.dump(adaptor); +} + +template +typename std::enable_if::value,void>::type +encode_ubjson(const T& val, std::ostream& os) +{ + ubjson_encoder encoder(os); + write_to(json(), val, encoder); +} + +// decode_ubjson + +template +typename std::enable_if::value,T>::type +decode_ubjson(const std::vector& v) +{ + jsoncons::json_decoder decoder; + auto adaptor = make_json_content_handler_adaptor(decoder); + basic_ubjson_reader reader(v, adaptor); + reader.read(); + return decoder.get_result(); +} + +template +typename std::enable_if::value,T>::type +decode_ubjson(const std::vector& v) +{ + jsoncons::json_decoder decoder; + basic_ubjson_reader reader(v, decoder); + reader.read(); + return decoder.get_result().template as(); +} + +template +typename std::enable_if::value,T>::type +decode_ubjson(std::istream& is) +{ + jsoncons::json_decoder decoder; + auto adaptor = make_json_content_handler_adaptor(decoder); + ubjson_reader reader(is, adaptor); + reader.read(); + return decoder.get_result(); +} + +template +typename std::enable_if::value,T>::type +decode_ubjson(std::istream& is) +{ + jsoncons::json_decoder decoder; + ubjson_reader reader(is, decoder); + reader.read(); + return decoder.get_result(); +} + +}} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/ubjson/ubjson_detail.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/ubjson/ubjson_detail.hpp new file mode 100644 index 0000000000..99f2bf922c --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/ubjson/ubjson_detail.hpp @@ -0,0 +1,42 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_UBJSON_UBJSON_DETAIL_HPP +#define JSONCONS_UBJSON_UBJSON_DETAIL_HPP + +#include +#include +#include + +namespace jsoncons { namespace ubjson { namespace detail { + +namespace ubjson_format +{ + const uint8_t null_type = 'Z'; + const uint8_t no_op_type = 'N'; + const uint8_t true_type = 'T'; + const uint8_t false_type = 'F'; + const uint8_t int8_type = 'i'; + const uint8_t uint8_type = 'U'; + const uint8_t int16_type = 'I'; + const uint8_t int32_type = 'l'; + const uint8_t int64_type = 'L'; + const uint8_t float32_type = 'd'; + const uint8_t float64_type = 'D'; + const uint8_t high_precision_number_type = 'H'; + const uint8_t char_type = 'C'; + const uint8_t string_type = 'S'; + const uint8_t start_array_marker = '['; + const uint8_t end_array_marker = ']'; + const uint8_t start_object_marker = '{'; + const uint8_t end_object_marker = '}'; + const uint8_t type_marker = '$'; + const uint8_t count_marker = '#'; +} + +}}} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/ubjson/ubjson_encoder.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/ubjson/ubjson_encoder.hpp new file mode 100644 index 0000000000..10085420c8 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/ubjson/ubjson_encoder.hpp @@ -0,0 +1,433 @@ +// Copyright 2018 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_UBJSON_UBJSON_ENCODER_HPP +#define JSONCONS_UBJSON_UBJSON_ENCODER_HPP + +#include +#include +#include // std::numeric_limits +#include +#include // std::move +#include +#include +#include +#include +#include +#include +#include + +namespace jsoncons { namespace ubjson { + +enum class ubjson_container_type {object, indefinite_length_object, array, indefinite_length_array}; + +template +class basic_ubjson_encoder final : public basic_json_content_handler +{ + + enum class decimal_parse_state { start, integer, exp1, exp2, fraction1 }; +public: + using typename basic_json_content_handler::string_view_type; + typedef Result result_type; + +private: + struct stack_item + { + ubjson_container_type type_; + size_t length_; + size_t count_; + + stack_item(ubjson_container_type type, size_t length = 0) + : type_(type), length_(length), count_(0) + { + } + + size_t length() const + { + return length_; + } + + size_t count() const + { + return count_; + } + + bool is_object() const + { + return type_ == ubjson_container_type::object || type_ == ubjson_container_type::indefinite_length_object; + } + + bool is_indefinite_length() const + { + return type_ == ubjson_container_type::indefinite_length_array || type_ == ubjson_container_type::indefinite_length_object; + } + + }; + std::vector stack_; + Result result_; + + // Noncopyable and nonmoveable + basic_ubjson_encoder(const basic_ubjson_encoder&) = delete; + basic_ubjson_encoder& operator=(const basic_ubjson_encoder&) = delete; +public: + basic_ubjson_encoder(result_type result) + : result_(std::move(result)) + { + } + + ~basic_ubjson_encoder() + { + try + { + result_.flush(); + } + catch (...) + { + } + } + +private: + // Implementing methods + + void do_flush() override + { + result_.flush(); + } + + bool do_begin_object(semantic_tag, const ser_context&) override + { + stack_.push_back(stack_item(ubjson_container_type::indefinite_length_object)); + result_.push_back(jsoncons::ubjson::detail::ubjson_format::start_object_marker); + + return true; + } + + bool do_begin_object(size_t length, semantic_tag, const ser_context&) override + { + stack_.push_back(stack_item(ubjson_container_type::object, length)); + result_.push_back(jsoncons::ubjson::detail::ubjson_format::start_object_marker); + result_.push_back(jsoncons::ubjson::detail::ubjson_format::count_marker); + put_length(length); + + return true; + } + + bool do_end_object(const ser_context&) override + { + JSONCONS_ASSERT(!stack_.empty()); + if (stack_.back().is_indefinite_length()) + { + result_.push_back(jsoncons::ubjson::detail::ubjson_format::end_object_marker); + } + else + { + if (stack_.back().count() < stack_.back().length()) + { + throw ser_error(ubjson_errc::too_few_items); + } + if (stack_.back().count() > stack_.back().length()) + { + throw ser_error(ubjson_errc::too_many_items); + } + } + stack_.pop_back(); + end_value(); + return true; + } + + bool do_begin_array(semantic_tag, const ser_context&) override + { + stack_.push_back(stack_item(ubjson_container_type::indefinite_length_array)); + result_.push_back(jsoncons::ubjson::detail::ubjson_format::start_array_marker); + + return true; + } + + bool do_begin_array(size_t length, semantic_tag, const ser_context&) override + { + stack_.push_back(stack_item(ubjson_container_type::array, length)); + result_.push_back(jsoncons::ubjson::detail::ubjson_format::start_array_marker); + result_.push_back(jsoncons::ubjson::detail::ubjson_format::count_marker); + put_length(length); + + return true; + } + + bool do_end_array(const ser_context&) override + { + JSONCONS_ASSERT(!stack_.empty()); + if (stack_.back().is_indefinite_length()) + { + result_.push_back(jsoncons::ubjson::detail::ubjson_format::end_array_marker); + } + else + { + if (stack_.back().count() < stack_.back().length()) + { + throw ser_error(ubjson_errc::too_few_items); + } + if (stack_.back().count() > stack_.back().length()) + { + throw ser_error(ubjson_errc::too_many_items); + } + } + stack_.pop_back(); + end_value(); + return true; + } + + bool do_name(const string_view_type& name, const ser_context&) override + { + auto result = unicons::validate(name.begin(), name.end()); + if (result.ec != unicons::conv_errc()) + { + throw ser_error(ubjson_errc::invalid_utf8_text_string); + } + + put_length(name.length()); + + for (auto c : name) + { + result_.push_back(c); + } + return true; + } + + bool do_null_value(semantic_tag, const ser_context&) override + { + // nil + jsoncons::detail::to_big_endian(static_cast(jsoncons::ubjson::detail::ubjson_format::null_type), std::back_inserter(result_)); + end_value(); + return true; + } + + bool do_string_value(const string_view_type& sv, semantic_tag tag, const ser_context&) override + { + switch (tag) + { + case semantic_tag::bigint: + case semantic_tag::bigdec: + { + result_.push_back(jsoncons::ubjson::detail::ubjson_format::high_precision_number_type); + break; + } + default: + { + result_.push_back(jsoncons::ubjson::detail::ubjson_format::string_type); + break; + } + } + + auto result = unicons::validate(sv.begin(), sv.end()); + if (result.ec != unicons::conv_errc()) + { + JSONCONS_THROW(json_runtime_error("Illegal unicode")); + } + + put_length(sv.length()); + + for (auto c : sv) + { + result_.push_back(c); + } + + end_value(); + return true; + } + + void put_length(size_t length) + { + if (length <= (std::numeric_limits::max)()) + { + result_.push_back('U'); + jsoncons::detail::to_big_endian(static_cast(length), std::back_inserter(result_)); + } + else if (length <= (size_t)(std::numeric_limits::max)()) + { + result_.push_back('I'); + jsoncons::detail::to_big_endian(static_cast(length), std::back_inserter(result_)); + } + else if (length <= (uint32_t)(std::numeric_limits::max)()) + { + result_.push_back('l'); + jsoncons::detail::to_big_endian(static_cast(length),std::back_inserter(result_)); + } + else if (length <= (uint64_t)(std::numeric_limits::max)()) + { + result_.push_back('L'); + jsoncons::detail::to_big_endian(static_cast(length),std::back_inserter(result_)); + } + } + + bool do_byte_string_value(const byte_string_view& b, + semantic_tag, + const ser_context&) override + { + + const size_t length = b.length(); + result_.push_back(jsoncons::ubjson::detail::ubjson_format::start_array_marker); + jsoncons::detail::to_big_endian(static_cast(jsoncons::ubjson::detail::ubjson_format::type_marker), std::back_inserter(result_)); + jsoncons::detail::to_big_endian(static_cast(jsoncons::ubjson::detail::ubjson_format::uint8_type), std::back_inserter(result_)); + put_length(length); + + for (auto c : b) + { + result_.push_back(c); + } + + end_value(); + return true; + } + + bool do_double_value(double val, + semantic_tag, + const ser_context&) override + { + float valf = (float)val; + if ((double)valf == val) + { + // float 32 + result_.push_back(static_cast(jsoncons::ubjson::detail::ubjson_format::float32_type)); + jsoncons::detail::to_big_endian(valf,std::back_inserter(result_)); + } + else + { + // float 64 + result_.push_back(static_cast(jsoncons::ubjson::detail::ubjson_format::float64_type)); + jsoncons::detail::to_big_endian(val,std::back_inserter(result_)); + } + + // write double + + end_value(); + return true; + } + + bool do_int64_value(int64_t val, + semantic_tag, + const ser_context&) override + { + if (val >= 0) + { + if (val <= (std::numeric_limits::max)()) + { + // uint 8 stores a 8-bit unsigned integer + result_.push_back(jsoncons::ubjson::detail::ubjson_format::uint8_type); + jsoncons::detail::to_big_endian(static_cast(val),std::back_inserter(result_)); + } + else if (val <= (std::numeric_limits::max)()) + { + // uint 16 stores a 16-bit big-endian unsigned integer + result_.push_back(jsoncons::ubjson::detail::ubjson_format::int16_type); + jsoncons::detail::to_big_endian(static_cast(val),std::back_inserter(result_)); + } + else if (val <= (std::numeric_limits::max)()) + { + // uint 32 stores a 32-bit big-endian unsigned integer + result_.push_back(jsoncons::ubjson::detail::ubjson_format::int32_type); + jsoncons::detail::to_big_endian(static_cast(val),std::back_inserter(result_)); + } + else if (val <= (std::numeric_limits::max)()) + { + // int 64 stores a 64-bit big-endian signed integer + result_.push_back(jsoncons::ubjson::detail::ubjson_format::int64_type); + jsoncons::detail::to_big_endian(static_cast(val),std::back_inserter(result_)); + } + else + { + // big integer + } + } + else + { + if (val >= (std::numeric_limits::lowest)()) + { + // int 8 stores a 8-bit signed integer + result_.push_back(jsoncons::ubjson::detail::ubjson_format::int8_type); + jsoncons::detail::to_big_endian(static_cast(val),std::back_inserter(result_)); + } + else if (val >= (std::numeric_limits::lowest)()) + { + // int 16 stores a 16-bit big-endian signed integer + result_.push_back(jsoncons::ubjson::detail::ubjson_format::int16_type); + jsoncons::detail::to_big_endian(static_cast(val),std::back_inserter(result_)); + } + else if (val >= (std::numeric_limits::lowest)()) + { + // int 32 stores a 32-bit big-endian signed integer + result_.push_back(jsoncons::ubjson::detail::ubjson_format::int32_type); + jsoncons::detail::to_big_endian(static_cast(val),std::back_inserter(result_)); + } + else if (val >= (std::numeric_limits::lowest)()) + { + // int 64 stores a 64-bit big-endian signed integer + result_.push_back(jsoncons::ubjson::detail::ubjson_format::int64_type); + jsoncons::detail::to_big_endian(static_cast(val),std::back_inserter(result_)); + } + } + end_value(); + return true; + } + + bool do_uint64_value(uint64_t val, + semantic_tag, + const ser_context&) override + { + if (val <= (std::numeric_limits::max)()) + { + result_.push_back(jsoncons::ubjson::detail::ubjson_format::uint8_type); + jsoncons::detail::to_big_endian(static_cast(val),std::back_inserter(result_)); + } + else if (val <= (std::numeric_limits::max)()) + { + result_.push_back(jsoncons::ubjson::detail::ubjson_format::int16_type); + jsoncons::detail::to_big_endian(static_cast(val),std::back_inserter(result_)); + } + else if (val <= (std::numeric_limits::max)()) + { + result_.push_back(jsoncons::ubjson::detail::ubjson_format::int32_type); + jsoncons::detail::to_big_endian(static_cast(val),std::back_inserter(result_)); + } + else if (val <= (uint64_t)(std::numeric_limits::max)()) + { + result_.push_back(jsoncons::ubjson::detail::ubjson_format::int64_type); + jsoncons::detail::to_big_endian(static_cast(val),std::back_inserter(result_)); + } + end_value(); + return true; + } + + bool do_bool_value(bool val, semantic_tag, const ser_context&) override + { + // true and false + result_.push_back(static_cast(val ? jsoncons::ubjson::detail::ubjson_format::true_type : jsoncons::ubjson::detail::ubjson_format::false_type)); + + end_value(); + return true; + } + + void end_value() + { + if (!stack_.empty()) + { + ++stack_.back().count_; + } + } +}; + +typedef basic_ubjson_encoder ubjson_encoder; +typedef basic_ubjson_encoder ubjson_bytes_encoder; + +#if !defined(JSONCONS_NO_DEPRECATED) +template +using basic_ubjson_serializer = basic_ubjson_encoder; + +typedef basic_ubjson_encoder ubjson_serializer; +typedef basic_ubjson_encoder ubjson_buffer_serializer; +#endif + +}} +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/ubjson/ubjson_error.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/ubjson/ubjson_error.hpp new file mode 100644 index 0000000000..dc11094ed9 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/ubjson/ubjson_error.hpp @@ -0,0 +1,89 @@ +/// Copyright 2018 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_UBJSON_UBJSON_ERROR_HPP +#define JSONCONS_UBJSON_UBJSON_ERROR_HPP + +#include +#include + +namespace jsoncons { namespace ubjson { + +enum class ubjson_errc +{ + ok = 0, + unexpected_eof = 1, + source_error, + count_required_after_type, + length_cannot_be_negative, + length_must_be_integer, + unknown_type, + invalid_utf8_text_string, + too_many_items, + too_few_items, + number_too_large +}; + +class ubjson_error_category_impl + : public std::error_category +{ +public: + const char* name() const noexcept override + { + return "jsoncons/ubjson"; + } + std::string message(int ev) const override + { + switch (static_cast(ev)) + { + case ubjson_errc::unexpected_eof: + return "Unexpected end of file"; + case ubjson_errc::source_error: + return "Source error"; + case ubjson_errc::count_required_after_type: + return "Type is specified for container, but count is not specified"; + case ubjson_errc::length_cannot_be_negative: + return "Length cannot be negative"; + case ubjson_errc::length_must_be_integer: + return "Length must be a integer numeric type (int8, uint8, int16, int32, int64)"; + case ubjson_errc::invalid_utf8_text_string: + return "Illegal UTF-8 encoding in text string"; + case ubjson_errc::too_many_items: + return "Too many items were added to a UBJSON object or array of known length"; + case ubjson_errc::too_few_items: + return "Too few items were added to a UBJSON object or array of known length"; + case ubjson_errc::number_too_large: + return "Number exceeds implementation limits"; + default: + return "Unknown UBJSON parser error"; + } + } +}; + +inline +const std::error_category& ubjson_error_category() +{ + static ubjson_error_category_impl instance; + return instance; +} + +inline +std::error_code make_error_code(ubjson_errc e) +{ + return std::error_code(static_cast(e),ubjson_error_category()); +} + + +}} + +namespace std { + template<> + struct is_error_code_enum : public true_type + { + }; +} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/ubjson/ubjson_reader.hpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/ubjson/ubjson_reader.hpp new file mode 100644 index 0000000000..540a588292 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/include/jsoncons_ext/ubjson/ubjson_reader.hpp @@ -0,0 +1,589 @@ +// Copyright 2017 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_UBJSON_UBJSON_READER_HPP +#define JSONCONS_UBJSON_UBJSON_READER_HPP + +#include +#include +#include // std::move +#include +#include +#include +#include +#include +#include + +namespace jsoncons { namespace ubjson { + +template +class basic_ubjson_reader : public ser_context +{ + Src source_; + json_content_handler& handler_; + size_t nesting_depth_; + std::string buffer_; +public: + template + basic_ubjson_reader(Source&& source, json_content_handler& handler) + : source_(std::forward(source)), + handler_(handler), + nesting_depth_(0) + { + } + + void read() + { + std::error_code ec; + read(ec); + if (ec) + { + throw ser_error(ec,line(),column()); + } + } + + void read(std::error_code& ec) + { + try + { + read_internal(ec); + } + catch (const ser_error& e) + { + ec = e.code(); + } + } + + size_t line() const override + { + return 0; + } + + size_t column() const override + { + return source_.position(); + } +private: + + void read_internal(std::error_code& ec) + { + if (source_.is_error()) + { + ec = ubjson_errc::source_error; + return; + } + //const uint8_t* pos = input_ptr_++; + + uint8_t type{}; + if (source_.get(type) == 0) + { + ec = ubjson_errc::unexpected_eof; + return; + } + read_value(type, ec); + } + + void read_value(uint8_t type, std::error_code& ec) + { + switch (type) + { + case jsoncons::ubjson::detail::ubjson_format::null_type: + { + handler_.null_value(semantic_tag::none, *this); + break; + } + case jsoncons::ubjson::detail::ubjson_format::no_op_type: + { + break; + } + case jsoncons::ubjson::detail::ubjson_format::true_type: + { + handler_.bool_value(true, semantic_tag::none, *this); + break; + } + case jsoncons::ubjson::detail::ubjson_format::false_type: + { + handler_.bool_value(false, semantic_tag::none, *this); + break; + } + case jsoncons::ubjson::detail::ubjson_format::int8_type: + { + uint8_t buf[sizeof(int8_t)]; + source_.read(buf, sizeof(int8_t)); + if (source_.eof()) + { + ec = ubjson_errc::unexpected_eof; + return; + } + const uint8_t* endp; + int8_t val = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + handler_.int64_value(val, semantic_tag::none, *this); + break; + } + case jsoncons::ubjson::detail::ubjson_format::uint8_type: + { + uint8_t val{}; + if (source_.get(val) == 0) + { + ec = ubjson_errc::unexpected_eof; + return; + } + handler_.uint64_value(val, semantic_tag::none, *this); + break; + } + case jsoncons::ubjson::detail::ubjson_format::int16_type: + { + uint8_t buf[sizeof(int16_t)]; + source_.read(buf, sizeof(int16_t)); + if (source_.eof()) + { + ec = ubjson_errc::unexpected_eof; + return; + } + const uint8_t* endp; + int16_t val = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + handler_.int64_value(val, semantic_tag::none, *this); + break; + } + case jsoncons::ubjson::detail::ubjson_format::int32_type: + { + uint8_t buf[sizeof(int32_t)]; + source_.read(buf, sizeof(int32_t)); + if (source_.eof()) + { + ec = ubjson_errc::unexpected_eof; + return; + } + const uint8_t* endp; + int32_t val = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + handler_.int64_value(val, semantic_tag::none, *this); + break; + } + case jsoncons::ubjson::detail::ubjson_format::int64_type: + { + uint8_t buf[sizeof(int64_t)]; + source_.read(buf, sizeof(int64_t)); + if (source_.eof()) + { + ec = ubjson_errc::unexpected_eof; + return; + } + const uint8_t* endp; + int64_t val = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + handler_.int64_value(val, semantic_tag::none, *this); + break; + } + case jsoncons::ubjson::detail::ubjson_format::float32_type: + { + uint8_t buf[sizeof(float)]; + source_.read(buf, sizeof(float)); + if (source_.eof()) + { + ec = ubjson_errc::unexpected_eof; + return; + } + const uint8_t* endp; + float val = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + handler_.double_value(val, semantic_tag::none, *this); + break; + } + case jsoncons::ubjson::detail::ubjson_format::float64_type: + { + uint8_t buf[sizeof(double)]; + source_.read(buf, sizeof(double)); + if (source_.eof()) + { + ec = ubjson_errc::unexpected_eof; + return; + } + const uint8_t* endp; + double val = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + handler_.double_value(val, semantic_tag::none, *this); + break; + } + case jsoncons::ubjson::detail::ubjson_format::char_type: + { + uint8_t buf[sizeof(char)]; + source_.read(buf, sizeof(char)); + if (source_.eof()) + { + ec = ubjson_errc::unexpected_eof; + return; + } + const uint8_t* endp; + char c = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + auto result = unicons::validate(&c,&c+1); + if (result.ec != unicons::conv_errc()) + { + ec = ubjson_errc::invalid_utf8_text_string; + return; + } + handler_.string_value(basic_string_view(&c,1), semantic_tag::none, *this); + break; + } + case jsoncons::ubjson::detail::ubjson_format::string_type: + { + size_t length = get_length(ec); + if (ec) + { + return; + } + std::string s; + source_.read(std::back_inserter(s), length); + if (source_.eof()) + { + ec = ubjson_errc::unexpected_eof; + return; + } + auto result = unicons::validate(s.begin(),s.end()); + if (result.ec != unicons::conv_errc()) + { + ec = ubjson_errc::invalid_utf8_text_string; + return; + } + handler_.string_value(basic_string_view(s.data(),s.length()), semantic_tag::none, *this); + break; + } + case jsoncons::ubjson::detail::ubjson_format::high_precision_number_type: + { + size_t length = get_length(ec); + if (ec) + { + return; + } + std::string s; + source_.read(std::back_inserter(s), length); + if (source_.eof()) + { + ec = ubjson_errc::unexpected_eof; + return; + } + if (jsoncons::detail::is_integer(s.data(),s.length())) + { + handler_.string_value(basic_string_view(s.data(),s.length()), semantic_tag::bigint, *this); + } + else + { + handler_.string_value(basic_string_view(s.data(),s.length()), semantic_tag::bigdec, *this); + } + break; + } + case jsoncons::ubjson::detail::ubjson_format::start_array_marker: + { + if (source_.peek() == jsoncons::ubjson::detail::ubjson_format::type_marker) + { + source_.ignore(1); + uint8_t item_type{}; + if (source_.get(item_type) == 0) + { + ec = ubjson_errc::unexpected_eof; + return; + } + if (source_.peek() == jsoncons::ubjson::detail::ubjson_format::count_marker) + { + source_.ignore(1); + size_t length = get_length(ec); + handler_.begin_array(length, semantic_tag::none, *this); + for (size_t i = 0; i < length; ++i) + { + read_value(item_type, ec); + if (ec) + { + return; + } + } + handler_.end_array(*this); + } + else + { + ec = ubjson_errc::count_required_after_type; + return; + } + } + else if (source_.peek() == jsoncons::ubjson::detail::ubjson_format::count_marker) + { + source_.ignore(1); + size_t length = get_length(ec); + handler_.begin_array(length, semantic_tag::none, *this); + for (size_t i = 0; i < length; ++i) + { + read(ec); + if (ec) + { + return; + } + } + handler_.end_array(*this); + } + else + { + handler_.begin_array(semantic_tag::none, *this); + while (source_.peek() != jsoncons::ubjson::detail::ubjson_format::end_array_marker) + { + read(ec); + if (ec) + { + return; + } + } + handler_.end_array(*this); + source_.ignore(1); + } + break; + } + case jsoncons::ubjson::detail::ubjson_format::start_object_marker: + { + if (source_.peek() == jsoncons::ubjson::detail::ubjson_format::type_marker) + { + source_.ignore(1); + uint8_t item_type{}; + if (source_.get(item_type) == 0) + { + ec = ubjson_errc::unexpected_eof; + return; + } + if (source_.peek() == jsoncons::ubjson::detail::ubjson_format::count_marker) + { + source_.ignore(1); + size_t length = get_length(ec); + handler_.begin_object(length, semantic_tag::none, *this); + for (size_t i = 0; i < length; ++i) + { + read_name(ec); + if (ec) + { + return; + } + read_value(item_type, ec); + if (ec) + { + return; + } + } + handler_.end_object(*this); + } + else + { + ec = ubjson_errc::count_required_after_type; + return; + } + } + else + { + if (source_.peek() == jsoncons::ubjson::detail::ubjson_format::count_marker) + { + source_.ignore(1); + size_t length = get_length(ec); + handler_.begin_object(length, semantic_tag::none, *this); + for (size_t i = 0; i < length; ++i) + { + read_name(ec); + if (ec) + { + return; + } + read(ec); + if (ec) + { + return; + } + } + handler_.end_object(*this); + } + else + { + handler_.begin_object(semantic_tag::none, *this); + while (source_.peek() != jsoncons::ubjson::detail::ubjson_format::end_object_marker) + { + read_name(ec); + if (ec) + { + return; + } + read(ec); + if (ec) + { + return; + } + } + handler_.end_object(*this); + source_.ignore(1); + } + } + break; + } + default: + { + ec = ubjson_errc::unknown_type; + return; + } + } + } + + size_t get_length(std::error_code& ec) + { + size_t length = 0; + if (JSONCONS_UNLIKELY(source_.eof())) + { + ec = ubjson_errc::unexpected_eof; + return length; + } + uint8_t type{}; + if (source_.get(type) == 0) + { + ec = ubjson_errc::unexpected_eof; + return length; + } + switch (type) + { + case jsoncons::ubjson::detail::ubjson_format::int8_type: + { + uint8_t buf[sizeof(int8_t)]; + source_.read(buf, sizeof(int8_t)); + if (source_.eof()) + { + ec = ubjson_errc::unexpected_eof; + return length; + } + const uint8_t* endp; + int8_t val = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + if (val >= 0) + { + length = val; + } + else + { + ec = ubjson_errc::length_cannot_be_negative; + return length; + } + break; + } + case jsoncons::ubjson::detail::ubjson_format::uint8_type: + { + uint8_t val{}; + if (source_.get(val) == 0) + { + ec = ubjson_errc::unexpected_eof; + return length; + } + length = val; + break; + } + case jsoncons::ubjson::detail::ubjson_format::int16_type: + { + uint8_t buf[sizeof(int16_t)]; + source_.read(buf, sizeof(int16_t)); + if (source_.eof()) + { + ec = ubjson_errc::unexpected_eof; + return length; + } + const uint8_t* endp; + int16_t val = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + if (val >= 0) + { + length = val; + } + else + { + ec = ubjson_errc::length_cannot_be_negative; + return length; + } + break; + } + case jsoncons::ubjson::detail::ubjson_format::int32_type: + { + uint8_t buf[sizeof(int32_t)]; + source_.read(buf, sizeof(int32_t)); + if (source_.eof()) + { + ec = ubjson_errc::unexpected_eof; + return length; + } + const uint8_t* endp; + int32_t val = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + if (val >= 0) + { + length = val; + } + else + { + ec = ubjson_errc::length_cannot_be_negative; + return length; + } + break; + } + case jsoncons::ubjson::detail::ubjson_format::int64_type: + { + uint8_t buf[sizeof(int64_t)]; + source_.read(buf, sizeof(int64_t)); + if (source_.eof()) + { + ec = ubjson_errc::unexpected_eof; + return length; + } + const uint8_t* endp; + int64_t val = jsoncons::detail::from_big_endian(buf,buf+sizeof(buf),&endp); + if (val >= 0) + { + length = (size_t)val; + if (length != (uint64_t)val) + { + ec = ubjson_errc::number_too_large; + return length; + } + } + else + { + ec = ubjson_errc::length_cannot_be_negative; + return length; + } + break; + } + default: + { + ec = ubjson_errc::length_must_be_integer; + return length; + } + } + return length; + } + + void read_name(std::error_code& ec) + { + size_t length = get_length(ec); + if (ec) + { + return; + } + std::string s; + source_.read(std::back_inserter(s), length); + if (source_.eof()) + { + ec = ubjson_errc::unexpected_eof; + return; + } + auto result = unicons::validate(s.begin(),s.end()); + if (result.ec != unicons::conv_errc()) + { + ec = ubjson_errc::invalid_utf8_text_string; + return; + } + handler_.name(basic_string_view(s.data(),s.length()), *this); + } +}; + +typedef basic_ubjson_reader ubjson_reader; + +typedef basic_ubjson_reader ubjson_bytes_reader; + +#if !defined(JSONCONS_NO_DEPRECATED) +typedef ubjson_bytes_reader ubjson_buffer_reader; +#endif + +}} + +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/CMakeLists.txt b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/CMakeLists.txt new file mode 100644 index 0000000000..241057fc7c --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/CMakeLists.txt @@ -0,0 +1,99 @@ +cmake_minimum_required(VERSION 3.1) + +if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) + project(jsoncons-test) + + find_package(jsoncons REQUIRED CONFIG) + set(JSONCONS_INCLUDE_DIR ${jsoncons_INCLUDE_DIRS}) +endif () + +if(NOT CMAKE_BUILD_TYPE) +message(STATUS "Forcing tests build type to Release") +set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE) +endif() + +include(CheckCXXCompilerFlag) + +string(TOUPPER "${CMAKE_BUILD_TYPE}" U_CMAKE_BUILD_TYPE) + +################ +# ARM SETTINGS # +################ + +OPTION(CROSS_COMPILE_ARM "cross compile for ARM targets" OFF) +OPTION(JSONCONS_SANITIZE "sanitize" OFF) +option(JSONCONS_VALGRIND "Execute tests with valgrind" OFF) + +if(JSONCONS_VALGRIND) + find_program(CMAKE_MEMORYCHECK_COMMAND valgrind) + message(STATUS "Executing test suite with Valgrind (${CMAKE_MEMORYCHECK_COMMAND})") + set(memcheck_command "${CMAKE_MEMORYCHECK_COMMAND} ${CMAKE_MEMORYCHECK_COMMAND_OPTIONS} --error-exitcode=1 --leak-check=full") + separate_arguments(memcheck_command) +endif() + +include (CTest) + +# Note: to compile on ARM (or cross compile), you may need to add the following: +# -DTARGET_ARCH="armv8-a -mfpu=neon -mfloat-abi=softfp -target arm-linux-gnueabi" +set(TARGET_ARCH "native" CACHE STRING "Target architecture arguments") +set(ARM_ARCH_DIRECTORY "arm-linux-gnueabi" CACHE STRING "ARM arch header dir") +set(ARM_GCC_VER "4.7.3" CACHE STRING "ARM GCC header dir") + +# load per-platform configuration +include (${JSONCONS_PROJECT_DIR}/build_files/cmake/${CMAKE_SYSTEM_NAME}.cmake) + +if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Intel") + if (CROSS_COMPILE_ARM) + # We're cross-compiling with clang++ on Travis, this is all pretty specific and just for testing + set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS) + set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS) + set(CMAKE_THREAD_LIBS_INIT) + + include_directories(/usr/${ARM_ARCH_DIRECTORY}/include/c++/${ARM_GCC_VER}/${ARM_ARCH_DIRECTORY}/) + include_directories(/usr/${ARM_ARCH_DIRECTORY}/include/c++/${ARM_GCC_VER}/) + include_directories(/usr/${ARM_ARCH_DIRECTORY}/include/) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=${TARGET_ARCH} -Wunused-parameter -Wextra -Wreorder -std=c++11") + endif() +endif() +if (JSONCONS_SANITIZE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O2 -fsanitize=address -fsanitize=undefined -fno-omit-frame-pointer") +endif() + +if(MSVC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc /MP /bigobj") + set(CMAKE_EXE_LINKER_FLAGS /MANIFEST:NO) +endif() + +set(CTEST_OUTPUT_ON_FAILURE ON) + +set(JSONCONS_TESTS_DIR ${JSONCONS_PROJECT_DIR}/tests) +set(JSONCONS_TESTS_SOURCE_DIR ${JSONCONS_PROJECT_DIR}/tests/src) +set(JSONCONS_INCLUDE_DIR ${JSONCONS_PROJECT_DIR}/include) +set(JSONCONS_THIRD_PARTY_INCLUDE_DIR ${JSONCONS_PROJECT_DIR}/third_party) + +set(CATCH_INCLUDE_DIR ${JSONCONS_THIRD_PARTY_INCLUDE_DIR}/catch) +add_library(Catch INTERFACE) +target_include_directories (Catch INTERFACE ${CATCH_INCLUDE_DIR}) + +file(GLOB_RECURSE JSONCONS_TESTS_SOURCES ${JSONCONS_TESTS_SOURCE_DIR}/*.cpp) + +#set(JSONCONS_TESTS_SOURCES +# ${JSONCONS_TESTS_SOURCE_DIR}/tests_main.cpp +# ${JSONCONS_TESTS_SOURCE_DIR}/jsonpath/jsonpath_tests.cpp +# ) +set(JSONCONS_TARGET test_jsoncons) +add_executable(${JSONCONS_TARGET} EXCLUDE_FROM_ALL ${JSONCONS_TESTS_SOURCES} ${JSONCONS_HEADERS}) + +add_test(example_test ${JSONCONS_TARGET}) + +target_include_directories (${JSONCONS_TARGET} PUBLIC ${JSONCONS_INCLUDE_DIR} + PUBLIC ${JSONCONS_THIRD_PARTY_INCLUDE_DIR}) + +target_link_libraries(${JSONCONS_TARGET} Catch) + +if (CROSS_COMPILE_ARM) + add_custom_target(jtest COMMAND qemu-arm -L /usr/arm-linux-gnueabi/ test_jsoncons DEPENDS ${JSONCONS_TARGET}) +else() + add_custom_target(jtest COMMAND test_jsoncons DEPENDS ${JSONCONS_TARGET}) +endif() + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/Readme.txt b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/Readme.txt new file mode 100644 index 0000000000..1674acf256 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/Readme.txt @@ -0,0 +1,37 @@ + +Build instructions + +Microsoft Visual Studio +======================= +To build the test suite with Visual C++ version 10 SP1 or later: + +Set BOOST_ROOT to the root directory containing Boost +Set BOOST_LIB to the directory containing Boost static libraries + +CMake +===== +* set current directory to jsonsons/test_suite/build/cmake + +* On Windows, set BOOST_ROOT and BOOST_LIBRARYDIR to enable cmake to locate boost stuff. + +* Generate build scripts of your choise: cmake -G + where can be (other choises are possible): + * Windows: "Visual Studio 10" or "NMake Makefiles" + * Unix: "Ninja" or "Unix Makefiles" + +* Compilation: use appropriate actions depending of generated files. + +* Tests execution: + * Windows: ./run_tests.bat + * Unix: ./run_tests.sh + +SCons +===== +WARNING: Only usable on Unix with gcc as compiler + +* set current directory to jsonsons/test_suite/build/scons + +* compilation: scons + +* Tests execution: + * Unix: ./run_tests.sh diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/document.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/document.json new file mode 100644 index 0000000000..216f518811 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/document.json @@ -0,0 +1,65 @@ +{ + "store": { + "book": [ + { "category": "reference", + "author": "Nigel Rees", + "title": "Sayings of the Century", + "price": 8.95 + }, + { "category": "fiction", + "author": "Evelyn Waugh", + "title": "Sword of Honour", + "price": 12.99 + }, + { "category": "fiction", + "author": "Herman Melville", + "title": "Moby Dick", + "isbn": "0-553-21311-3", + "price": 8.99 + }, + { "category": "fiction", + "author": "J. R. R. Tolkien", + "title": "The Lord of the Rings", + "isbn": "0-395-19395-8", + "price": 22.99 + } + ], + "bicycle": [{ + "color": "black/green", + "price": 97.50, + "options" : [{ + "color": "black/grey", + "price": 125.99 + }] + }] + }, + "boutique": { + "book": [ + { "category": "fiction", + "author": "Victor Hugo", + "title": "Les Miserables", + "price": 6.02 + }, + { "category": "cooking", + "author": "Paula Haney", + "title": "The Hoosier Mama Book of Pie", + "price": 13.77 + }, + { "category": "fiction", + "author": "David Lindsay", + "title": "A Voyage to Arcturus", + "price": 6.99 + }, + { "category": "travel", + "author": "Gillian Price", + "title": "Trekking in the Dolomites", + "isbn": "978 1 85284 563 6", + "price": 18.55 + } + ], + "bicycle": [{ + "color": "black/green", + "price": 97.50 + }] + } +} diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query1.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query1.json new file mode 100644 index 0000000000..d8c0fd6a38 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query1.json @@ -0,0 +1,30 @@ +[ + [ + { + "category" : "reference", + "author" : "Nigel Rees", + "title" : "Sayings of the Century", + "price" : 8.95 + }, + { + "category" : "fiction", + "author" : "Evelyn Waugh", + "title" : "Sword of Honour", + "price" : 12.99 + }, + { + "category" : "fiction", + "author" : "Herman Melville", + "title" : "Moby Dick", + "isbn" : "0-553-21311-3", + "price" : 8.99 + }, + { + "category" : "fiction", + "author" : "J. R. R. Tolkien", + "title" : "The Lord of the Rings", + "isbn" : "0-395-19395-8", + "price" : 22.99 + } + ] +] diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query1.jsonpath b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query1.jsonpath new file mode 100644 index 0000000000..b3e3b6a887 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query1.jsonpath @@ -0,0 +1 @@ +$['store']['book'] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query2.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query2.json new file mode 100644 index 0000000000..eff4bfb852 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query2.json @@ -0,0 +1,4 @@ +[ + 97.5, + 97.5 +] diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query2.jsonpath b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query2.jsonpath new file mode 100644 index 0000000000..5f19690b9a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query2.jsonpath @@ -0,0 +1 @@ +$..['bicycle'][*].price \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query3.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query3.json new file mode 100644 index 0000000000..1c09ec426e --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query3.json @@ -0,0 +1,5 @@ +[ + 97.5, + 125.99, + 97.5 +] diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query3.jsonpath b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query3.jsonpath new file mode 100644 index 0000000000..460c5fda6b --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query3.jsonpath @@ -0,0 +1 @@ +$..['bicycle']..price \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query4.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query4.json new file mode 100644 index 0000000000..1e490977dd --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query4.json @@ -0,0 +1,16 @@ +[ + { + "color" : "black/green", + "price" : 97.5, + "options" : [ + { + "color" : "black/grey", + "price" : 125.99 + } + ] + }, + { + "color" : "black/green", + "price" : 97.5 + } +] diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query4.jsonpath b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query4.jsonpath new file mode 100644 index 0000000000..700e61a08c --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query4.jsonpath @@ -0,0 +1 @@ +$..bicycle[?(@.price>=97)] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query5.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query5.json new file mode 100644 index 0000000000..3916f84801 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query5.json @@ -0,0 +1,6 @@ +[ + "Evelyn Waugh", + "J. R. R. Tolkien", + "Paula Haney", + "Gillian Price" +] diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query5.jsonpath b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query5.jsonpath new file mode 100644 index 0000000000..9c98cc02b7 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query5.jsonpath @@ -0,0 +1 @@ +$..book[1:4:2].author \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query6.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query6.json new file mode 100644 index 0000000000..cbb06d3c0f --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query6.json @@ -0,0 +1,8 @@ +[ + "Paula Haney", + "Evelyn Waugh", + "J. R. R. Tolkien", + "Victor Hugo", + "Nigel Rees", + "Gillian Price" +] diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query6.jsonpath b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query6.jsonpath new file mode 100644 index 0000000000..a222d3d5eb --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query6.jsonpath @@ -0,0 +1 @@ +$..book[1:4:2,0].author \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query7.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query7.json new file mode 100644 index 0000000000..2ab89dffb6 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query7.json @@ -0,0 +1,15 @@ +[ + { + "category" : "fiction", + "author" : "Herman Melville", + "title" : "Moby Dick", + "isbn" : "0-553-21311-3", + "price" : 8.99 + }, + { + "category" : "fiction", + "author" : "David Lindsay", + "title" : "A Voyage to Arcturus", + "price" : 6.99 + } +] diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query7.jsonpath b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query7.jsonpath new file mode 100644 index 0000000000..5ff10b0e40 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query7.jsonpath @@ -0,0 +1 @@ +$..book[(@.length - 2)] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query8.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query8.json new file mode 100644 index 0000000000..38a4b6d933 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query8.json @@ -0,0 +1,16 @@ +[ + { + "category" : "fiction", + "author" : "J. R. R. Tolkien", + "title" : "The Lord of the Rings", + "isbn" : "0-395-19395-8", + "price" : 22.99 + }, + { + "category" : "travel", + "author" : "Gillian Price", + "title" : "Trekking in the Dolomites", + "isbn" : "978 1 85284 563 6", + "price" : 18.55 + } +] diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query8.jsonpath b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query8.jsonpath new file mode 100644 index 0000000000..e252019011 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query8.jsonpath @@ -0,0 +1 @@ +$..book[-1:] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query9.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query9.json new file mode 100644 index 0000000000..9648d8c4cf --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query9.json @@ -0,0 +1,6 @@ +[ + "A Voyage to Arcturus","David Lindsay","Evelyn Waugh","Gillian Price", + "Herman Melville","J. R. R. Tolkien","Les Miserables","Moby Dick", + "Nigel Rees","Paula Haney","Sayings of the Century","Sword of Honour", + "The Hoosier Mama Book of Pie","The Lord of the Rings","Trekking in the Dolomites","Victor Hugo" +] diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query9.jsonpath b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query9.jsonpath new file mode 100644 index 0000000000..ec276f3040 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONPathTestSuite/query9.jsonpath @@ -0,0 +1 @@ +$..book[*]['author','title'] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_number_double_huge_neg_exp.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_number_double_huge_neg_exp.json new file mode 100644 index 0000000000..ae4c7b71f6 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_number_double_huge_neg_exp.json @@ -0,0 +1 @@ +[123.456e-789] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_number_huge_exp.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_number_huge_exp.json new file mode 100644 index 0000000000..9b5efa2368 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_number_huge_exp.json @@ -0,0 +1 @@ +[0.4e00669999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999969999999006] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_number_neg_int_huge_exp.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_number_neg_int_huge_exp.json new file mode 100644 index 0000000000..3abd58a5c4 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_number_neg_int_huge_exp.json @@ -0,0 +1 @@ +[-1e+9999] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_number_pos_double_huge_exp.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_number_pos_double_huge_exp.json new file mode 100644 index 0000000000..e10a7eb62a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_number_pos_double_huge_exp.json @@ -0,0 +1 @@ +[1.5e+9999] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_number_real_neg_overflow.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_number_real_neg_overflow.json new file mode 100644 index 0000000000..3d628a9943 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_number_real_neg_overflow.json @@ -0,0 +1 @@ +[-123123e100000] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_number_real_pos_overflow.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_number_real_pos_overflow.json new file mode 100644 index 0000000000..54d7d3dcdb --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_number_real_pos_overflow.json @@ -0,0 +1 @@ +[123123e100000] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_number_real_underflow.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_number_real_underflow.json new file mode 100644 index 0000000000..c5236eb26b --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_number_real_underflow.json @@ -0,0 +1 @@ +[123e-10000000] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_number_too_big_neg_int.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_number_too_big_neg_int.json new file mode 100644 index 0000000000..dfa3846197 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_number_too_big_neg_int.json @@ -0,0 +1 @@ +[-123123123123123123123123123123] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_number_too_big_pos_int.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_number_too_big_pos_int.json new file mode 100644 index 0000000000..338a8c3c0b --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_number_too_big_pos_int.json @@ -0,0 +1 @@ +[100000000000000000000] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_number_very_big_negative_int.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_number_very_big_negative_int.json new file mode 100644 index 0000000000..e2d9738c23 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_number_very_big_negative_int.json @@ -0,0 +1 @@ +[-237462374673276894279832749832423479823246327846] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_object_key_lone_2nd_surrogate.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_object_key_lone_2nd_surrogate.json new file mode 100644 index 0000000000..5be7ebaf98 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_object_key_lone_2nd_surrogate.json @@ -0,0 +1 @@ +{"\uDFAA":0} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_1st_surrogate_but_2nd_missing.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_1st_surrogate_but_2nd_missing.json new file mode 100644 index 0000000000..3b9e37c67a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_1st_surrogate_but_2nd_missing.json @@ -0,0 +1 @@ +["\uDADA"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_1st_valid_surrogate_2nd_invalid.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_1st_valid_surrogate_2nd_invalid.json new file mode 100644 index 0000000000..487592832e --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_1st_valid_surrogate_2nd_invalid.json @@ -0,0 +1 @@ +["\uD888\u1234"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_UTF-16LE_with_BOM.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_UTF-16LE_with_BOM.json new file mode 100644 index 0000000000..2a79c0629a Binary files /dev/null and b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_UTF-16LE_with_BOM.json differ diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_UTF-8_invalid_sequence.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_UTF-8_invalid_sequence.json new file mode 100644 index 0000000000..e2a968a159 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_UTF-8_invalid_sequence.json @@ -0,0 +1 @@ +["日ш"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_UTF8_surrogate_U+D800.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_UTF8_surrogate_U+D800.json new file mode 100644 index 0000000000..916bff920f --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_UTF8_surrogate_U+D800.json @@ -0,0 +1 @@ +[""] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_incomplete_surrogate_and_escape_valid.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_incomplete_surrogate_and_escape_valid.json new file mode 100644 index 0000000000..3cb11d2294 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_incomplete_surrogate_and_escape_valid.json @@ -0,0 +1 @@ +["\uD800\n"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_incomplete_surrogate_pair.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_incomplete_surrogate_pair.json new file mode 100644 index 0000000000..38ec23bb0a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_incomplete_surrogate_pair.json @@ -0,0 +1 @@ +["\uDd1ea"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_incomplete_surrogates_escape_valid.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_incomplete_surrogates_escape_valid.json new file mode 100644 index 0000000000..c9cd6f6c31 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_incomplete_surrogates_escape_valid.json @@ -0,0 +1 @@ +["\uD800\uD800\n"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_invalid_lonely_surrogate.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_invalid_lonely_surrogate.json new file mode 100644 index 0000000000..3abbd8d8d7 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_invalid_lonely_surrogate.json @@ -0,0 +1 @@ +["\ud800"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_invalid_surrogate.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_invalid_surrogate.json new file mode 100644 index 0000000000..ffddc04f52 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_invalid_surrogate.json @@ -0,0 +1 @@ +["\ud800abc"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_invalid_utf-8.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_invalid_utf-8.json new file mode 100644 index 0000000000..8e45a7ecae --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_invalid_utf-8.json @@ -0,0 +1 @@ +[""] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_inverted_surrogates_U+1D11E.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_inverted_surrogates_U+1D11E.json new file mode 100644 index 0000000000..0d5456cc38 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_inverted_surrogates_U+1D11E.json @@ -0,0 +1 @@ +["\uDd1e\uD834"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_iso_latin_1.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_iso_latin_1.json new file mode 100644 index 0000000000..9389c98231 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_iso_latin_1.json @@ -0,0 +1 @@ +[""] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_lone_second_surrogate.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_lone_second_surrogate.json new file mode 100644 index 0000000000..1dbd397f39 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_lone_second_surrogate.json @@ -0,0 +1 @@ +["\uDFAA"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_lone_utf8_continuation_byte.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_lone_utf8_continuation_byte.json new file mode 100644 index 0000000000..729337c0a3 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_lone_utf8_continuation_byte.json @@ -0,0 +1 @@ +[""] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_not_in_unicode_range.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_not_in_unicode_range.json new file mode 100644 index 0000000000..df90a2916c --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_not_in_unicode_range.json @@ -0,0 +1 @@ +[""] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_overlong_sequence_2_bytes.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_overlong_sequence_2_bytes.json new file mode 100644 index 0000000000..c8cee5e0a1 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_overlong_sequence_2_bytes.json @@ -0,0 +1 @@ +[""] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_overlong_sequence_6_bytes.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_overlong_sequence_6_bytes.json new file mode 100644 index 0000000000..9a91da791a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_overlong_sequence_6_bytes.json @@ -0,0 +1 @@ +[""] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_overlong_sequence_6_bytes_null.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_overlong_sequence_6_bytes_null.json new file mode 100644 index 0000000000..d24fffdd98 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_overlong_sequence_6_bytes_null.json @@ -0,0 +1 @@ +[""] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_truncated-utf-8.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_truncated-utf-8.json new file mode 100644 index 0000000000..63c7777fb1 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_truncated-utf-8.json @@ -0,0 +1 @@ +[""] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_utf16BE_no_BOM.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_utf16BE_no_BOM.json new file mode 100644 index 0000000000..57e5392ff6 Binary files /dev/null and b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_utf16BE_no_BOM.json differ diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_utf16LE_no_BOM.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_utf16LE_no_BOM.json new file mode 100644 index 0000000000..c49c1b25d8 Binary files /dev/null and b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_string_utf16LE_no_BOM.json differ diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_structure_500_nested_arrays.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_structure_500_nested_arrays.json new file mode 100644 index 0000000000..7118405898 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_structure_500_nested_arrays.json @@ -0,0 +1 @@ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_structure_UTF-8_BOM_empty_object.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_structure_UTF-8_BOM_empty_object.json new file mode 100644 index 0000000000..22fdca1b26 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/i_structure_UTF-8_BOM_empty_object.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_1_true_without_comma.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_1_true_without_comma.json new file mode 100644 index 0000000000..c14e3f6b1e --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_1_true_without_comma.json @@ -0,0 +1 @@ +[1 true] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_a_invalid_utf8.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_a_invalid_utf8.json new file mode 100644 index 0000000000..38a86e2e65 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_a_invalid_utf8.json @@ -0,0 +1 @@ +[a] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_colon_instead_of_comma.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_colon_instead_of_comma.json new file mode 100644 index 0000000000..0d02ad4483 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_colon_instead_of_comma.json @@ -0,0 +1 @@ +["": 1] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_comma_after_close.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_comma_after_close.json new file mode 100644 index 0000000000..2ccba8d950 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_comma_after_close.json @@ -0,0 +1 @@ +[""], \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_comma_and_number.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_comma_and_number.json new file mode 100644 index 0000000000..d2c84e374a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_comma_and_number.json @@ -0,0 +1 @@ +[,1] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_double_comma.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_double_comma.json new file mode 100644 index 0000000000..0431712bc1 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_double_comma.json @@ -0,0 +1 @@ +[1,,2] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_double_extra_comma.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_double_extra_comma.json new file mode 100644 index 0000000000..3f01d31292 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_double_extra_comma.json @@ -0,0 +1 @@ +["x",,] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_extra_close.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_extra_close.json new file mode 100644 index 0000000000..c12f9fae1c --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_extra_close.json @@ -0,0 +1 @@ +["x"]] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_extra_comma.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_extra_comma.json new file mode 100644 index 0000000000..5f8ce18e4b --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_extra_comma.json @@ -0,0 +1 @@ +["",] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_incomplete.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_incomplete.json new file mode 100644 index 0000000000..cc65b0b512 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_incomplete.json @@ -0,0 +1 @@ +["x" \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_incomplete_invalid_value.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_incomplete_invalid_value.json new file mode 100644 index 0000000000..c21a8f6cff --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_incomplete_invalid_value.json @@ -0,0 +1 @@ +[x \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_inner_array_no_comma.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_inner_array_no_comma.json new file mode 100644 index 0000000000..c70b716471 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_inner_array_no_comma.json @@ -0,0 +1 @@ +[3[4]] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_invalid_utf8.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_invalid_utf8.json new file mode 100644 index 0000000000..6099d3441a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_invalid_utf8.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_items_separated_by_semicolon.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_items_separated_by_semicolon.json new file mode 100644 index 0000000000..d4bd7314ca --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_items_separated_by_semicolon.json @@ -0,0 +1 @@ +[1:2] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_just_comma.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_just_comma.json new file mode 100644 index 0000000000..9d7077c680 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_just_comma.json @@ -0,0 +1 @@ +[,] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_just_minus.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_just_minus.json new file mode 100644 index 0000000000..29501c6ca2 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_just_minus.json @@ -0,0 +1 @@ +[-] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_missing_value.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_missing_value.json new file mode 100644 index 0000000000..3a6ba86f3a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_missing_value.json @@ -0,0 +1 @@ +[ , ""] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_newlines_unclosed.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_newlines_unclosed.json new file mode 100644 index 0000000000..6466800652 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_newlines_unclosed.json @@ -0,0 +1,3 @@ +["a", +4 +,1, \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_number_and_comma.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_number_and_comma.json new file mode 100644 index 0000000000..13f6f1d18a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_number_and_comma.json @@ -0,0 +1 @@ +[1,] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_number_and_several_commas.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_number_and_several_commas.json new file mode 100644 index 0000000000..0ac408cb8a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_number_and_several_commas.json @@ -0,0 +1 @@ +[1,,] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_spaces_vertical_tab_formfeed.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_spaces_vertical_tab_formfeed.json new file mode 100644 index 0000000000..6cd7cf5855 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_spaces_vertical_tab_formfeed.json @@ -0,0 +1 @@ +[" a"\f] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_star_inside.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_star_inside.json new file mode 100644 index 0000000000..5a5194647a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_star_inside.json @@ -0,0 +1 @@ +[*] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_unclosed.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_unclosed.json new file mode 100644 index 0000000000..0607330590 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_unclosed.json @@ -0,0 +1 @@ +["" \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_unclosed_trailing_comma.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_unclosed_trailing_comma.json new file mode 100644 index 0000000000..6604698ffc --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_unclosed_trailing_comma.json @@ -0,0 +1 @@ +[1, \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_unclosed_with_new_lines.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_unclosed_with_new_lines.json new file mode 100644 index 0000000000..4f61de3fb1 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_unclosed_with_new_lines.json @@ -0,0 +1,3 @@ +[1, +1 +,1 \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_unclosed_with_object_inside.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_unclosed_with_object_inside.json new file mode 100644 index 0000000000..043a87e2db --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_array_unclosed_with_object_inside.json @@ -0,0 +1 @@ +[{} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_incomplete_false.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_incomplete_false.json new file mode 100644 index 0000000000..eb18c6a143 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_incomplete_false.json @@ -0,0 +1 @@ +[fals] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_incomplete_null.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_incomplete_null.json new file mode 100644 index 0000000000..c18ef53851 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_incomplete_null.json @@ -0,0 +1 @@ +[nul] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_incomplete_true.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_incomplete_true.json new file mode 100644 index 0000000000..f451ac6d2e --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_incomplete_true.json @@ -0,0 +1 @@ +[tru] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_multidigit_number_then_00.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_multidigit_number_then_00.json new file mode 100644 index 0000000000..c22507b864 Binary files /dev/null and b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_multidigit_number_then_00.json differ diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_++.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_++.json new file mode 100644 index 0000000000..bdb62aaf4d --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_++.json @@ -0,0 +1 @@ +[++1234] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_+1.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_+1.json new file mode 100644 index 0000000000..3cbe58c92b --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_+1.json @@ -0,0 +1 @@ +[+1] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_+Inf.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_+Inf.json new file mode 100644 index 0000000000..871ae14d53 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_+Inf.json @@ -0,0 +1 @@ +[+Inf] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_-01.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_-01.json new file mode 100644 index 0000000000..0df32bac80 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_-01.json @@ -0,0 +1 @@ +[-01] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_-1.0..json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_-1.0..json new file mode 100644 index 0000000000..7cf55a85a7 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_-1.0..json @@ -0,0 +1 @@ +[-1.0.] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_-2..json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_-2..json new file mode 100644 index 0000000000..9be84365d0 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_-2..json @@ -0,0 +1 @@ +[-2.] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_-NaN.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_-NaN.json new file mode 100644 index 0000000000..f61615d404 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_-NaN.json @@ -0,0 +1 @@ +[-NaN] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_.-1.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_.-1.json new file mode 100644 index 0000000000..1c9f2dd1b7 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_.-1.json @@ -0,0 +1 @@ +[.-1] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_.2e-3.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_.2e-3.json new file mode 100644 index 0000000000..c6c976f257 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_.2e-3.json @@ -0,0 +1 @@ +[.2e-3] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_0.1.2.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_0.1.2.json new file mode 100644 index 0000000000..c83a25621e --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_0.1.2.json @@ -0,0 +1 @@ +[0.1.2] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_0.3e+.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_0.3e+.json new file mode 100644 index 0000000000..a55a1bfefa --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_0.3e+.json @@ -0,0 +1 @@ +[0.3e+] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_0.3e.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_0.3e.json new file mode 100644 index 0000000000..3dd5df4b3a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_0.3e.json @@ -0,0 +1 @@ +[0.3e] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_0.e1.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_0.e1.json new file mode 100644 index 0000000000..c92c71ccb2 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_0.e1.json @@ -0,0 +1 @@ +[0.e1] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_0_capital_E+.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_0_capital_E+.json new file mode 100644 index 0000000000..3ba2c7d6d0 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_0_capital_E+.json @@ -0,0 +1 @@ +[0E+] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_0_capital_E.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_0_capital_E.json new file mode 100644 index 0000000000..5301840d1c --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_0_capital_E.json @@ -0,0 +1 @@ +[0E] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_0e+.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_0e+.json new file mode 100644 index 0000000000..8ab0bc4b8b --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_0e+.json @@ -0,0 +1 @@ +[0e+] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_0e.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_0e.json new file mode 100644 index 0000000000..47ec421bb6 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_0e.json @@ -0,0 +1 @@ +[0e] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_1.0e+.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_1.0e+.json new file mode 100644 index 0000000000..cd84b9f69e --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_1.0e+.json @@ -0,0 +1 @@ +[1.0e+] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_1.0e-.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_1.0e-.json new file mode 100644 index 0000000000..4eb7afa0f9 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_1.0e-.json @@ -0,0 +1 @@ +[1.0e-] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_1.0e.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_1.0e.json new file mode 100644 index 0000000000..21753f4c74 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_1.0e.json @@ -0,0 +1 @@ +[1.0e] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_1_000.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_1_000.json new file mode 100644 index 0000000000..7b18b66b38 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_1_000.json @@ -0,0 +1 @@ +[1 000.0] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_1eE2.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_1eE2.json new file mode 100644 index 0000000000..4318a341d7 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_1eE2.json @@ -0,0 +1 @@ +[1eE2] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_2.e+3.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_2.e+3.json new file mode 100644 index 0000000000..4442f394dd --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_2.e+3.json @@ -0,0 +1 @@ +[2.e+3] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_2.e-3.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_2.e-3.json new file mode 100644 index 0000000000..a65060edfc --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_2.e-3.json @@ -0,0 +1 @@ +[2.e-3] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_2.e3.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_2.e3.json new file mode 100644 index 0000000000..66f7cf701b --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_2.e3.json @@ -0,0 +1 @@ +[2.e3] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_9.e+.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_9.e+.json new file mode 100644 index 0000000000..732a7b11ce --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_9.e+.json @@ -0,0 +1 @@ +[9.e+] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_Inf.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_Inf.json new file mode 100644 index 0000000000..c40c734c3c --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_Inf.json @@ -0,0 +1 @@ +[Inf] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_NaN.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_NaN.json new file mode 100644 index 0000000000..4992317909 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_NaN.json @@ -0,0 +1 @@ +[NaN] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_U+FF11_fullwidth_digit_one.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_U+FF11_fullwidth_digit_one.json new file mode 100644 index 0000000000..b14587e5eb --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_U+FF11_fullwidth_digit_one.json @@ -0,0 +1 @@ +[1] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_expression.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_expression.json new file mode 100644 index 0000000000..76fdbc8a49 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_expression.json @@ -0,0 +1 @@ +[1+2] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_hex_1_digit.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_hex_1_digit.json new file mode 100644 index 0000000000..3b214880c6 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_hex_1_digit.json @@ -0,0 +1 @@ +[0x1] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_hex_2_digits.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_hex_2_digits.json new file mode 100644 index 0000000000..83e516ab0e --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_hex_2_digits.json @@ -0,0 +1 @@ +[0x42] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_infinity.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_infinity.json new file mode 100644 index 0000000000..8c2baf783a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_infinity.json @@ -0,0 +1 @@ +[Infinity] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_invalid+-.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_invalid+-.json new file mode 100644 index 0000000000..1cce602b51 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_invalid+-.json @@ -0,0 +1 @@ +[0e+-1] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_invalid-negative-real.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_invalid-negative-real.json new file mode 100644 index 0000000000..5fc3c1efb6 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_invalid-negative-real.json @@ -0,0 +1 @@ +[-123.123foo] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_invalid-utf-8-in-bigger-int.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_invalid-utf-8-in-bigger-int.json new file mode 100644 index 0000000000..3b97e580e8 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_invalid-utf-8-in-bigger-int.json @@ -0,0 +1 @@ +[123] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_invalid-utf-8-in-exponent.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_invalid-utf-8-in-exponent.json new file mode 100644 index 0000000000..ea35d723cd --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_invalid-utf-8-in-exponent.json @@ -0,0 +1 @@ +[1e1] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_invalid-utf-8-in-int.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_invalid-utf-8-in-int.json new file mode 100644 index 0000000000..371226e4cd --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_invalid-utf-8-in-int.json @@ -0,0 +1 @@ +[0] diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_minus_infinity.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_minus_infinity.json new file mode 100644 index 0000000000..cf4133d22d --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_minus_infinity.json @@ -0,0 +1 @@ +[-Infinity] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_minus_sign_with_trailing_garbage.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_minus_sign_with_trailing_garbage.json new file mode 100644 index 0000000000..a6d8e78e7c --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_minus_sign_with_trailing_garbage.json @@ -0,0 +1 @@ +[-foo] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_minus_space_1.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_minus_space_1.json new file mode 100644 index 0000000000..9a5ebedf67 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_minus_space_1.json @@ -0,0 +1 @@ +[- 1] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_neg_int_starting_with_zero.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_neg_int_starting_with_zero.json new file mode 100644 index 0000000000..67af0960af --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_neg_int_starting_with_zero.json @@ -0,0 +1 @@ +[-012] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_neg_real_without_int_part.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_neg_real_without_int_part.json new file mode 100644 index 0000000000..1f2a43496e --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_neg_real_without_int_part.json @@ -0,0 +1 @@ +[-.123] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_neg_with_garbage_at_end.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_neg_with_garbage_at_end.json new file mode 100644 index 0000000000..2aa73119fb --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_neg_with_garbage_at_end.json @@ -0,0 +1 @@ +[-1x] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_real_garbage_after_e.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_real_garbage_after_e.json new file mode 100644 index 0000000000..9213dfca8d --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_real_garbage_after_e.json @@ -0,0 +1 @@ +[1ea] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_real_with_invalid_utf8_after_e.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_real_with_invalid_utf8_after_e.json new file mode 100644 index 0000000000..1e52ef964c --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_real_with_invalid_utf8_after_e.json @@ -0,0 +1 @@ +[1e] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_real_without_fractional_part.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_real_without_fractional_part.json new file mode 100644 index 0000000000..1de287cf89 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_real_without_fractional_part.json @@ -0,0 +1 @@ +[1.] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_starting_with_dot.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_starting_with_dot.json new file mode 100644 index 0000000000..f682dbdce0 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_starting_with_dot.json @@ -0,0 +1 @@ +[.123] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_with_alpha.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_with_alpha.json new file mode 100644 index 0000000000..1e42d81822 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_with_alpha.json @@ -0,0 +1 @@ +[1.2a-3] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_with_alpha_char.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_with_alpha_char.json new file mode 100644 index 0000000000..b79daccb8a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_with_alpha_char.json @@ -0,0 +1 @@ +[1.8011670033376514H-308] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_with_leading_zero.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_with_leading_zero.json new file mode 100644 index 0000000000..7106da1f3b --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_number_with_leading_zero.json @@ -0,0 +1 @@ +[012] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_bad_value.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_bad_value.json new file mode 100644 index 0000000000..a03a8c03b7 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_bad_value.json @@ -0,0 +1 @@ +["x", truth] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_bracket_key.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_bracket_key.json new file mode 100644 index 0000000000..cc443b4832 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_bracket_key.json @@ -0,0 +1 @@ +{[: "x"} diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_comma_instead_of_colon.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_comma_instead_of_colon.json new file mode 100644 index 0000000000..8d56377087 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_comma_instead_of_colon.json @@ -0,0 +1 @@ +{"x", null} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_double_colon.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_double_colon.json new file mode 100644 index 0000000000..80e8c7b89a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_double_colon.json @@ -0,0 +1 @@ +{"x"::"b"} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_emoji.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_emoji.json new file mode 100644 index 0000000000..cb4078eaa1 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_emoji.json @@ -0,0 +1 @@ +{🇨🇭} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_garbage_at_end.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_garbage_at_end.json new file mode 100644 index 0000000000..80c42cbadc --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_garbage_at_end.json @@ -0,0 +1 @@ +{"a":"a" 123} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_key_with_single_quotes.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_key_with_single_quotes.json new file mode 100644 index 0000000000..77c3275996 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_key_with_single_quotes.json @@ -0,0 +1 @@ +{key: 'value'} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_lone_continuation_byte_in_key_and_trailing_comma.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_lone_continuation_byte_in_key_and_trailing_comma.json new file mode 100644 index 0000000000..aa2cb637cd --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_lone_continuation_byte_in_key_and_trailing_comma.json @@ -0,0 +1 @@ +{"":"0",} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_missing_colon.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_missing_colon.json new file mode 100644 index 0000000000..b98eff62da --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_missing_colon.json @@ -0,0 +1 @@ +{"a" b} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_missing_key.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_missing_key.json new file mode 100644 index 0000000000..b4fb0f528e --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_missing_key.json @@ -0,0 +1 @@ +{:"b"} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_missing_semicolon.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_missing_semicolon.json new file mode 100644 index 0000000000..e3451384f8 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_missing_semicolon.json @@ -0,0 +1 @@ +{"a" "b"} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_missing_value.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_missing_value.json new file mode 100644 index 0000000000..3ef538a60e --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_missing_value.json @@ -0,0 +1 @@ +{"a": \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_no-colon.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_no-colon.json new file mode 100644 index 0000000000..f3797b3576 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_no-colon.json @@ -0,0 +1 @@ +{"a" \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_non_string_key.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_non_string_key.json new file mode 100644 index 0000000000..b9945b34b4 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_non_string_key.json @@ -0,0 +1 @@ +{1:1} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_non_string_key_but_huge_number_instead.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_non_string_key_but_huge_number_instead.json new file mode 100644 index 0000000000..b37fa86c0e --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_non_string_key_but_huge_number_instead.json @@ -0,0 +1 @@ +{9999E9999:1} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_repeated_null_null.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_repeated_null_null.json new file mode 100644 index 0000000000..f7d2959d0d --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_repeated_null_null.json @@ -0,0 +1 @@ +{null:null,null:null} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_several_trailing_commas.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_several_trailing_commas.json new file mode 100644 index 0000000000..3c9afe8dc9 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_several_trailing_commas.json @@ -0,0 +1 @@ +{"id":0,,,,,} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_single_quote.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_single_quote.json new file mode 100644 index 0000000000..e5cdf976ad --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_single_quote.json @@ -0,0 +1 @@ +{'a':0} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_trailing_comma.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_trailing_comma.json new file mode 100644 index 0000000000..a4b0250945 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_trailing_comma.json @@ -0,0 +1 @@ +{"id":0,} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_trailing_comment.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_trailing_comment.json new file mode 100644 index 0000000000..a372c6553d --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_trailing_comment.json @@ -0,0 +1 @@ +{"a":"b"}/**/ \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_trailing_comment_open.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_trailing_comment_open.json new file mode 100644 index 0000000000..d557f41ca4 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_trailing_comment_open.json @@ -0,0 +1 @@ +{"a":"b"}/**// \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_trailing_comment_slash_open.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_trailing_comment_slash_open.json new file mode 100644 index 0000000000..e335136c07 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_trailing_comment_slash_open.json @@ -0,0 +1 @@ +{"a":"b"}// \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_trailing_comment_slash_open_incomplete.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_trailing_comment_slash_open_incomplete.json new file mode 100644 index 0000000000..d892e49f17 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_trailing_comment_slash_open_incomplete.json @@ -0,0 +1 @@ +{"a":"b"}/ \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_two_commas_in_a_row.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_two_commas_in_a_row.json new file mode 100644 index 0000000000..7c639ae649 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_two_commas_in_a_row.json @@ -0,0 +1 @@ +{"a":"b",,"c":"d"} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_unquoted_key.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_unquoted_key.json new file mode 100644 index 0000000000..8ba137293c --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_unquoted_key.json @@ -0,0 +1 @@ +{a: "b"} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_unterminated-value.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_unterminated-value.json new file mode 100644 index 0000000000..7fe699a6a3 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_unterminated-value.json @@ -0,0 +1 @@ +{"a":"a \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_with_single_string.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_with_single_string.json new file mode 100644 index 0000000000..d63f7fbb7e --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_with_single_string.json @@ -0,0 +1 @@ +{ "foo" : "bar", "a" } \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_with_trailing_garbage.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_with_trailing_garbage.json new file mode 100644 index 0000000000..787c8f0a8c --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_object_with_trailing_garbage.json @@ -0,0 +1 @@ +{"a":"b"}# \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_single_space.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_single_space.json new file mode 100644 index 0000000000..0519ecba6e --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_single_space.json @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_1_surrogate_then_escape.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_1_surrogate_then_escape.json new file mode 100644 index 0000000000..acec66d8f4 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_1_surrogate_then_escape.json @@ -0,0 +1 @@ +["\uD800\"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_1_surrogate_then_escape_u.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_1_surrogate_then_escape_u.json new file mode 100644 index 0000000000..e834b05e96 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_1_surrogate_then_escape_u.json @@ -0,0 +1 @@ +["\uD800\u"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_1_surrogate_then_escape_u1.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_1_surrogate_then_escape_u1.json new file mode 100644 index 0000000000..a04cd34892 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_1_surrogate_then_escape_u1.json @@ -0,0 +1 @@ +["\uD800\u1"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_1_surrogate_then_escape_u1x.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_1_surrogate_then_escape_u1x.json new file mode 100644 index 0000000000..bfbd234098 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_1_surrogate_then_escape_u1x.json @@ -0,0 +1 @@ +["\uD800\u1x"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_accentuated_char_no_quotes.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_accentuated_char_no_quotes.json new file mode 100644 index 0000000000..fd6895693f --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_accentuated_char_no_quotes.json @@ -0,0 +1 @@ +[é] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_backslash_00.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_backslash_00.json new file mode 100644 index 0000000000..b5bf267b5d Binary files /dev/null and b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_backslash_00.json differ diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_escape_x.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_escape_x.json new file mode 100644 index 0000000000..fae291938d --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_escape_x.json @@ -0,0 +1 @@ +["\x00"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_escaped_backslash_bad.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_escaped_backslash_bad.json new file mode 100644 index 0000000000..016fcb47ef --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_escaped_backslash_bad.json @@ -0,0 +1 @@ +["\\\"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_escaped_ctrl_char_tab.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_escaped_ctrl_char_tab.json new file mode 100644 index 0000000000..f35ea382bb --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_escaped_ctrl_char_tab.json @@ -0,0 +1 @@ +["\ "] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_escaped_emoji.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_escaped_emoji.json new file mode 100644 index 0000000000..a277754213 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_escaped_emoji.json @@ -0,0 +1 @@ +["\🌀"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_incomplete_escape.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_incomplete_escape.json new file mode 100644 index 0000000000..3415c33ca8 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_incomplete_escape.json @@ -0,0 +1 @@ +["\"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_incomplete_escaped_character.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_incomplete_escaped_character.json new file mode 100644 index 0000000000..0f2197ea29 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_incomplete_escaped_character.json @@ -0,0 +1 @@ +["\u00A"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_incomplete_surrogate.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_incomplete_surrogate.json new file mode 100644 index 0000000000..75504a6561 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_incomplete_surrogate.json @@ -0,0 +1 @@ +["\uD834\uDd"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_incomplete_surrogate_escape_invalid.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_incomplete_surrogate_escape_invalid.json new file mode 100644 index 0000000000..bd9656060d --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_incomplete_surrogate_escape_invalid.json @@ -0,0 +1 @@ +["\uD800\uD800\x"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_invalid-utf-8-in-escape.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_invalid-utf-8-in-escape.json new file mode 100644 index 0000000000..0c43006430 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_invalid-utf-8-in-escape.json @@ -0,0 +1 @@ +["\u"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_invalid_backslash_esc.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_invalid_backslash_esc.json new file mode 100644 index 0000000000..d1eb60921a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_invalid_backslash_esc.json @@ -0,0 +1 @@ +["\a"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_invalid_unicode_escape.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_invalid_unicode_escape.json new file mode 100644 index 0000000000..7608cb6ba8 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_invalid_unicode_escape.json @@ -0,0 +1 @@ +["\uqqqq"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_invalid_utf8_after_escape.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_invalid_utf8_after_escape.json new file mode 100644 index 0000000000..2f757a25b5 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_invalid_utf8_after_escape.json @@ -0,0 +1 @@ +["\"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_leading_uescaped_thinspace.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_leading_uescaped_thinspace.json new file mode 100644 index 0000000000..7b297c6365 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_leading_uescaped_thinspace.json @@ -0,0 +1 @@ +[\u0020"asd"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_no_quotes_with_bad_escape.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_no_quotes_with_bad_escape.json new file mode 100644 index 0000000000..01bc70abae --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_no_quotes_with_bad_escape.json @@ -0,0 +1 @@ +[\n] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_single_doublequote.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_single_doublequote.json new file mode 100644 index 0000000000..9d68933c44 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_single_doublequote.json @@ -0,0 +1 @@ +" \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_single_quote.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_single_quote.json new file mode 100644 index 0000000000..caff239bfc --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_single_quote.json @@ -0,0 +1 @@ +['single quote'] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_single_string_no_double_quotes.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_single_string_no_double_quotes.json new file mode 100644 index 0000000000..f2ba8f84ab --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_single_string_no_double_quotes.json @@ -0,0 +1 @@ +abc \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_start_escape_unclosed.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_start_escape_unclosed.json new file mode 100644 index 0000000000..db62a46fcb --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_start_escape_unclosed.json @@ -0,0 +1 @@ +["\ \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_unescaped_crtl_char.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_unescaped_crtl_char.json new file mode 100644 index 0000000000..9f21348071 Binary files /dev/null and b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_unescaped_crtl_char.json differ diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_unescaped_newline.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_unescaped_newline.json new file mode 100644 index 0000000000..700d360869 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_unescaped_newline.json @@ -0,0 +1,2 @@ +["new +line"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_unescaped_tab.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_unescaped_tab.json new file mode 100644 index 0000000000..160264a2d9 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_unescaped_tab.json @@ -0,0 +1 @@ +[" "] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_unicode_CapitalU.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_unicode_CapitalU.json new file mode 100644 index 0000000000..17332bb174 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_unicode_CapitalU.json @@ -0,0 +1 @@ +"\UA66D" \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_with_trailing_garbage.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_with_trailing_garbage.json new file mode 100644 index 0000000000..efe3bd272c --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_string_with_trailing_garbage.json @@ -0,0 +1 @@ +""x \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_100000_opening_arrays.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_100000_opening_arrays.json new file mode 100644 index 0000000000..a4823eecce --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_100000_opening_arrays.json @@ -0,0 +1 @@ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_U+2060_word_joined.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_U+2060_word_joined.json new file mode 100644 index 0000000000..81156a6996 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_U+2060_word_joined.json @@ -0,0 +1 @@ +[⁠] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_UTF8_BOM_no_data.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_UTF8_BOM_no_data.json new file mode 100644 index 0000000000..5f282702bb --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_UTF8_BOM_no_data.json @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_angle_bracket_..json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_angle_bracket_..json new file mode 100644 index 0000000000..a56fef0b02 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_angle_bracket_..json @@ -0,0 +1 @@ +<.> \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_angle_bracket_null.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_angle_bracket_null.json new file mode 100644 index 0000000000..617f262549 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_angle_bracket_null.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_array_trailing_garbage.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_array_trailing_garbage.json new file mode 100644 index 0000000000..5a745e6f3c --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_array_trailing_garbage.json @@ -0,0 +1 @@ +[1]x \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_array_with_extra_array_close.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_array_with_extra_array_close.json new file mode 100644 index 0000000000..6cfb1398d2 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_array_with_extra_array_close.json @@ -0,0 +1 @@ +[1]] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_array_with_unclosed_string.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_array_with_unclosed_string.json new file mode 100644 index 0000000000..ba6b1788b6 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_array_with_unclosed_string.json @@ -0,0 +1 @@ +["asd] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_ascii-unicode-identifier.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_ascii-unicode-identifier.json new file mode 100644 index 0000000000..ef2ab62fe7 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_ascii-unicode-identifier.json @@ -0,0 +1 @@ +aå \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_capitalized_True.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_capitalized_True.json new file mode 100644 index 0000000000..7cd88469ab --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_capitalized_True.json @@ -0,0 +1 @@ +[True] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_close_unopened_array.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_close_unopened_array.json new file mode 100644 index 0000000000..d2af0c646a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_close_unopened_array.json @@ -0,0 +1 @@ +1] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_comma_instead_of_closing_brace.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_comma_instead_of_closing_brace.json new file mode 100644 index 0000000000..ac61b82006 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_comma_instead_of_closing_brace.json @@ -0,0 +1 @@ +{"x": true, \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_double_array.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_double_array.json new file mode 100644 index 0000000000..058d1626e5 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_double_array.json @@ -0,0 +1 @@ +[][] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_end_array.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_end_array.json new file mode 100644 index 0000000000..54caf60b13 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_end_array.json @@ -0,0 +1 @@ +] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_incomplete_UTF8_BOM.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_incomplete_UTF8_BOM.json new file mode 100644 index 0000000000..bfcdd514f3 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_incomplete_UTF8_BOM.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_lone-invalid-utf-8.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_lone-invalid-utf-8.json new file mode 100644 index 0000000000..8b1296cad2 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_lone-invalid-utf-8.json @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_lone-open-bracket.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_lone-open-bracket.json new file mode 100644 index 0000000000..8e2f0bef13 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_lone-open-bracket.json @@ -0,0 +1 @@ +[ \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_no_data.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_no_data.json new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_null-byte-outside-string.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_null-byte-outside-string.json new file mode 100644 index 0000000000..326db14422 Binary files /dev/null and b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_null-byte-outside-string.json differ diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_number_with_trailing_garbage.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_number_with_trailing_garbage.json new file mode 100644 index 0000000000..0746539d24 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_number_with_trailing_garbage.json @@ -0,0 +1 @@ +2@ \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_object_followed_by_closing_object.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_object_followed_by_closing_object.json new file mode 100644 index 0000000000..aa9ebaec57 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_object_followed_by_closing_object.json @@ -0,0 +1 @@ +{}} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_object_unclosed_no_value.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_object_unclosed_no_value.json new file mode 100644 index 0000000000..17d045147f --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_object_unclosed_no_value.json @@ -0,0 +1 @@ +{"": \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_object_with_comment.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_object_with_comment.json new file mode 100644 index 0000000000..ed1b569b70 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_object_with_comment.json @@ -0,0 +1 @@ +{"a":/*comment*/"b"} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_object_with_trailing_garbage.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_object_with_trailing_garbage.json new file mode 100644 index 0000000000..9ca2336d74 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_object_with_trailing_garbage.json @@ -0,0 +1 @@ +{"a": true} "x" \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_open_array_apostrophe.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_open_array_apostrophe.json new file mode 100644 index 0000000000..8bebe3af09 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_open_array_apostrophe.json @@ -0,0 +1 @@ +[' \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_open_array_comma.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_open_array_comma.json new file mode 100644 index 0000000000..6295fdc36d --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_open_array_comma.json @@ -0,0 +1 @@ +[, \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_open_array_object.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_open_array_object.json new file mode 100644 index 0000000000..e870445b2e --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_open_array_object.json @@ -0,0 +1 @@ +[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"": diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_open_array_open_object.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_open_array_open_object.json new file mode 100644 index 0000000000..7a63c8c57c --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_open_array_open_object.json @@ -0,0 +1 @@ +[{ \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_open_array_open_string.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_open_array_open_string.json new file mode 100644 index 0000000000..9822a6baf7 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_open_array_open_string.json @@ -0,0 +1 @@ +["a \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_open_array_string.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_open_array_string.json new file mode 100644 index 0000000000..42a6193620 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_open_array_string.json @@ -0,0 +1 @@ +["a" \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_open_object.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_open_object.json new file mode 100644 index 0000000000..81750b96f9 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_open_object.json @@ -0,0 +1 @@ +{ \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_open_object_close_array.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_open_object_close_array.json new file mode 100644 index 0000000000..eebc700a10 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_open_object_close_array.json @@ -0,0 +1 @@ +{] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_open_object_comma.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_open_object_comma.json new file mode 100644 index 0000000000..47bc9106f8 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_open_object_comma.json @@ -0,0 +1 @@ +{, \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_open_object_open_array.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_open_object_open_array.json new file mode 100644 index 0000000000..381ede5dea --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_open_object_open_array.json @@ -0,0 +1 @@ +{[ \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_open_object_open_string.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_open_object_open_string.json new file mode 100644 index 0000000000..328c30cd78 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_open_object_open_string.json @@ -0,0 +1 @@ +{"a \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_open_object_string_with_apostrophes.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_open_object_string_with_apostrophes.json new file mode 100644 index 0000000000..9dba17090c --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_open_object_string_with_apostrophes.json @@ -0,0 +1 @@ +{'a' \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_open_open.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_open_open.json new file mode 100644 index 0000000000..841fd5f864 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_open_open.json @@ -0,0 +1 @@ +["\{["\{["\{["\{ \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_single_eacute.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_single_eacute.json new file mode 100644 index 0000000000..92a39f398b --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_single_eacute.json @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_single_star.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_single_star.json new file mode 100644 index 0000000000..f59ec20aab --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_single_star.json @@ -0,0 +1 @@ +* \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_trailing_#.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_trailing_#.json new file mode 100644 index 0000000000..8986110875 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_trailing_#.json @@ -0,0 +1 @@ +{"a":"b"}#{} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_uescaped_LF_before_string.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_uescaped_LF_before_string.json new file mode 100644 index 0000000000..df2f0f2422 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_uescaped_LF_before_string.json @@ -0,0 +1 @@ +[\u000A""] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_unclosed_array.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_unclosed_array.json new file mode 100644 index 0000000000..11209515c8 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_unclosed_array.json @@ -0,0 +1 @@ +[1 \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_unclosed_array_partial_null.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_unclosed_array_partial_null.json new file mode 100644 index 0000000000..0d591762c1 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_unclosed_array_partial_null.json @@ -0,0 +1 @@ +[ false, nul \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_unclosed_array_unfinished_false.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_unclosed_array_unfinished_false.json new file mode 100644 index 0000000000..a2ff8504a9 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_unclosed_array_unfinished_false.json @@ -0,0 +1 @@ +[ true, fals \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_unclosed_array_unfinished_true.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_unclosed_array_unfinished_true.json new file mode 100644 index 0000000000..3149e8f5a7 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_unclosed_array_unfinished_true.json @@ -0,0 +1 @@ +[ false, tru \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_unclosed_object.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_unclosed_object.json new file mode 100644 index 0000000000..694d69dbd0 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_unclosed_object.json @@ -0,0 +1 @@ +{"asd":"asd" \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_unicode-identifier.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_unicode-identifier.json new file mode 100644 index 0000000000..7284aea33d --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_unicode-identifier.json @@ -0,0 +1 @@ +å \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_whitespace_U+2060_word_joiner.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_whitespace_U+2060_word_joiner.json new file mode 100644 index 0000000000..81156a6996 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_whitespace_U+2060_word_joiner.json @@ -0,0 +1 @@ +[⁠] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_whitespace_formfeed.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_whitespace_formfeed.json new file mode 100644 index 0000000000..a9ea535d1b --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/n_structure_whitespace_formfeed.json @@ -0,0 +1 @@ +[ ] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_array_arraysWithSpaces.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_array_arraysWithSpaces.json new file mode 100644 index 0000000000..582290798f --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_array_arraysWithSpaces.json @@ -0,0 +1 @@ +[[] ] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_array_empty-string.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_array_empty-string.json new file mode 100644 index 0000000000..93b6be2bcc --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_array_empty-string.json @@ -0,0 +1 @@ +[""] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_array_empty.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_array_empty.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_array_empty.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_array_ending_with_newline.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_array_ending_with_newline.json new file mode 100644 index 0000000000..eac5f7b46e --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_array_ending_with_newline.json @@ -0,0 +1 @@ +["a"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_array_false.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_array_false.json new file mode 100644 index 0000000000..67b2f07601 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_array_false.json @@ -0,0 +1 @@ +[false] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_array_heterogeneous.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_array_heterogeneous.json new file mode 100644 index 0000000000..d3c1e26484 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_array_heterogeneous.json @@ -0,0 +1 @@ +[null, 1, "1", {}] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_array_null.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_array_null.json new file mode 100644 index 0000000000..500db4a86a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_array_null.json @@ -0,0 +1 @@ +[null] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_array_with_1_and_newline.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_array_with_1_and_newline.json new file mode 100644 index 0000000000..994825500a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_array_with_1_and_newline.json @@ -0,0 +1,2 @@ +[1 +] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_array_with_leading_space.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_array_with_leading_space.json new file mode 100644 index 0000000000..18bfe6422c --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_array_with_leading_space.json @@ -0,0 +1 @@ + [1] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_array_with_several_null.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_array_with_several_null.json new file mode 100644 index 0000000000..99f6c5d1d8 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_array_with_several_null.json @@ -0,0 +1 @@ +[1,null,null,null,2] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_array_with_trailing_space.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_array_with_trailing_space.json new file mode 100644 index 0000000000..de9e7a9449 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_array_with_trailing_space.json @@ -0,0 +1 @@ +[2] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number.json new file mode 100644 index 0000000000..e5f5cc3340 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number.json @@ -0,0 +1 @@ +[123e65] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_0e+1.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_0e+1.json new file mode 100644 index 0000000000..d1d3967065 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_0e+1.json @@ -0,0 +1 @@ +[0e+1] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_0e1.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_0e1.json new file mode 100644 index 0000000000..3283a79365 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_0e1.json @@ -0,0 +1 @@ +[0e1] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_after_space.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_after_space.json new file mode 100644 index 0000000000..623570d960 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_after_space.json @@ -0,0 +1 @@ +[ 4] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_double_close_to_zero.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_double_close_to_zero.json new file mode 100644 index 0000000000..96555ff782 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_double_close_to_zero.json @@ -0,0 +1 @@ +[-0.000000000000000000000000000000000000000000000000000000000000000000000000000001] diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_int_with_exp.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_int_with_exp.json new file mode 100644 index 0000000000..a4ca9e754f --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_int_with_exp.json @@ -0,0 +1 @@ +[20e1] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_minus_zero.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_minus_zero.json new file mode 100644 index 0000000000..37af1312ab --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_minus_zero.json @@ -0,0 +1 @@ +[-0] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_negative_int.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_negative_int.json new file mode 100644 index 0000000000..8e30f8bd96 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_negative_int.json @@ -0,0 +1 @@ +[-123] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_negative_one.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_negative_one.json new file mode 100644 index 0000000000..99d21a2a0f --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_negative_one.json @@ -0,0 +1 @@ +[-1] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_negative_zero.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_negative_zero.json new file mode 100644 index 0000000000..37af1312ab --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_negative_zero.json @@ -0,0 +1 @@ +[-0] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_real_capital_e.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_real_capital_e.json new file mode 100644 index 0000000000..6edbdfcb18 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_real_capital_e.json @@ -0,0 +1 @@ +[1E22] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_real_capital_e_neg_exp.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_real_capital_e_neg_exp.json new file mode 100644 index 0000000000..0a01bd3ef4 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_real_capital_e_neg_exp.json @@ -0,0 +1 @@ +[1E-2] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_real_capital_e_pos_exp.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_real_capital_e_pos_exp.json new file mode 100644 index 0000000000..5a8fc09724 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_real_capital_e_pos_exp.json @@ -0,0 +1 @@ +[1E+2] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_real_exponent.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_real_exponent.json new file mode 100644 index 0000000000..da2522d61a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_real_exponent.json @@ -0,0 +1 @@ +[123e45] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_real_fraction_exponent.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_real_fraction_exponent.json new file mode 100644 index 0000000000..3944a7a454 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_real_fraction_exponent.json @@ -0,0 +1 @@ +[123.456e78] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_real_neg_exp.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_real_neg_exp.json new file mode 100644 index 0000000000..ca40d3c255 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_real_neg_exp.json @@ -0,0 +1 @@ +[1e-2] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_real_pos_exponent.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_real_pos_exponent.json new file mode 100644 index 0000000000..343601d51f --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_real_pos_exponent.json @@ -0,0 +1 @@ +[1e+2] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_simple_int.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_simple_int.json new file mode 100644 index 0000000000..e47f69afcf --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_simple_int.json @@ -0,0 +1 @@ +[123] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_simple_real.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_simple_real.json new file mode 100644 index 0000000000..b02878e5fc --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_number_simple_real.json @@ -0,0 +1 @@ +[123.456789] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_object.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_object.json new file mode 100644 index 0000000000..78262eda3f --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_object.json @@ -0,0 +1 @@ +{"asd":"sdf", "dfg":"fgh"} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_object_basic.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_object_basic.json new file mode 100644 index 0000000000..646bbe7bb1 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_object_basic.json @@ -0,0 +1 @@ +{"asd":"sdf"} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_object_duplicated_key.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_object_duplicated_key.json new file mode 100644 index 0000000000..bbc2e1ce43 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_object_duplicated_key.json @@ -0,0 +1 @@ +{"a":"b","a":"c"} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_object_duplicated_key_and_value.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_object_duplicated_key_and_value.json new file mode 100644 index 0000000000..211581c207 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_object_duplicated_key_and_value.json @@ -0,0 +1 @@ +{"a":"b","a":"b"} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_object_empty.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_object_empty.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_object_empty.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_object_empty_key.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_object_empty_key.json new file mode 100644 index 0000000000..c0013d3b8b --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_object_empty_key.json @@ -0,0 +1 @@ +{"":0} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_object_escaped_null_in_key.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_object_escaped_null_in_key.json new file mode 100644 index 0000000000..593f0f67f9 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_object_escaped_null_in_key.json @@ -0,0 +1 @@ +{"foo\u0000bar": 42} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_object_extreme_numbers.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_object_extreme_numbers.json new file mode 100644 index 0000000000..a0d3531c32 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_object_extreme_numbers.json @@ -0,0 +1 @@ +{ "min": -1.0e+28, "max": 1.0e+28 } \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_object_long_strings.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_object_long_strings.json new file mode 100644 index 0000000000..bdc4a08719 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_object_long_strings.json @@ -0,0 +1 @@ +{"x":[{"id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}], "id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_object_simple.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_object_simple.json new file mode 100644 index 0000000000..dacac917fb --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_object_simple.json @@ -0,0 +1 @@ +{"a":[]} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_object_string_unicode.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_object_string_unicode.json new file mode 100644 index 0000000000..8effdb297c --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_object_string_unicode.json @@ -0,0 +1 @@ +{"title":"\u041f\u043e\u043b\u0442\u043e\u0440\u0430 \u0417\u0435\u043c\u043b\u0435\u043a\u043e\u043f\u0430" } \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_object_with_newlines.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_object_with_newlines.json new file mode 100644 index 0000000000..246ec6b34d --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_object_with_newlines.json @@ -0,0 +1,3 @@ +{ +"a": "b" +} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_1_2_3_bytes_UTF-8_sequences.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_1_2_3_bytes_UTF-8_sequences.json new file mode 100644 index 0000000000..9967ddeb8b --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_1_2_3_bytes_UTF-8_sequences.json @@ -0,0 +1 @@ +["\u0060\u012a\u12AB"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_accepted_surrogate_pair.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_accepted_surrogate_pair.json new file mode 100644 index 0000000000..996875cc8c --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_accepted_surrogate_pair.json @@ -0,0 +1 @@ +["\uD801\udc37"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_accepted_surrogate_pairs.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_accepted_surrogate_pairs.json new file mode 100644 index 0000000000..3401021ece --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_accepted_surrogate_pairs.json @@ -0,0 +1 @@ +["\ud83d\ude39\ud83d\udc8d"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_allowed_escapes.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_allowed_escapes.json new file mode 100644 index 0000000000..7f495532fb --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_allowed_escapes.json @@ -0,0 +1 @@ +["\"\\\/\b\f\n\r\t"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_backslash_and_u_escaped_zero.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_backslash_and_u_escaped_zero.json new file mode 100644 index 0000000000..d4439eda73 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_backslash_and_u_escaped_zero.json @@ -0,0 +1 @@ +["\\u0000"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_backslash_doublequotes.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_backslash_doublequotes.json new file mode 100644 index 0000000000..ae03243b67 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_backslash_doublequotes.json @@ -0,0 +1 @@ +["\""] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_comments.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_comments.json new file mode 100644 index 0000000000..2260c20c2f --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_comments.json @@ -0,0 +1 @@ +["a/*b*/c/*d//e"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_double_escape_a.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_double_escape_a.json new file mode 100644 index 0000000000..6715d6f404 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_double_escape_a.json @@ -0,0 +1 @@ +["\\a"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_double_escape_n.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_double_escape_n.json new file mode 100644 index 0000000000..44ca56c4d9 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_double_escape_n.json @@ -0,0 +1 @@ +["\\n"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_escaped_control_character.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_escaped_control_character.json new file mode 100644 index 0000000000..5b014a9c25 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_escaped_control_character.json @@ -0,0 +1 @@ +["\u0012"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_escaped_noncharacter.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_escaped_noncharacter.json new file mode 100644 index 0000000000..2ff52e2c50 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_escaped_noncharacter.json @@ -0,0 +1 @@ +["\uFFFF"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_in_array.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_in_array.json new file mode 100644 index 0000000000..21d7ae4cd8 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_in_array.json @@ -0,0 +1 @@ +["asd"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_in_array_with_leading_space.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_in_array_with_leading_space.json new file mode 100644 index 0000000000..9e1887c1e4 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_in_array_with_leading_space.json @@ -0,0 +1 @@ +[ "asd"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_last_surrogates_1_and_2.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_last_surrogates_1_and_2.json new file mode 100644 index 0000000000..3919cef765 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_last_surrogates_1_and_2.json @@ -0,0 +1 @@ +["\uDBFF\uDFFF"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_nbsp_uescaped.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_nbsp_uescaped.json new file mode 100644 index 0000000000..2085ab1a1c --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_nbsp_uescaped.json @@ -0,0 +1 @@ +["new\u00A0line"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_nonCharacterInUTF-8_U+10FFFF.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_nonCharacterInUTF-8_U+10FFFF.json new file mode 100644 index 0000000000..059e4d9dd0 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_nonCharacterInUTF-8_U+10FFFF.json @@ -0,0 +1 @@ +["􏿿"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_nonCharacterInUTF-8_U+FFFF.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_nonCharacterInUTF-8_U+FFFF.json new file mode 100644 index 0000000000..4c913bd41a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_nonCharacterInUTF-8_U+FFFF.json @@ -0,0 +1 @@ +["￿"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_null_escape.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_null_escape.json new file mode 100644 index 0000000000..c1ad844043 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_null_escape.json @@ -0,0 +1 @@ +["\u0000"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_one-byte-utf-8.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_one-byte-utf-8.json new file mode 100644 index 0000000000..157185923a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_one-byte-utf-8.json @@ -0,0 +1 @@ +["\u002c"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_pi.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_pi.json new file mode 100644 index 0000000000..9df11ae88b --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_pi.json @@ -0,0 +1 @@ +["π"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_reservedCharacterInUTF-8_U+1BFFF.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_reservedCharacterInUTF-8_U+1BFFF.json new file mode 100644 index 0000000000..10a33a1717 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_reservedCharacterInUTF-8_U+1BFFF.json @@ -0,0 +1 @@ +["𛿿"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_simple_ascii.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_simple_ascii.json new file mode 100644 index 0000000000..8cadf7d051 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_simple_ascii.json @@ -0,0 +1 @@ +["asd "] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_space.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_space.json new file mode 100644 index 0000000000..efd782cc32 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_space.json @@ -0,0 +1 @@ +" " \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF.json new file mode 100644 index 0000000000..7620b66559 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF.json @@ -0,0 +1 @@ +["\uD834\uDd1e"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_three-byte-utf-8.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_three-byte-utf-8.json new file mode 100644 index 0000000000..108f1d67df --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_three-byte-utf-8.json @@ -0,0 +1 @@ +["\u0821"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_two-byte-utf-8.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_two-byte-utf-8.json new file mode 100644 index 0000000000..461503c310 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_two-byte-utf-8.json @@ -0,0 +1 @@ +["\u0123"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_u+2028_line_sep.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_u+2028_line_sep.json new file mode 100644 index 0000000000..897b6021af --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_u+2028_line_sep.json @@ -0,0 +1 @@ +["
"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_u+2029_par_sep.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_u+2029_par_sep.json new file mode 100644 index 0000000000..8cd998c89e --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_u+2029_par_sep.json @@ -0,0 +1 @@ +["
"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_uEscape.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_uEscape.json new file mode 100644 index 0000000000..f7b41a02fa --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_uEscape.json @@ -0,0 +1 @@ +["\u0061\u30af\u30EA\u30b9"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_uescaped_newline.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_uescaped_newline.json new file mode 100644 index 0000000000..3a5a220b69 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_uescaped_newline.json @@ -0,0 +1 @@ +["new\u000Aline"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_unescaped_char_delete.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_unescaped_char_delete.json new file mode 100644 index 0000000000..7d064f4987 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_unescaped_char_delete.json @@ -0,0 +1 @@ +[""] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_unicode.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_unicode.json new file mode 100644 index 0000000000..3598095b79 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_unicode.json @@ -0,0 +1 @@ +["\uA66D"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_unicodeEscapedBackslash.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_unicodeEscapedBackslash.json new file mode 100644 index 0000000000..0bb3b51e7e --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_unicodeEscapedBackslash.json @@ -0,0 +1 @@ +["\u005C"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_unicode_2.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_unicode_2.json new file mode 100644 index 0000000000..a7dcb97683 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_unicode_2.json @@ -0,0 +1 @@ +["⍂㈴⍂"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_unicode_U+10FFFE_nonchar.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_unicode_U+10FFFE_nonchar.json new file mode 100644 index 0000000000..9a8370b96a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_unicode_U+10FFFE_nonchar.json @@ -0,0 +1 @@ +["\uDBFF\uDFFE"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_unicode_U+1FFFE_nonchar.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_unicode_U+1FFFE_nonchar.json new file mode 100644 index 0000000000..c51f8ae45c --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_unicode_U+1FFFE_nonchar.json @@ -0,0 +1 @@ +["\uD83F\uDFFE"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_unicode_U+200B_ZERO_WIDTH_SPACE.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_unicode_U+200B_ZERO_WIDTH_SPACE.json new file mode 100644 index 0000000000..626d5f8157 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_unicode_U+200B_ZERO_WIDTH_SPACE.json @@ -0,0 +1 @@ +["\u200B"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_unicode_U+2064_invisible_plus.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_unicode_U+2064_invisible_plus.json new file mode 100644 index 0000000000..1e23972c65 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_unicode_U+2064_invisible_plus.json @@ -0,0 +1 @@ +["\u2064"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_unicode_U+FDD0_nonchar.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_unicode_U+FDD0_nonchar.json new file mode 100644 index 0000000000..18ef151b4f --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_unicode_U+FDD0_nonchar.json @@ -0,0 +1 @@ +["\uFDD0"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_unicode_U+FFFE_nonchar.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_unicode_U+FFFE_nonchar.json new file mode 100644 index 0000000000..13d261fdad --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_unicode_U+FFFE_nonchar.json @@ -0,0 +1 @@ +["\uFFFE"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_unicode_escaped_double_quote.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_unicode_escaped_double_quote.json new file mode 100644 index 0000000000..4e6257856d --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_unicode_escaped_double_quote.json @@ -0,0 +1 @@ +["\u0022"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_utf8.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_utf8.json new file mode 100644 index 0000000000..40878435f9 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_utf8.json @@ -0,0 +1 @@ +["€𝄞"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_with_del_character.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_with_del_character.json new file mode 100644 index 0000000000..8bd24907d9 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_string_with_del_character.json @@ -0,0 +1 @@ +["aa"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_structure_lonely_false.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_structure_lonely_false.json new file mode 100644 index 0000000000..02e4a84d62 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_structure_lonely_false.json @@ -0,0 +1 @@ +false \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_structure_lonely_int.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_structure_lonely_int.json new file mode 100644 index 0000000000..f70d7bba4a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_structure_lonely_int.json @@ -0,0 +1 @@ +42 \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_structure_lonely_negative_real.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_structure_lonely_negative_real.json new file mode 100644 index 0000000000..b5135a207d --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_structure_lonely_negative_real.json @@ -0,0 +1 @@ +-0.1 \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_structure_lonely_null.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_structure_lonely_null.json new file mode 100644 index 0000000000..ec747fa47d --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_structure_lonely_null.json @@ -0,0 +1 @@ +null \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_structure_lonely_string.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_structure_lonely_string.json new file mode 100644 index 0000000000..b6e982ca96 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_structure_lonely_string.json @@ -0,0 +1 @@ +"asd" \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_structure_lonely_true.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_structure_lonely_true.json new file mode 100644 index 0000000000..f32a5804e2 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_structure_lonely_true.json @@ -0,0 +1 @@ +true \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_structure_string_empty.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_structure_string_empty.json new file mode 100644 index 0000000000..3cc762b550 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_structure_string_empty.json @@ -0,0 +1 @@ +"" \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_structure_trailing_newline.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_structure_trailing_newline.json new file mode 100644 index 0000000000..0c3426d4c2 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_structure_trailing_newline.json @@ -0,0 +1 @@ +["a"] diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_structure_true_in_array.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_structure_true_in_array.json new file mode 100644 index 0000000000..de601e305f --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_structure_true_in_array.json @@ -0,0 +1 @@ +[true] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_structure_whitespace_array.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_structure_whitespace_array.json new file mode 100644 index 0000000000..2bedf7f2de --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSONTestSuite/y_structure_whitespace_array.json @@ -0,0 +1 @@ + [] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/Acknowledgement.txt b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/Acknowledgement.txt new file mode 100644 index 0000000000..5f19a6715f --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/Acknowledgement.txt @@ -0,0 +1,3 @@ +These files are from the JSON_checker test suite + +http://www.json.org/JSON_checker/ diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail1.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail1.json new file mode 100644 index 0000000000..6216b865f1 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail1.json @@ -0,0 +1 @@ +"A JSON payload should be an object or array, not a string." \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail10.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail10.json new file mode 100644 index 0000000000..5d8c0047bd --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail10.json @@ -0,0 +1 @@ +{"Extra value after close": true} "misplaced quoted value" \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail11.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail11.json new file mode 100644 index 0000000000..76eb95b458 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail11.json @@ -0,0 +1 @@ +{"Illegal expression": 1 + 2} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail12.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail12.json new file mode 100644 index 0000000000..77580a4522 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail12.json @@ -0,0 +1 @@ +{"Illegal invocation": alert()} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail13.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail13.json new file mode 100644 index 0000000000..379406b59b --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail13.json @@ -0,0 +1 @@ +{"Numbers cannot have leading zeroes": 013} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail14.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail14.json new file mode 100644 index 0000000000..0ed366b38a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail14.json @@ -0,0 +1 @@ +{"Numbers cannot be hex": 0x14} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail15.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail15.json new file mode 100644 index 0000000000..fc8376b605 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail15.json @@ -0,0 +1 @@ +["Illegal backslash escape: \x15"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail16.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail16.json new file mode 100644 index 0000000000..3fe21d4b53 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail16.json @@ -0,0 +1 @@ +[\naked] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail17.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail17.json new file mode 100644 index 0000000000..62b9214aed --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail17.json @@ -0,0 +1 @@ +["Illegal backslash escape: \017"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail18.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail18.json new file mode 100644 index 0000000000..edac92716f --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail18.json @@ -0,0 +1 @@ +[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail19.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail19.json new file mode 100644 index 0000000000..3b9c46fa9a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail19.json @@ -0,0 +1 @@ +{"Missing colon" null} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail2.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail2.json new file mode 100644 index 0000000000..6b7c11e5a5 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail2.json @@ -0,0 +1 @@ +["Unclosed array" \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail20.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail20.json new file mode 100644 index 0000000000..27c1af3e72 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail20.json @@ -0,0 +1 @@ +{"Double colon":: null} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail21.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail21.json new file mode 100644 index 0000000000..62474573b2 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail21.json @@ -0,0 +1 @@ +{"Comma instead of colon", null} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail22.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail22.json new file mode 100644 index 0000000000..a7752581bc --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail22.json @@ -0,0 +1 @@ +["Colon instead of comma": false] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail23.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail23.json new file mode 100644 index 0000000000..494add1ca1 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail23.json @@ -0,0 +1 @@ +["Bad value", truth] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail24.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail24.json new file mode 100644 index 0000000000..caff239bfc --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail24.json @@ -0,0 +1 @@ +['single quote'] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail25.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail25.json new file mode 100644 index 0000000000..8b7ad23e01 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail25.json @@ -0,0 +1 @@ +[" tab character in string "] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail26.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail26.json new file mode 100644 index 0000000000..845d26a6a5 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail26.json @@ -0,0 +1 @@ +["tab\ character\ in\ string\ "] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail27.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail27.json new file mode 100644 index 0000000000..6b01a2ca4a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail27.json @@ -0,0 +1,2 @@ +["line +break"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail28.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail28.json new file mode 100644 index 0000000000..621a0101c6 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail28.json @@ -0,0 +1,2 @@ +["line\ +break"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail29.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail29.json new file mode 100644 index 0000000000..47ec421bb6 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail29.json @@ -0,0 +1 @@ +[0e] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail3.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail3.json new file mode 100644 index 0000000000..168c81eb78 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail3.json @@ -0,0 +1 @@ +{unquoted_key: "keys must be quoted"} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail30.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail30.json new file mode 100644 index 0000000000..8ab0bc4b8b --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail30.json @@ -0,0 +1 @@ +[0e+] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail31.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail31.json new file mode 100644 index 0000000000..1cce602b51 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail31.json @@ -0,0 +1 @@ +[0e+-1] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail32.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail32.json new file mode 100644 index 0000000000..45cba7396f --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail32.json @@ -0,0 +1 @@ +{"Comma instead if closing brace": true, \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail33.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail33.json new file mode 100644 index 0000000000..ca5eb19dc9 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail33.json @@ -0,0 +1 @@ +["mismatch"} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail4.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail4.json new file mode 100644 index 0000000000..9de168bf34 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail4.json @@ -0,0 +1 @@ +["extra comma",] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail5.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail5.json new file mode 100644 index 0000000000..ddf3ce3d24 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail5.json @@ -0,0 +1 @@ +["double extra comma",,] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail6.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail6.json new file mode 100644 index 0000000000..ed91580e1b --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail6.json @@ -0,0 +1 @@ +[ , "<-- missing value"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail7.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail7.json new file mode 100644 index 0000000000..8a96af3e4e --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail7.json @@ -0,0 +1 @@ +["Comma after the close"], \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail8.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail8.json new file mode 100644 index 0000000000..b28479c6ec --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail8.json @@ -0,0 +1 @@ +["Extra close"]] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail9.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail9.json new file mode 100644 index 0000000000..5815574f36 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/fail9.json @@ -0,0 +1 @@ +{"Extra comma": true,} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/pass1.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/pass1.json new file mode 100644 index 0000000000..70e2685436 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/pass1.json @@ -0,0 +1,58 @@ +[ + "JSON Test Pattern pass1", + {"object with 1 member":["array with 1 element"]}, + {}, + [], + -42, + true, + false, + null, + { + "integer": 1234567890, + "real": -9876.543210, + "e": 0.123456789e-12, + "E": 1.234567890E+34, + "": 23456789012E66, + "zero": 0, + "one": 1, + "space": " ", + "quote": "\"", + "backslash": "\\", + "controls": "\b\f\n\r\t", + "slash": "/ & \/", + "alpha": "abcdefghijklmnopqrstuvwyz", + "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ", + "digit": "0123456789", + "0123456789": "digit", + "special": "`1~!@#$%^&*()_+-={':[,]}|;.?", + "hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A", + "true": true, + "false": false, + "null": null, + "array":[ ], + "object":{ }, + "address": "50 St. James Street", + "url": "http://www.JSON.org/", + "comment": "// /* */": " ", + " s p a c e d " :[1,2 , 3 + +, + +4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7], + "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}", + "quotes": "" \u0022 %22 0x22 034 "", + "\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?" +: "A key can be any string" + }, + 0.5 ,98.6 +, +99.44 +, + +1066, +1e1, +0.1e1, +1e-1, +1e00,2e+00,2e-00 +,"rosebud"] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/pass2.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/pass2.json new file mode 100644 index 0000000000..d3c63c7ad8 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/pass2.json @@ -0,0 +1 @@ +[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/pass3.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/pass3.json new file mode 100644 index 0000000000..4528d51f1a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/JSON_checker/pass3.json @@ -0,0 +1,6 @@ +{ + "JSON Test Pattern pass3": { + "The outermost value": "must be an object or array.", + "In this test": "It is an object." + } +} diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/address-book.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/address-book.json new file mode 100644 index 0000000000..c3d5d98369 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/address-book.json @@ -0,0 +1,13 @@ + { + "address-book" : + [ + { + "name":"Jane Roe", + "email":"jane.roe@example.com" + }, + { + "name":"John", + "email" : "john.doe@example.com" + } + ] + } diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/countries.csv b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/countries.csv new file mode 100644 index 0000000000..750b1937d7 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/countries.csv @@ -0,0 +1,5 @@ +country_code,name +ABW,ARUBA +ATF,"FRENCH SOUTHERN TERRITORIES, D.R. OF" +VUT,VANUATU +WLF,WALLIS & FUTUNA ISLANDS diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/countries.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/countries.json new file mode 100644 index 0000000000..29629e4253 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/countries.json @@ -0,0 +1,7 @@ +[ + ["country_code","name"], + ["ABW","ARUBA"], + ["ATF","FRENCH SOUTHERN TERRITORIES, D.R. OF"], + ["VUT","VANUATU"], + ["WLF","WALLIS & FUTUNA ISLANDS"] +] diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/cyrillic.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/cyrillic.json new file mode 100644 index 0000000000..067839e9d4 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/cyrillic.json @@ -0,0 +1,731 @@ +{ + "Xml": { + "SLMS": [ + { + "-idSLMS": "1", + "LMS": [ + { + "PostTh": "Абвгдеёжзик лмнопрстуфхцчшщъ(Кккккккк ккккккк кккккккк)", + "PostSh": "Абвгде.жзиклм-но(Кккккккк к.к.)", + "KodeMod": "$A", + "PostTabNum": "0000000004" + }, + { + "PostTh": "Абвгдеёжзик лмнопрстуфхцчшщъ(Кккккккк ккккккк кккккккк)", + "PostSh": "Абвгде.жзиклм-но(Кккккккк к.к.)", + "KodeMod": "$A", + "PostTabNum": "0000000004" + }, + { + "PostTh": "Абвгдеёжзик лмнопрстуфхцчшщъ(Кккккккк ккккккк кккккккк)", + "PostSh": "Абвгде.жзиклм-но(Кккккккк к.к.)", + "KodeMod": "$A", + "PostTabNum": "0000000004" + } + ] + }, + { + "-idSLMS": "2", + "LMS": [ + { + "PostTh": "Абвгдеёжзик лмнопрстуфхцчшщъ(Кккккккк ккккккк кккккккк)", + "PostSh": "Абвгде.жзиклм-но(Кккккккк к.к.)", + "KodeMod": "$A", + "PostTabNum": "0000000004" + }, + { + "PostTh": "Абвгдеёжзик лмнопрстуфхцчшщъ(Кккккккк ккккккк кккккккк)", + "PostSh": "Абвгде.жзиклм-но(Кккккккк к.к.)", + "KodeMod": "$A", + "PostTabNum": "0000000004" + }, + { + "PostTh": "Абвгдеёжзик лмнопрстуфхцчшщъ(Кккккккк ккккккк кккккккк)", + "PostSh": "Абвгде.жзиклм-но(Кккккккк к.к.)", + "KodeMod": "$A", + "PostTabNum": "0000000004" + } + ] + }, + { + "-idSLMS": "3", + "LMS": [ + { + "PostTh": "Абвгдеёжзик лмнопрстуфхцчшщъ(Кккккккк ккккккк кккккккк)", + "PostSh": "Абвгде.жзиклм-но(Кккккккк к.к.)", + "KodeMod": "$A", + "PostTabNum": "0000000004" + }, + { + "PostTh": "Абвгдеёжзик лмнопрстуфхцчшщъ(Кккккккк ккккккк кккккккк)", + "PostSh": "Абвгде.жзиклм-но(Кккккккк к.к.)", + "KodeMod": "$A", + "PostTabNum": "0000000004" + }, + { + "PostTh": "Абвгдеёжзик лмнопрстуфхцчшщъ(Кккккккк ккккккк кккккккк)", + "PostSh": "Абвгде.жзиклм-но(Кккккккк к.к.)", + "KodeMod": "$A", + "PostTabNum": "0000000004" + } + ] + }, + { + "-idSLMS": "4", + "LMS": [ + { + "PostTh": "Абвгдеёжзик лмнопрстуфхцчшщъ(Кккккккк ккккккк кккккккк)", + "PostSh": "Абвгде.жзиклм-но(Кккккккк к.к.)", + "KodeMod": "$A", + "PostTabNum": "0000000004" + }, + { + "PostTh": "Абвгдеёжзик лмнопрстуфхцчшщъ(Кккккккк ккккккк кккккккк)", + "PostSh": "Абвгде.жзиклм-но(Кккккккк к.к.)", + "KodeMod": "$A", + "PostTabNum": "0000000004" + }, + { + "PostTh": "Абвгдеёжзик лмнопрстуфхцчшщъ(Кккккккк ккккккк кккккккк)", + "PostSh": "Абвгде.жзиклм-но(Кккккккк к.к.)", + "KodeMod": "$A", + "PostTabNum": "0000000004" + } + ] + }, + { + "-idSLMS": "5", + "LMS": [ + { + "PostTh": "Абвгдеёжзик лмнопрстуфхцчшщъ(Кккккккк ккккккк кккккккк)", + "PostSh": "Абвгде.жзиклм-но(Кккккккк к.к.)", + "KodeMod": "$A", + "PostTabNum": "0000000004" + }, + { + "PostTh": "Абвгдеёжзик лмнопрстуфхцчшщъ(Кккккккк ккккккк кккккккк)", + "PostSh": "Абвгде.жзиклм-но(Кккккккк к.к.)", + "KodeMod": "$A", + "PostTabNum": "0000000004" + }, + { + "PostTh": "Абвгдеёжзик лмнопрстуфхцчшщъ(Кккккккк ккккккк кккккккк)", + "PostSh": "Абвгде.жзиклм-но(Кккккккк к.к.)", + "KodeMod": "$A", + "PostTabNum": "0000000004" + } + ] + }, + { + "-idSLMS": "6", + "LMS": [ + { + "PostTh": "Абвгдеёжзик лмнопрстуфхцчшщъ(Кккккккк ккккккк кккккккк)", + "PostSh": "Абвгде.жзиклм-но(Кккккккк к.к.)", + "KodeMod": "$A", + "PostTabNum": "0000000004" + }, + { + "PostTh": "Абвгдеёжзик лмнопрстуфхцчшщъ(Кккккккк ккккккк кккккккк)", + "PostSh": "Абвгде.жзиклм-но(Кккккккк к.к.)", + "KodeMod": "$A", + "PostTabNum": "0000000004" + }, + { + "PostTh": "Абвгдеёжзик лмнопрстуфхцчшщъ(Кккккккк ккккккк кккккккк)", + "PostSh": "Абвгде.жзиклм-но(Кккккккк к.к.)", + "KodeMod": "$A", + "PostTabNum": "0000000004" + } + ] + }, + { + "-idSLMS": "7", + "LMS": [ + { + "PostTh": "Абвгдеёжзик лмнопрстуфхцчшщъ(Кккккккк ккккккк кккккккк)", + "PostSh": "Абвгде.жзиклм-но(Кккккккк к.к.)", + "KodeMod": "$A", + "PostTabNum": "0000000004" + }, + { + "PostTh": "Абвгдеёжзик лмнопрстуфхцчшщъ(Кккккккк ккккккк кккккккк)", + "PostSh": "Абвгде.жзиклм-но(Кккккккк к.к.)", + "KodeMod": "$A", + "PostTabNum": "0000000004" + }, + { + "PostTh": "Абвгдеёжзик лмнопрстуфхцчшщъ(Кккккккк ккккккк кккккккк)", + "PostSh": "Абвгде.жзиклм-но(Кккккккк к.к.)", + "KodeMod": "$A", + "PostTabNum": "0000000004" + } + ] + }, + { + "-idSLMS": "8", + "LMS": [ + { + "PostTh": "Абвгдеёжзик лмнопрстуфхцчшщъ(Кккккккк ккккккк кккккккк)", + "PostSh": "Абвгде.жзиклм-но(Кккккккк к.к.)", + "KodeMod": "$A", + "PostTabNum": "0000000004" + }, + { + "PostTh": "Абвгдеёжзик лмнопрстуфхцчшщъ(Кккккккк ккккккк кккккккк)", + "PostSh": "Абвгде.жзиклм-но(Кккккккк к.к.)", + "KodeMod": "$A", + "PostTabNum": "0000000004" + }, + { + "PostTh": "Абвгдеёжзик лмнопрстуфхцчшщъ(Кккккккк ккккккк кккккккк)", + "PostSh": "Абвгде.жзиклм-но(Кккккккк к.к.)", + "KodeMod": "$A", + "PostTabNum": "0000000004" + } + ] + }, + { + "-idSLMS": "9", + "LMS": [ + { + "PostTh": "Абвгдеёжзик лмнопрстуфхцчшщъ(Кккккккк ккккккк кккккккк)", + "PostSh": "Абвгде.жзиклм-но(Кккккккк к.к.)", + "KodeMod": "$A", + "PostTabNum": "0000000004" + }, + { + "PostTh": "Абвгдеёжзик лмнопрстуфхцчшщъ(Кккккккк ккккккк кккккккк)", + "PostSh": "Абвгде.жзиклм-но(Кккккккк к.к.)", + "KodeMod": "$A", + "PostTabNum": "0000000004" + }, + { + "PostTh": "Абвгдеёжзик лмнопрстуфхцчшщъ(Кккккккк ккккккк кккккккк)", + "PostSh": "Абвгде.жзиклм-но(Кккккккк к.к.)", + "KodeMod": "$A", + "PostTabNum": "0000000004" + } + ] + }, + { + "-idSLMS": "10", + "LMS": [ + { + "PostTh": "Абвгдеёжзик лмнопрстуфхцчшщъ(Кккккккк ккккккк кккккккк)", + "PostSh": "Абвгде.жзиклм-но(Кккккккк к.к.)", + "KodeMod": "$A", + "PostTabNum": "0000000004" + }, + { + "PostTh": "Абвгдеёжзик лмнопрстуфхцчшщъ(Кккккккк ккккккк кккккккк)", + "PostSh": "Абвгде.жзиклм-но(Кккккккк к.к.)", + "KodeMod": "$A", + "PostTabNum": "0000000004" + }, + { + "PostTh": "Абвгдеёжзик лмнопрстуфхцчшщъ(Кккккккк ккккккк кккккккк)", + "PostSh": "Абвгде.жзиклм-но(Кккккккк к.к.)", + "KodeMod": "$A", + "PostTabNum": "0000000004" + } + ] + }, + { + "-idSLMS": "11", + "LMS": [ + { + "PostTh": "Абвгдеёжзик лмнопрстуфхцчшщъ(Кккккккк ккккккк кккккккк)", + "PostSh": "Абвгде.жзиклм-но(Кккккккк к.к.)", + "KodeMod": "$A", + "PostTabNum": "0000000004" + }, + { + "PostTh": "Абвгдеёжзик лмнопрстуфхцчшщъ(Кккккккк ккккккк кккккккк)", + "PostSh": "Абвгде.жзиклм-но(Кккккккк к.к.)", + "KodeMod": "$A", + "PostTabNum": "0000000004" + }, + { + "PostTh": "Абвгдеёжзик лмнопрстуфхцчшщъ(Кккккккк ккккккк кккккккк)", + "PostSh": "Абвгде.жзиклм-но(Кккккккк к.к.)", + "KodeMod": "$A", + "PostTabNum": "0000000004" + } + ] + }, + { + "-idSLMS": "12", + "LMS": [ + { + "PostTh": "Департамент ведомственного финансового контроля и аудита МО РФ", + "PostSh": "ДВФКиА МО", + "KodeMod": "$$", + "PostTabNum": "0000000001" + }, + { + "PostTh": "Консультант (Мирошниченко Ирина Владимировна)", + "PostSh": "Консультант(Мирошниченко И.В)", + "KodeMod": "$5", + "PostTabNum": "0000000015" + }, + { + "PostTh": "Главный специалист-эксперт (Власова Екатерина Генадьевнна)", + "PostSh": "Гл.спец-эксперт(Власова Е.Г)", + "KodeMod": "$7", + "PostTabNum": "0000000013" + } + ] + }, + { + "-idSLMS": "13", + "LMS": [ + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + }, + { + "PostTh": "Учёт обращений граждан (Еееееее еееее ееееее)", + "PostSh": "Учет обращений гр.(Ееееееее Е.Е)", + "KodeMod": "$d", + "PostTabNum": "0000000033" + } + ] + } + ] + } +} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/employees.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/employees.json new file mode 100644 index 0000000000..7fff289e9b --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/employees.json @@ -0,0 +1,30 @@ +[ + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee Dependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + } +] diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/employees.txt b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/employees.txt new file mode 100644 index 0000000000..553ea8af00 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/employees.txt @@ -0,0 +1,6 @@ +employee-no employee-name dept salary note +00000001 Smith, Matthew sales 150,000.00 +00000002 Brown, Sarah sales 89,000.00 +00000003 Oberc, Scott finance 110,000.00 +00000004 Scott, Colette sales 75,000.00 """Exemplary"" employee +Dependable, trustworthy" diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/json-exception-1.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/json-exception-1.json new file mode 100644 index 0000000000..ccfa766300 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/json-exception-1.json @@ -0,0 +1,20 @@ + { + // Members + "members" : [ + { + "first_name":"Jane", + "last_name":"Roe", + "events_attended":10, + "accept_waiver_of_liability" : true + }, + /* Missing + *left* + brace */ + + "first_name":"John", + "last_name":"Doe", + "events_attended":2, + "accept_waiver_of_liability" : true + } + ] + } diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/json-exception-2.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/json-exception-2.json new file mode 100644 index 0000000000..7673749abf --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/json-exception-2.json @@ -0,0 +1,18 @@ + { + // Members + "members" : [ + { + "first_name":"Jane", + "last_name":"Roe", + "events_attended":10, + "accept_waiver_of_liability" : true + }, + { + "first_name":"John", + "last_name":"Doe", + "events_attended":2, + "accept_waiver_of_liability" : true + /* Missing *right* + brace */ + ] + } diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/json-multiline-comment.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/json-multiline-comment.json new file mode 100644 index 0000000000..3f481aa256 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/json-multiline-comment.json @@ -0,0 +1,2524 @@ +[ +/* + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + }, + { + "dept":"sales", + "employee-name":"Smith, Matthew", + "employee-no":"00000001", + "note":"", + "salary":"150,000.00" + }, + { + "dept":"sales", + "employee-name":"Brown, Sarah", + "employee-no":"00000002", + "note":"", + "salary":"89,000.00" + }, + { + "dept":"finance", + "employee-name":"Oberc, Scott", + "employee-no":"00000003", + "salary":"110,000.00" + }, + { + "dept":"sales", + "employee-name":"Scott, Colette", + "employee-no":"00000004", + "note":"\"Exemplary\" employee\nDependable, trustworthy", + "comment":"Team player", + "salary":"75,000.00" + } +*/ +] diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/locations.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/locations.json new file mode 100644 index 0000000000..ec7c8b05fd --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/locations.json @@ -0,0 +1,17 @@ + { + // Members + "members" : [ + { + "first_name":"Jane", + "last_name":"Roe", + "events_attended":10, + "accept_waiver_of_liability" : true + }, + /* Error - missing *left* brace */ + "first_name":"John", + "last_name":"Doe", + "events_attended":2, + "accept_waiver_of_liability" : true + } + ] + } diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/members.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/members.json new file mode 100644 index 0000000000..02808f47a9 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/members.json @@ -0,0 +1,17 @@ + { + // Members + "members" : [ + { + "first_name":"Jane", + "last_name":"Roe", + "events_attended":10, + "accept_waiver_of_liability" : true + }, + { + "first_name":"John", + "last_name":"Doe", + "events_attended":2, + "accept_waiver_of_liability" : true + } + ] + } diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/persons.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/persons.json new file mode 100644 index 0000000000..b4685503c1 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/input/persons.json @@ -0,0 +1,3 @@ +{ + "persons" : ["John","David"] +} diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/output/address-book-new.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/output/address-book-new.json new file mode 100644 index 0000000000..f0cc264027 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/output/address-book-new.json @@ -0,0 +1,13 @@ +{ + "address-book": [ + { + "first-name": "Jane", + "last-name": "Roe", + "email2": "jane.roe@example.com" + }, + { + "first-name": "John", + "email2": "john.doe@example.com" + } + ] +} \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/output/store.cbor b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/output/store.cbor new file mode 100644 index 0000000000..03e6321d73 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/output/store.cbor @@ -0,0 +1 @@ +kapplicationfhikinghreputonsiassertionlstrong-hikereratediMarilyn CeraterxHikingAsylum.example.comfrating? \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/output/test.json b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/output/test.json new file mode 100644 index 0000000000..eb66f851e4 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/output/test.json @@ -0,0 +1,1502 @@ +[ + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + }, + { + "person": { + "first_name": "john", + "last_name": "doe", + "birthdate": "1998-05-13", + "sex": "m", + "salary": 70000, + "interests": ["Reading","Mountain biking","Hacking"], + "favorites": { + "color": "blue", + "sport": "soccer", + "food": "spaghetti" + } + } + } +] \ No newline at end of file diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/JSONTestSuite_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/JSONTestSuite_tests.cpp new file mode 100644 index 0000000000..4650aa16e6 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/JSONTestSuite_tests.cpp @@ -0,0 +1,76 @@ +// Copyright 2013-2018 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) && _MSC_VER >= 1900 +#include +namespace fs = std::experimental::filesystem; +#else +//#include +//namespace fs = std::filesystem; +#endif + +using namespace jsoncons; + +#if defined(_MSC_VER) && _MSC_VER >= 1900 +TEST_CASE("JSON Parsing Test Suite") +{ + SECTION("Expected success") + { + std::string path = "./input/JSONTestSuite"; + for (auto& p : fs::directory_iterator(path)) + { + if (fs::exists(p) && fs::is_regular_file(p) && p.path().extension() == ".json" && p.path().filename().c_str()[0] == 'y') + { + std::ifstream is(p.path().c_str()); + strict_parse_error_handler err_handler; + json_reader reader(is, err_handler); + std::error_code ec; + reader.read(ec); + if (ec) + { + std::cout << p.path().filename().string() << " failed, expected success\n"; + } + CHECK_FALSE(ec); + } + } + } + SECTION("Expected failure") + { + std::string path = "./input/JSONTestSuite"; + for (auto& p : fs::directory_iterator(path)) + { + if (fs::exists(p) && fs::is_regular_file(p) && p.path().extension() == ".json" && p.path().filename().c_str()[0] == 'n') + { + std::ifstream is(p.path().c_str()); + strict_parse_error_handler err_handler; + json_reader reader(is, err_handler); + std::error_code ec; + reader.read(ec); + if (!ec) + { + std::cout << p.path().filename().string() << " succeeded, expected failure\n"; + } + CHECK(ec); + } + } + } +} +#endif + + + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/bignum_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/bignum_tests.cpp new file mode 100644 index 0000000000..927ccf087a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/bignum_tests.cpp @@ -0,0 +1,329 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#if defined(_MSC_VER) +#include "windows.h" +#endif +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +TEST_CASE("test_positive_bignum") +{ + std::string expected = "18446744073709551616"; + std::vector v = {1,0,0,0,0,0,0,0,0}; + bignum x(1,v.data(),v.size()); + + std::string sx; + x.dump(sx); + CHECK(sx == expected); + + bignum y(x); + std::string sy; + y.dump(sy); + CHECK(sy == expected); + + bignum z; + z = x; + std::string sz; + y.dump(sz); + CHECK(sz == expected); + + SECTION("dump_hex_string") + { + std::string exp = "10000000000000000"; + std::string s; + x.dump_hex_string(s); + CHECK(s == exp); + } + +} + +TEST_CASE("bignums are equal") +{ + std::string s = "18446744073709551616"; + bignum x(s); + bignum y(s); + + bool test = x == y; + CHECK(test); +} + +TEST_CASE("test_negative_bignum") +{ + std::string expected = "-18446744073709551617"; + std::vector b = {0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + bignum x(-1,b.data(),b.size()); + + std::string sx; + x.dump(sx); + CHECK(sx == expected); + + bignum y(x); + std::string sy; + y.dump(sy); + CHECK(sy == expected); + + bignum z; + z = x; + std::string sz; + y.dump(sz); + CHECK(sz == expected); + + int signum; + std::vector v; + x.dump(signum, v); + + REQUIRE(v.size() == b.size()); + for (size_t i = 0; i < v.size(); ++i) + { + REQUIRE(v[i] == b[i]); + } + + SECTION("dump_hex_string") + { + std::string exp = "-10000000000000001"; + std::string s; + x.dump_hex_string(s); + //std::cout << "bignum: " << expected << ", s: " << s << "\n"; + CHECK(s == exp); + } +} + +TEST_CASE("test_longlong") +{ + long long n = (std::numeric_limits::max)(); + + bignum val = n; + + //std::cout << "long long " << n << " == " << val << std::endl; + //std::cout << val.to_string(16) << std::endl; +} + +TEST_CASE("test_bignum2") +{ + std::string v = "10000000000000000"; + bignum val(v.data()); + + //std::cout << val << std::endl; +} + +TEST_CASE("test_logical_operations") +{ + bignum x( "888888888888888888" ); + bignum y( "888888888888888888" ); + + bignum z = x & y; + + bool test = z == x; + CHECK(test); +} + +TEST_CASE("test_addition") +{ + bignum x( "4444444444444444444444444444444" ); + bignum y( "4444444444444444444444444444444" ); + bignum a( "8888888888888888888888888888888" ); + + bignum z = x + y; + bool test = z == a; + CHECK(test); +} + +TEST_CASE("test_multiplication") +{ + bignum x( "4444444444444444444444444444444" ); + bignum a( "8888888888888888888888888888888" ); + + bignum z = 2*x; + bool test = z == a; + CHECK(test); + + z = x*2; + + test = z == a; + CHECK(test); +} + +TEST_CASE("test_conversion_0") +{ + bignum x(1, {}); + + json j(x); + + bignum y = j.as(); + CHECK(bool(x == y)); + + std::string s; + y.dump(s); + + CHECK(s == "0"); +} + +TEST_CASE("test_traits1") +{ + bignum x(1, {0x01,0x00}); + + json j(x); + + bignum y = j.as(); + CHECK(bool(x == y)); + + std::string s; + y.dump(s); + + CHECK(s == "256"); +} + +TEST_CASE("test_traits2") +{ + bignum x(1, {0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}); + + json j(x); + + bignum y = j.as(); + CHECK(bool(x == y)); + + std::string s; + y.dump(s); + + CHECK(s == "18446744073709551616"); +} + +TEST_CASE("test_traits3") +{ + bignum x(-1, {0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}); + + int signum; + std::vector v; + x.dump(signum,v); + + REQUIRE(signum == -1); + //for (auto c : v) + //{ + // //std::cout << std::hex << (int)c; + //} + //std::cout << std::endl; + + json j(x); + + bignum y = j.as(); + CHECK(bool(x == y)); + + std::string s; + y.dump(s); + + CHECK(s == "-18446744073709551617"); +} + +TEST_CASE("test shift left") +{ + SECTION("n << 1") + { + bignum n("1"); + bignum x = n << 1; + std::string s; + x.dump(s); + CHECK(s == "2"); + } + SECTION("n << 100") + { + bignum n(1); + bignum x = n << 100; + std::string s; + x.dump(s); + CHECK(s == "1267650600228229401496703205376"); + } + SECTION("n << 100, += 1") + { + bignum n(1); + bignum x = n << 100; + x += 1; + std::string s; + x.dump(s); + CHECK(s == "1267650600228229401496703205377"); + } +} + +TEST_CASE("times 10") +{ + SECTION("1") + { + bignum n("1234"); + bignum m = n * 10; + std::string s; + m.dump(s); + CHECK(s == "12340"); + } + SECTION("31") + { + std::string expected("1234"); + bignum n(expected); + + for (size_t i = 0; i < 31; ++i) + { + n *= (uint64_t)10; + expected.push_back('0'); + } + std::string s; + n.dump(s); + CHECK(s == expected); + //std::cout << "x31: " << s << "\n"; + } + SECTION("32") + { + std::string expected("1234"); + bignum n(expected); + for (size_t i = 0; i < 32; ++i) + { + n *= (uint64_t)10; + expected.push_back('0'); + } + std::string s; + n.dump(s); + CHECK(s == expected); + //std::cout << "x31: " << s << "\n"; + } +} + + +TEST_CASE("bignum div") +{ +#if defined(_MSC_VER) && _MSC_VER >= 1910 + SECTION("bignum") + { + bignum big_pos = bignum("18364494661702398480"); + bignum small_pos = bignum("65535"); + bignum res_pos = bignum("280224226164681"); + bignum big_neg = -big_pos; + bignum small_neg = -small_pos; + bignum res_neg = -res_pos; + + CHECK((big_neg / big_neg) == bignum(1)); + CHECK((big_neg / small_neg) == res_pos); + CHECK((big_neg / small_pos) == res_neg); + CHECK((big_neg / big_pos) == bignum(-1)); + + CHECK((small_neg / big_neg) == bignum(0)); + CHECK((small_neg / small_neg) == bignum(1)); + CHECK((small_neg / small_pos) == bignum(-1)); + CHECK((small_neg / big_pos) == bignum(0)); + + CHECK((small_pos / big_neg) == bignum(0)); + CHECK((small_pos / small_neg) == bignum(-1)); + CHECK((small_pos / small_pos) == bignum(1)); + CHECK((small_pos / big_pos) == bignum(0)); + + CHECK((big_pos / big_neg) == bignum(-1)); + CHECK((big_pos / small_neg) == res_neg); + CHECK((big_pos / small_pos) == res_pos); + CHECK((big_pos / big_pos) == bignum(1)); + } +#endif +} diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/bson/bson_encoder_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/bson/bson_encoder_tests.cpp new file mode 100644 index 0000000000..f8dd2f9f0e --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/bson/bson_encoder_tests.cpp @@ -0,0 +1,247 @@ +// Copyright 2016 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +TEST_CASE("serialize object to bson") +{ + std::vector v; + bson::bson_bytes_encoder encoder(v); + + encoder.begin_object(); + encoder.name("null"); + encoder.null_value(); + encoder.end_object(); + encoder.flush(); + + try + { + json result = bson::decode_bson(v); + std::cout << result << std::endl; + } + catch (const std::exception& e) + { + std::cout << e.what() << std::endl; + } +} + +namespace jsoncons { namespace bson { + + void test_equal(const std::vector& v, const std::vector& expected) + { + REQUIRE(v.size() == expected.size()); + + for (size_t i = 0; i < v.size(); ++i) + { + CHECK(v[i] == expected[i]); + } + } + + void check_equal(const std::vector& v, const std::vector& expected) + { + test_equal(v, expected); + try + { + json j = bson::decode_bson(v); + std::vector u; + bson::encode_bson(j, u); + test_equal(v,u); + } + catch (const std::exception& e) + { + std::cout << e.what() << std::endl; + } + } +}} + +TEST_CASE("serialize to bson") +{ + SECTION("array") + { + std::vector v; + bson::bson_bytes_encoder encoder(v); + + encoder.begin_array(); + encoder.int64_value((std::numeric_limits::max)()); + encoder.uint64_value((uint64_t)(std::numeric_limits::max)()); + encoder.double_value((std::numeric_limits::max)()); + encoder.bool_value(true); + encoder.bool_value(false); + encoder.null_value(); + encoder.string_value("Pussy cat"); + encoder.byte_string_value(byte_string({'h','i','s','s'})); + encoder.end_array(); + encoder.flush(); + + std::vector bson = {0x4d,0x00,0x00,0x00, + 0x12, // int64 + 0x30, // '0' + 0x00, // terminator + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, + 0x12, // int64 + 0x31, // '1' + 0x00, // terminator + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, + 0x01, // double + 0x32, // '2' + 0x00, // terminator + 0xff,0xff,0xff,0xff,0xff,0xff,0xef,0x7f, + 0x08, // bool + 0x33, // '3' + 0x00, // terminator + 0x01, + 0x08, // bool + 0x34, // '4' + 0x00, // terminator + 0x00, + 0x0a, // null + 0x35, // '5' + 0x00, // terminator + 0x02, // string + 0x36, // '6' + 0x00, // terminator + 0x0a,0x00,0x00,0x00, // string length + 'P','u','s','s','y',' ','c','a','t', + 0x00, // terminator + 0x05, // binary + 0x37, // '7' + 0x00, // terminator + 0x04,0x00,0x00,0x00, // byte string length + 'h','i','s','s', + 0x00 // terminator + }; + jsoncons::bson::check_equal(v,bson); + + } + SECTION("object") + { + std::vector v; + bson::bson_bytes_encoder encoder(v); + + encoder.begin_object(); + encoder.name("0"); + encoder.int64_value((std::numeric_limits::max)()); + encoder.name("1"); + encoder.uint64_value((uint64_t)(std::numeric_limits::max)()); + encoder.name("2"); + encoder.double_value((std::numeric_limits::max)()); + encoder.name("3"); + encoder.bool_value(true); + encoder.name("4"); + encoder.bool_value(false); + encoder.name("5"); + encoder.null_value(); + encoder.name("6"); + encoder.string_value("Pussy cat"); + encoder.name("7"); + encoder.byte_string_value(byte_string({'h','i','s','s'})); + encoder.end_object(); + encoder.flush(); + + std::vector bson = {0x4d,0x00,0x00,0x00, + 0x12, // int64 + 0x30, // '0' + 0x00, // terminator + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, + 0x12, // int64 + 0x31, // '1' + 0x00, // terminator + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, + 0x01, // double + 0x32, // '2' + 0x00, // terminator + 0xff,0xff,0xff,0xff,0xff,0xff,0xef,0x7f, + 0x08, // bool + 0x33, // '3' + 0x00, // terminator + 0x01, + 0x08, // bool + 0x34, // '4' + 0x00, // terminator + 0x00, + 0x0a, // null + 0x35, // '5' + 0x00, // terminator + 0x02, // string + 0x36, // '6' + 0x00, // terminator + 0x0a,0x00,0x00,0x00, // string length + 'P','u','s','s','y',' ','c','a','t', + 0x00, // terminator + 0x05, // binary + 0x37, // '7' + 0x00, // terminator + 0x04,0x00,0x00,0x00, // byte string length + 'h','i','s','s', + 0x00 // terminator + }; + jsoncons::bson::check_equal(v,bson); + } + + SECTION("outer object") + { + std::vector v; + bson::bson_bytes_encoder encoder(v); + + encoder.begin_object(); + encoder.name("a"); + encoder.begin_object(); + encoder.name("0"); + encoder.int64_value((std::numeric_limits::max)()); + encoder.end_object(); + encoder.end_object(); + encoder.flush(); + + std::vector bson = {0x18,0x00,0x00,0x00, + 0x03, // object + 'a', + 0x00, + 0x10,0x00,0x00,0x00, + 0x12, // int64 + 0x30, // '0' + 0x00, // terminator + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, + 0x00, // terminator + 0x00 // terminator + }; + jsoncons::bson::check_equal(v,bson); + } + + SECTION("outer array") + { + std::vector v; + bson::bson_bytes_encoder encoder(v); + + encoder.begin_array(); + encoder.begin_object(); + encoder.name("0"); + encoder.int64_value((std::numeric_limits::max)()); + encoder.end_object(); + encoder.end_array(); + encoder.flush(); + + std::vector bson = {0x18,0x00,0x00,0x00, + 0x03, // object + '0', + 0x00, + 0x10,0x00,0x00,0x00, + 0x12, // int64 + 0x30, // '0' + 0x00, // terminator + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, + 0x00, // terminator + 0x00 // terminator + }; + jsoncons::bson::check_equal(v,bson); + } +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/bson/bson_reader_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/bson/bson_reader_tests.cpp new file mode 100644 index 0000000000..a903d8a210 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/bson/bson_reader_tests.cpp @@ -0,0 +1,40 @@ +// Copyright 2016 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +void check_decode_bson(const std::vector& v, const json& expected) +{ + json result = bson::decode_bson(v); + REQUIRE(result == expected); + + std::string s; + for (auto c : v) + { + s.push_back(c); + } + std::istringstream is(s); + json j2 = bson::decode_bson(is); + REQUIRE(j2 == expected); +} + +TEST_CASE("bson hello world") +{ + check_decode_bson({0x16,0x00,0x00,0x00, // total document size + 0x02, // string + 'h','e','l','l','o', 0x00, // field name + 0x06,0x00,0x00,0x00, // size of value + 'w','o','r','l','d',0x00, // field value and null terminator + 0x00 // end of document + },json::parse("{\"hello\":\"world\"}")); +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/byte_string_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/byte_string_tests.cpp new file mode 100644 index 0000000000..297c111f10 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/byte_string_tests.cpp @@ -0,0 +1,106 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +// https://tools.ietf.org/html/rfc4648#section-4 test vectors + +void check_encode_base64(const std::vector& input, const std::string& expected) +{ + std::string result; + encode_base64(input.begin(),input.end(),result); + REQUIRE(result.size() == expected.size()); + for (size_t i = 0; i < result.size(); ++i) + { + CHECK(result[i] == expected[i]); + } + + std::vector output; + decode_base64(result.begin(), result.end(), output); + REQUIRE(output.size() == input.size()); + for (size_t i = 0; i < output.size(); ++i) + { + CHECK(output[i] == input[i]); + } +} + +void check_encode_base64url(const std::vector& input, const std::string& expected) +{ + std::string result; + encode_base64url(input.begin(),input.end(),result); + REQUIRE(result.size() == expected.size()); + for (size_t i = 0; i < result.size(); ++i) + { + CHECK(result[i] == expected[i]); + } + + std::vector output; + decode_base64url(result.begin(), result.end(), output); + REQUIRE(output.size() == input.size()); + for (size_t i = 0; i < output.size(); ++i) + { + CHECK(output[i] == input[i]); + } +} + +void check_encode_base16(const std::vector& input, const std::string& expected) +{ + std::string result; + encode_base16(input.begin(),input.end(),result); + REQUIRE(result.size() == expected.size()); + for (size_t i = 0; i < result.size(); ++i) + { + CHECK(result[i] == expected[i]); + } + + std::vector output; + decode_base16(result.begin(), result.end(), output); + REQUIRE(output.size() == input.size()); + for (size_t i = 0; i < output.size(); ++i) + { + CHECK(output[i] == input[i]); + } +} +TEST_CASE("test_base64_conversion") +{ + check_encode_base64({}, ""); + check_encode_base64({'f'}, "Zg=="); + check_encode_base64({'f','o'}, "Zm8="); + check_encode_base64({'f','o','o'}, "Zm9v"); + check_encode_base64({'f','o','o','b'}, "Zm9vYg=="); + check_encode_base64({'f','o','o','b','a'}, "Zm9vYmE="); + check_encode_base64({'f','o','o','b','a','r'}, "Zm9vYmFy"); +} + +TEST_CASE("test_base64url_conversion") +{ + check_encode_base64url({}, ""); + check_encode_base64url({'f'}, "Zg"); + check_encode_base64url({'f','o'}, "Zm8"); + check_encode_base64url({'f','o','o'}, "Zm9v"); + check_encode_base64url({'f','o','o','b'}, "Zm9vYg"); + check_encode_base64url({'f','o','o','b','a'}, "Zm9vYmE"); + check_encode_base64url({'f','o','o','b','a','r'}, "Zm9vYmFy"); +} + +TEST_CASE("test_base16_conversion") +{ + check_encode_base16({}, ""); + check_encode_base16({'f'}, "66"); + check_encode_base16({'f','o'}, "666F"); + check_encode_base16({'f','o','o'}, "666F6F"); + check_encode_base16({'f','o','o','b'}, "666F6F62"); + check_encode_base16({'f','o','o','b','a'}, "666F6F6261"); + check_encode_base16({'f','o','o','b','a','r'}, "666F6F626172"); +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/cbor/cbor_encoder_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/cbor/cbor_encoder_tests.cpp new file mode 100644 index 0000000000..44eef14b57 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/cbor/cbor_encoder_tests.cpp @@ -0,0 +1,393 @@ +// Copyright 2016 Daniel Parker +// Distributed under Boost license + +#if defined(_MSC_VER) +#include "windows.h" +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +TEST_CASE("test_serialize_to_stream") +{ +json j = json::parse(R"( +{ + "application": "hiking", + "reputons": [ + { + "rater": "HikingAsylum.example.com", + "assertion": "strong-hiker", + "rated": "Marilyn C", + "rating": 0.90 + } + ] +} +)"); + + std::ofstream os; + os.open("./output/store.cbor", std::ios::binary | std::ios::out); + cbor::encode_cbor(j,os); + + std::vector v; + std::ifstream is; + is.open("./output/store.cbor", std::ios::binary | std::ios::in); + + json j2 = cbor::decode_cbor(is); + + //std::cout << pretty_print(j2) << std::endl; + + CHECK(j == j2); +} + +TEST_CASE("serialize array to cbor") +{ + std::vector v; + cbor::cbor_bytes_encoder encoder(v); + //encoder.begin_object(1); + encoder.begin_array(3); + encoder.bool_value(true); + encoder.bool_value(false); + encoder.null_value(); + encoder.end_array(); + //encoder.end_object(); + encoder.flush(); + + try + { + json result = cbor::decode_cbor(v); + //std::cout << result << std::endl; + } + catch (const std::exception& e) + { + std::cout << e.what() << std::endl; + } +} + +TEST_CASE("test_serialize_indefinite_length_array") +{ + std::vector v; + cbor::cbor_bytes_encoder encoder(v); + encoder.begin_array(); + encoder.begin_array(4); + encoder.bool_value(true); + encoder.bool_value(false); + encoder.null_value(); + encoder.string_value("Hello"); + encoder.end_array(); + encoder.end_array(); + encoder.flush(); + + try + { + json result = cbor::decode_cbor(v); + //std::cout << result << std::endl; + } + catch (const std::exception& e) + { + std::cout << e.what() << std::endl; + } +} +TEST_CASE("test_serialize_bignum") +{ + std::vector v; + cbor::cbor_bytes_encoder encoder(v); + encoder.begin_array(); + + std::vector bytes = {0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + bignum n(1, bytes.data(), bytes.size()); + std::string s; + n.dump(s); + encoder.string_value(s, semantic_tag::bigint); + encoder.end_array(); + encoder.flush(); + + try + { + json result = cbor::decode_cbor(v); + CHECK(result[0].as() == std::string("18446744073709551616")); + } + catch (const std::exception& e) + { + std::cout << e.what() << std::endl; + } +} + +TEST_CASE("test_serialize_negative_bignum1") +{ + std::vector v; + cbor::cbor_bytes_encoder encoder(v); + encoder.begin_array(); + + std::vector bytes = {0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + bignum n(-1, bytes.data(), bytes.size()); + std::string s; + n.dump(s); + encoder.string_value(s, semantic_tag::bigint); + encoder.end_array(); + encoder.flush(); + + try + { + json result = cbor::decode_cbor(v); + CHECK(result[0].as() == std::string("-18446744073709551617")); + } + catch (const std::exception& e) + { + std::cout << e.what() << std::endl; + } +} + +TEST_CASE("test_serialize_negative_bignum2") +{ + std::vector v; + cbor::cbor_bytes_encoder encoder(v); + encoder.begin_array(); + + std::vector bytes = {0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + bignum n(-1, bytes.data(), bytes.size()); + std::string s; + n.dump(s); + encoder.string_value(s, semantic_tag::bigint); + encoder.end_array(); + encoder.flush(); + + try + { + json result = cbor::decode_cbor(v); + json_options options; + options.bigint_format(bigint_chars_format::number); + std::string text; + result.dump(text,options); + CHECK(text == std::string("[-18446744073709551617]")); + } + catch (const std::exception& e) + { + std::cout << e.what() << std::endl; + } +} + +TEST_CASE("test_serialize_negative_bignum3") +{ + std::vector v; + cbor::cbor_bytes_encoder encoder(v); + encoder.begin_array(); + + std::vector bytes = {0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + + bignum n(-1, bytes.data(), bytes.size()); + std::string s; + n.dump(s); + encoder.string_value(s, semantic_tag::bigint); + encoder.end_array(); + encoder.flush(); + + try + { + json result = cbor::decode_cbor(v); + json_options options; + options.bigint_format(bigint_chars_format::base64url); + std::string text; + result.dump(text,options); + CHECK(text == std::string("[\"~AQAAAAAAAAAA\"]")); + } + catch (const std::exception& e) + { + std::cout << e.what() << std::endl; + } +} + +TEST_CASE("serialize bigdec to cbor") +{ + SECTION("-1 184467440737095516160") + { + std::vector v; + cbor::cbor_bytes_encoder encoder(v); + encoder.string_value("18446744073709551616.0", semantic_tag::bigdec); + encoder.flush(); + try + { + json result = cbor::decode_cbor(v); + CHECK(result.as() == std::string("1.84467440737095516160e+19")); + } + catch (const std::exception& e) + { + std::cout << e.what() << std::endl; + } + } + SECTION("18446744073709551616e-5") + { + std::vector v; + cbor::cbor_bytes_encoder encoder(v); + encoder.string_value("18446744073709551616e-5", semantic_tag::bigdec); + encoder.flush(); + try + { + json result = cbor::decode_cbor(v); + CHECK(result.as() == std::string("184467440737095.51616")); + } + catch (const std::exception& e) + { + std::cout << e.what() << std::endl; + } + } + SECTION("-18446744073709551616e-5") + { + std::vector v; + cbor::cbor_bytes_encoder encoder(v); + encoder.string_value("-18446744073709551616e-5", semantic_tag::bigdec); + encoder.flush(); + try + { + json result = cbor::decode_cbor(v); + CHECK(result.as() == std::string("-184467440737095.51616")); + } + catch (const std::exception& e) + { + std::cout << e.what() << std::endl; + } + } + SECTION("-18446744073709551616e5") + { + std::vector v; + cbor::cbor_bytes_encoder encoder(v); + encoder.string_value("-18446744073709551616e5", semantic_tag::bigdec); + encoder.flush(); + try + { + json result = cbor::decode_cbor(v); + CHECK(result.as() == std::string("-1.8446744073709551616e+24")); + } + catch (const std::exception& e) + { + std::cout << e.what() << std::endl; + } + } +} + +TEST_CASE("Too many and too few items in CBOR map or array") +{ + std::error_code ec{}; + std::vector v; + cbor::cbor_bytes_encoder encoder(v); + + SECTION("Too many items in array") + { + CHECK(encoder.begin_array(3)); + CHECK(encoder.bool_value(true)); + CHECK(encoder.bool_value(false)); + CHECK(encoder.null_value()); + CHECK(encoder.begin_array(2)); + CHECK(encoder.string_value("cat")); + CHECK(encoder.string_value("feline")); + CHECK(encoder.end_array()); + REQUIRE_THROWS_WITH(encoder.end_array(), cbor::cbor_error_category_impl().message((int)cbor::cbor_errc::too_many_items).c_str()); + encoder.flush(); + } + SECTION("Too few items in array") + { + CHECK(encoder.begin_array(5)); + CHECK(encoder.bool_value(true)); + CHECK(encoder.bool_value(false)); + CHECK(encoder.null_value()); + CHECK(encoder.begin_array(2)); + CHECK(encoder.string_value("cat")); + CHECK(encoder.string_value("feline")); + CHECK(encoder.end_array()); + REQUIRE_THROWS_WITH(encoder.end_array(), cbor::cbor_error_category_impl().message((int)cbor::cbor_errc::too_few_items).c_str()); + encoder.flush(); + } + SECTION("Too many items in map") + { + CHECK(encoder.begin_object(3)); + CHECK(encoder.name("a")); + CHECK(encoder.bool_value(true)); + CHECK(encoder.name("b")); + CHECK(encoder.bool_value(false)); + CHECK(encoder.name("c")); + CHECK(encoder.null_value()); + CHECK(encoder.name("d")); + CHECK(encoder.begin_array(2)); + CHECK(encoder.string_value("cat")); + CHECK(encoder.string_value("feline")); + CHECK(encoder.end_array()); + REQUIRE_THROWS_WITH(encoder.end_object(), cbor::cbor_error_category_impl().message((int)cbor::cbor_errc::too_many_items).c_str()); + encoder.flush(); + } + SECTION("Too few items in map") + { + CHECK(encoder.begin_object(5)); + CHECK(encoder.name("a")); + CHECK(encoder.bool_value(true)); + CHECK(encoder.name("b")); + CHECK(encoder.bool_value(false)); + CHECK(encoder.name("c")); + CHECK(encoder.null_value()); + CHECK(encoder.name("d")); + CHECK(encoder.begin_array(2)); + CHECK(encoder.string_value("cat")); + CHECK(encoder.string_value("feline")); + CHECK(encoder.end_array()); + REQUIRE_THROWS_WITH(encoder.end_object(), cbor::cbor_error_category_impl().message((int)cbor::cbor_errc::too_few_items).c_str()); + encoder.flush(); + } + SECTION("Just enough items") + { + CHECK(encoder.begin_array(4)); // a fixed length array + CHECK(encoder.string_value("foo")); + CHECK(encoder.byte_string_value(byte_string{'P','u','s','s'})); // no suggested conversion + CHECK(encoder.string_value("-18446744073709551617", semantic_tag::bigint)); + CHECK(encoder.string_value("273.15", semantic_tag::bigdec)); + CHECK(encoder.end_array()); + CHECK_FALSE(ec); + encoder.flush(); + } +} + +TEST_CASE("encode stringref") +{ + ojson j = ojson::parse(R"( +[ + { + "name" : "Cocktail", + "count" : 417, + "rank" : 4 + }, + { + "rank" : 4, + "count" : 312, + "name" : "Bath" + }, + { + "count" : 691, + "name" : "Food", + "rank" : 4 + } + ] +)"); + + cbor::cbor_options options; + options.pack_strings(true); + std::vector buf; + + cbor::encode_cbor(j, buf, options); + + //for (auto c : buf) + //{ + // std::cout << std::hex << std::setprecision(2) << std::setw(2) + // << std::noshowbase << std::setfill('0') << static_cast(c); + //} + //std::cout << "\n"; + + ojson j2 = cbor::decode_cbor(buf); + CHECK(j2 == j); +} diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/cbor/cbor_reader_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/cbor/cbor_reader_tests.cpp new file mode 100644 index 0000000000..3591056cba --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/cbor/cbor_reader_tests.cpp @@ -0,0 +1,733 @@ +// Copyright 2016 Daniel Parker +// Distributed under Boost license + +#if defined(_MSC_VER) +#include "windows.h" +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; +using namespace jsoncons::cbor; + +void check_parse_cbor(const std::vector& v, const json& expected) +{ + try + { + std::error_code ec; + + jsoncons::json_decoder decoder; + cbor_bytes_reader parser(v, decoder); + parser.read(ec); + + json result = decoder.get_result(); + + if (!(result == expected)) + { + std::cout << "v: "; + for (auto b : v) + { + std::cout << "0x" << std::hex << (int)b; + } + std::cout << "\n"; + std::cout << "result: " << result << "\n"; + std::cout << "expected: " << expected << "\n"; + } + + REQUIRE(result == expected); + CHECK(result.get_semantic_tag() == expected.get_semantic_tag()); + + std::string s; + for (auto c : v) + { + s.push_back(c); + } + std::istringstream is(s); + json j2 = decode_cbor(is); + REQUIRE(j2 == expected); + } + catch (const std::exception& e) + { + std::cout << e.what() << std::endl; + std::cout << expected.to_string() << std::endl; + } +} +TEST_CASE("test_cbor_parsing") +{ + // unsigned integer + check_parse_cbor({0x00},json(0U)); + check_parse_cbor({0x01},json(1U)); + check_parse_cbor({0x0a},json(10U)); + check_parse_cbor({0x17},json(23U)); + check_parse_cbor({0x18,0x18},json(24U)); + check_parse_cbor({0x18,0xff},json(255U)); + check_parse_cbor({0x19,0x01,0x00},json(256U)); + check_parse_cbor({0x19,0xff,0xff},json(65535U)); + check_parse_cbor({0x1a,0,1,0x00,0x00},json(65536U)); + check_parse_cbor({0x1a,0xff,0xff,0xff,0xff},json(4294967295U)); + check_parse_cbor({0x1b,0,0,0,1,0,0,0,0},json(4294967296U)); + check_parse_cbor({0x1b,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff},json((std::numeric_limits::max)())); + + // positive signed integer + check_parse_cbor({0x00},json(0)); + check_parse_cbor({0x01},json(1)); + check_parse_cbor({0x0a},json(10)); + check_parse_cbor({0x17},json(23)); + check_parse_cbor({0x18,0x18},json(24)); + check_parse_cbor({0x18,0xff},json(255)); + check_parse_cbor({0x19,0x01,0x00},json(256)); + check_parse_cbor({0x19,0xff,0xff},json(65535)); + check_parse_cbor({0x1a,0,1,0x00,0x00},json(65536)); + check_parse_cbor({0x1a,0xff,0xff,0xff,0xff},json(4294967295)); + check_parse_cbor({0x1b,0,0,0,1,0,0,0,0},json(4294967296)); + check_parse_cbor({0x1b,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff},json((std::numeric_limits::max)())); + // negative integers + check_parse_cbor({0x20},json(-1)); + check_parse_cbor({0x21},json(-2)); + check_parse_cbor({0x37},json(-24)); + check_parse_cbor({0x38,0x18},json(-25)); + check_parse_cbor({0x38,0xff},json(-256)); + check_parse_cbor({0x39,0x01,0x00},json(-257)); + check_parse_cbor({0x39,0xff,0xff},json(-65536)); + check_parse_cbor({0x3a,0,1,0x00,0x00},json(-65537)); + + check_parse_cbor({0x3a,0xff,0xff,0xff,0xff},json(-4294967296)); + check_parse_cbor({0x3b,0,0,0,1,0,0,0,0},json(-4294967297)); + + // null, undefined, true, false + check_parse_cbor({0xf6},json::null()); + check_parse_cbor({0xf7},json{null_type(),semantic_tag::undefined}); + check_parse_cbor({0xf5},json(true)); + check_parse_cbor({0xf4},json(false)); + + // floating point + check_parse_cbor({0xfb,0,0,0,0,0,0,0,0},json(0.0)); + check_parse_cbor({0xfb,0xbf,0xf0,0,0,0,0,0,0},json(-1.0)); + check_parse_cbor({0xfb,0xc1,0x6f,0xff,0xff,0xe0,0,0,0},json(-16777215.0)); + check_parse_cbor({0xfa,0xcb,0x7f,0xff,0xff},json(-16777215.0)); + + // byte string + std::vector v; + check_parse_cbor({0x40},json(byte_string_view(v.data(),v.size()))); + v = {' '}; + check_parse_cbor({0x41,' '},json(byte_string_view(v.data(),v.size()))); + v = {0}; + check_parse_cbor({0x41,0},json(byte_string_view(v.data(),v.size()))); + v = {'H','e','l','l','o'}; + check_parse_cbor({0x45,'H','e','l','l','o'},json(byte_string_view(v.data(),v.size()))); + v = {'1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4'}; + check_parse_cbor({0x58,0x18,'1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4'}, + json(byte_string_view(v.data(),v.size()))); + + // string + check_parse_cbor({0x60},json("")); + check_parse_cbor({0x61,' '},json(" ")); + check_parse_cbor({0x78,0x18,'1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4'}, + json("123456789012345678901234")); + + // byte strings with undefined length + check_parse_cbor({0x5f,0xff}, json(byte_string())); + check_parse_cbor({0x5f,0x40,0xff}, json(byte_string())); + check_parse_cbor({0x5f,0x40,0x40,0xff}, json(byte_string())); + + check_parse_cbor({0x5f,0x43,'H','e','l',0x42,'l','o',0xff}, json(byte_string("Hello"))); + check_parse_cbor({0x5f,0x41,'H',0x41,'e',0x41,'l',0x41,'l',0x41,'o',0xff}, json(byte_string("Hello"))); + check_parse_cbor({0x5f,0x41,'H',0x41,'e',0x40,0x41,'l',0x41,'l',0x41,'o',0xff}, json(byte_string("Hello"))); + + // text strings with undefined length + + check_parse_cbor({0x7f,0xff}, json("")); + + check_parse_cbor({0x7f,0x60,0xff}, json("")); + check_parse_cbor({0x7f,0x60,0x60,0xff}, json("")); + check_parse_cbor({0x7f,0x63,'H','e','l',0x62,'l','o',0xff}, json("Hello")); + check_parse_cbor({0x7f,0x61,'H',0x61,'e',0x61,'l',0x61,'l',0x61,'o',0xff}, json("Hello")); + check_parse_cbor({0x7f,0x61,'H',0x61,'e',0x61,'l',0x60,0x61,'l',0x61,'o',0xff}, json("Hello")); + + SECTION ("arrays with definite length") + { + check_parse_cbor({0x80},json::array()); + check_parse_cbor({0x81,'\0'},json::parse("[0]")); + check_parse_cbor({0x82,'\0','\0'},json::array({0,0})); + check_parse_cbor({0x82,0x81,'\0','\0'}, json::parse("[[0],0]")); + check_parse_cbor({0x81,0x65,'H','e','l','l','o'},json::parse("[\"Hello\"]")); + + check_parse_cbor({0x83,0x01,0x82,0x02,0x03,0x82,0x04,0x05},json::parse("[1, [2, 3], [4, 5]]")); + check_parse_cbor({0x82, + 0x7f,0xff, + 0x7f,0xff}, + json::parse("[\"\",\"\"]")); + + check_parse_cbor({0x82, + 0x5f,0xff, + 0x5f,0xff}, + json::array{json(byte_string()),json(byte_string())}); + } + + SECTION("arrays with indefinite length") + { + //check_parse_cbor({0x9f,0xff},json::array()); + check_parse_cbor({0x9f,0x9f,0xff,0xff},json::parse("[[]]")); + + check_parse_cbor({0x9f,0x01,0x82,0x02,0x03,0x9f,0x04,0x05,0xff,0xff},json::parse("[1, [2, 3], [4, 5]]")); + check_parse_cbor({0x9f,0x01,0x82,0x02,0x03,0x82,0x04,0x05,0xff},json::parse("[1, [2, 3], [4, 5]]")); + + check_parse_cbor({0x83,0x01,0x82,0x02,0x03,0x9f,0x04,0x05,0xff},json::parse("[1, [2, 3], [4, 5]]")); + check_parse_cbor({0x83, // Array of length 3 + 0x01, // 1 + 0x9f, // Start indefinite-length array + 0x02, // 2 + 0x03, // 3 + 0xff, // "break" + 0x82, // Array of length 2 + 0x04, // 4 + 0x05}, // 5 + json::parse("[1, [2, 3], [4, 5]]")); + + } + + // big float + + check_parse_cbor({0xc5, // Tag 5 + 0x82, // Array of length 2 + 0x21, // -2 + 0x19, 0x6a, 0xb3 // 27315 + },json("0x6AB3p-2",semantic_tag::bigfloat)); + + SECTION("maps with definite length") + { + //check_parse_cbor({0xa0},json::object()); + check_parse_cbor({0xa1,0x62,'o','c',0x81,'\0'}, json::parse("{\"oc\": [0]}")); + //check_parse_cbor({0xa1,0x62,'o','c',0x84,'\0','\1','\2','\3'}, json::parse("{\"oc\": [0, 1, 2, 3]}")); + } + SECTION("maps with indefinite length") + { + check_parse_cbor({0xbf,0xff},json::object()); + check_parse_cbor({0xbf,0x64,'N','a','m','e',0xbf,0xff,0xff},json::parse("{\"Name\":{}}")); + + check_parse_cbor({0xbf, // Start indefinite-length map + 0x63, // First key, UTF-8 string length 3 + 0x46,0x75,0x6e, // "Fun" + 0xf5, // First value, true + 0x63, // Second key, UTF-8 string length 3 + 0x41,0x6d,0x74, // "Amt" + 0x21, // -2 + 0xff}, // "break" + json::parse("{\"Fun\": true, \"Amt\": -2}")); + check_parse_cbor({0xbf, // Start indefinite-length map + 0x21, // First key, -2 + 0xf5, // First value, true + 0xf5, // Second key, UTF-8 string length 3 + 0x21, // -2 + 0xff}, // "break" + json::parse("{\"-2\": true, \"true\": -2}")); + } + + SECTION("maps with non-string keys") + { + check_parse_cbor({0xbf, // Start indefinite-length map + 0x21, // First key, -2 + 0xf5, // First value, true + 0xf5, // Second key, UTF-8 string length 3 + 0x21, // -2 + 0xff}, // "break" + json::parse("{\"-2\": true, \"true\": -2}")); + } + + // bignum + check_parse_cbor({0xc2,0x49,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, + json(bignum(1,{0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}))); + + // datetime + check_parse_cbor({0xc0,0x78,0x19,'2','0','1','5','-','0','5','-','0','7',' ','1','2',':','4','1',':','0','7','-','0','7',':','0','0'}, + json("2015-05-07 12:41:07-07:00", semantic_tag::datetime)); + + // epoch_time + check_parse_cbor({0xc1,0x1a,0x55,0x4b,0xbf,0xd3}, + json(1431027667, semantic_tag::timestamp)); +} + +TEST_CASE("cbor decimal fraction") +{ + check_parse_cbor({0xc4, // Tag 4 + 0x82, // Array of length 2 + 0x21, // -2 + 0x19,0x6a,0xb3 // 27315 + }, + json("273.15", semantic_tag::bigdec)); + check_parse_cbor({0xc4, // Tag 4 + 0x82, // Array of length 2 + 0x22, // -3 + 0x19,0x6a,0xb3 // 27315 + }, + json("27.315", semantic_tag::bigdec)); + check_parse_cbor({0xc4, // Tag 4 + 0x82, // Array of length 2 + 0x23, // -4 + 0x19,0x6a,0xb3 // 27315 + }, + json("2.7315", semantic_tag::bigdec)); + check_parse_cbor({0xc4, // Tag 4 + 0x82, // Array of length 2 + 0x24, // -5 + 0x19,0x6a,0xb3 // 27315 + }, + json("0.27315", semantic_tag::bigdec)); + check_parse_cbor({0xc4, // Tag 4 + 0x82, // Array of length 2 + 0x25, // -6 + 0x19,0x6a,0xb3 // 27315 + }, + json("0.027315", semantic_tag::bigdec)); + + check_parse_cbor({0xc4, // Tag 4 + 0x82, // Array of length 2 + 0x04, // 4 + 0x19,0x6a,0xb3 // 27315 + }, + json("273150000.0", semantic_tag::bigdec)); +} + +TEST_CASE("test_decimal_as_string") +{ + SECTION("-2 27315") + { + std::vector v = {0xc4, // Tag 4, + 0x82, // Array of length 2 + 0x21, // -2 + 0x19,0x6a,0xb3 // 27315 + }; + + json j = decode_cbor(v); + CHECK(j.as() == std::string("273.15")); + } + SECTION("-6 27315") + { + std::vector v = {0xc4, // Tag 4, + 0x82, // Array of length 2 + 0x25, // -6 + 0x19,0x6a,0xb3 // 27315 + }; + + json j = decode_cbor(v); + CHECK(j.as() == std::string("0.027315")); + } + SECTION("-5 27315") + { + std::vector v = {0xc4, // Tag 4, + 0x82, // Array of length 2 + 0x24, // -5 + 0x19,0x6a,0xb3 // 27315 + }; + + json j = decode_cbor(v); + CHECK(j.as() == std::string("0.27315")); + } + SECTION("0 27315") + { + std::vector v = {0xc4, // Tag 4, + 0x82, // Array of length 2 + 0x00, // 0 + 0x19,0x6a,0xb3 // 27315 + }; + + json j = decode_cbor(v); + CHECK(j.as() == std::string("27315.0")); + } + SECTION("2 27315") + { + std::vector v = {0xc4, // Tag 4, + 0x82, // Array of length 2 + 0x02, // 2 + 0x19,0x6a,0xb3 // 27315 + }; + + json j = decode_cbor(v); + CHECK(j.as() == std::string("2731500.0")); + } + SECTION("-2 18446744073709551616") + { + std::vector v = {0xc4, // Tag 4, + 0x82, // Array of length 2 + 0x21, // -2 + 0xc2,0x49,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 // 18446744073709551616 + }; + + json j = decode_cbor(v); + CHECK(j.as() == std::string("1.8446744073709551616e+17")); + } + SECTION("-2 -65537") + { + std::vector v = {0xc4, // Tag 4, + 0x82, // Array of length 2 + 0x21, // -2 + 0x3a,0,1,0x00,0x00 // -65537 + }; + + json j = decode_cbor(v); + CHECK(j.as() == std::string("-655.37")); + } + SECTION("-5 -65537") + { + std::vector v = {0xc4, // Tag 4, + 0x82, // Array of length 2 + 0x24, // -5 + 0x3a,0,1,0x00,0x00 // -65537 + }; + + json j = decode_cbor(v); + CHECK(j.as() == std::string("-0.65537")); + } + SECTION("-6 -65537") + { + std::vector v = {0xc4, // Tag 4, + 0x82, // Array of length 2 + 0x25, // -6 + 0x3a,0,1,0x00,0x00 // -65537 + }; + + json j = decode_cbor(v); + CHECK(j.as() == std::string("-0.065537")); + } +} + +TEST_CASE("Compare CBOR packed item and jsoncons item") +{ + std::vector bytes; + cbor::cbor_bytes_encoder encoder(bytes); + encoder.begin_array(); // indefinite length outer array + encoder.string_value("foo"); + encoder.byte_string_value(byte_string{'b','a','r'}); + encoder.string_value("-18446744073709551617", semantic_tag::bigint); + encoder.string_value("-273.15", semantic_tag::bigdec); + encoder.string_value("273.15", semantic_tag::bigdec); + encoder.string_value("18446744073709551616.15", semantic_tag::bigdec); + encoder.string_value("-18446744073709551617.15", semantic_tag::bigdec); + encoder.string_value("2018-10-19 12:41:07-07:00", semantic_tag::datetime) ; + encoder.int64_value(1431027667, semantic_tag::timestamp); + encoder.int64_value(-1431027667, semantic_tag::timestamp); + encoder.double_value(1431027667.5, semantic_tag::timestamp); + encoder.end_array(); + encoder.flush(); + + json expected = json::array(); + expected.emplace_back("foo"); + expected.emplace_back(byte_string{ 'b','a','r' }); + expected.emplace_back("-18446744073709551617", semantic_tag::bigint); + expected.emplace_back("-273.15", semantic_tag::bigdec); + expected.emplace_back("273.15", semantic_tag::bigdec); + expected.emplace_back("1.844674407370955161615e+19", semantic_tag::bigdec); + expected.emplace_back("-1.844674407370955161715e+19", semantic_tag::bigdec); + expected.emplace_back("2018-10-19 12:41:07-07:00", semantic_tag::datetime); + expected.emplace_back(1431027667, semantic_tag::timestamp); + expected.emplace_back(-1431027667, semantic_tag::timestamp); + expected.emplace_back(1431027667.5, semantic_tag::timestamp); + + json j = cbor::decode_cbor(bytes); + + REQUIRE(j == expected); + for (size_t i = 0; i < j.size(); ++i) + { + CHECK(j[i].get_semantic_tag() == expected[i].get_semantic_tag()); + } +} + +TEST_CASE("CBOR stringref tag 1") +{ + std::vector v = {0xd9,0x01,0x00, // tag(256) + 0x83, // array(3) + 0xa3, // map(3) + 0x44, // bytes(4) + 0x72,0x61,0x6e,0x6b, // "rank" + 0x04, // unsigned(4) + 0x45, // bytes(5) + 0x63,0x6f,0x75,0x6e,0x74, // "count" + 0x19,0x01,0xa1, // unsigned(417) + 0x44, // bytes(4) + 0x6e,0x61,0x6d,0x65, // "name" + 0x48, // bytes(8) + 0x43,0x6f,0x63,0x6b,0x74,0x61,0x69,0x6c, // "Cocktail" + 0xa3, // map(3) + 0xd8,0x19, // tag(25) + 0x02, // unsigned(2) + 0x44, // bytes(4) + 0x42,0x61,0x74,0x68, // "Bath" + 0xd8,0x19, // tag(25) + 0x01, // unsigned(1) + 0x19,0x01,0x38, // unsigned(312) + 0xd8,0x19, // tag(25) + 0x00, // unsigned(0) + 0x04, // unsigned(4) + 0xa3, // map(3) + 0xd8,0x19, // tag(25) + 0x02, // unsigned(2) + 0x44, // bytes(4) + 0x46,0x6f,0x6f,0x64, // "Food" + 0xd8,0x19, // tag(25) + 0x01, // unsigned(1) + 0x19,0x02,0xb3, // unsigned(691) + 0xd8,0x19, // tag(25) + 0x00, // unsigned(0) + 0x04 // unsigned(4) + }; + + SECTION("decode") + { + ojson j = decode_cbor(v); + //std::cout << pretty_print(j) << "\n"; + + { + auto it = j[0].object_range().begin(); + std::string key1; + decode_base64url(it->key().begin(),it->key().end(),key1); + CHECK(key1 == std::string("rank")); + ++it; + std::string key2; + decode_base64url(it->key().begin(),it->key().end(),key2); + CHECK(key2 == std::string("count")); + ++it; + std::string key3; + decode_base64url(it->key().begin(),it->key().end(),key3); + CHECK(key3 == std::string("name")); + } + { + auto it = j[1].object_range().begin(); + std::string key3; + decode_base64url(it->key().begin(),it->key().end(),key3); + CHECK(key3 == std::string("name")); + ++it; + std::string key2; + decode_base64url(it->key().begin(),it->key().end(),key2); + CHECK(key2 == std::string("count")); + ++it; + std::string key1; + decode_base64url(it->key().begin(),it->key().end(),key1); + CHECK(key1 == std::string("rank")); + } + { + auto it = j[2].object_range().begin(); + std::string key3; + decode_base64url(it->key().begin(),it->key().end(),key3); + CHECK(key3 == std::string("name")); + ++it; + std::string key2; + decode_base64url(it->key().begin(),it->key().end(),key2); + CHECK(key2 == std::string("count")); + ++it; + std::string key1; + decode_base64url(it->key().begin(),it->key().end(),key1); + CHECK(key1 == std::string("rank")); + } + } +} + +TEST_CASE("CBOR stringref tag 2") +{ + std::vector v = {0xd9, 0x01, 0x00, // tag(256) + 0x98, 0x20, // array(32) + 0x41, // bytes(1) + 0x31, // "1" + 0x43, // bytes(3) + 0x32,0x32,0x32, // "222" + 0x43, // bytes(3) + 0x33,0x33,0x33, // "333" + 0x41, // bytes(1) + 0x34, // "4" + 0x43, // bytes(3) + 0x35,0x35,0x35, // "555" + 0x43, // bytes(3) + 0x36,0x36,0x36, // "666" + 0x43, // bytes(3) + 0x37,0x37,0x37, // "777" + 0x43, // bytes(3) + 0x38,0x38,0x38, // "888" + 0x43, // bytes(3) + 0x39,0x39,0x39, // "999" + 0x43, // bytes(3) + 0x61,0x61,0x61, // "aaa" + 0x43, // bytes(3) + 0x62,0x62,0x62, // "bbb" + 0x43, // bytes(3) + 0x63,0x63,0x63, // "ccc" + 0x43, // bytes(3) + 0x64,0x64,0x64, // "ddd" + 0x43, // bytes(3) + 0x65,0x65,0x65, // "eee" + 0x43, // bytes(3) + 0x66,0x66,0x66, // "fff" + 0x43, // bytes(3) + 0x67,0x67,0x67, // "ggg" + 0x43, // bytes(3) + 0x68,0x68,0x68, // "hhh" + 0x43, // bytes(3) + 0x69,0x69,0x69, // "iii" + 0x43, // bytes(3) + 0x6a,0x6a,0x6a, // "jjj" + 0x43, // bytes(3) + 0x6b,0x6b,0x6b, // "kkk" + 0x43, // bytes(3) + 0x6c,0x6c,0x6c, // "lll" + 0x43, // bytes(3) + 0x6d,0x6d,0x6d, // "mmm" + 0x43, // bytes(3) + 0x6e,0x6e,0x6e, // "nnn" + 0x43, // bytes(3) + 0x6f,0x6f,0x6f, // "ooo" + 0x43, // bytes(3) + 0x70,0x70,0x70, // "ppp" + 0x43, // bytes(3) + 0x71,0x71,0x71, // "qqq" + 0x43, // bytes(3) + 0x72,0x72,0x72, // "rrr" + 0xd8, 0x19, // tag(25) + 0x01, // unsigned(1) + 0x44, // bytes(4) + 0x73,0x73,0x73,0x73, // "ssss" + 0xd8, 0x19, // tag(25) + 0x17, // unsigned(23) + 0x43, // bytes(3) + 0x72,0x72,0x72, // "rrr" + 0xd8, 0x19, // tag(25) + 0x18, 0x18 // unsigned(24) + }; + + ojson j = decode_cbor(v); + + byte_string bs = j[0].as(); + CHECK(std::string(bs.begin(),bs.end()) == std::string("1")); + + bs = j[1].as(); // 0 + CHECK(std::string(bs.begin(),bs.end()) == std::string("222")); + + bs = j[2].as(); // 1 + CHECK(std::string(bs.begin(),bs.end()) == std::string("333")); + + bs = j[3].as(); + CHECK(std::string(bs.begin(),bs.end()) == std::string("4")); + + bs = j[4].as(); // 2 + CHECK(std::string(bs.begin(),bs.end()) == std::string("555")); + + bs = j[5].as(); + CHECK(std::string(bs.begin(),bs.end()) == std::string("666")); + + bs = j[6].as(); + CHECK(std::string(bs.begin(),bs.end()) == std::string("777")); + + bs = j[7].as(); + CHECK(std::string(bs.begin(),bs.end()) == std::string("888")); + + bs = j[8].as(); + CHECK(std::string(bs.begin(),bs.end()) == std::string("999")); + + bs = j[9].as(); + CHECK(std::string(bs.begin(),bs.end()) == std::string("aaa")); + + bs = j[10].as(); + CHECK(std::string(bs.begin(),bs.end()) == std::string("bbb")); + + bs = j[11].as(); + CHECK(std::string(bs.begin(),bs.end()) == std::string("ccc")); + + bs = j[12].as(); + CHECK(std::string(bs.begin(),bs.end()) == std::string("ddd")); + + bs = j[13].as(); + CHECK(std::string(bs.begin(),bs.end()) == std::string("eee")); + + bs = j[14].as(); + CHECK(std::string(bs.begin(),bs.end()) == std::string("fff")); + + bs = j[15].as(); + CHECK(std::string(bs.begin(),bs.end()) == std::string("ggg")); + + bs = j[16].as(); + CHECK(std::string(bs.begin(),bs.end()) == std::string("hhh")); + + bs = j[17].as(); + CHECK(std::string(bs.begin(),bs.end()) == std::string("iii")); + + bs = j[18].as(); + CHECK(std::string(bs.begin(),bs.end()) == std::string("jjj")); + + bs = j[19].as(); + CHECK(std::string(bs.begin(),bs.end()) == std::string("kkk")); + + bs = j[20].as(); + CHECK(std::string(bs.begin(),bs.end()) == std::string("lll")); + + bs = j[21].as(); + CHECK(std::string(bs.begin(),bs.end()) == std::string("mmm")); + + bs = j[22].as(); + CHECK(std::string(bs.begin(),bs.end()) == std::string("nnn")); + + bs = j[23].as(); + CHECK(std::string(bs.begin(),bs.end()) == std::string("ooo")); + + bs = j[24].as(); + CHECK(std::string(bs.begin(),bs.end()) == std::string("ppp")); + + bs = j[25].as(); + CHECK(std::string(bs.begin(),bs.end()) == std::string("qqq")); + + bs = j[26].as(); + CHECK(std::string(bs.begin(),bs.end()) == std::string("rrr")); + + bs = j[27].as(); + CHECK(std::string(bs.begin(),bs.end()) == std::string("333")); + + bs = j[28].as(); + CHECK(std::string(bs.begin(),bs.end()) == std::string("ssss")); + + bs = j[29].as(); + CHECK(std::string(bs.begin(),bs.end()) == std::string("qqq")); + + bs = j[30].as(); + CHECK(std::string(bs.begin(),bs.end()) == std::string("rrr")); + + bs = j[31].as(); + CHECK(std::string(bs.begin(),bs.end()) == std::string("ssss")); +} + +TEST_CASE("CBOR stringref tag 3") +{ + std::vector v = {0xd9,0x01,0x00, // tag(256) + 0x85, // array(5) + 0x63, // text(3) + 0x61,0x61,0x61, // "aaa" + 0xd8, 0x19, // tag(25) + 0x00, // unsigned(0) + 0xd9, 0x01,0x00, // tag(256) + 0x83, // array(3) + 0x63, // text(3) + 0x62,0x62,0x62, // "bbb" + 0x63, // text(3) + 0x61,0x61,0x61, // "aaa" + 0xd8, 0x19, // tag(25) + 0x01, // unsigned(1) + 0xd9, 0x01,0x00, // tag(256) + 0x82, // array(2) + 0x63, // text(3) + 0x63,0x63,0x63, // "ccc" + 0xd8, 0x19, // tag(25) + 0x00, // unsigned(0) + 0xd8, 0x19, // tag(25) + 0x00 // unsigned(0) + }; + + json j = cbor::decode_cbor(v); + + json expected = json::parse(R"( + ["aaa","aaa",["bbb","aaa","aaa"],["ccc","ccc"],"aaa"] + )"); + + CHECK(j == expected); +} diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/cbor/cbor_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/cbor/cbor_tests.cpp new file mode 100644 index 0000000000..0e4717b977 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/cbor/cbor_tests.cpp @@ -0,0 +1,185 @@ +// Copyright 2016 Daniel Parker +// Distributed under Boost license + +#if defined(_MSC_VER) +#include "windows.h" +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +TEST_CASE("cbor_test_floating_point") +{ + json j1; + j1["max double"] = (std::numeric_limits::max)(); + j1["max float"] = (std::numeric_limits::max)(); + + std::vector v; + cbor::encode_cbor(j1, v); + + json j2 = cbor::decode_cbor(v); + + CHECK(j1 == j2); +} + +TEST_CASE("cbor_test") +{ + json j1; + j1["zero"] = 0; + j1["one"] = 1; + j1["two"] = 2; + j1["null"] = null_type(); + j1["true"] = true; + j1["false"] = false; + j1["max int64_t"] = (std::numeric_limits::max)(); + j1["max uint64_t"] = (std::numeric_limits::max)(); + j1["min int64_t"] = (std::numeric_limits::lowest)(); + j1["max int32_t"] = (std::numeric_limits::max)(); + j1["max uint32_t"] = (std::numeric_limits::max)(); + j1["min int32_t"] = (std::numeric_limits::lowest)(); + j1["max int16_t"] = (std::numeric_limits::max)(); + j1["max uint16_t"] = (std::numeric_limits::max)(); + j1["min int16_t"] = (std::numeric_limits::lowest)(); + j1["max int8_t"] = (std::numeric_limits::max)(); + j1["max uint8_t"] = (std::numeric_limits::max)(); + j1["min int8_t"] = (std::numeric_limits::lowest)(); + j1["max double"] = (std::numeric_limits::max)(); + j1["min double"] = (std::numeric_limits::lowest)(); + j1["max float"] = (std::numeric_limits::max)(); + j1["zero float"] = 0.0; + j1["min float"] = (std::numeric_limits::lowest)(); + j1["String too long for small string optimization"] = "String too long for small string optimization"; + + json ja = json::array(); + ja.push_back(0); + ja.push_back(1); + ja.push_back(2); + ja.push_back(null_type()); + ja.push_back(true); + ja.push_back(false); + ja.push_back((std::numeric_limits::max)()); + ja.push_back((std::numeric_limits::max)()); + ja.push_back((std::numeric_limits::lowest)()); + ja.push_back((std::numeric_limits::max)()); + ja.push_back((std::numeric_limits::max)()); + ja.push_back((std::numeric_limits::lowest)()); + ja.push_back((std::numeric_limits::max)()); + ja.push_back((std::numeric_limits::max)()); + ja.push_back((std::numeric_limits::lowest)()); + ja.push_back((std::numeric_limits::max)()); + ja.push_back((std::numeric_limits::max)()); + ja.push_back((std::numeric_limits::lowest)()); + ja.push_back((std::numeric_limits::max)()); + ja.push_back((std::numeric_limits::lowest)()); + ja.push_back((std::numeric_limits::max)()); + ja.push_back(0.0); + ja.push_back((std::numeric_limits::lowest)()); + ja.push_back("String too long for small string optimization"); + + j1["An array"] = ja; + + std::vector v; + cbor::encode_cbor(j1, v); + + json j2 = cbor::decode_cbor(v); + + CHECK(j1 == j2); +} + +TEST_CASE("cbor_test2") +{ + wjson j1; + j1[L"zero"] = 0; + j1[L"one"] = 1; + j1[L"two"] = 2; + j1[L"null"] = null_type(); + j1[L"true"] = true; + j1[L"false"] = false; + j1[L"max int64_t"] = (std::numeric_limits::max)(); + j1[L"max uint64_t"] = (std::numeric_limits::max)(); + j1[L"min int64_t"] = (std::numeric_limits::lowest)(); + j1[L"max int32_t"] = (std::numeric_limits::max)(); + j1[L"max uint32_t"] = (std::numeric_limits::max)(); + j1[L"min int32_t"] = (std::numeric_limits::lowest)(); + j1[L"max int16_t"] = (std::numeric_limits::max)(); + j1[L"max uint16_t"] = (std::numeric_limits::max)(); + j1[L"min int16_t"] = (std::numeric_limits::lowest)(); + j1[L"max int8_t"] = (std::numeric_limits::max)(); + j1[L"max uint8_t"] = (std::numeric_limits::max)(); + j1[L"min int8_t"] = (std::numeric_limits::lowest)(); + j1[L"max double"] = (std::numeric_limits::max)(); + j1[L"min double"] = (std::numeric_limits::lowest)(); + j1[L"max float"] = (std::numeric_limits::max)(); + j1[L"zero float"] = 0.0; + j1[L"min float"] = (std::numeric_limits::lowest)(); + j1[L"S"] = L"S"; + j1[L"String too long for small string optimization"] = L"String too long for small string optimization"; + + wjson ja = wjson::array(); + ja.push_back(0); + ja.push_back(1); + ja.push_back(2); + ja.push_back(null_type()); + ja.push_back(true); + ja.push_back(false); + ja.push_back((std::numeric_limits::max)()); + ja.push_back((std::numeric_limits::max)()); + ja.push_back((std::numeric_limits::lowest)()); + ja.push_back((std::numeric_limits::max)()); + ja.push_back((std::numeric_limits::max)()); + ja.push_back((std::numeric_limits::lowest)()); + ja.push_back((std::numeric_limits::max)()); + ja.push_back((std::numeric_limits::max)()); + ja.push_back((std::numeric_limits::lowest)()); + ja.push_back((std::numeric_limits::max)()); + ja.push_back((std::numeric_limits::max)()); + ja.push_back((std::numeric_limits::lowest)()); + ja.push_back((std::numeric_limits::max)()); + ja.push_back((std::numeric_limits::lowest)()); + ja.push_back((std::numeric_limits::max)()); + ja.push_back(0.0); + ja.push_back((std::numeric_limits::lowest)()); + ja.push_back(L"S"); + ja.push_back(L"String too long for small string optimization"); + + j1[L"An array"] = ja; + + std::vector v; + cbor::encode_cbor(j1, v); + + wjson j2 = cbor::decode_cbor(v); + + CHECK(j1 == j2); +} + +TEST_CASE("cbor_reputon_test") +{ +ojson j1 = ojson::parse(R"( +{ + "application": "hiking", + "reputons": [ + { + "rater": "HikingAsylum.example.com", + "assertion": "strong-hiker", + "rated": "Marilyn C", + "rating": 0.90 + } + ] +} +)"); + + std::vector v; + cbor::encode_cbor(j1, v); + + ojson j2 = cbor::decode_cbor(v); + CHECK(j1 == j2); + //std::cout << pretty_print(j2) << std::endl; +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/cbor/decode_cbor_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/cbor/decode_cbor_tests.cpp new file mode 100644 index 0000000000..09bfa00894 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/cbor/decode_cbor_tests.cpp @@ -0,0 +1,663 @@ +// Copyright 2016 Daniel Parker +// Distributed under Boost license + +#if defined(_MSC_VER) +#include "windows.h" +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +TEST_CASE("cbor_view_test") +{ + ojson j1 = ojson::parse(R"( + { + "application": "hiking", + "reputons": [ + { + "rater": "HikingAsylum.example.com", + "assertion": "strong-hiker", + "rated": "Marilyn C", + "rating": 0.90 + } + ] + } + )"); + + std::vector c; + cbor::encode_cbor(j1, c); + + json v = cbor::decode_cbor(c); + CHECK(v.is_object()); + CHECK_FALSE(v.is_array()); + + const json& reputons = v.at("reputons"); + CHECK(reputons.is_array()); + + const json& reputons_0 = reputons.at(0); + + const json& reputons_0_rated = reputons_0.at("rated"); + (void)reputons_0_rated; + + const json& rating = reputons_0.at("rating"); + CHECK(rating.as_double() == 0.90); + + for (const auto& member : v.object_range()) + { + const auto& key = member.key(); + const json& jval = member.value(); + + (void)key; + (void)jval; + + //std::cout << key << ": " << jval << std::endl; + } + //std::cout << std::endl; + + for (auto element : reputons.array_range()) + { + json j = element; + //std::cout << j << std::endl; + } + //std::cout << std::endl; +} + +TEST_CASE("jsonpointer_test") +{ + json j = json::parse(R"( + { + "application": "hiking", + "reputons": [ + { + "rater": "HikingAsylum.example.com", + "assertion": "strong-hiker", + "rated": "Marilyn C", + "rating": 0.90 + } + ] + } + )"); + + std::vector v; + cbor::encode_cbor(j, v); + + json jdoc = cbor::decode_cbor(v); + std::string s; + jdoc.dump(s); + json j1 = json::parse(s); + CHECK(j1 == j); + + std::error_code ec; + const json& application = jsonpointer::get(jdoc, "/application", ec); + CHECK_FALSE(ec); + + CHECK(application == j["application"]); + + const json& reputons_0_rated = jsonpointer::get(jdoc, "/reputons", ec); + CHECK_FALSE(ec); + + json j4 = j["reputons"]; + CHECK(reputons_0_rated == j4); + + //std::cout << pretty_print(j3) << std::endl; +} + +TEST_CASE("as_string_test") +{ + std::vector v; + cbor::cbor_bytes_encoder encoder(v); + encoder.begin_array(10); + encoder.bool_value(true); + encoder.bool_value(false); + encoder.null_value(); + encoder.string_value("Toronto"); + encoder.byte_string_value(byte_string{'H','e','l','l','o'}); + encoder.int64_value(-100); + encoder.uint64_value(100); + encoder.string_value("18446744073709551616", semantic_tag::bigint); + encoder.double_value(10.5); + encoder.string_value("-18446744073709551617", semantic_tag::bigint); + encoder.end_array(); + encoder.flush(); + + json j = cbor::decode_cbor(v); + + std::string s0; + j[0].dump(s0); + CHECK(std::string("true") == s0); + CHECK(std::string("true") == j[0].as_string()); + CHECK(true == j[0].as()); + CHECK(j[0].is()); + + std::string s1; + j[1].dump(s1); + CHECK(std::string("false") == s1); + CHECK(std::string("false") == j[1].as_string()); + CHECK(false == j[1].as()); + CHECK(j[1].is()); + + std::string s2; + j[2].dump(s2); + CHECK(std::string("null") == s2); + CHECK(std::string("null") == j[2].as_string()); + + std::string s3; + j[3].dump(s3); + CHECK(std::string("\"Toronto\"") == s3); + CHECK(std::string("Toronto") == j[3].as_string()); + CHECK(std::string("Toronto") ==j[3].as()); + + std::string s4; + j[4].dump(s4); + CHECK(std::string("\"SGVsbG8\"") == s4); + CHECK(std::string("SGVsbG8") == j[4].as_string()); + CHECK(byte_string({'H','e','l','l','o'}) == j[4].as()); + + std::string s5; + j[5].dump(s5); + CHECK(std::string("-100") ==s5); + CHECK(std::string("-100") == j[5].as_string()); + CHECK(-100 ==j[5].as()); + + std::string s6; + j[6].dump(s6); + CHECK(std::string("100") == s6); + CHECK(std::string("100") == j[6].as_string()); + + std::string s7; + j[7].dump(s7); + CHECK(std::string("\"18446744073709551616\"") == s7); + CHECK(std::string("18446744073709551616") == j[7].as_string()); + + std::string s8; + j[8].dump(s8); + CHECK(std::string("10.5") == s8); + CHECK(std::string("10.5") == j[8].as_string()); + + std::string s9; + j[9].dump(s9); + CHECK(std::string("\"-18446744073709551617\"") == s9); + CHECK(std::string("-18446744073709551617") == j[9].as_string()); + +} + +TEST_CASE("dump cbor to string test") +{ + std::vector v; + cbor::cbor_bytes_encoder encoder(v); + encoder.begin_array(); + std::vector bytes = {0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + bignum n(-1, bytes.data(), bytes.size()); + std::string s; + n.dump(s); + encoder.string_value(s, semantic_tag::bigint); + encoder.end_array(); + encoder.flush(); + + json j = cbor::decode_cbor(v); + + std::string s0; + j.dump(s0); + CHECK("[\"-18446744073709551617\"]" == s0); + //std::cout << s0 << std::endl; + + std::string s1; + json_options options1; + options1.bigint_format(bigint_chars_format::number); + j.dump(s1,options1); + CHECK("[-18446744073709551617]" == s1); + //std::cout << s1 << std::endl; + + std::string s2; + json_options options2; + options2.bigint_format(bigint_chars_format::base10); + j.dump(s2,options2); + CHECK("[\"-18446744073709551617\"]" == s2); + //std::cout << s2 << std::endl; + + std::string s3; + json_options options3; + options3.bigint_format(bigint_chars_format::base64url); + j.dump(s3,options3); + CHECK("[\"~AQAAAAAAAAAA\"]" == s3); + //std::cout << s3 << std::endl; +} + +TEST_CASE("test_dump_to_stream") +{ + std::vector v; + cbor::cbor_bytes_encoder encoder(v); + encoder.begin_array(); + std::vector bytes = {0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + bignum n(-1, bytes.data(), bytes.size()); + std::string s; + n.dump(s); + encoder.string_value(s, semantic_tag::bigint); + encoder.end_array(); + encoder.flush(); + + json j = cbor::decode_cbor(v); + + std::ostringstream os0; + j.dump(os0); + CHECK("[\"-18446744073709551617\"]" == os0.str()); + //std::cout << os0.str() << std::endl; + + std::ostringstream os1; + json_options options1; + options1.bigint_format(bigint_chars_format::number); + j.dump(os1,options1); + CHECK("[-18446744073709551617]" == os1.str()); + //std::cout << os1.str() << std::endl; + + std::ostringstream os2; + json_options options2; + options2.bigint_format(bigint_chars_format::base10); + j.dump(os2,options2); + CHECK("[\"-18446744073709551617\"]" == os2.str()); + //std::cout << os2.str() << std::endl; + + std::ostringstream os3; + json_options options3; + options3.bigint_format(bigint_chars_format::base64url); + j.dump(os3,options3); + CHECK("[\"~AQAAAAAAAAAA\"]" == os3.str()); + //std::cout << os3.str() << std::endl; +} + +TEST_CASE("test_indefinite_length_object_iterator") +{ + std::vector v; + cbor::cbor_bytes_encoder encoder(v); + encoder.begin_object(); // indefinite length object + encoder.name("City"); + encoder.string_value("Toronto"); + encoder.name("Province"); + encoder.string_value("Ontario"); + encoder.end_object(); + encoder.flush(); + json bv2 = cbor::decode_cbor(v); + + auto it2 = bv2.object_range().begin(); + CHECK_FALSE((it2 == bv2.object_range().end())); + CHECK_FALSE((++it2 == bv2.object_range().end())); + CHECK((++it2 == bv2.object_range().end())); +} + +TEST_CASE("test_indefinite_length_array_iterator") +{ + std::vector v; + cbor::cbor_bytes_encoder encoder(v); + encoder.begin_array(); // indefinite length array + encoder.string_value("Toronto"); + encoder.string_value("Ontario"); + encoder.end_array(); + encoder.flush(); + json j = cbor::decode_cbor(v); + + CHECK(j.size() == 2); + + auto it2 = j.array_range().begin(); + CHECK_FALSE((it2 == j.array_range().end())); + CHECK_FALSE((++it2 == j.array_range().end())); + CHECK((++it2 == j.array_range().end())); + +} + +TEST_CASE("cbor array comparison test") +{ + std::vector v1; + cbor::cbor_bytes_encoder encoder1(v1); + encoder1.begin_array(); // indefinite length array + encoder1.string_value("Toronto"); + encoder1.string_value("Vancouver"); + encoder1.end_array(); + encoder1.flush(); + json j1 = cbor::decode_cbor(v1); + + std::vector v2; + cbor::cbor_bytes_encoder serializer2(v2); + serializer2.begin_array(); // indefinite length array + serializer2.string_value("Toronto"); + serializer2.string_value("Vancouver"); + serializer2.end_array(); + serializer2.flush(); + json j2 = cbor::decode_cbor(v2); + + std::vector v3; + cbor::cbor_bytes_encoder serializer3(v3); + serializer3.begin_array(); // indefinite length array + serializer3.string_value("Toronto"); + serializer3.string_value("Montreal"); + serializer3.end_array(); + serializer3.flush(); + json j3 = cbor::decode_cbor(v3); + + SECTION("operator== test") + { + CHECK(j1 == j2); + REQUIRE(j1.size() == 2); + REQUIRE(j2.size() == 2); + CHECK(j1[0] == j2[0]); + CHECK(j1[1] == j2[1]); + } + + SECTION("element operator== test") + { + CHECK_FALSE(j1 == j3); + REQUIRE(j1.size() == 2); + REQUIRE(j1.size() == j3.size()); + CHECK(j1[0] == j3[0]); + CHECK_FALSE(j1[1] == j3[1]); + } +} + +TEST_CASE("cbor object comparison") +{ + std::vector v; + cbor::cbor_bytes_encoder encoder1(v); + encoder1.begin_object(); // indefinite length array + encoder1.name("City"); + encoder1.string_value("Montreal"); + encoder1.name("Amount"); + encoder1.string_value("273.15", semantic_tag::bigdec); + encoder1.name("Date"); + encoder1.string_value("2018-05-07 12:41:07-07:00", semantic_tag::datetime) ; + encoder1.end_object(); + encoder1.flush(); + json j1 = cbor::decode_cbor(v); + + //std::cout << pretty_print(j1) << "\n"; + + REQUIRE(j1.size() == 3); + + std::vector buf2; + cbor::cbor_bytes_encoder serializer2(buf2); + serializer2.begin_object(); // indefinite length array + serializer2.name("City"); + serializer2.string_value("Toronto"); + serializer2.name("Amount"); + serializer2.string_value("273.15", semantic_tag::bigdec); + serializer2.name("Date"); + serializer2.string_value("2018-10-18 12:41:07-07:00", semantic_tag::datetime) ; + serializer2.end_object(); + serializer2.flush(); + json j2 = cbor::decode_cbor(buf2); + REQUIRE(j2.size() == j1.size()); + + std::vector buf3; + cbor::cbor_bytes_encoder serializer3(buf3); + serializer3.begin_object(); // indefinite length array + serializer3.name("empty-object"); + serializer3.begin_object(0); + serializer3.end_object(); + serializer3.name("empty-array"); + serializer3.begin_array(0); + serializer3.end_array(); + serializer3.name("empty-string"); + serializer3.string_value(""); + serializer3.name("empty-byte_string"); + serializer3.byte_string_value(jsoncons::byte_string{}); + serializer3.end_object(); + serializer3.flush(); + json j3 = cbor::decode_cbor(buf3); + + SECTION("contains") + { + CHECK(j1.contains("City")); + CHECK(j1.contains("Amount")); + CHECK(j1.contains("Date")); + CHECK_FALSE(j1.contains("Country")); + } + + SECTION("empty") + { + CHECK_FALSE(j3.empty()); + CHECK(j3["empty-object"].empty()); + CHECK(j3["empty-array"].empty()); + CHECK(j3["empty-string"].empty()); + CHECK(j3["empty-byte_string"].empty()); + } + + SECTION("size") + { + CHECK(j1.size() == 3); + } + + SECTION("operator==") + { + CHECK_FALSE(j1 == j2); + CHECK_FALSE(j1["City"] == j2["City"]); + CHECK(j1["Amount"] == j2["Amount"]); + CHECK_FALSE(j1["Date"] == j2["Date"]); + } +} + +TEST_CASE("cbor member tests") +{ + std::vector v; + cbor::cbor_bytes_encoder encoder(v); + encoder.begin_object(); // indefinite length object + encoder.name("empty-object"); + encoder.begin_object(0); + encoder.end_object(); + encoder.name("empty-array"); + encoder.begin_array(0); + encoder.end_array(); + encoder.name("empty-string"); + encoder.string_value(""); + encoder.name("empty-byte_string"); + encoder.byte_string_value(jsoncons::byte_string{}); + + encoder.name("City"); + encoder.string_value("Montreal"); + encoder.name("Amount"); + encoder.string_value("273.15", semantic_tag::bigdec); + encoder.name("Date"); + encoder.string_value("2018-05-07 12:41:07-07:00", semantic_tag::datetime) ; + + encoder.end_object(); + encoder.flush(); + json j = cbor::decode_cbor(v); + + SECTION("contains") + { + CHECK(j.contains("City")); + CHECK(j.contains("Amount")); + CHECK(j.contains("Date")); + CHECK_FALSE(j.contains("Country")); + } + + SECTION("empty") + { + CHECK_FALSE(j.empty()); + CHECK(j["empty-object"].empty()); + CHECK(j["empty-array"].empty()); + CHECK(j["empty-string"].empty()); + CHECK(j["empty-byte_string"].empty()); + } + + SECTION("size") + { + CHECK(j.size() == 7); + } +} + +TEST_CASE("cbor conversion tests") +{ + std::vector v; + cbor::cbor_bytes_encoder encoder(v); + encoder.begin_array(); // indefinite length outer array + encoder.begin_array(4); // a fixed length array + encoder.string_value("foo"); + encoder.byte_string_value(byte_string{'P','u','s','s'}); // no suggested conversion + encoder.string_value("-18446744073709551617", semantic_tag::bigint); + encoder.string_value("273.15", semantic_tag::bigdec); + encoder.end_array(); + encoder.end_array(); + encoder.flush(); + + json j = cbor::decode_cbor(v); + REQUIRE(j.size() == 1); + + auto range1 = j.array_range(); + auto it = range1.begin(); + const json& inner_array = *it++; + REQUIRE(inner_array.size() == 4); + REQUIRE((it == range1.end())); + + auto range2 = inner_array.array_range(); + auto it2 = range2.begin(); + CHECK(it2->as_string() == "foo"); + it2++; + CHECK(it2->as_byte_string() == byte_string{'P','u','s','s'}); + it2++; + CHECK(bool(it2->as_bignum() == bignum{"-18446744073709551617"})); + it2++; + CHECK(bool(it2->as_string() == std::string{"273.15"})); + it2++; + CHECK((it2 == range2.end())); +} + +TEST_CASE("cbor array as<> test") +{ + std::vector v; + cbor::cbor_bytes_encoder encoder(v); + encoder.begin_array(); // indefinite length outer array + encoder.string_value("foo"); + encoder.byte_string_value(byte_string({'b','a','r'})); + encoder.string_value("-18446744073709551617", semantic_tag::bigint); + encoder.string_value("273.15", semantic_tag::bigdec); + encoder.string_value("2015-05-07 12:41:07-07:00", semantic_tag::datetime) ; + encoder.int64_value(1431027667, semantic_tag::timestamp); + encoder.int64_value(-1431027667, semantic_tag::timestamp); + encoder.double_value(1431027667.5, semantic_tag::timestamp); + encoder.end_array(); + encoder.flush(); + +/* +9f -- Start indefinite length array + 63 -- String value of length 3 + 666f6f -- "foo" + 43 -- Byte string value of length 3 + 626172 -- 'b''a''r' + c3 -- Tag 3 (negative bignum) + 49 Byte string value of length 9 + 010000000000000000 -- Bytes content + c4 - Tag 4 (decimal fraction) + 82 -- Array of length 2 + 21 -- -2 + 19 6ab3 -- 27315 + c0 -- Tag 0 (date-time) + 78 19 -- Length (25) + 323031352d30352d30372031323a34313a30372d30373a3030 -- "2015-05-07 12:41:07-07:00" + c1 -- Tag 1 (epoch time) + 1a -- uint32_t + 554bbfd3 -- 1431027667 + c1 + 3a + 554bbfd2 + c1 + fb + 41d552eff4e00000 + ff -- "break" +*/ + + //std::cout << "v: \n"; + //for (auto c : v) + //{ + // std::cout << std::hex << std::setprecision(2) << std::setw(2) + // << std::setfill('0') << static_cast(c); + //} + //std::cout << "\n\n"; + + json j = cbor::decode_cbor(v); // a non-owning view of the CBOR v + + CHECK(j.size() == 8); + + SECTION("j[0].is()") + { + CHECK(j[0].is()); + CHECK(j[1].is()); + CHECK(j[1].is()); + CHECK(j[2].is()); + CHECK(j[3].is_string()); + CHECK(j[3].get_semantic_tag() == semantic_tag::bigdec); + CHECK(j[4].is()); + CHECK(j[5].is()); + CHECK(j[5].is()); + CHECK(j[6].is()); + CHECK_FALSE(j[6].is()); + CHECK(j[7].is()); + } + + SECTION("j[0].as()") + { + CHECK(j[0].as() == std::string("foo")); + CHECK(j[1].as() == jsoncons::byte_string({'b','a','r'})); + CHECK(j[2].as() == std::string("-18446744073709551617")); + CHECK(bool(j[2].as() == jsoncons::bignum("-18446744073709551617"))); + CHECK(j[3].as() == std::string("273.15")); + CHECK(j[4].as() == std::string("2015-05-07 12:41:07-07:00")); + CHECK(j[5].as() == 1431027667); + CHECK(j[5].as() == 1431027667U); + CHECK(j[6].as() == -1431027667); + CHECK(j[7].as() == 1431027667.5); + } + + SECTION("array_iterator is test") + { + auto it = j.array_range().begin(); + CHECK(it++->is()); + CHECK(it++->is()); + CHECK(it++->is()); + CHECK(it++->is()); + CHECK(it++->is()); + CHECK(it++->is()); + CHECK(it++->is()); + CHECK(it++->is()); + } +} + +TEST_CASE("cbor bigfloat tests") +{ + SECTION("1.5") + { + std::vector v = {0xc5, // Tag 5 + 0x82, // Array of length 2 + 0x20, // -1 + 0x03 // 3 + }; + + json j = cbor::decode_cbor(v); + + //std::string s = j.as(); + + double val = j.as(); + CHECK(val == Approx(1.5).epsilon(0.0000000001)); + } + SECTION("-1.5") + { + std::vector v = {0xc5, // Tag 5 + 0x82, // Array of length 2 + 0x20, // -1 + 0x22 // -3 + }; + + json j = cbor::decode_cbor(v); + //std::string s = j.as(); + //CHECK(s == std::string("-1.5")); + + double val = j.as(); + CHECK(val == Approx(-1.5).epsilon(0.0000000001)); + } +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/cbor/encode_cbor_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/cbor/encode_cbor_tests.cpp new file mode 100644 index 0000000000..ce5507f1f9 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/cbor/encode_cbor_tests.cpp @@ -0,0 +1,143 @@ +// Copyright 2016 Daniel Parker +// Distributed under Boost license + +#if defined(_MSC_VER) +#include "windows.h" // test no inadvertant macro expansions +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +// test vectors from tinycbor https://github.com/01org/tinycbor tst_encoder.cpp +// MIT license + +void check_encode_cbor(const std::vector& expected, const json& j) +{ + std::vector result; + cbor::encode_cbor(j,result); + REQUIRE(result.size() == expected.size()); + for (size_t i = 0; i < expected.size(); ++i) + { + REQUIRE(result[i] == expected[i]); + } +} + +TEST_CASE("cbor_encoder_test") +{ + // unsigned integer + check_encode_cbor({0x00},json(0U)); + check_encode_cbor({0x01},json(1U)); + check_encode_cbor({0x0a},json(10U)); + check_encode_cbor({0x17},json(23U)); + check_encode_cbor({0x18,0x18},json(24U)); + check_encode_cbor({0x18,0xff},json(255U)); + check_encode_cbor({0x19,0x01,0x00},json(256U)); + check_encode_cbor({0x19,0xff,0xff},json(65535U)); + check_encode_cbor({0x1a,0,1,0x00,0x00},json(65536U)); + check_encode_cbor({0x1a,0xff,0xff,0xff,0xff},json(4294967295U)); + check_encode_cbor({0x1b,0,0,0,1,0,0,0,0},json(4294967296U)); + check_encode_cbor({0x1b,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff},json((std::numeric_limits::max)())); + + // positive signed integer + check_encode_cbor({0x00},json(0)); + check_encode_cbor({0x01},json(1)); + check_encode_cbor({0x0a},json(10)); + check_encode_cbor({0x17},json(23)); + check_encode_cbor({0x18,0x18},json(24)); + check_encode_cbor({0x18,0xff},json(255)); + check_encode_cbor({0x19,0x01,0x00},json(256)); + check_encode_cbor({0x19,0xff,0xff},json(65535)); + check_encode_cbor({0x1a,0,1,0x00,0x00},json(65536)); + check_encode_cbor({0x1a,0xff,0xff,0xff,0xff},json(4294967295)); + check_encode_cbor({0x1b,0,0,0,1,0,0,0,0},json(4294967296)); + check_encode_cbor({0x1b,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff},json((std::numeric_limits::max)())); + + // negative integers + check_encode_cbor({0x20},json(-1)); + check_encode_cbor({0x21},json(-2)); + check_encode_cbor({0x37},json(-24)); + check_encode_cbor({0x38,0x18},json(-25)); + check_encode_cbor({0x38,0xff},json(-256)); + check_encode_cbor({0x39,0x01,0x00},json(-257)); + check_encode_cbor({0x39,0xff,0xff},json(-65536)); + check_encode_cbor({0x3a,0,1,0x00,0x00},json(-65537)); + check_encode_cbor({0x3a,0xff,0xff,0xff,0xff},json(-4294967296)); + check_encode_cbor({0x3b,0,0,0,1,0,0,0,0},json(-4294967297)); + + // null, true, false + check_encode_cbor({0xf6},json::null()); + check_encode_cbor({0xf5},json(true)); + check_encode_cbor({0xf4},json(false)); + + // floating point + check_encode_cbor({0xfa,0,0,0,0},json(0.0)); + check_encode_cbor({0xfa,0xbf,0x80,0,0},json(-1.0)); + + SECTION("-16777215.0") + { + double val = -16777215.0; + float valf = (float)val; + CHECK((double)valf == val); + check_encode_cbor({0xfa,0xcb,0x7f,0xff,0xff},json(val)); + } + // From https://en.wikipedia.org/wiki/Double-precision_floating-point_format + SECTION("0.333333333333333314829616256247390992939472198486328125") + { + double val = 0.333333333333333314829616256247390992939472198486328125; + float valf = (float)val; + CHECK((double)valf != val); + check_encode_cbor({0xfb,0x3F,0xD5,0x55,0x55,0x55,0x55,0x55,0x55},json(val)); + } + + // byte string + check_encode_cbor({0x40},json(byte_string())); + check_encode_cbor({0x41,' '},json(byte_string({' '}))); + check_encode_cbor({0x41,0},json(byte_string({0}))); + check_encode_cbor({0x45,'H','e','l','l','o'},json(byte_string("Hello"))); + check_encode_cbor({0x58,0x18,'1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4'}, + json(byte_string("123456789012345678901234"))); + + // text string + check_encode_cbor({0x60},json("")); + check_encode_cbor({0x61,' '},json(" ")); + check_encode_cbor({0x78,0x18,'1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4'}, + json("123456789012345678901234")); + +} + +TEST_CASE("cbor_arrays_and_maps") +{ + check_encode_cbor({ 0x80 }, json::array()); + check_encode_cbor({ 0xa0 }, json::object()); + + check_encode_cbor({ 0x81,'\0' }, json::parse("[0]")); + check_encode_cbor({ 0x82,'\0','\0' }, json::array({ 0,0 })); + check_encode_cbor({ 0x82,0x81,'\0','\0' }, json::parse("[[0],0]")); + check_encode_cbor({ 0x81,0x65,'H','e','l','l','o' }, json::parse("[\"Hello\"]")); + + // big float + json j("0x6AB3p-2", semantic_tag::bigfloat); + CHECK(j.get_semantic_tag() == semantic_tag::bigfloat); + json j2 = j; + CHECK(j2.get_semantic_tag() == semantic_tag::bigfloat); + json j3; + j3 = j; + CHECK(j3.get_semantic_tag() == semantic_tag::bigfloat); + + check_encode_cbor({ 0xc5, // Tag 5 + 0x82, // Array of length 2 + 0x21, // -2 + 0x19, 0x6a, 0xb3 // 27315 + }, json("0x6AB3p-2", semantic_tag::bigfloat)); + + check_encode_cbor({ 0xa1,0x62,'o','c',0x81,'\0' }, json::parse("{\"oc\": [0]}")); + check_encode_cbor({ 0xa1,0x62,'o','c',0x84,'\0','\1','\2','\3' }, json::parse("{\"oc\": [0, 1, 2, 3]}")); +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/csv/csv_subfield_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/csv/csv_subfield_tests.cpp new file mode 100644 index 0000000000..9657c5a705 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/csv/csv_subfield_tests.cpp @@ -0,0 +1,150 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#if defined(_MSC_VER) +#include "windows.h" // test no inadvertant macro expansions +#endif +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; +using namespace jsoncons::literals; + +TEST_CASE("test_n_objects") +{ + const std::string s = R"(calculationPeriodCenters,paymentCenters,resetCenters +NY;LON,TOR,LON +NY,LON,TOR;LON +"NY";"LON","TOR","LON" +"NY","LON","TOR";"LON" +)"; + csv::csv_options options; + options.assume_header(true) + .subfield_delimiter(';'); + + json expected = R"( +[ + { + "calculationPeriodCenters": ["NY","LON"], + "paymentCenters": "TOR", + "resetCenters": "LON" + }, + { + "calculationPeriodCenters": "NY", + "paymentCenters": "LON", + "resetCenters": ["TOR","LON"] + }, + { + "calculationPeriodCenters": ["NY","LON"], + "paymentCenters": "TOR", + "resetCenters": "LON" + }, + { + "calculationPeriodCenters": "NY", + "paymentCenters": "LON", + "resetCenters": ["TOR","LON"] + } +] + )"_json; + + try + { + json j = csv::decode_csv(s,options); + CHECK(j == expected); + //std::cout << pretty_print(j) << std::endl; + } + catch (const std::exception& e) + { + std::cerr << e.what() << std::endl; + } +} + +TEST_CASE("test_n_rows") +{ + const std::string s = R"(calculationPeriodCenters,paymentCenters,resetCenters +NY;LON,TOR,LON +NY,LON,TOR;LON +"NY";"LON","TOR","LON" +"NY","LON","TOR";"LON" +)"; + csv::csv_options options; + options.mapping(csv::mapping_type::n_rows) + .subfield_delimiter(';'); + + json expected = R"( +[ + ["calculationPeriodCenters","paymentCenters","resetCenters"], + [ + ["NY","LON"],"TOR","LON" + ], + ["NY","LON", + ["TOR","LON"] + ], + [ + ["NY","LON"],"TOR","LON" + ], + ["NY","LON", + ["TOR","LON"] + ] +] + )"_json; + + try + { + json j = csv::decode_csv(s,options); + CHECK(j == expected); + //std::cout << pretty_print(j) << std::endl; + } + catch (const std::exception& e) + { + std::cerr << e.what() << std::endl; + } +} + +TEST_CASE("test_m_columns") +{ + const std::string s = R"(calculationPeriodCenters,paymentCenters,resetCenters +NY;LON,TOR,LON +NY,LON,TOR;LON +"NY";"LON","TOR","LON" +"NY","LON","TOR";"LON" +)"; + csv::csv_options options; + options.assume_header(true) + .mapping(csv::mapping_type::m_columns) + .subfield_delimiter(';'); + + json expected = R"( +{ + "calculationPeriodCenters": [ + ["NY","LON"],"NY", + ["NY","LON"],"NY" + ], + "paymentCenters": ["TOR","LON","TOR","LON"], + "resetCenters": ["LON", + ["TOR","LON"],"LON", + ["TOR","LON"] + ] +} + )"_json; + + try + { + json j = csv::decode_csv(s,options); + CHECK(j == expected); + //std::cout << pretty_print(j) << std::endl; + } + catch (const std::exception& e) + { + std::cerr << e.what() << std::endl; + } +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/csv/csv_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/csv/csv_tests.cpp new file mode 100644 index 0000000000..3ef4e8d656 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/csv/csv_tests.cpp @@ -0,0 +1,1227 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#if defined(_MSC_VER) +#include "windows.h" // test no inadvertant macro expansions +#endif +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +TEST_CASE("n_objects_test") +{ + const std::string bond_yields = R"(Date,1Y,2Y,3Y,5Y +2017-01-09,0.0062,0.0075,0.0083,0.011 +2017-01-08,0.0063,0.0076,0.0084,0.0112 +2017-01-08,0.0063,0.0076,0.0084,0.0112 +)"; + + json_decoder decoder; + csv::csv_options options; + options.assume_header(true) + .subfield_delimiter(0); + //.column_types("string,float,float,float,float"); + + options.mapping(csv::mapping_type::n_rows); + csv::csv_reader reader1(bond_yields,decoder,options); + reader1.read(); + ojson val1 = decoder.get_result(); + //std::cout << "\n(1)\n"<< pretty_print(val1) << "\n"; + CHECK(val1.size() == 4); + + options.mapping(csv::mapping_type::n_objects); + csv::csv_reader reader2(bond_yields,decoder,options); + reader2.read(); + ojson val2 = decoder.get_result(); + //std::cout << "\n(2)\n"<< pretty_print(val2) << "\n"; + REQUIRE(val2.size() == 3); + CHECK("2017-01-09" == val2[0]["Date"].as()); +} + +TEST_CASE("m_columns_test") +{ + const std::string bond_yields = R"(Date,ProductType,1Y,2Y,3Y,5Y +2017-01-09,"Bond",0.0062,0.0075,0.0083,0.011 +2017-01-08,"Bond",0.0063,0.0076,0.0084,0.0112 +2017-01-08,"Bond",0.0063,0.0076,0.0084,0.0112 +)"; + + json_decoder decoder; + csv::csv_options options; + options.assume_header(true) + .mapping(csv::mapping_type::m_columns); + + std::istringstream is(bond_yields); + csv::csv_reader reader(is, decoder, options); + reader.read(); + ojson j = decoder.get_result(); + CHECK(6 == j.size()); + CHECK(3 == j["Date"].size()); + CHECK(3 == j["1Y"].size()); + CHECK(3 == j["2Y"].size()); + CHECK(3 == j["3Y"].size()); + CHECK(3 == j["5Y"].size()); +} + +TEST_CASE("m_columns with ignore_empty_value") +{ + const std::string bond_yields = R"(Date,ProductType,1Y,2Y,3Y,5Y +2017-01-09,"Bond",0.0062,0.0075,0.0083,0.011 +2017-01-08,"Bond",0.0063,0.0076,,0.0112 +2017-01-08,"Bond",0.0063,0.0076,0.0084, +)"; + //std::cout << bond_yields << std::endl < decoder; + csv::csv_options options; + options.assume_header(true) + .ignore_empty_values(true) + .mapping(csv::mapping_type::m_columns); + + std::istringstream is(bond_yields); + csv::csv_reader reader(is, decoder, options); + reader.read(); + ojson j = decoder.get_result(); + //std::cout << "\n(1)\n"<< pretty_print(j) << "\n"; + CHECK(6 == j.size()); + CHECK(3 == j["Date"].size()); + CHECK(3 == j["1Y"].size()); + CHECK(3 == j["2Y"].size()); + CHECK(2 == j["3Y"].size()); + CHECK(2 == j["5Y"].size()); +} + +TEST_CASE("csv_test_empty_values") +{ + std::string input = "bool-f,int-f,float-f,string-f" +"\n,,,," +"\ntrue,12,24.7,\"test string\"," +"\n,,,,"; + + std::istringstream is(input); + + json_decoder decoder; + + csv::csv_options options; + options.assume_header(true) + .column_types("boolean,integer,float,string"); + + csv::csv_reader reader(is,decoder,options); + reader.read(); + json val = decoder.get_result(); + + CHECK(val[0]["bool-f"].is_null()); + CHECK(val[0]["bool-f"].is()); + CHECK(val[0]["int-f"].is_null()); + CHECK(val[0]["int-f"].is()); + CHECK(val[0]["float-f"].is_null()); + CHECK(val[0]["float-f"].is()); + CHECK(val[0]["string-f"].as() == ""); + CHECK(val[0]["string-f"].is()); + + CHECK(val[1]["bool-f"] .as()== true); + CHECK(val[1]["bool-f"].is()); + CHECK(val[1]["int-f"] .as()== 12); + CHECK(val[1]["int-f"].is()); + CHECK(val[1]["float-f"] .as()== 24.7); + CHECK(val[1]["float-f"].is()); + CHECK(val[1]["string-f"].as() == "test string"); + CHECK(val[1]["string-f"].is()); + + CHECK(val[0]["bool-f"].is_null()); + CHECK(val[0]["bool-f"].is()); + CHECK(val[0]["int-f"].is_null()); + CHECK(val[0]["int-f"].is()); + CHECK(val[0]["float-f"].is_null()); + CHECK(val[0]["float-f"].is()); + CHECK(val[0]["string-f"] .as() == ""); + CHECK(val[0]["string-f"].is()); +} + +TEST_CASE("csv_test_empty_values_with_defaults") +{ + std::string input = "bool-f,int-f,float-f,string-f" +"\n,,,," +"\ntrue,12,24.7,\"test string\"," +"\n,,,,"; + + std::istringstream is(input); + + json_decoder decoder; + + csv::csv_options options; + options.assume_header(true) + .column_types("boolean,integer,float,string") + .column_defaults("false,0,0.0,\"\""); + + csv::csv_reader reader(is,decoder,options); + reader.read(); + json val = decoder.get_result(); + + std::cout << pretty_print(val) << std::endl; + + CHECK(val[0]["bool-f"].as() == false); + CHECK(val[0]["bool-f"].is()); + CHECK(val[0]["int-f"] .as()== 0); + CHECK(val[0]["int-f"].is()); + CHECK(val[0]["float-f"].as() == 0.0); + CHECK(val[0]["float-f"].is()); + CHECK(val[0]["string-f"] .as() == ""); + CHECK(val[0]["string-f"].is()); + + CHECK(val[1]["bool-f"] .as()== true); + CHECK(val[1]["bool-f"].is()); + CHECK(val[1]["int-f"] .as()== 12); + CHECK(val[1]["int-f"].is()); + CHECK(val[1]["float-f"] .as()== 24.7); + CHECK(val[1]["float-f"].is()); + CHECK(val[1]["string-f"].as() == "test string"); + CHECK(val[1]["string-f"].is()); + + CHECK(val[2]["bool-f"].as() == false); + CHECK(val[2]["bool-f"].is()); + CHECK(val[2]["int-f"] .as()== 0); + CHECK(val[2]["int-f"].is()); + CHECK(val[2]["float-f"].as() == 0.0); + CHECK(val[2]["float-f"].is()); + CHECK(val[2]["string-f"].as() == ""); + CHECK(val[2]["string-f"].is()); +} + +TEST_CASE("csv_test_empty_values_with_empty_defaults") +{ + std::string input = "bool-f,int-f,float-f,string-f" +"\n,,,," +"\ntrue,12,24.7,\"test string\"," +"\n,,,,"; + + std::istringstream is(input); + + json_decoder decoder; + + csv::csv_options options; + options.assume_header(true) + .column_types("boolean,integer,float,string") + .column_defaults(",,,"); + + csv::csv_reader reader(is,decoder,options); + reader.read(); + json val = decoder.get_result(); + + CHECK(val[0]["bool-f"].is_null()); + CHECK(val[0]["bool-f"].is()); + CHECK(val[0]["int-f"].is_null()); + CHECK(val[0]["int-f"].is()); + CHECK(val[0]["float-f"].is_null()); + CHECK(val[0]["float-f"].is()); + CHECK(val[0]["string-f"] .as() == ""); + CHECK(val[0]["string-f"].is()); + + CHECK(val[1]["bool-f"] .as() == true); + CHECK(val[1]["bool-f"].is()); + CHECK(val[1]["int-f"] .as()== 12); + CHECK(val[1]["int-f"].is()); + CHECK(val[1]["float-f"] .as()== 24.7); + CHECK(val[1]["float-f"].is()); + CHECK(val[1]["string-f"].as() == "test string"); + CHECK(val[1]["string-f"].is()); + + CHECK(val[0]["bool-f"].is_null()); + CHECK(val[0]["bool-f"].is()); + CHECK(val[0]["int-f"].is_null()); + CHECK(val[0]["int-f"].is()); + CHECK(val[0]["float-f"].is_null()); + CHECK(val[0]["float-f"].is()); + CHECK(val[0]["string-f"] .as() == ""); + CHECK(val[0]["string-f"].is()); +} + +TEST_CASE("csv_test1_array_1col_skip1_a") +{ + std::string text = "a\n1\n4"; + std::istringstream is(text); + + json_decoder decoder; + + csv::csv_options options; + options.header_lines(1); + + csv::csv_reader reader(is,decoder,options); + reader.read(); + json val = decoder.get_result(); + + CHECK(val.size()==2); + CHECK(val[0].size()==1); + CHECK(val[1].size()==1); + CHECK(val[0][0]==json(1)); + CHECK(val[1][0]==json(4)); +} + +TEST_CASE("csv_test1_array_1col_skip1_b") +{ + std::string text = "a\n1\n4"; + std::istringstream is(text); + + json_decoder decoder; + + csv::csv_options options; + options.header_lines(1); + options.infer_types(false); + + csv::csv_reader reader(is,decoder,options); + reader.read(); + json val = decoder.get_result(); + + CHECK(val.size()==2); + CHECK(val[0].size()==1); + CHECK(val[1].size()==1); + CHECK(val[0][0]==json("1")); + CHECK(val[1][0]==json("4")); +} + +TEST_CASE("csv_test1_array_1col_a") +{ + std::string text = "1\n4"; + std::istringstream is(text); + + json_decoder decoder; + + csv::csv_options options; + options.assume_header(false); + + csv::csv_reader reader(is,decoder,options); + reader.read(); + json val = decoder.get_result(); + + CHECK(val.size()==2); + CHECK(val[0].size()==1); + CHECK(val[1].size()==1); + CHECK(val[0][0]==json(1)); + CHECK(val[1][0]==json(4)); +} + +TEST_CASE("csv_test1_array_1col_b") +{ + std::string text = "1\n4"; + std::istringstream is(text); + + json_decoder decoder; + + csv::csv_options options; + options.assume_header(false) + .infer_types(false); + + csv::csv_reader reader(is,decoder,options); + reader.read(); + json val = decoder.get_result(); + + CHECK(val.size()==2); + CHECK(val[0].size()==1); + CHECK(val[1].size()==1); + CHECK(val[0][0]==json("1")); + CHECK(val[1][0]==json("4")); +} + +TEST_CASE("csv_test1_array_3cols") +{ + std::string text = "a,b,c\n1,2,3\n4,5,6"; + std::istringstream is(text); + + json_decoder decoder; + + csv::csv_options options; + options.assume_header(false); + + csv::csv_reader reader(is,decoder,options); + reader.read(); + json val = decoder.get_result(); + + CHECK(val.size()==3); + CHECK(val[0].size()==3); + CHECK(val[1].size()==3); + CHECK(val[2].size()==3); + CHECK(val[0][0]==json("a")); + CHECK(val[0][1]==json("b")); + CHECK(val[0][2]==json("c")); + CHECK(val[1][0]==json(1)); + CHECK(val[1][1]==json(2)); + CHECK(val[1][2]==json(3)); + CHECK(val[2][0]==json(4)); + CHECK(val[2][1]==json(5)); + CHECK(val[2][2]==json(6)); +} +TEST_CASE("csv_test1_array_3cols_trim_leading") +{ + std::string text = "a ,b ,c \n 1, 2, 3\n 4 , 5 , 6 "; + std::istringstream is(text); + + json_decoder decoder; + + csv::csv_options options; + options.assume_header(false) + .trim_leading(true); + + csv::csv_reader reader(is,decoder,options); + reader.read(); + json val = decoder.get_result(); + + CHECK(val.size()==3); + CHECK(val[0].size()==3); + CHECK(val[1].size()==3); + CHECK(val[2].size()==3); + CHECK(val[0][0]==json("a ")); + CHECK(val[0][1]==json("b ")); + CHECK(val[0][2]==json("c ")); + CHECK(val[1][0]==json(1)); + CHECK(val[1][1]==json(2)); + CHECK(val[1][2]==json(3)); + CHECK(val[2][0]==json("4 ")); + CHECK(val[2][1]==json("5 ")); + CHECK(val[2][2]==json("6 ")); +} + +TEST_CASE("csv_test1_array_3cols_trim_trailing") +{ + std::string text = "a ,b ,c \n 1, 2, 3\n 4 , 5 , 6 "; + std::istringstream is(text); + + json_decoder decoder; + + csv::csv_options options; + options.assume_header(false) + .trim_trailing(true); + + csv::csv_reader reader(is,decoder,options); + reader.read(); + json val = decoder.get_result(); + + CHECK(val.size()==3); + CHECK(val[0].size()==3); + CHECK(val[1].size()==3); + CHECK(val[2].size()==3); + CHECK(val[0][0]==json("a")); + CHECK(val[0][1]==json("b")); + CHECK(val[0][2]==json("c")); + CHECK(json(" 1") == val[1][0]); + CHECK(val[1][1]==json(" 2")); + CHECK(val[1][2]==json(" 3")); + CHECK(val[2][0]==json(" 4")); + CHECK(val[2][1]==json(" 5")); + CHECK(val[2][2]==json(" 6")); +} + +TEST_CASE("csv_test1_array_3cols_trim") +{ + std::string text = "a ,, \n 1, 2, 3\n 4 , 5 , 6 "; + std::istringstream is(text); + + json_decoder decoder; + + csv::csv_options options; + options.assume_header(false) + .trim(true) + .unquoted_empty_value_is_null(true); + + csv::csv_reader reader(is,decoder,options); + reader.read(); + json val = decoder.get_result(); + + CHECK(val.size()==3); + CHECK(val[0].size()==3); + CHECK(val[1].size()==3); + CHECK(val[2].size()==3); + CHECK(val[0][0]==json("a")); + CHECK(val[0][1]==json::null()); + CHECK(val[0][2]==json::null()); + CHECK(val[1][0]==json(1)); + CHECK(val[1][1]==json(2)); + CHECK(val[1][2]==json(3)); + CHECK(val[2][0]==json(4)); + CHECK(val[2][1]==json(5)); + CHECK(val[2][2]==json(6)); +} + +TEST_CASE("csv_test1_array_3cols_comment") +{ + std::string text = "a,b,c\n#1,2,3\n4,5,6"; + std::istringstream is(text); + + json_decoder decoder; + + csv::csv_options options; + options.comment_starter('#'); + + csv::csv_reader reader(is,decoder,options); + reader.read(); + json val = decoder.get_result(); + + CHECK(val.size()==2); + CHECK(val[0].size()==3); + CHECK(val[1].size()==3); + CHECK(val[0][0]==json("a")); + CHECK(val[0][1]==json("b")); + CHECK(val[0][2]==json("c")); + CHECK(val[1][0]==json(4)); + CHECK(val[1][1]==json(5)); + CHECK(val[1][2]==json(6)); +} + +TEST_CASE("csv_test1_object_1col") +{ + std::string text = "a\n1\n4"; + std::istringstream is(text); + + json_decoder decoder; + + csv::csv_options options; + options.assume_header(true); + + csv::csv_reader reader(is,decoder,options); + reader.read(); + json val = decoder.get_result(); + + CHECK(val.size()==2); + CHECK(val[0].size()==1); + CHECK(val[1].size()==1); + CHECK(val[0]["a"]==json(1)); + CHECK(val[1]["a"]==json(4)); +} + +TEST_CASE("csv_test1_object_3cols") +{ + std::string text = "a,b,c\n1,2,3\n4,5,6"; + std::istringstream is(text); + + json_decoder decoder; + + csv::csv_options options; + options.assume_header(true); + + csv::csv_reader reader(is,decoder,options); + reader.read(); + json val = decoder.get_result(); + + CHECK(val.size()==2); + CHECK(val[0].size()==3); + CHECK(val[1].size()==3); + CHECK(val[0]["a"]==json(1)); + CHECK(val[0]["b"]==json(2)); + CHECK(val[0]["c"]==json(3)); + CHECK(val[1]["a"]==json(4)); + CHECK(val[1]["b"]==json(5)); + CHECK(val[1]["c"]==json(6)); +} + +TEST_CASE("csv_test1_object_3cols_header") +{ + std::string text = "a,b,c\n1,2,3\n4,5,6"; + std::istringstream is(text); + + json_decoder decoder; + + csv::csv_options options; + options.column_names("x,y,z") + .header_lines(1); + + csv::csv_reader reader(is,decoder,options); + reader.read(); + json val = decoder.get_result(); + + CHECK(val.size()==2); + CHECK(val[0].size()==3); + CHECK(val[1].size()==3); + CHECK(val[0]["x"]==json(1)); + CHECK(val[0]["y"]==json(2)); + CHECK(val[0]["z"]==json(3)); + CHECK(val[1]["x"]==json(4)); + CHECK(val[1]["y"]==json(5)); + CHECK(val[1]["z"]==json(6)); +} + +TEST_CASE("csv_test1_object_3cols_bool") +{ + std::string text = "a,b,c\n1,0,1\ntrue,FalSe,TrUe"; + std::istringstream is(text); + + json_decoder decoder; + + csv::csv_options options; + options.column_names("x,y,z") + .column_types("boolean,boolean,boolean") + .header_lines(1); + + csv::csv_reader reader(is,decoder,options); + reader.read(); + json val = decoder.get_result(); + + CHECK(val.size()==2); + CHECK(val[0].size()==3); + CHECK(val[1].size()==3); + CHECK(val[0]["x"]==json(true)); + CHECK(val[0]["y"]==json(false)); + CHECK(val[0]["z"]==json(true)); + CHECK(val[1]["x"]==json(true)); + CHECK(val[1]["y"]==json(false)); + CHECK(val[1]["z"]==json(true)); +} + +TEST_CASE("csv_test1_object_1col_quoted") +{ + std::string text = "a\n\"1\"\n\"4\""; + std::istringstream is(text); + + json_decoder decoder; + + csv::csv_options options; + options.assume_header(true); + + csv::csv_reader reader(is,decoder,options); + reader.read(); + json val = decoder.get_result(); + + CHECK(val.size()==2); + CHECK(val[0].size()==1); + CHECK(val[1].size()==1); + CHECK(val[0]["a"]==json("1")); + CHECK(val[1]["a"]==json("4")); +} + +TEST_CASE("csv_test1_object_3cols_quoted") +{ + std::string text = "a,b,c\n\"1\",\"2\",\"3\"\n4,5,\"6\""; + std::istringstream is(text); + + json_decoder decoder; + + csv::csv_options options; + options.assume_header(true); + + csv::csv_reader reader(is,decoder,options); + reader.read(); + json val = decoder.get_result(); + + CHECK(val.size()==2); + CHECK(val[0].size()==3); + CHECK(val[1].size()==3); + CHECK(val[0]["a"]==json("1")); + CHECK(val[0]["b"]==json("2")); + CHECK(val[0]["c"]==json("3")); + CHECK(val[1]["a"]==json(4)); + CHECK(val[1]["b"]==json(5)); + CHECK(val[1]["c"]==json("6")); +} + +TEST_CASE("csv_test1_array_1col_crlf") +{ + std::string text = "1\r\n4"; + std::istringstream is(text); + + json_decoder decoder; + + csv::csv_options options; + options.assume_header(false); + + csv::csv_reader reader(is,decoder,options); + reader.read(); + json val = decoder.get_result(); + + CHECK(val.size()==2); + CHECK(val[0].size()==1); + CHECK(val[1].size()==1); + CHECK(val[0][0]==json(1)); + CHECK(val[1][0]==json(4)); +} + +TEST_CASE("csv_test1_array_3cols_crlf") +{ + std::string text = "a,b,c\r\n1,2,3\r\n4,5,6"; + std::istringstream is(text); + + json_decoder decoder; + + csv::csv_options options; + options.assume_header(false); + + csv::csv_reader reader(is,decoder,options); + reader.read(); + json val = decoder.get_result(); + + CHECK(val.size()==3); + CHECK(val[0].size()==3); + CHECK(val[1].size()==3); + CHECK(val[2].size()==3); + CHECK(val[0][0]==json("a")); + CHECK(val[0][1]==json("b")); + CHECK(val[0][2]==json("c")); + CHECK(val[1][0]==json(1)); + CHECK(val[1][1]==json(2)); + CHECK(val[1][2]==json(3)); + CHECK(val[2][0]==json(4)); + CHECK(val[2][1]==json(5)); + CHECK(val[2][2]==json(6)); +} + +TEST_CASE("csv_test1_object_1col_crlf") +{ + std::string text = "a\r\n1\r\n4"; + std::istringstream is(text); + + json_decoder decoder; + + csv::csv_options options; + options.assume_header(true); + + csv::csv_reader reader(is,decoder,options); + reader.read(); + json val = decoder.get_result(); + + CHECK(val.size()==2); + CHECK(val[0].size()==1); + CHECK(val[1].size()==1); + CHECK(val[0]["a"]==json(1)); + CHECK(val[1]["a"]==json(4)); +} + +TEST_CASE("csv_test1_object_3cols_crlf") +{ + std::string text = "a,b,c\r\n1,2,3\r\n4,5,6"; + std::istringstream is(text); + + json_decoder decoder; + + csv::csv_options options; + options.assume_header(true); + + csv::csv_reader reader(is,decoder,options); + reader.read(); + json val = decoder.get_result(); + + CHECK(val.size()==2); + CHECK(val[0].size()==3); + CHECK(val[1].size()==3); + CHECK(val[0]["a"]==json(1)); + CHECK(val[0]["b"]==json(2)); + CHECK(val[0]["c"]==json(3)); + CHECK(val[1]["a"]==json(4)); + CHECK(val[1]["b"]==json(5)); + CHECK(val[1]["c"]==json(6)); +} + +TEST_CASE("read_comma_delimited_file") +{ + std::string in_file = "./input/countries.csv"; + std::ifstream is(in_file); + + json_decoder decoder; + + csv::csv_options options; + options.assume_header(true); + + csv::csv_reader reader(is,decoder,options); + reader.read(); + json countries = decoder.get_result(); + + CHECK(4 == countries.size()); + CHECK(json("ABW") == countries[0]["country_code"]); + CHECK(json("ARUBA") ==countries[0]["name"]); + CHECK(json("ATF") == countries[1]["country_code"]); + CHECK(json("FRENCH SOUTHERN TERRITORIES, D.R. OF") == countries[1]["name"]); + CHECK(json("VUT") == countries[2]["country_code"]); + CHECK(json("VANUATU") ==countries[2]["name"]); + CHECK(json("WLF") == countries[3]["country_code"]); + CHECK(json("WALLIS & FUTUNA ISLANDS") == countries[3]["name"]); +} + +TEST_CASE("read_comma_delimited_file_header") +{ + std::string in_file = "./input/countries.csv"; + std::ifstream is(in_file); + + json_decoder decoder; + + csv::csv_options options; + options.column_names("Country Code,Name") + .header_lines(1); + + csv::csv_reader reader(is,decoder,options); + reader.read(); + json countries = decoder.get_result(); + CHECK(4 == countries.size()); + CHECK(json("ABW") == countries[0]["Country Code"]); + CHECK(json("ARUBA") ==countries[0]["Name"]); + CHECK(json("ATF") == countries[1]["Country Code"]); + CHECK(json("FRENCH SOUTHERN TERRITORIES, D.R. OF") == countries[1]["Name"]); + CHECK(json("VUT") == countries[2]["Country Code"]); + CHECK(json("VANUATU") == countries[2]["Name"]); + CHECK(json("WLF") == countries[3]["Country Code"]); + CHECK(json("WALLIS & FUTUNA ISLANDS") == countries[3]["Name"]); +} + +TEST_CASE("serialize_comma_delimited_file") +{ + std::string in_file = "./input/countries.json"; + std::ifstream is(in_file); + + csv::csv_options options; + options.assume_header(false); + + json_decoder encoder1; + json_reader reader1(is,encoder1); + reader1.read(); + ojson countries1 = encoder1.get_result(); + + std::stringstream ss; + csv::csv_encoder encoder(ss,options); + countries1.dump(encoder); + + json_decoder encoder2; + csv::csv_reader reader2(ss,encoder2,options); + reader2.read(); + ojson countries2 = encoder2.get_result(); + + CHECK(countries1 == countries2); +} + +TEST_CASE("test_tab_delimited_file") +{ + std::string in_file = "./input/employees.txt"; + std::ifstream is(in_file); + + json_decoder decoder; + csv::csv_options options; + options.field_delimiter('\t') + .assume_header(true); + + csv::csv_reader reader(is,decoder,options); + reader.read(); + json employees = decoder.get_result(); + CHECK(4 == employees.size()); + CHECK(std::string("00000001") ==employees[0]["employee-no"].as()); + CHECK(std::string("00000002") ==employees[1]["employee-no"].as()); + CHECK(std::string("00000003") ==employees[2]["employee-no"].as()); + CHECK(std::string("00000004") ==employees[3]["employee-no"].as()); +} + +TEST_CASE("serialize_tab_delimited_file") +{ + std::string in_file = "./input/employees.json"; + std::ifstream is(in_file); + + json_decoder decoder; + csv::csv_options options; + options.assume_header(false) + .header_lines(1) + .column_names("dept,employee-name,employee-no,note,comment,salary") + .field_delimiter('\t'); + + json_reader reader(is,decoder); + reader.read_next(); + ojson employees1 = decoder.get_result(); + + std::stringstream ss; + csv::csv_encoder encoder(ss,options); + //std::cout << pretty_print(employees1) << std::endl; + employees1.dump(encoder); + //std::cout << ss.str() << std::endl; + + json_decoder encoder2; + csv::csv_reader reader2(ss,encoder2,options); + reader2.read(); + ojson employees2 = encoder2.get_result(); + //std::cout << pretty_print(employees2) << std::endl; + + CHECK(employees1.size() == employees2.size()); + + for (size_t i = 0; i < employees1.size(); ++i) + { + CHECK(employees1[i]["dept"] == employees2[i]["dept"]); + CHECK(employees1[i]["employee-name"] ==employees2[i]["employee-name"]); + CHECK(employees1[i]["employee-no"] ==employees2[i]["employee-no"]); + CHECK(employees1[i]["salary"] == employees2[i]["salary"]); + CHECK(employees1[i].get_with_default("note","") == employees2[i].get_with_default("note","")); + } +} + +TEST_CASE("csv_test1_array_3cols_grouped1") +{ + std::string text = "1,2,3\n4,5,6\n7,8,9"; + std::istringstream is(text); + + json_decoder decoder; + + csv::csv_options options; + options.assume_header(false) + .column_types("integer,[integer]*"); + + csv::csv_reader reader(is,decoder,options); + reader.read(); + json val = decoder.get_result(); + + //std::cout << val << std::endl; + + /*CHECK(val.size()==3); + CHECK(val[0].size()==3); + CHECK(val[1].size()==3); + CHECK(val[2].size()==3); + CHECK(val[0][0]==json(1)); + CHECK(val[0][1]==json(2)); + CHECK(val[0][2]==json(3)); + CHECK(val[1][0]==json(4)); + CHECK(val[1][1]==json(5)); + CHECK(val[1][2]==json(6)); + CHECK(val[2][0]==json(7)); + CHECK(val[2][1]==json(8)); + CHECK(val[2][2]==json(9));*/ +} + +TEST_CASE("csv_test1_array_3cols_grouped2") +{ + std::string text = "1,2,3,4,5\n4,5,6,7,8\n7,8,9,10,11"; + std::istringstream is(text); + + json_decoder decoder; + + csv::csv_options options; + options.assume_header(false) + .column_types("integer,[integer,integer]*"); + + csv::csv_reader reader(is,decoder,options); + reader.read(); + json val = decoder.get_result(); + + //std::cout << val << std::endl; +/* + REQUIRE(options.column_types().size() == 4); + CHECK(options.column_types()[0].first == csv::csv_column_type::integer_t); + CHECK(options.column_types()[0].second == 0); + CHECK(options.column_types()[1].first == csv::csv_column_type::integer_t); + CHECK(options.column_types()[1].second == 1); + CHECK(options.column_types()[2].first == csv::csv_column_type::integer_t); + CHECK(options.column_types()[2].second == 1); + CHECK(options.column_types()[3].first == csv::csv_column_type::repeat_t); + CHECK(options.column_types()[3].second == 2); +*/ +} + +TEST_CASE("csv_test1_repeat") +{ + const std::string text = R"(Date,1Y,2Y,3Y,5Y + 2017-01-09,0.0062,0.0075,0.0083,0.011,0.012 + 2017-01-08,0.0063,0.0076,0.0084,0.0112,0.013 + 2017-01-08,0.0063,0.0076,0.0084,0.0112,0.014 + )"; + + auto result = csv::csv_options::parse_column_types("string,float*"); + REQUIRE(result.size() == 3); + CHECK(result[0].col_type == csv::csv_column_type::string_t); + CHECK(result[0].level == 0); + CHECK(0 == result[0].rep_count); + CHECK(result[1].col_type == csv::csv_column_type::float_t); + CHECK(result[1].level == 0); + CHECK(0 == result[1].rep_count); + CHECK(result[2].col_type == csv::csv_column_type::repeat_t); + CHECK(result[2].level == 0); + CHECK(1 == result[2].rep_count); + + auto result2 = csv::csv_options::parse_column_types("string,[float*]"); + REQUIRE(result2.size() == 3); + CHECK(result2[0].col_type == csv::csv_column_type::string_t); + CHECK(result2[0].level == 0); + CHECK(0 == result2[0].rep_count); + CHECK(result2[1].col_type == csv::csv_column_type::float_t); + CHECK(result2[1].level == 1); + CHECK(0 == result2[1].rep_count); + CHECK(result2[2].col_type == csv::csv_column_type::repeat_t); + CHECK(result2[2].level == 1); + CHECK(1 == result2[2].rep_count); + + auto result3 = csv::csv_options::parse_column_types("string,[float]*"); + REQUIRE(result3.size() == 3); + CHECK(result3[0].col_type == csv::csv_column_type::string_t); + CHECK(result3[0].level == 0); + CHECK(0 == result3[0].rep_count); + CHECK(result3[1].col_type == csv::csv_column_type::float_t); + CHECK(result3[1].level == 1); + CHECK(0 == result3[1].rep_count); + CHECK(result3[2].col_type == csv::csv_column_type::repeat_t); + CHECK(result3[2].level == 0); + CHECK(1 == result3[2].rep_count); +} + +TEST_CASE("csv_test1_repeat2") +{ + csv::csv_options options1; + options1.column_types("[integer,string]*"); + for (auto x : options1.column_types()) + { + std::cout << (int)x.col_type << " " << x.level << " " << x.rep_count << std::endl; + } +} + +TEST_CASE("empty_line_test_1") +{ + std::string input = R"(country_code,name +ABW,ARUBA + +ATF,"FRENCH SOUTHERN TERRITORIES, D.R. OF" +VUT,VANUATU +WLF,WALLIS & FUTUNA ISLANDS +)"; + + std::istringstream is(input); + + json_decoder decoder; + + csv::csv_options options; + options.assume_header(true); + + csv::csv_reader reader(is,decoder,options); + reader.read(); + json j = decoder.get_result(); + CHECK(j.size() == 4); + + std::cout << pretty_print(j) << std::endl; +} + +TEST_CASE("empty_line_test_2") +{ + std::string input = R"(country_code,name +ABW,ARUBA + +ATF,"FRENCH SOUTHERN TERRITORIES, D.R. OF" +VUT,VANUATU +WLF,WALLIS & FUTUNA ISLANDS +)"; + + std::istringstream is(input); + + json_decoder decoder; + + csv::csv_options options; + options.assume_header(true) + .ignore_empty_lines(false); + + csv::csv_reader reader(is,decoder,options); + reader.read(); + json j = decoder.get_result(); + CHECK(j.size() == 5); + + std::cout << pretty_print(j) << std::endl; +} + +TEST_CASE("line_with_one_space") +{ + std::string input = R"(country_code,name +ABW,ARUBA +\t +ATF,"FRENCH SOUTHERN TERRITORIES, D.R. OF" +VUT,VANUATU +WLF,WALLIS & FUTUNA ISLANDS +)"; + + std::istringstream is(input); + + json_decoder decoder; + + csv::csv_options options; + options.assume_header(true); + + csv::csv_reader reader(is,decoder,options); + reader.read(); + json j = decoder.get_result(); + CHECK(j.size() == 5); + + std::cout << pretty_print(j) << std::endl; +} + +TEST_CASE("line_with_one_space_and_trim") +{ + std::string input = R"(country_code,name +ABW,ARUBA + +ATF,"FRENCH SOUTHERN TERRITORIES, D.R. OF" +VUT,VANUATU +WLF,WALLIS & FUTUNA ISLANDS +)"; + + std::istringstream is(input); + + json_decoder decoder; + + csv::csv_options options; + options.assume_header(true) + .trim(true); + + csv::csv_reader reader(is,decoder,options); + reader.read(); + json j = decoder.get_result(); + CHECK(j.size() == 4); + + std::cout << pretty_print(j) << std::endl; +} + +TEST_CASE("test_decode_csv_from_string") +{ + std::string s = "some label\nsome value"; + csv::csv_options options; + options.assume_header(true); + std::cout << csv::decode_csv(s,options) << std::endl; +} + +TEST_CASE("test_decode_csv_from_stream") +{ + std::string s = "some label\nsome value"; + std::stringstream is(s); + csv::csv_options options; + options.assume_header(true); + std::cout << csv::decode_csv(is,options) << std::endl; +} + +TEST_CASE("test_encode_csv_to_stream") +{ + json j = json::array(); + j.push_back(json::object({ {"a",1},{"b",2} })); + std::cout << j << std::endl; + csv::csv_options options; + options.assume_header(true); + std::ostringstream os; + csv::encode_csv(j, os, options); + std::cout << os.str() << std::endl; +} + +TEST_CASE("test_type_inference") +{ + const std::string input = R"(customer_name,has_coupon,phone_number,zip_code,sales_tax_rate,total_amount +"John Roe",true,0272561313,01001,0.05,431.65 +"Jane Doe",false,416-272-2561,55416,0.15,480.70 +"Joe Bloggs",false,"4162722561","55416",0.15,300.70 +"John Smith",FALSE,NULL,22313-1450,0.15,300.70 +)"; + + std::cout << input << std::endl; + + json_decoder decoder; + + csv::csv_options options; + options.assume_header(true) + .mapping(csv::mapping_type::n_rows); + + ojson j1 = csv::decode_csv(input,options); + std::cout << "\n(1)\n"<< pretty_print(j1) << "\n"; + //CHECK(j1.size() == 4); + + options.mapping(csv::mapping_type::n_objects); + ojson j2 = csv::decode_csv(input,options); + std::cout << "\n(2)\n"<< pretty_print(j2) << "\n"; + + options.mapping(csv::mapping_type::m_columns); + ojson j3 = csv::decode_csv(input,options); + std::cout << "\n(3)\n"<< pretty_print(j3) << "\n"; + //REQUIRE(j2.size() == 3); + //CHECK("2017-01-09" == j2[0]["Date"].as()); +} + +TEST_CASE("csv_options lossless_number") +{ + const std::string input = R"(index_id,observation_date,rate +EUR_LIBOR_06M,2015-10-23,0.0000214 +EUR_LIBOR_06M,2015-10-26,0.0000143 +EUR_LIBOR_06M,2015-10-27,0.0000001 +)"; + + std::cout << input << std::endl; + + json_decoder decoder; + + csv::csv_options options; + options.assume_header(true) + .mapping(csv::mapping_type::n_objects) + .trim(true) + .lossless_number(true); + + ojson j1 = csv::decode_csv(input,options); + std::cout << pretty_print(j1) << "\n"; + REQUIRE(j1.size() == 3); + CHECK((j1[0]["rate"].as() == "0.0000214")); +} + +// Test case contributed by karimhm +TEST_CASE("csv detect bom") +{ + const std::string input = "\xEF\xBB\xBFstop_id,stop_name,stop_lat,stop_lon,location_type,parent_station\n" +"\"8220B007612\",\"Hotel Merrion Street\",\"53\",\"-6\",\"\",\"\""; + + csv::csv_options options; + options.assume_header(true); + + std::istringstream is(input); + ojson j = csv::decode_csv(is, options); + REQUIRE(j.size() == 1); + ojson station = j[0]; + + try { + auto it = station.find("stop_id"); + REQUIRE((it != station.object_range().end())); + std::string stop_id = it->value().as(); + CHECK((stop_id == "8220B007612")); + } catch (const std::exception& e) { + std::cout << e.what() << std::endl; + } +} + +TEST_CASE("test_encode_decode csv string") +{ + typedef std::vector> cpp_type; + std::string s1 = "\"a\",1\n\"b\",2"; + csv::csv_options options; + options.mapping(csv::mapping_type::n_rows) + .assume_header(false); + + SECTION("string") + { + cpp_type v = csv::decode_csv(s1, options); + REQUIRE(v.size() == 2); + CHECK(std::get<0>(v[0]) == "a"); + CHECK(std::get<1>(v[0]) == 1); + CHECK(std::get<0>(v[1]) == "b"); + CHECK(std::get<1>(v[1]) == 2); + + std::string s2; + csv::encode_csv(v, s2, options); + + json j1 = csv::decode_csv(s1); + json j2 = csv::decode_csv(s2); + + CHECK(j1 == j2); + } + + SECTION("stream") + { + std::stringstream ss1(s1); + cpp_type v = csv::decode_csv(ss1, options); + REQUIRE(v.size() == 2); + CHECK(std::get<0>(v[0]) == "a"); + CHECK(std::get<1>(v[0]) == 1); + CHECK(std::get<0>(v[1]) == "b"); + CHECK(std::get<1>(v[1]) == 2); + + std::stringstream ss2; + csv::encode_csv(v, ss2, options); + + json j1 = csv::decode_csv(s1); + json j2 = csv::decode_csv(ss2); + + CHECK(j1 == j2); + } +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/double_round_trip_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/double_round_trip_tests.cpp new file mode 100644 index 0000000000..53b8b44f02 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/double_round_trip_tests.cpp @@ -0,0 +1,45 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +TEST_CASE("test_round_trip") +{ + { + std::ostringstream os; + double d = 42.229999999999997; + json j = d; + os << j; + CHECK(json::parse(os.str()).as() == d); + } + { + std::ostringstream os; + double d = 9.0099999999999998; + json j = d; + os << j; + CHECK(json::parse(os.str()).as() == d); + } + { + std::ostringstream os; + double d = 13.449999999999999; + json j = d; + os << j; + CHECK(json::parse(os.str()).as() == d); + } + { + std::ostringstream os; + double d = 0.000071; + json j = d; + os << j; + CHECK(json::parse(os.str()).as() == d); + } +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/double_to_string_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/double_to_string_tests.cpp new file mode 100644 index 0000000000..9abec2bb37 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/double_to_string_tests.cpp @@ -0,0 +1,170 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +template +std::basic_string float_to_string(double val, int precision) +{ + jsoncons::detail::print_double print(floating_point_options(chars_format::general,precision,0)); + + std::basic_string s; + jsoncons::string_result> writer(s); + print(val, writer); + writer.flush(); + return s; +} + +TEST_CASE("test_double_to_string") +{ + double x = 1.0e100; + std::string s = float_to_string(x, std::numeric_limits::digits10); + //std::cout << x << ": " << s << std::endl; + CHECK(s == std::string("1e+100")); + + x = 1.0e-100; + s = float_to_string(x, std::numeric_limits::digits10); + CHECK(s == std::string("1e-100")); + + x = 0.123456789e-100; + s = float_to_string(x, std::numeric_limits::digits10); + CHECK(s == std::string("1.23456789e-101")); + + x = 0.123456789e100; + s = float_to_string(x, std::numeric_limits::digits10); + CHECK(s == std::string("1.23456789e+99")); + + x = 1234563; + s = float_to_string(x, 6); + CHECK(s == std::string("1.23456e+06")); + + x = 0.0000001234563; + s = float_to_string(x, 6); + CHECK(s == std::string("1.23456e-07")); + + x = -1.0e+100; + s = float_to_string(x, std::numeric_limits::digits10); + std::cout << s << "\n"; + CHECK(s == std::string("-1e+100")); + + x = -1.0e-100; + s = float_to_string(x, std::numeric_limits::digits10); + CHECK(s == std::string("-1e-100")); + + x = 0; + s = float_to_string(x, std::numeric_limits::digits10); + CHECK(s == std::string("0.0")); + + x = -0; + s = float_to_string(x, std::numeric_limits::digits10); + CHECK(s == std::string("0.0")); + + x = 1; + s = float_to_string(x, std::numeric_limits::digits10); + CHECK(s == std::string("1.0")); + + x = 0.1; + s = float_to_string(x, std::numeric_limits::digits10); + CHECK(s == std::string("0.1")); + + x = 1.1; + s = float_to_string(x, 17); + CHECK(s == std::string("1.1000000000000001")); + + x = -1; + s = float_to_string(x, std::numeric_limits::digits10); + CHECK(s == std::string("-1.0")); + + x = 10; + s = float_to_string(x, std::numeric_limits::digits10); + CHECK(s == std::string("10.0")); + + x = -10; + s = float_to_string(x, std::numeric_limits::digits10); + CHECK(s == std::string("-10.0")); + + x = 11; + s = float_to_string(x, std::numeric_limits::digits10); + CHECK(s == std::string("11.0")); + + x = -11; + s = float_to_string(x, std::numeric_limits::digits10); + CHECK(s == std::string("-11.0")); +} + +#if defined(_MSC_VER) +TEST_CASE("test_locale") +{ + wchar_t * loc = _wsetlocale(LC_ALL, L"de-DE"); + CHECK_FALSE(loc == nullptr); + + double x = 123456789.0123; + std::wstring s = float_to_string(x, 13); + //std::wcout << std::setprecision(13) << x << L": " << s << std::endl; + CHECK(std::wstring(L"123456789.0123") == s); + _wsetlocale(LC_ALL, L"C"); +} +#endif + +TEST_CASE("test_double_to_wstring") +{ + double x = 1.0e100; + std::wstring s = float_to_string(x, std::numeric_limits::digits10); + //std::wcout << x << L":" << s << std::endl; + CHECK(s == std::wstring(L"1e+100")); + + x = 1.0e-100; + s = float_to_string(x, std::numeric_limits::digits10); + CHECK(s == std::wstring(L"1e-100")); + + x = -1.0e+100; + s = float_to_string(x, std::numeric_limits::digits10); + CHECK(s == std::wstring(L"-1e+100")); + + x = -1.0e-100; + s = float_to_string(x, std::numeric_limits::digits10); + CHECK(s == std::wstring(L"-1e-100")); + + x = 0; + s = float_to_string(x, std::numeric_limits::digits10); + CHECK(s == std::wstring(L"0.0")); + + x = -0; + s = float_to_string(x, std::numeric_limits::digits10); + CHECK(s == std::wstring(L"0.0")); + + x = 1; + s = float_to_string(x, std::numeric_limits::digits10); + CHECK(s == std::wstring(L"1.0")); + + x = -1; + s = float_to_string(x, std::numeric_limits::digits10); + CHECK(s == std::wstring(L"-1.0")); + + x = 10; + s = float_to_string(x, std::numeric_limits::digits10); + CHECK(s == std::wstring(L"10.0")); + + x = -10; + s = float_to_string(x, std::numeric_limits::digits10); + CHECK(s == std::wstring(L"-10.0")); + + x = 11; + s = float_to_string(x, std::numeric_limits::digits10); + CHECK(s == std::wstring(L"11.0")); + + x = -11; + s = float_to_string(x, std::numeric_limits::digits10); + CHECK(s == std::wstring(L"-11.0")); +} + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/dtoa_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/dtoa_tests.cpp new file mode 100644 index 0000000000..b8e3a4cfd5 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/dtoa_tests.cpp @@ -0,0 +1,100 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include + +using namespace jsoncons; + +static void check_safe_dtoa(double x, const std::vector& expected) +{ + std::string s; + bool result = jsoncons::detail::dtoa(x, '.', s, std::false_type()); + if (!result) + { + std::cout << "safe dtoa failed " << s << "\n"; + } + REQUIRE(result); + + bool accept = false; + for (size_t i = 0; !accept && i < expected.size(); ++i) + { + accept = s == expected[i]; + } + if (!accept) + { + std::cout << "safe dtoa does not match expected " << x << " " << s << "\n"; + } + + CHECK(accept); +} + +static void check_dtoa(double x, const std::vector& expected) +{ + std::string s; + bool result = jsoncons::detail::dtoa(x, '.', s); + if (!result) + { + std::cout << "dtoa failed " << s << "\n"; + } + REQUIRE(result); + + bool accept = false; + for (size_t i = 0; !accept && i < expected.size(); ++i) + { + accept = s == expected[i]; + } + if (!accept) + { + std::cout << "dtoa does not match expected " << x << " " << s << "\n"; + } + CHECK(accept); + + check_safe_dtoa(x,expected); +} + +TEST_CASE("test grisu3") +{ + check_dtoa(1.0e100, {"1e+100"}); + check_dtoa(1.0e-100, {"1e-100"}); + check_dtoa(0.123456789e-100, {"1.23456789e-101"}); + check_dtoa(0.123456789e100, {"1.23456789e+99"}); + + check_dtoa(1234563, {"1234563.0"}); + + check_dtoa(0.0000001234563, {"1.234563e-07"}); + + check_dtoa(-1.0e+100, {"-1e+100"}); + + check_dtoa(-1.0e-100, {"-1e-100"}); + + check_dtoa(0, {"0.0"}); + check_dtoa(-0, {"0.0"}); + check_dtoa(1, {"1.0"}); + check_dtoa(0.1, {"0.1"}); + + check_dtoa(1.1, {"1.1"}); + + check_dtoa(-1, {"-1.0"}); + check_dtoa(10, {"10.0"}); + check_dtoa(-10, {"-10.0"}); + check_dtoa(-11, {"-11.0"}); + + check_dtoa(12.272727012634277, {"12.272727012634277"}); + + check_dtoa(4094.1111111111113, {"4094.1111111111113"}); + + check_dtoa(0.119942, {"0.119942"}); + + check_dtoa(-36.973846435546875, {"-36.973846435546875"}); + + check_dtoa(42.229999999999997, {"42.23"}); + check_dtoa(9.0099999999999998, {"9.01"}); + check_dtoa(13.449999999999999, {"13.45"}); + + check_dtoa(0.000071, {"7.1e-05"}); +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/error_recovery_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/error_recovery_tests.cpp new file mode 100644 index 0000000000..d005d57bcf --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/error_recovery_tests.cpp @@ -0,0 +1,79 @@ + +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +class relaxed_error_handler : public parse_error_handler +{ +private: + + bool do_error(std::error_code ec, + const ser_context&) noexcept override + { + if (ec == jsoncons::json_errc::extra_comma) + { + return true; + } + return false; + } +}; + +TEST_CASE("test_array_extra_comma") +{ + relaxed_error_handler err_handler; + + json expected = json::parse("[1,2,3]"); + json val = json::parse("[1,2,3,]", err_handler); + + CHECK(val == expected); +} + +TEST_CASE("test_object_extra_comma") +{ + relaxed_error_handler err_handler; + + json expected = json::parse(R"( + { + "first" : 1, + "second" : 2 + } + )", + err_handler); + + json val = json::parse(R"( + { + "first" : 1, + "second" : 2, + } + )", + err_handler); + + CHECK(val == expected); +} + +TEST_CASE("test_name_without_quotes") +{ + relaxed_error_handler err_handler; + + /*json val = json::parse(R"( + { + first : 1, + second : 2 + } + )", + err_handler); + + std::cout << val << std::endl;*/ +} + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/heap_only_string_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/heap_only_string_tests.cpp new file mode 100644 index 0000000000..cce6ed84e6 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/heap_only_string_tests.cpp @@ -0,0 +1,36 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +TEST_CASE("test_heap_only_string") +{ + std::string input = "Hello World"; + auto s = jsoncons::detail::heap_only_string_factory>::create(input.data(), input.size()); + + //std::cout << s->c_str() << std::endl; + CHECK(input == std::string(s->c_str())); + + jsoncons::detail::heap_only_string_factory>::destroy(s); +} + +TEST_CASE("test_heap_only_string_wchar_t") +{ + std::wstring input = L"Hello World"; + auto s = jsoncons::detail::heap_only_string_factory>::create(input.data(), input.size()); + + //std::wcout << s->c_str() << std::endl; + + CHECK(input == std::wstring(s->c_str())); + + jsoncons::detail::heap_only_string_factory>::destroy(s); +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_array_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_array_tests.cpp new file mode 100644 index 0000000000..36bbecfb08 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_array_tests.cpp @@ -0,0 +1,462 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +TEST_CASE("test_initializer_list_of_integers") +{ + json arr = json::array{0,1,2,3}; + CHECK(arr.is_array()); + CHECK(arr.size() == 4); + for (size_t i = 0; i < arr.size(); ++i) + { + CHECK(i == arr[i].as()); + } +} + +TEST_CASE("test_assignment_to_initializer_list") +{ + json arr = json::array({0,1,2,3}); + + arr = json::array{0,1,2,3}; + CHECK(arr.is_array()); + CHECK(arr.size() == 4); + for (size_t i = 0; i < arr.size(); ++i) + { + CHECK(i == arr[i].as()); + } +} + +TEST_CASE("test_assignment_to_initializer_list2") +{ + json val; + val["data"]["id"] = json::array{0,1,2,3,4,5,6,7}; + val["data"]["item"] = json::array{json::array{2}, + json::array{4,5,2,3}, + json::array{4}, + json::array{4,5,2,3}, + json::array{2}, + json::array{4,5,3}, + json::array{2}, + json::array{4,3}}; + + CHECK(val["data"]["item"][0][0] == json(2)); + CHECK(val["data"]["item"][1][0] == json(4)); + CHECK(val["data"]["item"][2][0] == json(4)); + CHECK(val["data"]["item"][3][0] == json(4)); + CHECK(val["data"]["item"][4][0] == json(2)); + CHECK(val["data"]["item"][5][0] == json(4)); + CHECK(val["data"]["item"][6][0] == json(2)); + CHECK(val["data"]["item"][7][0] == json(4)); + CHECK(val["data"]["item"][7][1] == json(3)); +} + +TEST_CASE("test_assignment_to_initializer_list3") +{ + json val; + val["data"]["id"] = json::array{0,1,2,3,4,5,6,7}; + val["data"]["item"] = json::array{json::object{{"first",1},{"second",2}}}; + + json expected_id = json::parse(R"( +[0,1,2,3,4,5,6,7] + )"); + + json expected_item = json::parse(R"( + [{"first":1,"second":2}] + )"); + + CHECK(expected_id == val["data"]["id"]); + CHECK(expected_item == val["data"]["item"]); +} + +TEST_CASE("test_assign_initializer_list_of_object") +{ + json arr = json::array(); + + json transaction; + transaction["Debit"] = 10000; + + arr = json::array{transaction}; + CHECK(arr.is_array()); + CHECK(arr.size() == 1); + CHECK(arr[0] == transaction); +} + +TEST_CASE("test_initializer_list_of_objects") +{ + json book1; + book1["author"] = "Smith"; + book1["title"] = "Old Bones"; + + json book2; + book2["author"] = "Jones"; + book2["title"] = "New Things"; + + json arr = json::array{book1, book2}; + CHECK(arr.is_array()); + CHECK(arr.size() == 2); + + CHECK(book1 == arr[0]); + CHECK(book2 == arr[1]); +} + +TEST_CASE("test_array_constructor") +{ + json arr = json::array(); + arr.resize(10,10.0); + CHECK(arr.is_array()); + CHECK(arr.size() == 10); + CHECK(arr[0].as() == Approx(10.0).epsilon(0.0000001)); +} + +TEST_CASE("test_make_array") +{ + json arr = json::array(); + CHECK(arr.size() == 0); + arr.resize(10,10.0); + CHECK(arr.is_array()); + CHECK(arr.size() == 10); + CHECK(arr[0].as() == Approx(10.0).epsilon(0.0000001)); + +} + +TEST_CASE("test_add_element_to_array") +{ + json arr = json::array(); + CHECK(arr.is_array()); + CHECK(arr.is()); + arr.push_back("Toronto"); + arr.push_back("Vancouver"); + arr.insert(arr.array_range().begin(),"Montreal"); + + CHECK(arr.size() == 3); + + CHECK(arr[0].as() == std::string("Montreal")); + CHECK(arr[1].as() == std::string("Toronto")); + CHECK(arr[2].as() == std::string("Vancouver")); +} + +TEST_CASE("test_emplace_element_to_array") +{ + json a = json::array(); + CHECK(a.is_array()); + CHECK(a.is()); + a.emplace_back("Toronto"); + a.emplace_back("Vancouver"); + a.emplace(a.array_range().begin(),"Montreal"); + + CHECK(a.size() == 3); + + CHECK(a[0].as() == std::string("Montreal")); + CHECK(a[1].as() == std::string("Toronto")); + CHECK(a[2].as() == std::string("Vancouver")); +} + +TEST_CASE("test_array_add_pos") +{ + json arr = json::array(); + CHECK(arr.is_array()); + CHECK(arr.is()); + arr.push_back("Toronto"); + arr.push_back("Vancouver"); + arr.insert(arr.array_range().begin(),"Montreal"); + + CHECK(arr.size() == 3); + + CHECK(arr[0].as() == std::string("Montreal")); + CHECK(arr[1].as() == std::string("Toronto")); + CHECK(arr[2].as() == std::string("Vancouver")); +} + +TEST_CASE("test_array_erase_range") +{ + json arr = json::array(); + CHECK(arr.is_array()); + CHECK(arr.is()); + arr.push_back("Toronto"); + arr.push_back("Vancouver"); + arr.insert(arr.array_range().begin(),"Montreal"); + + CHECK(arr.size() == 3); + + arr.erase(arr.array_range().begin()+1,arr.array_range().end()); + + CHECK(arr.size() == 1); + CHECK(arr[0].as() == std::string("Montreal")); +} + +TEST_CASE("test_reserve_array_capacity") +{ + json cities = json::array(); + CHECK(cities.is_array()); + CHECK(cities.is()); + cities.reserve(10); // storage is allocated + CHECK(cities.capacity() == 10); + CHECK(cities.size() == 0); + + cities.push_back("Toronto"); + CHECK(cities.is_array()); + CHECK(cities.is()); + CHECK(cities.capacity() == 10); + CHECK(cities.size() == 1); + cities.push_back("Vancouver"); + cities.insert(cities.array_range().begin(),"Montreal"); + CHECK(cities.capacity() == 10); + CHECK(cities.size() == 3); +} + +TEST_CASE("test make_array()") +{ + json j = json::make_array(); + CHECK(j.is_array()); + CHECK(j.size() == 0); + j.emplace_back("Toronto"); + j.emplace_back("Vancouver"); + j.emplace(j.array_range().begin(),"Montreal"); + CHECK(j[0].as() == std::string("Montreal")); + CHECK(j[1].as() == std::string("Toronto")); + CHECK(j[2].as() == std::string("Vancouver")); +} + +TEST_CASE("test_one_dim_array") +{ + basic_json> a = basic_json>::make_array<1>(10,0); + CHECK(a.size() == 10); + CHECK(a[0].as() == 0); + a[1] = 1; + a[2] = 2; + CHECK(a[1].as() == 1); + CHECK(a[2].as() == 2); + CHECK(a[9].as() == 0); + + CHECK(a[1].as() == 1); + CHECK(a[2].as() == 2); + CHECK(a[9].as() == 0); +} + +TEST_CASE("test_two_dim_array") +{ + json a = json::make_array<2>(3,4,0); + CHECK(a.size() == 3); + a[0][0] = "Tenor"; + a[0][1] = "ATM vol"; + a[0][2] = "25-d-MS"; + a[0][3] = "25-d-RR"; + a[1][0] = "1Y"; + a[1][1] = 0.20; + a[1][2] = 0.009; + a[1][3] = -0.006; + a[2][0] = "2Y"; + a[2][1] = 0.18; + a[2][2] = 0.009; + a[2][3] = -0.005; + + CHECK(a[0][0].as() ==std::string("Tenor")); + CHECK(a[2][3].as() == Approx(-0.005).epsilon(0.00000001)); + + CHECK(a[0][0].as() ==std::string("Tenor")); + CHECK(a[2][3].as() == Approx(-0.005).epsilon(0.00000001)); +} + +TEST_CASE("test_three_dim_array") +{ + json a = json::make_array<3>(4,3,2,0); + CHECK(a.size() == 4); + a[0][2][0] = 2; + a[0][2][1] = 3; + + CHECK(a[0][2][0].as() == 2); + CHECK(a[0][2][1].as() == 3); + CHECK(a[3][2][1].as() == 0); + + CHECK(a[0][2][0].as() == 2); + CHECK(a[0][2][1].as() == 3); + CHECK(a[3][2][1].as() == 0); +} + +TEST_CASE("test_array_assign_vector") +{ + std::vector vec; + vec.push_back("Toronto"); + vec.push_back("Vancouver"); + vec.push_back("Montreal"); + + json val; + val = vec; + + CHECK(val.size() == 3); + CHECK(val[0].as() ==std::string("Toronto")); + CHECK(val[1].as() ==std::string("Vancouver")); + CHECK(val[2].as() ==std::string("Montreal")); + +} + +TEST_CASE("test_array_assign_vector_of_bool") +{ + std::vector vec; + vec.push_back(true); + vec.push_back(false); + vec.push_back(true); + + json val; + val = vec; + + CHECK(val.size() == 3); + CHECK(val[0].as() == true); + CHECK(val[1].as() == false); + CHECK(val[2].as() == true); + +} + +TEST_CASE("test_array_add_null") +{ + json a = json::array(); + a.push_back(jsoncons::null_type()); + a.push_back(json::null()); + CHECK(a[0].is_null()); + CHECK(a[1].is_null()); +} + +TEST_CASE("test_array_from_container") +{ + std::vector vec; + vec.push_back(10); + vec.push_back(20); + vec.push_back(30); + + json val1 = vec; + REQUIRE(vec.size() == 3); + CHECK(vec[0] == 10); + CHECK(vec[1] == 20); + CHECK(vec[2] == 30); + + std::list list; + list.push_back(10.5); + list.push_back(20.5); + list.push_back(30.5); + + json val2 = list; + REQUIRE(val2.size() == 3); + CHECK(val2[0].as() == Approx(10.5).epsilon(0.000001)); + CHECK(val2[1].as() == Approx(20.5).epsilon(0.000001)); + CHECK(val2[2].as() == Approx(30.5).epsilon(0.000001)); +} + +TEST_CASE("test_array_as_vector_of_double") +{ + std::string s("[0,1.1,2,3.1]"); + json val = json::parse(s); + + std::vector v = val.as>(); + CHECK(v.size() == 4); + CHECK(v[0] == Approx(0.0).epsilon(0.0000000001)); + CHECK(v[1] == Approx(1.1).epsilon(0.0000000001)); + CHECK(v[2] == Approx(2.0).epsilon(0.0000000001)); + CHECK(v[3] == Approx(3.1).epsilon(0.0000000001)); +} + +TEST_CASE("test_array_as_vector_of_bool") +{ + std::string s("[true,false,true]"); + json val = json::parse(s); + + std::vector v = val.as>(); + CHECK(v.size() == 3); + CHECK(v[0] == true); + CHECK(v[1] == false); + CHECK(v[2] == true); +} + +TEST_CASE("test_array_as_vector_of_string") +{ + std::string s("[\"Hello\",\"World\"]"); + json val = json::parse(s); + + std::vector v = val.as>(); + CHECK(v.size() == 2); + CHECK(v[0] == "Hello"); + CHECK(v[1] == "World"); +} + +TEST_CASE("test_array_as_vector_of_char") +{ + std::string s("[20,30]"); + json val = json::parse(s); + + std::vector v = val.as>(); + CHECK(v.size() == 2); + CHECK(v[0] == 20); + CHECK(v[1] == 30); +} + +TEST_CASE("test_array_as_vector_of_int") +{ + std::string s("[0,1,2,3]"); + json val = json::parse(s); + + std::vector v = val.as>(); + CHECK(v.size() == 4); + CHECK(v[0]==0); + CHECK(v[1]==1); + CHECK(v[2]==2); + CHECK(v[3]==3); + + std::vector v1 = val.as>(); + CHECK(v1.size() == 4); + CHECK(v1[0]==0); + CHECK(v1[1]==1); + CHECK(v1[2]==2); + CHECK(v1[3]==3); + + std::vector v2 = val.as>(); + CHECK(v2.size() == 4); + CHECK(v2[0]==0); + CHECK(v2[1]==1); + CHECK(v2[2]==2); + CHECK(v2[3]==3); + + std::vector v3 = val.as>(); + CHECK(v3.size() == 4); + CHECK(v3[0]==0); + CHECK(v3[1]==1); + CHECK(v3[2]==2); + CHECK(v3[3]==3); + + std::vector v4 = val.as>(); + CHECK(v4.size() == 4); + CHECK(v4[0]==0); + CHECK(v4[1]==1); + CHECK(v4[2]==2); + CHECK(v4[3]==3); + + std::vector v5 = val.as>(); + CHECK(v5.size() == 4); + CHECK(v5[0]==0); + CHECK(v5[1]==1); + CHECK(v5[2]==2); + CHECK(v5[3]==3); +} + +TEST_CASE("test_array_as_vector_of_int_on_proxy") +{ + std::string s("[0,1,2,3]"); + json val = json::parse(s); + json root; + root["val"] = val; + std::vector v = root["val"].as>(); + CHECK(v.size() == 4); + CHECK(v[0]==0); + CHECK(v[1]==1); + CHECK(v[2]==2); + CHECK(v[3]==3); +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_as_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_as_tests.cpp new file mode 100644 index 0000000000..9559887ee4 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_as_tests.cpp @@ -0,0 +1,75 @@ +// Copyright 2018 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include +#include + +TEST_CASE("json::as()") +{ + std::string s1("Short"); + jsoncons::json j1(s1); + CHECK(j1.as() == jsoncons::string_view(s1)); + + std::string s2("String to long for short string"); + jsoncons::json j2(s2); + CHECK(j2.as() == jsoncons::string_view(s2)); +} + +TEST_CASE("json::as()") +{ + SECTION("from integer") + { + jsoncons::json j(-1000); + CHECK(bool(j.as() == jsoncons::bignum(-1000))); + } + SECTION("from unsigned integer") + { + jsoncons::json j(1000u); + CHECK(bool(j.as() == jsoncons::bignum(1000u))); + } + SECTION("from double") + { + jsoncons::json j(1000.0); + CHECK(bool(j.as() == jsoncons::bignum(1000.0))); + } + SECTION("from bignum") + { + std::string s = "-18446744073709551617"; + jsoncons::json j(s, jsoncons::semantic_tag::bigint); + CHECK(bool(j.as() == jsoncons::bignum(s))); + } +} + +#if (defined(__GNUC__) || defined(__clang__)) && (!defined(__STRICT_ANSI__) && defined(_GLIBCXX_USE_INT128)) +TEST_CASE("json::as<__int128>()") +{ + std::string s = "-18446744073709551617"; + + jsoncons::detail::to_integer_result<__int128> result = jsoncons::detail::to_integer<__int128>(s.data(),s.size()); + REQUIRE(result.ec == jsoncons::detail::to_integer_errc()); + + jsoncons::json j(s); + + __int128 val = j.as<__int128>(); + CHECK(result.value == val); +} + +TEST_CASE("json::as()") +{ + std::string s = "18446744073709551616"; + + jsoncons::detail::to_integer_result result = jsoncons::detail::to_integer(s.data(),s.size()); + REQUIRE(result.ec == jsoncons::detail::to_integer_errc()); + + jsoncons::json j(s); + + unsigned __int128 val = j.as(); + CHECK(result.value == val); +} +#endif diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_checker_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_checker_tests.cpp new file mode 100644 index 0000000000..00bb54e00c --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_checker_tests.cpp @@ -0,0 +1,716 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +TEST_CASE("test_fail1") +{ + std::string path = "./input/JSON_checker/fail1.json"; + std::fstream is(path); + REQUIRE(is); + CHECK_NOTHROW(json::parse(is)); +} + +TEST_CASE("test_fail2") +{ + std::string in_file = "./input/JSON_checker/fail2.json"; + std::ifstream is(in_file); + REQUIRE(is); + + std::error_code err; + + try + { + json::parse(is); + } + catch (const ser_error& e) + { + err = e.code(); + } + CHECK(err == jsoncons::json_errc::unexpected_eof); +} + +TEST_CASE("test_fail3") +{ + std::string in_file = "./input/JSON_checker/fail3.json"; + std::ifstream is(in_file); + REQUIRE(is); + + std::error_code err; + + try + { + json::parse(is); + } + catch (const ser_error& e) + { + err = e.code(); + } + CHECK(err == jsoncons::json_errc::expected_name); +} + +TEST_CASE("test_fail4") +{ + std::string in_file = "./input/JSON_checker/fail4.json"; + std::ifstream is(in_file); + REQUIRE(is); + + std::error_code err; + + try + { + json::parse(is); + } + catch (const ser_error& e) + { + err = e.code(); + } + CHECK(err == jsoncons::json_errc::extra_comma); +} + +TEST_CASE("test_fail5") +{ + std::string in_file = "./input/JSON_checker/fail5.json"; + std::ifstream is(in_file); + REQUIRE(is); + + std::error_code err; + + try + { + json::parse(is); + } + catch (const ser_error& e) + { + err = e.code(); + } + CHECK(err == jsoncons::json_errc::expected_value); +} + +TEST_CASE("test_fail6") +{ + std::string in_file = "./input/JSON_checker/fail6.json"; + std::ifstream is(in_file); + REQUIRE(is); + + std::error_code err; + + try + { + json::parse(is); + } + catch (const ser_error& e) + { + err = e.code(); + //std::cout << in_file << " " << e.what() << std::endl; + } + CHECK(err == jsoncons::json_errc::expected_value); +} + +TEST_CASE("test_fail7") +{ + std::string in_file = "./input/JSON_checker/fail7.json"; + std::ifstream is(in_file); + REQUIRE(is); + + std::error_code err; + + try + { + json::parse(is); + } + catch (const ser_error& e) + { + err = e.code(); + } + CHECK(err == jsoncons::json_errc::extra_character); +} + +TEST_CASE("test_fail8") +{ + std::string in_file = "./input/JSON_checker/fail8.json"; + std::ifstream is(in_file); + REQUIRE(is); + + std::error_code err; + + try + { + json::parse(is); + } + catch (const ser_error& e) + { + err = e.code(); + //std::cout << in_file << " " << e.what() << std::endl; + } + CHECK(err == jsoncons::json_errc::extra_character); +} + +TEST_CASE("test_fail9") +{ + std::string in_file = "./input/JSON_checker/fail9.json"; + std::ifstream is(in_file); + REQUIRE(is); + + std::error_code err; + + try + { + json::parse(is); + } + catch (const ser_error& e) + { + err = e.code(); + //std::cout << in_file << " " << e.what() << std::endl; + } + CHECK(err == jsoncons::json_errc::extra_comma); +} + +TEST_CASE("test_fail10") +{ + std::string in_file = "./input/JSON_checker/fail10.json"; + std::ifstream is(in_file); + REQUIRE(is); + + std::error_code err; + + try + { + json::parse(is); + } + catch (const ser_error& e) + { + err = e.code(); + } + CHECK(err == jsoncons::json_errc::extra_character); +} + +TEST_CASE("test_fail11") +{ + std::string in_file = "./input/JSON_checker/fail11.json"; + std::ifstream is(in_file); + REQUIRE(is); + + std::error_code err; + + try + { + json::parse(is); + } + catch (const ser_error& e) + { + err = e.code(); + //std::cout << in_file << " " << e.what() << std::endl; + } + CHECK(err == jsoncons::json_errc::expected_comma_or_right_brace); +} + +TEST_CASE("test_fail12") +{ + std::string in_file = "./input/JSON_checker/fail12.json"; + std::ifstream is(in_file); + REQUIRE(is); + + std::error_code err; + + try + { + json::parse(is); + } + catch (const ser_error& e) + { + err = e.code(); + //std::cout << in_file << " " << e.what() << std::endl; + } + CHECK(err == jsoncons::json_errc::expected_value); +} + +TEST_CASE("test_fail13") +{ + std::string in_file = "./input/JSON_checker/fail13.json"; + std::ifstream is(in_file); + REQUIRE(is); + + std::error_code err; + + try + { + json::parse(is); + } + catch (const ser_error& e) + { + err = e.code(); + //std::cout << in_file << " " << e.what() << std::endl; + } + CHECK(err == jsoncons::json_errc::leading_zero); +} + +TEST_CASE("test_fail14") +{ + std::string in_file = "./input/JSON_checker/fail14.json"; + std::ifstream is(in_file); + REQUIRE(is); + + std::error_code err; + + try + { + json::parse(is); + } + catch (const ser_error& e) + { + err = e.code(); + //std::cout << in_file << " " << e.what() << std::endl; + } + CHECK(err == jsoncons::json_errc::invalid_number); +} + +TEST_CASE("test_fail15") +{ + std::string in_file = "./input/JSON_checker/fail15.json"; + std::ifstream is(in_file); + REQUIRE(is); + + std::error_code err; + + try + { + json::parse(is); + } + catch (const ser_error& e) + { + err = e.code(); + //std::cout << in_file << " " << e.what() << std::endl; + } + CHECK(err == jsoncons::json_errc::illegal_escaped_character); +} + +TEST_CASE("test_fail16") +{ + std::string in_file = "./input/JSON_checker/fail16.json"; + std::ifstream is(in_file); + REQUIRE(is); + + std::error_code err; + + try + { + json::parse(is); + } + catch (const ser_error& e) + { + err = e.code(); + //std::cout << in_file << " " << e.what() << std::endl; + } + CHECK(err == jsoncons::json_errc::expected_value); +} + +TEST_CASE("test_fail17") +{ + std::string in_file = "./input/JSON_checker/fail17.json"; + std::ifstream is(in_file); + REQUIRE(is); + + std::error_code err; + + try + { + json::parse(is); + } + catch (const ser_error& e) + { + err = e.code(); + //std::cout << in_file << " " << e.what() << std::endl; + } + CHECK(err == jsoncons::json_errc::illegal_escaped_character); +} + +TEST_CASE("test_fail18") +{ + std::error_code err; + + std::string in_file = "./input/JSON_checker/fail18.json"; + std::ifstream is(in_file); + REQUIRE(is); + try + { + json_options options; + options.max_nesting_depth(19); + json::parse(is, options); + } + catch (const ser_error& e) + { + err = e.code(); + //std::cout << in_file << " " << e.what() << std::endl; + } + CHECK(err == jsoncons::json_errc::max_depth_exceeded); +} + +TEST_CASE("test_fail19") +{ + std::string in_file = "./input/JSON_checker/fail19.json"; + std::ifstream is(in_file); + REQUIRE(is); + + std::error_code err; + + try + { + json::parse(is); + } + catch (const ser_error& e) + { + err = e.code(); + //std::cout << in_file << " " << e.what() << std::endl; + } + CHECK(err == jsoncons::json_errc::expected_colon); +} + +TEST_CASE("test_fail20") +{ + std::string in_file = "./input/JSON_checker/fail20.json"; + std::ifstream is(in_file); + REQUIRE(is); + + std::error_code err; + + try + { + json::parse(is); + } + catch (const ser_error& e) + { + err = e.code(); + //std::cout << in_file << " " << e.what() << std::endl; + } + CHECK(err == jsoncons::json_errc::expected_value); +} + +TEST_CASE("test_fail21") +{ + std::string in_file = "./input/JSON_checker/fail21.json"; + std::ifstream is(in_file); + REQUIRE(is); + + std::error_code err; + + try + { + json::parse(is); + } + catch (const ser_error& e) + { + err = e.code(); + //std::cout << in_file << " " << e.what() << std::endl; + } + CHECK(err == jsoncons::json_errc::expected_colon); +} + +TEST_CASE("test_fail22") +{ + std::string in_file = "./input/JSON_checker/fail22.json"; + std::ifstream is(in_file); + REQUIRE(is); + + std::error_code err; + + try + { + json::parse(is); + } + catch (const ser_error& e) + { + err = e.code(); + //std::cout << in_file << " " << e.what() << std::endl; + } + CHECK(err == jsoncons::json_errc::expected_comma_or_right_bracket); +} + +TEST_CASE("test_fail23") +{ + std::string in_file = "./input/JSON_checker/fail23.json"; + std::ifstream is(in_file); + REQUIRE(is); + + std::error_code err; + + try + { + json::parse(is); + } + catch (const ser_error& e) + { + err = e.code(); + //std::cout << in_file << " " << e.what() << std::endl; + } + CHECK(err == jsoncons::json_errc::invalid_value); +} + +TEST_CASE("test_fail24") +{ + std::string in_file = "./input/JSON_checker/fail24.json"; + std::ifstream is(in_file); + REQUIRE(is); + + std::error_code err; + + try + { + json::parse(is); + } + catch (const ser_error& e) + { + err = e.code(); + //std::cout << in_file << " " << e.what() << std::endl; + } + // Single quote + CHECK(err == jsoncons::json_errc::single_quote); +} + +TEST_CASE("test_fail25") +{ + std::string in_file = "./input/JSON_checker/fail25.json"; + std::ifstream is(in_file); + REQUIRE(is); + + std::error_code err; + + try + { + json::parse(is); + } + catch (const ser_error& e) + { + err = e.code(); + //std::cout << in_file << " " << e.what() << std::endl; + } + CHECK(err == jsoncons::json_errc::illegal_character_in_string); +} + +TEST_CASE("test_fail26") +{ + std::string in_file = "./input/JSON_checker/fail26.json"; + std::ifstream is(in_file); + REQUIRE(is); + + std::error_code err; + + try + { + json::parse(is); + } + catch (const ser_error& e) + { + err = e.code(); + //std::cout << in_file << " " << e.what() << std::endl; + } + CHECK(err == jsoncons::json_errc::illegal_escaped_character); +} + +TEST_CASE("test_fail27") +{ + std::string in_file = "./input/JSON_checker/fail27.json"; + std::ifstream is(in_file); + REQUIRE(is); + + std::error_code err; + + try + { + json::parse(is); + } + catch (const ser_error& e) + { + err = e.code(); + //std::cout << in_file << " " << e.what() << std::endl; + } + CHECK(err == jsoncons::json_errc::illegal_character_in_string); +} + +TEST_CASE("test_fail28") +{ + std::string in_file = "./input/JSON_checker/fail28.json"; + std::ifstream is(in_file); + REQUIRE(is); + + std::error_code err; + + try + { + json::parse(is); + } + catch (const ser_error& e) + { + err = e.code(); + //std::cout << in_file << " " << e.what() << std::endl; + } + CHECK(err == jsoncons::json_errc::illegal_escaped_character); +} + +TEST_CASE("test_fail29") +{ + std::string in_file = "./input/JSON_checker/fail29.json"; + std::ifstream is(in_file); + REQUIRE(is); + + std::error_code err; + + try + { + json::parse(is); + } + catch (const ser_error& e) + { + err = e.code(); + //std::cout << in_file << " " << e.what() << std::endl; + } + CHECK(err == jsoncons::json_errc::expected_value); +} + +TEST_CASE("test_fail30") +{ + std::string in_file = "./input/JSON_checker/fail30.json"; + std::ifstream is(in_file); + REQUIRE(is); + + std::error_code err; + + try + { + json::parse(is); + } + catch (const ser_error& e) + { + err = e.code(); + //std::cout << in_file << " " << e.what() << std::endl; + } + CHECK(err == jsoncons::json_errc::expected_value); +} + +TEST_CASE("test_fail31") +{ + std::string in_file = "./input/JSON_checker/fail31.json"; + std::ifstream is(in_file); + REQUIRE(is); + + std::error_code err; + + try + { + json::parse(is); + } + catch (const ser_error& e) + { + err = e.code(); + //std::cout << in_file << " " << e.what() << std::endl; + } + CHECK(err == jsoncons::json_errc::expected_value); +} + +TEST_CASE("test_fail32") +{ + std::string in_file = "./input/JSON_checker/fail32.json"; + std::ifstream is(in_file); + REQUIRE(is); + + std::error_code err; + + try + { + json::parse(is); + } + catch (const ser_error& e) + { + err = e.code(); + //std::cout << in_file << " " << e.what() << std::endl; + } + CHECK(err == jsoncons::json_errc::unexpected_eof); +} + +TEST_CASE("test_fail33") +{ + std::string in_file = "./input/JSON_checker/fail33.json"; + std::ifstream is(in_file); + REQUIRE(is); + + std::error_code err; + + try + { + json::parse(is); + } + catch (const ser_error& e) + { + err = e.code(); + //std::cout << in_file << " " << e.what() << std::endl; + } + CHECK(err == jsoncons::json_errc::expected_comma_or_right_bracket); +} + +TEST_CASE("test_pass1") +{ + std::string in_file = "./input/JSON_checker/pass1.json"; + std::ifstream is(in_file); + REQUIRE(is); + + std::error_code err; + + try + { + json::parse(is); + } + catch (const ser_error& e) + { + std::cout << in_file << " " << e.what() << std::endl; + throw; + } +} + +TEST_CASE("test_pass2") +{ + std::string in_file = "./input/JSON_checker/pass2.json"; + std::ifstream is(in_file); + REQUIRE(is); + + std::error_code err; + + try + { + json::parse(is); + } + catch (const ser_error& e) + { + std::cout << in_file << " " << e.what() << std::endl; + throw; + } +} + +TEST_CASE("test_pass3") +{ + std::string in_file = "./input/JSON_checker/pass3.json"; + std::ifstream is(in_file); + REQUIRE(is); + + std::error_code err; + + try + { + json::parse(is); + } + catch (const ser_error& e) + { + std::cout << in_file << " " << e.what() << std::endl; + throw; + } +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_cursor_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_cursor_tests.cpp new file mode 100644 index 0000000000..0675b039f5 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_cursor_tests.cpp @@ -0,0 +1,336 @@ +// Copyright 2018 Daniel Parker +// Distributed under Boost license + +#if defined(_MSC_VER) +#include "windows.h" // test no inadvertant macro expansions +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +TEST_CASE("json_cursor string_value test") +{ + std::string s = R"("Tom")"; + std::istringstream is(s); + + json_cursor reader(is); + + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::string_value); + CHECK(reader.current().as() == std::string("Tom")); + CHECK((reader.current().as() == jsoncons::string_view("Tom"))); + reader.next(); + CHECK(reader.done()); +} + +TEST_CASE("json_cursor string_value as test") +{ + std::string s = R"("-100")"; + std::istringstream is(s); + + json_cursor reader(is); + + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::string_value); + CHECK(reader.current().as() == -100); + reader.next(); + CHECK(reader.done()); +} + +TEST_CASE("json_cursor string_value as test") +{ + std::string s = R"("100")"; + std::istringstream is(s); + + json_cursor reader(is); + + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::string_value); + CHECK(reader.current().as() == 100); + CHECK(reader.current().as() == 100); + reader.next(); + CHECK(reader.done()); +} + +TEST_CASE("json_cursor null_value test") +{ + std::string s = "null"; + std::istringstream is(s); + + json_cursor reader(is); + + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::null_value); + reader.next(); + CHECK(reader.done()); +} + +TEST_CASE("json_cursor bool_value test") +{ + std::string s = "false"; + std::istringstream is(s); + + json_cursor reader(is); + + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::bool_value); + reader.next(); + CHECK(reader.done()); +} + +TEST_CASE("json_cursor int64_value test") +{ + std::string s = "-100"; + std::istringstream is(s); + + json_cursor reader(is); + + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::int64_value); + CHECK(reader.current().as() == -100); + reader.next(); + CHECK(reader.done()); +} + +TEST_CASE("json_cursor uint64_value test") +{ + std::string s = "100"; + std::istringstream is(s); + + json_cursor reader(is); + + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::uint64_value); + CHECK(reader.current().as() == 100); + CHECK(reader.current().as() == 100); + reader.next(); + CHECK(reader.done()); +} + +TEST_CASE("json_cursor string_value as bignum test") +{ + std::string s = "-18446744073709551617"; + std::istringstream is("\""+s+"\""); + + json_cursor reader(is); + + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::string_value); + CHECK(s == reader.current().as()); + bignum c = reader.current().as(); + CHECK(bool(bignum("-18446744073709551617") == c)); + reader.next(); + CHECK(reader.done()); +} + +TEST_CASE("json_cursor bigint value as bignum") +{ + std::string s = "-18446744073709551617"; + std::istringstream is(s); + + json_cursor reader(is); + + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::string_value); + CHECK(reader.current().get_semantic_tag() == semantic_tag::bigint); + bignum c = reader.current().as(); + CHECK(bool(bignum(s) == c)); + reader.next(); + CHECK(reader.done()); +} + +TEST_CASE("json_cursor double_value test") +{ + std::string s = "100.0"; + std::istringstream is(s); + + json_cursor reader(is); + + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::double_value); + reader.next(); + CHECK(reader.done()); +} + +TEST_CASE("json_cursor array_value test") +{ + std::string s = R"( + [ + { + "enrollmentNo" : 100, + "firstName" : "Tom", + "lastName" : "Cochrane", + "mark" : 55 + }, + { + "enrollmentNo" : 101, + "firstName" : "Catherine", + "lastName" : "Smith", + "mark" : 95}, + { + "enrollmentNo" : 102, + "firstName" : "William", + "lastName" : "Skeleton", + "mark" : 60 + } + ] + )"; + + std::istringstream is(s); + + json_cursor reader(is); + + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::begin_array); + reader.next(); + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::begin_object); + reader.next(); + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::name); + reader.next(); + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::uint64_value); + reader.next(); + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::name); + reader.next(); + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::string_value); + reader.next(); + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::name); + reader.next(); + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::string_value); + reader.next(); + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::name); + reader.next(); + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::uint64_value); + reader.next(); + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::end_object); + reader.next(); + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::begin_object); + reader.next(); + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::name); + reader.next(); + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::uint64_value); + reader.next(); + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::name); + reader.next(); + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::string_value); + reader.next(); + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::name); + reader.next(); + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::string_value); + reader.next(); + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::name); + reader.next(); + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::uint64_value); + reader.next(); + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::end_object); + reader.next(); + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::begin_object); + reader.next(); + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::name); + reader.next(); + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::uint64_value); + reader.next(); + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::name); + reader.next(); + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::string_value); + reader.next(); + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::name); + reader.next(); + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::string_value); + reader.next(); + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::name); + reader.next(); + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::uint64_value); + reader.next(); + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::end_object); + reader.next(); + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::end_array); + reader.next(); + CHECK(reader.done()); +} + +TEST_CASE("json_cursor object_value test") +{ + std::string s = R"( + { + "enrollmentNo" : 100, + "firstName" : "Tom", + "lastName" : "Cochrane", + "mark" : 55 + } + )"; + + json_cursor reader(s); + + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::begin_object); + reader.next(); + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::name); + reader.next(); + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::uint64_value); + reader.next(); + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::name); + reader.next(); + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::string_value); + reader.next(); + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::name); + reader.next(); + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::string_value); + reader.next(); + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::name); + reader.next(); + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::uint64_value); + reader.next(); + REQUIRE_FALSE(reader.done()); + CHECK(reader.current().event_type() == staj_event_type::end_object); + reader.next(); + CHECK(reader.done()); +} + + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_encode_and_decode_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_encode_and_decode_tests.cpp new file mode 100644 index 0000000000..559f75e844 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_encode_and_decode_tests.cpp @@ -0,0 +1,327 @@ +// Copyright 2017 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +TEST_CASE("encode and decode json") +{ + json j(std::make_pair(false,std::string("foo"))); + + SECTION("string test") + { + std::string s; + encode_json(j, s); + json result = decode_json(s); + CHECK(result == j); + } + + SECTION("stream test") + { + std::stringstream ss; + encode_json(j, ss); + json result = decode_json(ss); + CHECK(result == j); + } +} + +TEST_CASE("encode and decode wjson") +{ + wjson j(std::make_pair(false,std::wstring(L"foo"))); + + SECTION("string test") + { + std::wstring s; + encode_json(j, s); + wjson result = decode_json(s); + CHECK(result == j); + } + + SECTION("stream test") + { + std::wstringstream ss; + encode_json(j, ss); + wjson result = decode_json(ss); + CHECK(result == j); + } +} + +TEST_CASE("convert_pair_test") +{ + auto val = std::make_pair(false,std::string("foo")); + std::string s; + + jsoncons::encode_json(val, s); + + auto result = jsoncons::decode_json>(s); + + CHECK(val == result); +} + +TEST_CASE("convert_vector_test") +{ + std::vector v = {1,2,3,4,5,6}; + + std::string s; + jsoncons::encode_json(v,s); + + auto result = jsoncons::decode_json>(s); + + REQUIRE(v.size() == result.size()); + for (size_t i = 0; i < result.size(); ++i) + { + CHECK(v[i] == result[i]); + } +} + +TEST_CASE("convert_map_test") +{ + std::map m = {{"a",1},{"b",2}}; + + std::string s; + jsoncons::encode_json(m,s); + auto result = jsoncons::decode_json>(s); + + REQUIRE(result.size() == m.size()); + CHECK(m["a"] == result["a"]); + CHECK(m["b"] == result["b"]); +} + +TEST_CASE("convert_array_test") +{ + std::array v{1,2,3,4}; + + std::string s; + jsoncons::encode_json(v,s); + std::array result = jsoncons::decode_json>(s); + REQUIRE(result.size() == v.size()); + for (size_t i = 0; i < result.size(); ++i) + { + CHECK(v[i] == result[i]); + } +} + +#if !(defined(__GNUC__) && __GNUC__ <= 5) +TEST_CASE("convert_tuple_test") +{ + typedef std::map> employee_collection; + + employee_collection employees = + { + {"John Smith",{"Hourly","Software Engineer",10000}}, + {"Jane Doe",{"Commission","Sales",20000}} + }; + + std::string s; + jsoncons::encode_json(employees, s, jsoncons::indenting::indent); + std::cout << "(1)\n" << s << std::endl; + auto employees2 = jsoncons::decode_json(s); + REQUIRE(employees2.size() == employees.size()); + + std::cout << "\n(2)\n"; + for (const auto& pair : employees2) + { + std::cout << pair.first << ": " << std::get<1>(pair.second) << std::endl; + } +} +#endif + +namespace ns { + +struct book +{ + std::string author; + std::string title; + double price; + + friend std::ostream& operator<<(std::ostream& os, const book& b) + { + std::cout << "author: " << b.author << ", title: " << b.title << ", price: " << b.price << "\n"; + return os; + } +}; + +} // namespace ns + +JSONCONS_MEMBER_TRAITS_DECL(ns::book,author,title,price) + +TEST_CASE("book_conversion_test") +{ + ns::book book_list{"Haruki Murakami", "Kafka on the Shore", 25.17}; + + std::string s; + encode_json(book_list, s, indenting::indent); + + std::cout << "s: " << s << "\n"; + +} + +namespace ns { + + struct reputon + { + std::string rater; + std::string assertion; + std::string rated; + double rating; + + friend bool operator==(const reputon& lhs, const reputon& rhs) + { + return lhs.rater == rhs.rater && lhs.assertion == rhs.assertion && + lhs.rated == rhs.rated && lhs.rating == rhs.rating; + } + + friend bool operator!=(const reputon& lhs, const reputon& rhs) + { + return !(lhs == rhs); + }; + }; + + class reputation_object + { + std::string application; + std::vector reputons; + + // Make json_type_traits specializations friends to give accesses to private members + JSONCONS_TYPE_TRAITS_FRIEND; + public: + reputation_object() + { + } + reputation_object(const std::string& application, const std::vector& reputons) + : application(application), reputons(reputons) + {} + + friend bool operator==(const reputation_object& lhs, const reputation_object& rhs) + { + return (lhs.application == rhs.application) && (lhs.reputons == rhs.reputons); + } + + friend bool operator!=(const reputation_object& lhs, const reputation_object& rhs) + { + return !(lhs == rhs); + }; + }; + +} // namespace ns + +// Declare the traits. Specify which data members need to be serialized. +JSONCONS_MEMBER_TRAITS_DECL(ns::reputon, rater, assertion, rated, rating) +JSONCONS_MEMBER_TRAITS_DECL(ns::reputation_object, application, reputons) + +TEST_CASE("reputation_object") +{ + ns::reputation_object val("hiking", { ns::reputon{"HikingAsylum.example.com","strong-hiker","Marilyn C",0.90} }); + + SECTION("1") + { + std::string s; + encode_json(val, s); + auto val2 = decode_json(s); + CHECK(val2 == val); + } + + SECTION("2") + { + std::string s; + encode_json(val, s, indenting::indent); + auto val2 = decode_json(s); + CHECK(val2 == val); + } + + SECTION("3") + { + std::string s; + json_options options; + encode_json(val, s, options, indenting::indent); + auto val2 = decode_json(s, options); + CHECK(val2 == val); + } + + SECTION("4") + { + std::string s; + encode_json(ojson(), val, s); + auto val2 = decode_json(ojson(), s); + CHECK(val2 == val); + } + + SECTION("5") + { + std::string s; + encode_json(ojson(), val, s, indenting::indent); + auto val2 = decode_json(ojson(), s); + CHECK(val2 == val); + } + + SECTION("6") + { + std::string s; + json_options options; + encode_json(ojson(), val, s, options, indenting::indent); + auto val2 = decode_json(ojson(), s, options); + CHECK(val2 == val); + } + + SECTION("os 1") + { + std::stringstream os; + encode_json(val, os); + auto val2 = decode_json(os); + CHECK(val2 == val); + } + + SECTION("os 2") + { + std::stringstream os; + encode_json(val, os, indenting::indent); + auto val2 = decode_json(os); + CHECK(val2 == val); + } + + SECTION("os 3") + { + std::stringstream os; + json_options options; + encode_json(val, os, options, indenting::indent); + auto val2 = decode_json(os, options); + CHECK(val2 == val); + } + + SECTION("os 4") + { + std::stringstream os; + encode_json(ojson(), val, os); + auto val2 = decode_json(ojson(), os); + CHECK(val2 == val); + } + + SECTION("os 5") + { + std::stringstream os; + encode_json(ojson(), val, os, indenting::indent); + auto val2 = decode_json(ojson(), os); + CHECK(val2 == val); + } + + SECTION("os 6") + { + std::stringstream os; + json_options options; + encode_json(ojson(), val, os, options, indenting::indent); + auto val2 = decode_json(ojson(), os, options); + CHECK(val2 == val); + } + +} + + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_encoder_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_encoder_tests.cpp new file mode 100644 index 0000000000..99ea9ced5e --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_encoder_tests.cpp @@ -0,0 +1,31 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +TEST_CASE("test_byte_string_serialization") +{ + const uint8_t bs[] = {'H','e','l','l','o'}; + json j(byte_string_view(bs,sizeof(bs))); + + std::ostringstream os; + os << j; + + std::string expected; + expected.push_back('\"'); + encode_base64url(bs,bs+sizeof(bs),expected); + expected.push_back('\"'); + + //std::cout << expected << " " << os.str() << std::endl; + + CHECK(os.str() == expected); +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_equal_to_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_equal_to_tests.cpp new file mode 100644 index 0000000000..d8a45a26e4 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_equal_to_tests.cpp @@ -0,0 +1,159 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +TEST_CASE("test_object_equals_basic") +{ + json o1; + o1["a"] = 1; + o1["b"] = 2; + o1["c"] = 3; + + json o2; + o2["c"] = 3; + o2["a"] = 1; + o2["b"] = 2; + + CHECK(o1 == o2); + CHECK(o2 == o1); + CHECK_FALSE((o1 != o2)); + CHECK_FALSE((o2 != o1)); +} + +TEST_CASE("test_object_equals_diff_vals") +{ + json o1; + o1["a"] = 1; + o1["b"] = 2; + o1["c"] = 3; + + json o2; + o2["a"] = 1; + o2["b"] = 4; + o2["c"] = 3; + + CHECK_FALSE((o1 == o2)); + CHECK_FALSE((o2 == o1)); + CHECK(o1 != o2); + CHECK(o2 != o1); +} + +TEST_CASE("test_object_equals_diff_el_names") +{ + json o1; + o1["a"] = 1; + o1["b"] = 2; + o1["c"] = 3; + + json o2; + o2["d"] = 1; + o2["e"] = 2; + o2["f"] = 3; + + CHECK_FALSE((o1 == o2)); + CHECK_FALSE((o2 == o1)); + CHECK(o1 != o2); + CHECK(o2 != o1); +} + +TEST_CASE("test_object_equals_diff_sizes") +{ + json o1; + o1["a"] = 1; + o1["b"] = 2; + o1["c"] = 3; + + json o2; + o2["a"] = 1; + o2["b"] = 2; + + CHECK_FALSE((o1 == o2)); + CHECK_FALSE((o2 == o1)); + CHECK(o1 != o2); + CHECK(o2 != o1); +} + +TEST_CASE("test_object_equals_subtle_offsets") +{ + json o1; + o1["a"] = 1; + o1["b"] = 1; + + json o2; + o2["b"] = 1; + o2["c"] = 1; + + CHECK_FALSE((o1 == o2)); + CHECK_FALSE((o2 == o1)); + CHECK(o1 != o2); + CHECK(o2 != o1); +} + +TEST_CASE("test_object_equals_empty_objects") +{ + json def_constructed_1; + json def_constructed_2; + json parsed_1 = json::parse("{}"); + json parsed_2 = json::parse("{}"); + json type_constructed_1 = json::object(); + json type_constructed_2 = json::object(); + + CHECK(def_constructed_1 == def_constructed_1); + CHECK(parsed_1 == parsed_2); + CHECK(type_constructed_1 == type_constructed_2); + + CHECK(def_constructed_1 == parsed_1); + CHECK(def_constructed_1 == type_constructed_1); + CHECK(parsed_1 == type_constructed_1); +} + +TEST_CASE("test_object_equals_empty_arrays") +{ + json parsed_1 = json::parse("[]"); + json parsed_2 = json::parse("[]"); + json type_constructed_1 = json::array(); + json type_constructed_2 = json::array(); + + CHECK(parsed_1 == parsed_2); + CHECK(type_constructed_1 == type_constructed_2); + + CHECK(parsed_1 == type_constructed_1); +} + +TEST_CASE("test_empty_object_equal") +{ + CHECK(json() == json(json::object())); + CHECK(json(json::object()) == json()); +} + +TEST_CASE("test_string_not_equals_empty_object") +{ + json o1("42"); + json o2; + + CHECK(o1 != o2); + CHECK(o2 != o1); +} + +TEST_CASE("test_byte_strings_equal") +{ + json o1(byte_string("123456789")); + json o2(byte_string{'1','2','3','4','5','6','7','8','9'}); + json o3(byte_string{'1','2','3','4','5','6','7','8'}); + + CHECK(o1 == o2); + CHECK(o2 == o1); + CHECK(o3 != o1); + CHECK(o2 != o3); +} + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_exception_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_exception_tests.cpp new file mode 100644 index 0000000000..0d772f91cd --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_exception_tests.cpp @@ -0,0 +1,74 @@ + +// Copyright 2016 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +TEST_CASE("test_object_at") +{ + json a; + REQUIRE_THROWS_AS(a.at("key1"), std::out_of_range); + REQUIRE_THROWS_AS(static_cast(a).at("key1"), std::out_of_range); + + a["key1"] = "value1"; + REQUIRE_THROWS_AS(a.at("key2"), std::out_of_range); + REQUIRE_THROWS_AS(static_cast(a).at("key2"), std::out_of_range); + + json b = json::array(); + REQUIRE_THROWS_AS(b.at("key1"), std::runtime_error); + REQUIRE_THROWS_AS(static_cast(b).at("key1"), std::runtime_error); +} + +TEST_CASE("test_object_find") +{ + json b = json::array(); + b.resize(3); + REQUIRE_THROWS_AS(b.find("key1"), std::runtime_error); + REQUIRE_THROWS_AS(static_cast(b).find("key1"), std::runtime_error); + REQUIRE_THROWS_AS(b.find(std::string("key1")), std::runtime_error); + REQUIRE_THROWS_AS(static_cast(b).find(std::string("key1")), std::runtime_error); +} + +TEST_CASE("test_array_at") +{ + json a = json::array(); + REQUIRE_THROWS_AS(a.at(0), std::out_of_range); + REQUIRE_THROWS_AS(static_cast(a).at(0), std::out_of_range); + + a.resize(3); + REQUIRE_THROWS_AS(a.at(3), std::out_of_range); + REQUIRE_THROWS_AS(static_cast(a).at(3), std::out_of_range); +} + +TEST_CASE("test_object_set") +{ + json b = json::array(); + b.resize(3); + REQUIRE_THROWS_AS(b.insert_or_assign("key1","value1"), std::runtime_error); +} + +TEST_CASE("test_array_add") +{ + json b; + b["key1"] = "value1"; + REQUIRE_THROWS_AS(b.push_back(0), std::runtime_error); +} + +TEST_CASE("test_object_index") +{ + json b; + REQUIRE_THROWS_AS(b["key1"].as(), std::out_of_range); + + b["key1"] = "value1"; + REQUIRE_THROWS_AS(b["key2"].as(), std::out_of_range); +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_filter_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_filter_tests.cpp new file mode 100644 index 0000000000..5ee27c18b3 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_filter_tests.cpp @@ -0,0 +1,170 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +struct warning +{ + std::string name; + size_t line_number; + size_t column_number; +}; + +class name_fix_up_filter : public json_filter +{ + std::string member_name_; +public: + std::vector warnings; + + name_fix_up_filter(json_content_handler& handler) + : json_filter(handler) + { + } + +private: + bool do_name(const string_view_type& name, + const ser_context& context) override + { + member_name_ = std::string(name); + if (member_name_ != "name") + { + this->to_handler().name(name,context); + } + return true; + } + + bool do_string_value(const string_view_type& s, + semantic_tag tag, + const ser_context& context) override + { + if (member_name_ == "name") + { + size_t end_first = s.find_first_of(" \t"); + size_t start_last = s.find_first_not_of(" \t", end_first); + this->to_handler().name("first-name", context); + string_view_type first = s.substr(0, end_first); + this->to_handler().string_value(first, tag, context); + if (start_last != string_view_type::npos) + { + this->to_handler().name("last-name", context); + string_view_type last = s.substr(start_last); + this->to_handler().string_value(last, tag, context); + } + else + { + warnings.push_back(warning{std::string(s), + context.line(), + context.column()}); + } + } + else + { + this->to_handler().string_value(s, tag, context); + } + return true; + } +}; + +TEST_CASE("test_filter") +{ + std::string in_file = "./input/address-book.json"; + std::string out_file = "./output/address-book-new.json"; + std::ifstream is(in_file, std::ofstream::binary); + std::ofstream os(out_file); + + json_encoder encoder(os); + name_fix_up_filter filter(encoder); + json_reader reader(is, filter); + reader.read_next(); + + CHECK(1 == filter.warnings.size()); + CHECK("John" ==filter.warnings[0].name); + CHECK(9 == filter.warnings[0].line_number); + CHECK(26 == filter.warnings[0].column_number); +} + +TEST_CASE("test_filter2") +{ + std::string in_file = "./input/address-book.json"; + std::string out_file = "./output/address-book-new.json"; + std::ifstream is(in_file, std::ofstream::binary); + std::ofstream os(out_file); + + json_encoder encoder(os); + + name_fix_up_filter filter2(encoder); + + rename_object_member_filter filter1("email","email2",filter2); + + json_reader reader(is, filter1); + reader.read_next(); + + CHECK(1 == filter2.warnings.size()); + CHECK("John" ==filter2.warnings[0].name); + CHECK(9 == filter2.warnings[0].line_number); + CHECK(26 == filter2.warnings[0].column_number); +} + +TEST_CASE("test_rename_name") +{ + json j; + try + { + j = json::parse(R"( +{"store": +{"book": [ +{"category": "reference", +"author": "Margaret Weis", +"title": "Dragonlance Series", +"price": 31.96}, {"category": "reference", +"author": "Brent Weeks", +"title": "Night Angel Trilogy", +"price": 14.70 +}]}} +)"); + } + catch (const ser_error& e) + { + std::cout << e.what() << std::endl; + } + CHECK(j["store"]["book"][0]["price"].as() == Approx(31.96).epsilon(0.001)); + + std::stringstream ss; + json_encoder encoder(ss); + rename_object_member_filter filter("price","price2",encoder); + j.dump(filter); + + json j2 = json::parse(ss); + CHECK(j2["store"]["book"][0]["price2"].as() == Approx(31.96).epsilon(0.001)); +} + +TEST_CASE("test_chained_filters") +{ + ojson j = ojson::parse(R"({"first":1,"second":2,"fourth":3,"fifth":4})"); + + json_decoder decoder; + + rename_object_member_filter filter2("fifth", "fourth", decoder); + rename_object_member_filter filter1("fourth", "third", filter2); + + j.dump(filter1); + ojson j2 = decoder.get_result(); + CHECK(j2.size() == 4); + CHECK(j2["first"] == 1); + CHECK(j2["second"] == 2); + CHECK(j2["third"] == 3); + CHECK(j2["fourth"] == 4); +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_integer_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_integer_tests.cpp new file mode 100644 index 0000000000..63de637972 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_integer_tests.cpp @@ -0,0 +1,57 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +TEST_CASE("test_integer_limits") +{ + { + std::ostringstream os; + + os << "{\"max int64_t\":" << (std::numeric_limits::max)() << "}"; + json val = json::parse(os.str()); + REQUIRE(val["max int64_t"].is_int64()); + CHECK(val["max int64_t"].as() == (std::numeric_limits::max)()); + } + { + std::ostringstream os; + + os << "{\"min int64_t\":" << (std::numeric_limits::lowest)() << "}"; + json val = json::parse(os.str()); + REQUIRE(val["min int64_t"].is_int64()); + CHECK(val["min int64_t"].as() == (std::numeric_limits::lowest)()); + } + + // test overflow + { + std::ostringstream os; + + os << "{\"int overflow\":-" << (std::numeric_limits::max)() << "0}"; + json val = json::parse(os.str()); + REQUIRE(val["int overflow"].is_bignum()); + } + { + std::ostringstream os; + + os << "{\"max uint64_t\":" << (std::numeric_limits::max)() << "}"; + json val = json::parse(os.str()); + REQUIRE(val["max uint64_t"].is_uint64()); + CHECK(val["max uint64_t"].as() == (std::numeric_limits::max)()); + } + { + std::ostringstream os; + + os << "{\"uint overflow\":" << (std::numeric_limits::max)() << "0}"; + json val = json::parse(os.str()); + REQUIRE(val["uint overflow"].is_bignum()); + } +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_less_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_less_tests.cpp new file mode 100644 index 0000000000..fe87ca5d0d --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_less_tests.cpp @@ -0,0 +1,157 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +TEST_CASE("json null less") +{ + json j1 = null_type(); + + SECTION("empty object") + { + json j2; + + CHECK(j1 < j2); + CHECK_FALSE(j2 < j1); + } + + SECTION("object") + { + json j2; + j2["a"] = 1; + j2["b"] = 3; + j2["c"] = 3; + + CHECK(j1 < j2); + CHECK_FALSE(j2 < j1); + } +} + +TEST_CASE("json empty object less") +{ + json j1; + + SECTION("empty object") + { + json j2; + + CHECK_FALSE(j1 < j2); + } + + SECTION("object with no members") + { + json j2 = json::object(); + + CHECK_FALSE(j1 < j2); + } + + SECTION("object with members") + { + json j2; + j2["a"] = 1; + j2["b"] = 3; + j2["c"] = 3; + + CHECK(j1 < j2); + } +} + +TEST_CASE("json bool less") +{ + json jtrue = true; + json jfalse = false; + + SECTION("bool") + { + CHECK(jfalse < jtrue); + CHECK_FALSE(jtrue < jfalse); + } + + SECTION("null") + { + json j = null_type(); + CHECK(j < jfalse); + CHECK(j < jtrue); + } +} + +TEST_CASE("json int64 less") +{ + json j1 = -100; +} + +TEST_CASE("json short string less") +{ + json j1 = "bcd"; + + SECTION("short string") + { + json j2 = "cde"; + CHECK(j1 < j2); + CHECK_FALSE(j2 < j1); + json j3 = "bcda"; + CHECK(j1 < j3); + CHECK_FALSE(j3 < j1); + } + + SECTION("long string") + { + json j2 = "string too long for short string"; + CHECK(j1 < j2); + CHECK_FALSE(j2 < j1); + + json j3 = "a string too long for short string"; + CHECK(j3 < j1); + CHECK_FALSE(j1 < j3); + } +} + +TEST_CASE("json long string less") +{ + json j1 = "a string too long for short string"; + + SECTION("short string") + { + json j2 = "a s"; + CHECK(j2 < j1); + CHECK_FALSE(j1 < j2); + json j3 = "bcd"; + CHECK(j1 < j3); + CHECK_FALSE(j3 < j1); + } + + SECTION("long string") + { + json j2 = "string too long for short string"; + CHECK(j1 < j2); + CHECK_FALSE(j2 < j1); + } +} + +TEST_CASE("json array of string less") +{ + json j1 = json::array(); + j1.push_back("b"); + j1.push_back("c"); + j1.push_back("d"); + + SECTION("array") + { + json j2 = json::array(); + j2.push_back("a"); + j2.push_back("b"); + j2.push_back("c"); + + CHECK(j2 < j1); + CHECK_FALSE(j1 < j2); + } +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_line_split_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_line_split_tests.cpp new file mode 100644 index 0000000000..ec77cded5d --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_line_split_tests.cpp @@ -0,0 +1,241 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; +using namespace jsoncons::literals; + +bool are_equal(const std::string& s1, const std::string& s2) +{ + size_t len1 = s1.size(); + size_t len2 = s2.size(); + + size_t len = std::min(len1,len2); + + for (size_t i = 0; i < len; ++i) + { + if (s1[i] != s2[i]) + { + for (size_t j = 0; j <= i; ++j) + { + std::cout << s1[j]; + } + std::cout << "|"; + std::cout << "\n"; + std::cout << i << " s1: " << s1[i] << ", " << (int)s1[i] << " s2: " << s2[i] << ", " << (int)s2[i] << "\n"; + std::cout << s1 << "\n"; + std::cout << "---\n"; + std::cout << s2 << "\n"; + return false; + } + } + return true; +} + +TEST_CASE("json_encoder line split tests") +{ + json val = json::parse(R"( + { + "header" : {"properties": {}}, + "data": + { + "tags" : [], + "id" : [1,2,3], + "item": [[1,2,3]] + } + } +)"); + + SECTION("Default line splits") + { +std::string expected = R"({ + "data": { + "id": [1,2,3], + "item": [ + [1,2,3] + ], + "tags": [] + }, + "header": { + "properties": {} + } +})"; + json_options options; + options.spaces_around_comma(spaces_option::no_spaces); + std::ostringstream os; + os << pretty_print(val, options); + CHECK(os.str() == expected); + } + + SECTION("array_array same_line") + { + json_options options; + options.spaces_around_comma(spaces_option::no_spaces) + .array_array_line_splits(line_split_kind::same_line); + std::string expected = R"({ + "data": { + "id": [1,2,3], + "item": [[1,2,3]], + "tags": [] + }, + "header": { + "properties": {} + } +})"; + std::ostringstream os; + os << pretty_print(val,options); + + //std::cout << os.str() << "\n"; + CHECK(os.str() == expected); + } + + SECTION("array_array new_line") + { + json_options options; + options.spaces_around_comma(spaces_option::no_spaces) + .array_array_line_splits(line_split_kind::new_line); + std::string expected = R"({ + "data": { + "id": [1,2,3], + "item": [ + [1,2,3] + ], + "tags": [] + }, + "header": { + "properties": {} + } +})"; + std::ostringstream os; + os << pretty_print(val,options); + + //std::cout << os.str() << "\n"; + CHECK(os.str() == expected); + } + + SECTION("array_array multi_line") + { + json_options options; + options.spaces_around_comma(spaces_option::no_spaces) + .array_array_line_splits(line_split_kind::multi_line); + std::string expected = R"({ + "data": { + "id": [1,2,3], + "item": [ + [ + 1, + 2, + 3 + ] + ], + "tags": [] + }, + "header": { + "properties": {} + } +})"; + std::ostringstream os; + os << pretty_print(val,options); + //std::cout << os.str() << "\n"; + CHECK(os.str() == expected); + } + + SECTION("object_array same_line") + { + json_options options; + options.spaces_around_comma(spaces_option::no_spaces) + .object_array_line_splits(line_split_kind::same_line); + std::string expected = R"({ + "data": { + "id": [1,2,3], + "item": [ + [1,2,3] + ], + "tags": [] + }, + "header": { + "properties": {} + } +})"; + std::ostringstream os; + os << pretty_print(val,options); + //std::cout << os.str() << "\n"; + CHECK(os.str() == expected); + } + + SECTION("object_array new_line") + { + json_options options; + options.spaces_around_comma(spaces_option::no_spaces) + .object_array_line_splits(line_split_kind::new_line); + std::string expected = R"({ + "data": { + "id": [ + 1,2,3 + ], + "item": [ + [1,2,3] + ], + "tags": [] + }, + "header": { + "properties": {} + } +})"; + std::ostringstream os; + os << pretty_print(val,options); + //std::cout << os.str() << "\n"; + CHECK(os.str() == expected); + } + + SECTION("") + { + json_options options; + options.spaces_around_comma(spaces_option::no_spaces) + .object_array_line_splits(line_split_kind::multi_line); + std::string expected = R"({ + "data": { + "id": [ + 1, + 2, + 3 + ], + "item": [ + [1,2,3] + ], + "tags": [] + }, + "header": { + "properties": {} + } +})"; + std::ostringstream os; + os << pretty_print(val,options); + //std::cout << os.str() << "\n"; + CHECK(os.str() == expected); + } +} + +// array_array_line_splits_(line_split_kind::new_line) + +TEST_CASE("test_array_of_array_of_string_string_array") +{ + json j = R"( +[ + ["NY","LON", + ["TOR","LON"] + ] +] + )"_json; + + //std::cout << pretty_print(j) << std::endl; +} + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_literal_operator_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_literal_operator_tests.cpp new file mode 100644 index 0000000000..6fcf305a4c --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_literal_operator_tests.cpp @@ -0,0 +1,91 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; +using namespace jsoncons::literals; + +TEST_CASE("json_literal_operator_test1") +{ + json j = R"( +{ + "StartDate" : "2017-03-01", + "MaturityDate" : "2020-12-30", + "Currency" : "USD", + "DiscountCurve" : "USD-LIBOR", + "FixedRate" : 0.01, + "PayFrequency" : "6M", + "DayCountBasis" : "ACT/360", + "Notional" : 1000000 +} +)"_json; + + CHECK(j["Currency"] == "USD"); + +} + +TEST_CASE("ojson_literal_operator_test1") +{ + ojson j = R"( +{ + "StartDate" : "2017-03-01", + "MaturityDate" : "2020-12-30", + "Currency" : "USD", + "DiscountCurve" : "USD-LIBOR", + "FixedRate" : 0.01, + "PayFrequency" : "6M", + "DayCountBasis" : "ACT/360", + "Notional" : 1000000 +} +)"_ojson; + + CHECK(j["Currency"] == "USD"); + +} + +TEST_CASE("json_literal_operator_test2") +{ + wjson j = LR"( +{ + "StartDate" : "2017-03-01", + "MaturityDate" : "2020-12-30", + "Currency" : "USD", + "DiscountCurve" : "USD-LIBOR", + "FixedRate" : 0.01, + "PayFrequency" : "6M", + "DayCountBasis" : "ACT/360", + "Notional" : 1000000 +} +)"_json; + + CHECK(j[L"Currency"] == L"USD"); + +} + +TEST_CASE("ojson_literal_operator_test2") +{ + wojson j = LR"( +{ + "StartDate" : "2017-03-01", + "MaturityDate" : "2020-12-30", + "Currency" : "USD", + "DiscountCurve" : "USD-LIBOR", + "FixedRate" : 0.01, + "PayFrequency" : "6M", + "DayCountBasis" : "ACT/360", + "Notional" : 1000000 +} +)"_ojson; + + CHECK(j[L"Currency"] == L"USD"); + +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_member_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_member_tests.cpp new file mode 100644 index 0000000000..638025dc25 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_member_tests.cpp @@ -0,0 +1,102 @@ +// Copyright 2018 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +TEST_CASE("json(string_view)") +{ + json::string_view_type sv("Hello world."); + + json j(sv); + + CHECK(j.as() == sv); + CHECK(j.as_string_view() == sv); +} + +TEST_CASE("json(string, semantic_tag::datetime)") +{ + std::string s("2015-05-07 12:41:07-07:00"); + + json j(s, semantic_tag::datetime); + + CHECK(j.get_semantic_tag() == semantic_tag::datetime); + CHECK(j.as() == s); +} + + +TEST_CASE("json(string, semantic_tag::timestamp)") +{ + SECTION("positive integer") + { + int t = 10000; + json j(t, semantic_tag::timestamp); + + CHECK(j.get_semantic_tag() == semantic_tag::timestamp); + CHECK(j.as() == t); + } + SECTION("negative integer") + { + int t = -10000; + json j(t, semantic_tag::timestamp); + + CHECK(j.get_semantic_tag() == semantic_tag::timestamp); + CHECK(j.as() == t); + } + SECTION("floating point") + { + double t = 10000.1; + json j(t, semantic_tag::timestamp); + + CHECK(j.get_semantic_tag() == semantic_tag::timestamp); + CHECK(j.as() == t); + } + +} + +TEST_CASE("json get_allocator() tests") +{ + SECTION("short string") + { + json j("short"); + + CHECK(j.get_allocator() == json::allocator_type()); + } + SECTION("long string") + { + json::allocator_type alloc; + json j("string too long for short string", alloc); + + CHECK(j.get_allocator() == alloc); + } + SECTION("byte string") + { + json::allocator_type alloc; + json j(byte_string({'H','e','l','l','o'}),alloc); + + CHECK(j.get_allocator() == alloc); + } + SECTION("array") + { + json::allocator_type alloc; + json j = json::array(alloc); + + CHECK(j.get_allocator() == alloc); + } + SECTION("object") + { + json::allocator_type alloc; + json j(alloc); + + CHECK(j.get_allocator() == alloc); + } +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_object_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_object_tests.cpp new file mode 100644 index 0000000000..6c8b805904 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_object_tests.cpp @@ -0,0 +1,1219 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +TEST_CASE("json = json::object(first,last)") +{ + SECTION("copy map into json") + { + std::map m = {{"c",1},{"b",2},{"a",3}}; + + json j = json::object(m.begin(),m.end()); + + REQUIRE(j.size() == 3); + auto it = j.object_range().begin(); + CHECK(it++->key() == "a"); + CHECK(it++->key() == "b"); + CHECK(it++->key() == "c"); + } +} + +TEST_CASE("json insert(first,last) test") +{ + SECTION("copy map into json") + { + std::map m1 = {{"f",4},{"e",5},{"d",6}}; + std::map m2 = {{"c",1},{"b",2},{"a",3}}; + + json j; + j.insert(m1.begin(),m1.end()); + j.insert(m2.begin(),m2.end()); + + //std::cout << j << "\n"; + + REQUIRE(j.size() == 6); + auto it = j.object_range().begin(); + CHECK(it++->key() == "a"); + CHECK(it++->key() == "b"); + CHECK(it++->key() == "c"); + CHECK(it++->key() == "d"); + CHECK(it++->key() == "e"); + CHECK(it++->key() == "f"); + } + SECTION("copy map into ojson") + { + std::map m1 = {{"f",4},{"e",5},{"d",6}}; + std::map m2 = {{"c",1},{"b",2},{"a",3}}; + + ojson j; + j.insert(m1.begin(),m1.end()); + j.insert(m2.begin(),m2.end()); + + //std::cout << j << "\n"; + + REQUIRE(j.size() == 6); + auto it = j.object_range().begin(); + CHECK(it++->key() == "d"); + CHECK(it++->key() == "e"); + CHECK(it++->key() == "f"); + CHECK(it++->key() == "a"); + CHECK(it++->key() == "b"); + CHECK(it++->key() == "c"); + } + + // Fails with xenial-armhf +/* + SECTION("move map into json") + { + std::map m1 = {{"a",1},{"b",2},{"c",3}}; + std::map m2 = {{"d",4},{"e",5},{"f",6}}; + + json j; + j.insert(std::make_move_iterator(m1.begin()),std::make_move_iterator(m1.end())); + j.insert(std::make_move_iterator(m2.begin()),std::make_move_iterator(m2.end())); + + //std::cout << j << "\n"; + + REQUIRE(j.size() == 6); + auto it = j.object_range().begin(); + CHECK(it++->key() == "a"); + CHECK(it++->key() == "b"); + CHECK(it++->key() == "c"); + CHECK(it++->key() == "d"); + CHECK(it++->key() == "e"); + CHECK(it++->key() == "f"); + } +*/ +} + +TEST_CASE("json as") +{ + SECTION("empty object as string") + { + json j; + std::string s = j.as(); + CHECK("{}" == s); + } + + SECTION("key not found") + { + try + { + json j; + std::string s = j["empty"].as(); + CHECK(false); + } + catch (const std::out_of_range& e) + { + CHECK(e.what() == std::string("Key 'empty' not found")); + } + } +} + +TEST_CASE("parse_duplicate_names") +{ + json j1 = json::parse(R"({"first":1,"second":2,"third":3})"); + CHECK(3 == j1.size()); + CHECK(1 == j1["first"].as()); + CHECK(2 == j1["second"].as()); + CHECK(3 == j1["third"].as()); + + json j2 = json::parse(R"({"first":1,"second":2,"first":3})"); + CHECK(2 == j2.size()); + CHECK(1 == j2["first"].as()); + CHECK(2 == j2["second"].as()); +} + +TEST_CASE("test_erase_member") +{ + json o; + o["key"] = "Hello"; + + CHECK(o.size() == 1); + o.erase("key"); + CHECK(o.size() == 0); + + json a; + json b = json::object(); + b["input-file"] = "config_file"; + json b_copy = b; + + a["b"] = std::move(b); + + CHECK(true == a["b"].is_object()); + CHECK(a["b"] == b_copy); +} + +TEST_CASE("test_object_erase_range") +{ + json o; + o["key1"] = "value1"; + o["key2"] = "value2"; + o["key3"] = "value3"; + o["key4"] = "value4"; + + auto first = o.find("key2"); + auto last = o.find("key4"); + + o.erase(first,last); + + CHECK(2 == o.size()); + CHECK(1 == o.count("key1")); + CHECK(1 == o.count("key4")); +} + +TEST_CASE("test_empty_object") +{ + json a; + CHECK(a.size() == 0); + CHECK(a.is_object()); + CHECK(a.is()); + + json::object_iterator begin = a.object_range().begin(); + json::object_iterator end = a.object_range().end(); + + for (json::object_iterator it = begin; it != end; ++it) + { + CHECK(false); + } + + a["key"] = "Hello"; + CHECK(a.size() == 1); + CHECK(a.is_object()); + CHECK(a.is()); +} + +TEST_CASE("test_const_empty_object") +{ + const json b; + CHECK(b.size() == 0); + CHECK(b.is_object()); + CHECK(b.is()); + + json::const_object_iterator begin = b.object_range().begin(); + json::const_object_iterator end = b.object_range().end(); + + for (json::const_object_iterator it = begin; it != end; ++it) + { + CHECK(false); + } +} + +TEST_CASE("test_empty_object_reserve") +{ + json c; + CHECK(c.size() == 0); + CHECK(c.is_object()); + CHECK(c.is()); + c.reserve(100); + CHECK(c.capacity() == 100); + c["key"] = "Hello"; + CHECK(c.size() == 1); + CHECK(c.is_object()); + CHECK(c.is()); + CHECK(c.capacity() == 100); +} + +TEST_CASE("test_empty_object_copy") +{ + json a; + CHECK(a.size() == 0); + CHECK(a.is_object()); + CHECK(a.is()); + + json b = a; + CHECK(b.size() == 0); + CHECK(b.is_object()); + CHECK(b.is()); +} + +TEST_CASE("test_empty_object_assignment") +{ + json a; + CHECK(a.size() == 0); + CHECK(a.is_object()); + CHECK(a.is()); + + json b = json::make_array<1>(10); + CHECK(b.size() == 10); + CHECK(b.is_array()); + CHECK(b.is()); + + b = a; + CHECK(b.size() == 0); + CHECK(b.is_object()); + CHECK(b.is()); + + json c; + c["key"] = "value"; + CHECK(c.size() == 1); + CHECK(c.is_object()); + CHECK(c.is()); + c = a; + CHECK(c.size() == 0); + CHECK(c.is_object()); + CHECK(c.is()); +} + +TEST_CASE("test_get") +{ + json a; + + a["field1"] = "value1"; + + std::string s1 = a.at("field1").as(); + std::string s1a = a.at("field1").as(); + std::string s2 = a.get_with_default("field2","null"); + REQUIRE_THROWS_AS(a.at("field2"), std::out_of_range); + + CHECK(s1 == std::string("value1")); + CHECK(s1a == std::string("value1")); + + //std::cout << "s2=" << s2 << std::endl; + CHECK(std::string("null") == s2); +} + +TEST_CASE("test_proxy_get") +{ + json a; + + a["object1"] = json(); + a["object1"]["field1"] = "value1"; + + std::string s1 = a["object1"].at("field1").as(); + std::string s1a = a["object1"].at("field1").as(); + std::string s2 = a["object1"].get_with_default("field2",json::null()).as(); + CHECK(a["object1"].get_with_default("field2", json::null()).is_null()); + //std::cout << s2 << std::endl; + REQUIRE_THROWS_AS(a["object1"].at("field2").as(), std::out_of_range); + + CHECK(std::string("value1") == s1); + CHECK(std::string("value1") == s1a); + CHECK(std::string("null") == s2); +} + +TEST_CASE("test_proxy_get_with_default") +{ + json a; + + a["object1"] = json(); + a["object1"]["field1"] = "3.7"; + a["object1"]["field2"] = 1.5; + + std::string s1 = a["object1"].get_with_default("field1","default"); + std::string s2 = a["object1"].get_with_default("field2","1.0"); + std::string s3 = a["object1"].get_with_default("field3","1.0"); + std::string s4 = a["object1"].get_with_default("field2","1.0"); + std::string s5 = a["object1"].get_with_default("field3","1.0"); + double d1 = a["object1"].get_with_default("field1",1.0); + double d2 = a["object1"].get_with_default("field2",1.0); + double d3 = a["object1"].get_with_default("field3",1.0); + + CHECK(std::string("3.7") == s1); + CHECK(std::string("1.5") == s2); + CHECK(std::string("1.0") == s3); + CHECK(std::string("1.5") == s4); + CHECK(std::string("1.0") == s5); + CHECK(3.7 == d1); + CHECK(1.5 == d2); + CHECK(1 == d3); +} + +TEST_CASE("test_set_and_proxy_set") +{ + json a; + + a.insert_or_assign("object1",json()); + a.insert_or_assign("field1","value1"); + a["object1"].insert_or_assign("field2","value2"); + + CHECK(std::string("value1") == a["field1"].as()); + CHECK(std::string("value2") == a["object1"]["field2"].as()); +} + +TEST_CASE("test_emplace_and_proxy_set") +{ + json a; + + a.try_emplace("object1",json()); + a.try_emplace("field1","value1"); + a["object1"].try_emplace("field2","value2"); + + CHECK(std::string("value1") == a["field1"].as()); + CHECK(std::string("value2") == a["object1"]["field2"].as()); +} + +TEST_CASE("test_const_member_read") +{ + json a; + + a["field1"] = 10; + + a["field2"]; + + const json b(a); + + int val1 = b["field1"].as(); + CHECK(val1 == 10); + REQUIRE_THROWS_AS(b["field2"], std::out_of_range); +} + +TEST_CASE("test_proxy_const_member_read") +{ + json a; + + a["object1"] = json(); + a["object1"]["field1"] = "value1"; + a["object1"]["field2"]; // No throw yet + + const json b(a); + + std::string s1 = b["object1"]["field1"].as(); + REQUIRE_THROWS_AS(b["object1"]["field2"], std::out_of_range); + + CHECK(s1 == std::string("value1")); +} + +TEST_CASE("test_object_equals") +{ + json a; + a["field1"] = "value1"; + + json b; + b["field1"] = "value1"; + + CHECK(a == b); + + json c; + c["field1"] = 10; + + CHECK_FALSE(a == c); +} + +TEST_CASE("test_json_object_iterator_1") +{ + json a; + a["name1"] = "value1"; + a["name2"] = "value2"; + a["name3"] = "value3"; + + json::object_iterator it = a.object_range().begin(); + CHECK((*it).key() == "name1"); + CHECK((*it).value() == json("value1")); + ++it; + CHECK((*it).key() == "name2"); + CHECK((*it).value() == json("value2")); + + CHECK((*(it++)).key() == "name2"); + CHECK((*it).key() == "name3"); + CHECK((*it).value() == json("value3")); + + CHECK((*(it--)).key() == "name3"); + CHECK((*it).value() == json("value2")); + CHECK((*(--it)).value() == json("value1")); + + json::key_value_type member = *it; + CHECK(member.key() == "name1"); + CHECK(member.value() == json("value1")); +} + +TEST_CASE("test_json_object_iterator_2") +{ + json a; + a["name1"] = "value1"; + a["name2"] = "value2"; + a["name3"] = "value3"; + + json::const_object_iterator it = a.object_range().begin(); + CHECK((*it).key() == "name1"); + CHECK((*it).value() == json("value1")); + ++it; + CHECK((*it).key() == "name2"); + CHECK((*it).value() == json("value2")); + + CHECK((*(it++)).key() == "name2"); + CHECK((*it).key() == "name3"); + CHECK((*it).value() == json("value3")); + + CHECK((*(it--)).key() == "name3"); + CHECK((*it).value() == json("value2")); + + CHECK((*(--it)).value() == json("value1")); + + json::key_value_type member = *it; + CHECK(member.key() == "name1"); + CHECK(member.value() == json("value1")); +} + +TEST_CASE("test_json_object_iterator_3") +{ + json a; + a["name1"] = "value1"; + a["name2"] = "value2"; + a["name3"] = "value3"; + + json::const_object_iterator it = static_cast(a).object_range().begin(); + CHECK((it == a.object_range().begin())); + CHECK_FALSE((it == a.object_range().end())); + CHECK((*it).key() == "name1"); + CHECK((*it).value() == json("value1")); + ++it; + CHECK_FALSE((it == a.object_range().end())); + CHECK((*it).key() == "name2"); + CHECK((*it).value() == json("value2")); + + CHECK((*(it++)).key() == "name2"); + CHECK_FALSE((it == a.object_range().end())); + CHECK((*it).key() == "name3"); + CHECK((*it).value() == json("value3")); + + CHECK((*(it--)).key() == "name3"); + CHECK((*it).value() == json("value2")); + + CHECK((*(--it)).value() == json("value1")); + CHECK((it == a.object_range().begin())); + + json::key_value_type member = *it; + CHECK(member.key() == "name1"); + CHECK(member.value() == json("value1")); + + //*it = member; // Don't want this to compile +} + +TEST_CASE("test_object_key_proxy") +{ + json a; + a["key1"] = "value1"; + + json b; + b["key2"] = json(); + b["key2"]["key3"] = std::move(a); + + CHECK_FALSE((a.is_object() || a.is_array() || a.is_string())); +} + +// accessor tests + + +TEST_CASE("test_get_with_string_default") +{ + json example; + + std::string s("too long string for short string"); + std::string result = example.get_with_default("test", s); + CHECK(s == result); +} + +TEST_CASE("test_compare_with_string") +{ + json a; + a["key"] = "value"; + a["key1"] = "value1"; + a["key2"] = "value2"; + CHECK(a["key"] == a["key"]); + CHECK_FALSE((a["key"] == a["key1"])); + CHECK_FALSE((a["key"] == a["key2"])); +} + +TEST_CASE("test_count") +{ + json a; + a["key1"] = "value1"; + a["key2"] = "value2"; + + CHECK(1 == a.count("key1")); + CHECK(1 == a.count("key2")); + CHECK(0 == a.count("key3")); + + json b = json::parse( + "{\"key1\":\"a value\",\"key1\":\"another value\"}" + ); + CHECK(1 == b.count("key1")); +} + +TEST_CASE("test_find") +{ + json obj; + + json::object_iterator it = obj.find("key"); + CHECK((it == obj.object_range().end())); + + obj["key1"] = 10; + obj["key2"] = true; + obj["key3"] = 'c'; + obj["key4"] = "value4"; + + json::object_iterator it2 = obj.find("key"); + CHECK((it2 == obj.object_range().end())); + + json::object_iterator it3 = obj.find("key4"); + CHECK_FALSE((it3 == obj.object_range().end())); + CHECK(std::string("value4") ==it3->value().as()); +} + +TEST_CASE("test_as") +{ + json obj; + obj["field1"] = 10; + obj["field2"] = true; + obj["char_field"] = 'c'; + obj["string_field"] = "char"; + + std::string s = obj["field1"].as(); + CHECK(std::string("10") == s); + int int_val = obj["field2"].as(); + CHECK(1 == int_val); + int short_val = obj["field2"].as(); + CHECK(short_val == 1); + int ushort_val = obj["field2"].as(); + CHECK(ushort_val == static_cast(1)); + char char_val = obj["field2"].as(); + CHECK(int(char_val) == 1); + + CHECK(obj["char_field"].is()); + CHECK_FALSE(obj["string_field"].is()); + + json parent; + parent["child"] = obj; + s = parent["child"]["field1"].as(); + CHECK(s == std::string("10")); + int_val = parent["child"]["field2"].as(); + CHECK(int_val == 1); + short_val = parent["child"]["field2"].as(); + CHECK(short_val == 1); + + //json::object x = parent["child"].as(); + // Compile time error, "as not supported" + + json empty; + CHECK(empty.is_object()); + CHECK(empty.empty()); + + //json::object y = empty.as(); + // Compile time error, "as not supported" +} + +TEST_CASE("test_as2") +{ + json obj; + obj["field1"] = "10"; + obj["field2"] = "-10"; + obj["field3"] = "10.1"; + + CHECK(10 == obj["field1"].as()); + CHECK(-10 ==obj["field2"].as()); + CHECK(10.1 == obj["field3"].as()); +} + +TEST_CASE("test_is") +{ + json obj; + obj["field1"] = 10; + obj["field2"] = -10; + obj["field3"] = 10U; + + CHECK(obj["field1"].get_storage_type() == jsoncons::storage_type::int64_val); + CHECK(obj["field2"].get_storage_type() == jsoncons::storage_type::int64_val); + CHECK(obj["field3"].get_storage_type() == jsoncons::storage_type::uint64_val); + + CHECK_FALSE(obj["field1"].is()); + CHECK(obj["field1"].is()); + CHECK(obj["field1"].is()); + CHECK(obj["field1"].is()); + CHECK(obj["field1"].is()); + CHECK(obj["field1"].is()); + CHECK(obj["field1"].is()); + CHECK(obj["field1"].is()); + CHECK_FALSE(obj["field1"].is()); + + CHECK_FALSE(obj["field2"].is()); + CHECK(obj["field2"].is()); + CHECK(obj["field2"].is()); + CHECK(obj["field2"].is()); + CHECK(obj["field2"].is()); + CHECK_FALSE(obj["field2"].is()); + CHECK_FALSE(obj["field2"].is()); + CHECK_FALSE(obj["field2"].is()); + CHECK_FALSE(obj["field2"].is()); + CHECK_FALSE(obj["field2"].is()); + + CHECK_FALSE(obj["field3"].is()); + CHECK(obj["field3"].is()); + CHECK(obj["field3"].is()); + CHECK(obj["field3"].is()); + CHECK(obj["field3"].is()); + CHECK(obj["field3"].is()); + CHECK(obj["field3"].is()); + CHECK(obj["field3"].is()); + CHECK_FALSE(obj["field3"].is()); +} + +TEST_CASE("test_is2") +{ + json obj = json::parse("{\"field1\":10}"); + + CHECK(obj["field1"].get_storage_type() == jsoncons::storage_type::uint64_val); + + CHECK_FALSE(obj["field1"].is()); + CHECK(obj["field1"].is()); + CHECK(obj["field1"].is()); + CHECK(obj["field1"].is()); + CHECK(obj["field1"].is()); + CHECK(obj["field1"].is()); + CHECK(obj["field1"].is()); + CHECK_FALSE(obj["field1"].is()); +} + +TEST_CASE("test_is_type") +{ + json obj; + CHECK(obj.is_object()); + CHECK(obj.is()); + + // tests for proxy is_type methods + obj["string"] = "val1"; + + CHECK(obj.is_object()); + CHECK(obj.is()); + + CHECK(obj["string"].is_string()); + CHECK(obj["string"].is()); + + obj["double"] = 10.7; + CHECK(obj["double"].is_double()); + CHECK(obj["double"].is()); + + obj["int"] = -10; + CHECK(obj["int"].is_int64()); + CHECK(obj["int"].is()); + + obj["uint"] = 10u; + CHECK(obj["uint"].is_uint64()); + CHECK(obj["uint"].is()); + + obj["long"] = static_cast(10); + CHECK(obj["long"].is_int64()); + CHECK(obj["long"].is()); + + obj["ulong"] = static_cast(10); + CHECK(obj["ulong"].is_uint64()); + CHECK(obj["ulong"].is()); + + obj["longlong"] = static_cast(10); + CHECK(obj["longlong"].is_int64()); + CHECK(obj["longlong"].is()); + + obj["ulonglong"] = static_cast(10); + CHECK(obj["ulonglong"].is_uint64()); + CHECK(obj["ulonglong"].is()); + + obj["true"] = true; + CHECK(obj["true"].is_bool()); + CHECK(obj["true"].is()); + + obj["false"] = false; + CHECK(obj["false"].is_bool()); + CHECK(obj["false"].is()); + + obj["null1"] = json::null(); + CHECK(obj["null1"].is_null()); + + obj["object"] = json(); + CHECK(obj["object"].is_object()); + CHECK(obj["object"].is()); + + obj["array"] = json::array(); + CHECK(obj["array"].is_array()); + CHECK(obj["array"].is()); + + // tests for json is_type methods + + json str = obj["string"]; + CHECK(str.is()); + CHECK(str.is()); +} + +TEST_CASE("test_object_get_defaults") +{ + json obj; + + obj["field1"] = 1; + obj["field3"] = "Toronto"; + + double x1 = obj.contains("field1") ? obj["field1"].as() : 10.0; + double x2 = obj.contains("field2") ? obj["field2"].as() : 20.0; + + + CHECK(x1 == 1.0); + CHECK(x2 == 20.0); + + std::string s1 = obj.get_with_default("field3", "Montreal"); + std::string s2 = obj.get_with_default("field4", "San Francisco"); + + CHECK(s1 =="Toronto"); + CHECK(s2 == "San Francisco"); +} + +TEST_CASE("test_object_accessing") +{ + json obj; + obj["first_name"] = "Jane"; + obj["last_name"] = "Roe"; + obj["events_attended"] = 10; + obj["accept_waiver_of_liability"] = true; + + CHECK(obj["first_name"].as() == "Jane"); + CHECK(obj.at("last_name").as() == "Roe"); + CHECK(obj["events_attended"].as() == 10); + CHECK(obj["accept_waiver_of_liability"].as()); +} + +TEST_CASE("test_value_not_found_and_defaults") +{ + json obj; + obj["first_name"] = "Jane"; + obj["last_name"] = "Roe"; + + try + { + auto val = obj["outdoor_experience"].as(); + CHECK(false); + } + catch (const std::out_of_range& e) + { + CHECK(e.what() == std::string("Key 'outdoor_experience' not found")); + } + + //REQUIRE_THROWS_AS((obj["outdoor_experience"].as()),jsoncons::key_not_found); + //REQUIRE_THROWS_WITH((obj["outdoor_experience"].as()),"Key 'outdoor_experience' not found"); + + std::string experience = obj.contains("outdoor_experience") ? obj["outdoor_experience"].as() : ""; + + CHECK(experience == ""); + + try + { + auto val = obj["first_aid_certification"].as(); + CHECK(false); + } + catch (const std::out_of_range& e) + { + CHECK(e.what() == std::string("Key 'first_aid_certification' not found")); + } + + //REQUIRE_THROWS_AS(obj["first_aid_certification"].as(),std::out_of_range); + //REQUIRE_THROWS_WITH(obj["first_aid_certification"].as(),"Key 'first_aid_certification' not found"); +} + +TEST_CASE("test_set_override") +{ + json obj; + obj["first_name"] = "Jane"; + obj["height"] = 0.9; + + obj["first_name"] = "Joe"; + obj["height"] = "0.3"; + + CHECK(obj["first_name"] == "Joe"); + CHECK(obj["height"].as() == Approx(0.3).epsilon(0.00000000001)); +} + +TEST_CASE("try_emplace tests") +{ + json j = json::parse(R"( + { + "a" : 1, + "b" : 2 + } + )"); + + json expected = json::parse(R"( + { + "a" : 1, + "b" : 2, + "c" : 3 + } + )"); + + SECTION("try_emplace(const string_view_type& name, Args&&... args)") + { + j.try_emplace("c",3); + + CHECK(j == expected); + } + + SECTION("try_emplace(iterator hint, const string_view_type& name, Args&&... args)") + { + json::object_iterator it = j.object_range().begin(); + + j.try_emplace(it,"c",3); + + CHECK(j == expected); + } +} + + +// merge tests + +TEST_CASE("test_json_merge") +{ +json j = json::parse(R"( +{ + "a" : 1, + "b" : 2 +} +)"); +json j2 = j; + +const json source = json::parse(R"( +{ + "a" : 2, + "c" : 3 +} +)"); + +const json expected = json::parse(R"( +{ + "a" : 1, + "b" : 2, + "c" : 3 +} +)"); + + j.merge(source); + CHECK(j.size() == 3); + CHECK(j == expected); + + j2.merge(j2.object_range().begin()+1,source); + CHECK(j2.size() == 3); + CHECK(j2 == expected); + + //std::cout << j << std::endl; +} + +TEST_CASE("test_json_merge_move") +{ +json j = json::parse(R"( +{ + "a" : "1", + "b" : [1,2,3] +} +)"); + json j2 = j; + +json source = json::parse(R"( +{ + "a" : "2", + "c" : [4,5,6] +} +)"); + +json expected = json::parse(R"( +{ + "a" : "1", + "b" : [1,2,3], + "c" : [4,5,6] +} +)"); + + json source2 = source; + + j.merge(std::move(source)); + CHECK(j.size() == 3); + CHECK(j == expected); + + j2.merge(std::move(source2)); + CHECK(j2.size() == 3); + CHECK(j2 == expected); + + //std::cout << source << std::endl; +} + +// merge_or_update tests + +TEST_CASE("test_json_merge_or_update") +{ +json j = json::parse(R"( +{ + "a" : 1, + "b" : 2 +} +)"); +json j2 = j; + +const json source = json::parse(R"( +{ + "a" : 2, + "c" : 3 +} +)"); + +const json expected = json::parse(R"( +{ + "a" : 2, + "b" : 2, + "c" : 3 +} +)"); + + j.merge_or_update(source); + CHECK(j.size() == 3); + CHECK(j == expected); + + j2.merge_or_update(j2.object_range().begin()+1,source); + CHECK(j2.size() == 3); + CHECK(j2 == expected); + + //std::cout << j << std::endl; +} + +TEST_CASE("test_json_merge_or_update_move") +{ +json j = json::parse(R"( +{ + "a" : "1", + "b" : [1,2,3] +} +)"); + json j2 = j; + +json source = json::parse(R"( +{ + "a" : "2", + "c" : [4,5,6] +} +)"); + +json expected = json::parse(R"( +{ + "a" : "2", + "b" : [1,2,3], + "c" : [4,5,6] +} +)"); + + json source2 = source; + + j.merge_or_update(std::move(source)); + CHECK(j.size() == 3); + CHECK(j == expected); + + j2.merge_or_update(std::move(source2)); + CHECK(j2.size() == 3); + CHECK(j2 == expected); + + //std::cout << source << std::endl; +} + +TEST_CASE("ojson parse_duplicate_names") +{ + ojson oj1 = ojson::parse(R"({"first":1,"second":2,"third":3})"); + CHECK(3 == oj1.size()); + CHECK(1 == oj1["first"].as()); + CHECK(2 == oj1["second"].as()); + CHECK(3 == oj1["third"].as()); + + ojson oj2 = ojson::parse(R"({"first":1,"second":2,"first":3})"); + CHECK(2 == oj2.size()); + CHECK(1 == oj2["first"].as()); + CHECK(2 == oj2["second"].as()); +} +TEST_CASE("test_ojson_merge") +{ +ojson j = ojson::parse(R"( +{ + "a" : 1, + "b" : 2 +} +)"); + +const ojson source = ojson::parse(R"( +{ + "a" : 2, + "c" : 3, + "d" : 4, + "b" : 5, + "e" : 6 +} +)"); + + SECTION("merge j with source") + { + const ojson expected = ojson::parse(R"( + { + "a" : 1, + "b" : 2, + "c" : 3, + "d" : 4, + "e" : 6 + } + )"); + j.merge(source); + CHECK(j == expected); + } + + SECTION("merge j") + { + const ojson expected = ojson::parse(R"( +{"a":1,"c":3,"d":4,"b":2,"e":6} + )"); + j.merge(j.object_range().begin()+1,source); + CHECK(j == expected); + } + + //std::cout << j << std::endl; +} + +TEST_CASE("test_ojson_merge_move") +{ +ojson j = ojson::parse(R"( +{ + "a" : "1", + "d" : [1,2,3] +} +)"); + +ojson source = ojson::parse(R"( +{ + "a" : "2", + "c" : [4,5,6] +} +)"); + SECTION("merge source into j") + { + ojson expected = ojson::parse(R"( + { + "a" : "1", + "d" : [1,2,3], + "c" : [4,5,6] + } + )"); + + j.merge(std::move(source)); + CHECK(j == expected); + } + SECTION("merge source into j at begin") + { + ojson expected = ojson::parse(R"( + { + "a" : "1", + "c" : [4,5,6], + "d" : [1,2,3] + } + )"); + + j.merge(j.object_range().begin(),std::move(source)); + CHECK(j == expected); + } + + + //std::cout << "(1)\n" << j << std::endl; + //std::cout << "(2)\n" << source << std::endl; +} + +TEST_CASE("test_ojson_merge_or_update") +{ +ojson j = ojson::parse(R"( +{ + "a" : 1, + "b" : 2 +} +)"); + +const ojson source = ojson::parse(R"( +{ + "a" : 2, + "c" : 3 +} +)"); + + SECTION("merge_or_update source into j") + { + const ojson expected = ojson::parse(R"( + { + "a" : 2, + "b" : 2, + "c" : 3 + } + )"); + j.merge_or_update(source); + CHECK(j == expected); + } + + SECTION("merge_or_update source into j at pos 1") + { + const ojson expected = ojson::parse(R"( + { + "a" : 2, + "c" : 3, + "b" : 2 + } + )"); + j.merge_or_update(j.object_range().begin()+1,source); + CHECK(j == expected); + } + + //std::cout << j << std::endl; +} + +TEST_CASE("test_ojson_merge_or_update_move") +{ +ojson j = ojson::parse(R"( +{ + "a" : "1", + "d" : [1,2,3] +} +)"); + +ojson source = ojson::parse(R"( +{ + "a" : "2", + "c" : [4,5,6] +} +)"); + + SECTION("merge or update j from source") + { + ojson expected = ojson::parse(R"( + { + "a" : "2", + "d" : [1,2,3], + "c" : [4,5,6] + } + )"); + + j.merge_or_update(std::move(source)); + CHECK(j == expected); + } + + SECTION("merge or update j from source at pos") + { + ojson expected = ojson::parse(R"( + { + "a" : "2", + "c" : [4,5,6], + "d" : [1,2,3] + } + )"); + + j.merge_or_update(j.object_range().begin(),std::move(source)); + CHECK(j.size() == 3); + CHECK(j == expected); + } + + + //std::cout << "(1)\n" << j << std::endl; + //std::cout << "(2)\n" << source << std::endl; +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_options_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_options_tests.cpp new file mode 100644 index 0000000000..01090a746d --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_options_tests.cpp @@ -0,0 +1,438 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +TEST_CASE("test_default_nan_replacement") +{ + json obj; + obj["field1"] = std::sqrt(-1.0); + obj["field2"] = 1.79e308 * 1000; + obj["field3"] = -1.79e308 * 1000; + + std::ostringstream os; + os << print(obj); + std::string expected = R"({"field1":null,"field2":null,"field3":null})"; + + CHECK(os.str() == expected); +} + +TEST_CASE("test_write_nan_replacement") +{ + json j; + j["field1"] = std::sqrt(-1.0); + j["field2"] = 1.79e308 * 1000; + j["field3"] = -1.79e308 * 1000; + + json_options options; + options.inf_to_num("1e9999"); + + std::ostringstream os; + os << print(j, options); + std::string expected = R"({"field1":null,"field2":1e9999,"field3":-1e9999})"; + + CHECK(os.str() == expected); +} + +TEST_CASE("test_read_write_read_nan_replacement") +{ + json j; + j["field1"] = std::sqrt(-1.0); + j["field2"] = 1.79e308 * 1000; + j["field3"] = -1.79e308 * 1000; + + json_options options; + options.nan_to_str("NaN") + .inf_to_str("Inf"); + + std::ostringstream os; + os << pretty_print(j, options); + + json j2 = json::parse(os.str(),options); + + json expected; + expected["field1"] = std::nan(""); + expected["field2"] = std::numeric_limits::infinity(); + expected["field3"] = -std::numeric_limits::infinity(); + + CHECK(expected.to_string(options) == j.to_string(options)); + CHECK(expected.to_string() == j.to_string()); +} + +TEST_CASE("object_array empty array") +{ + std::string s = R"( +{ + "foo": [] +} + )"; + + SECTION("same_line") + { + json j = json::parse(s); + + json_options options; + options.object_array_line_splits(line_split_kind::same_line); + + std::ostringstream os; + os << pretty_print(j, options); + + std::string expected = R"({ + "foo": [] +})"; + CHECK(os.str() == expected); + } + + SECTION("new_line") + { + json j = json::parse(s); + + json_options options; + options.object_array_line_splits(line_split_kind::new_line); + + std::ostringstream os; + os << pretty_print(j, options); + + std::string expected = R"({ + "foo": [] +})"; + CHECK(os.str() == expected); + } + + SECTION("multi_line") + { + json j = json::parse(s); + + json_options options; + options.object_array_line_splits(line_split_kind::multi_line); + + std::ostringstream os; + os << pretty_print(j, options); + + std::string expected = R"({ + "foo": [] +})"; + CHECK(os.str() == expected); + } + +} + +TEST_CASE("object_array with/without line_length_limit") +{ + std::string s = R"( +{ + "foo": ["bar", "baz", [1, 2, 3]], + "qux": [1, 2, 3, null, 123, 45.3, 342334, 234] +} + )"; + + SECTION("same_line") + { + std::string expected = R"({ + "foo": ["bar","baz", + [1,2,3] + ], + "qux": [1,2,3,null,123,45.3,342334,234] +})"; + + json j = json::parse(s); + + json_options options; + options.line_length_limit(120) + .spaces_around_comma(spaces_option::no_spaces) + .object_array_line_splits(line_split_kind::same_line); + + std::ostringstream os; + os << pretty_print(j, options); + + CHECK(os.str() == expected); + } + + SECTION("new_line") + { + std::string expected = R"({ + "foo": [ + "bar","baz", + [1,2,3] + ], + "qux": [ + 1,2,3,null,123,45.3,342334,234 + ] +})"; + + json j = json::parse(s); + + json_options options; + options.line_length_limit(120) + .spaces_around_comma(spaces_option::no_spaces) + .object_array_line_splits(line_split_kind::new_line); + + std::ostringstream os; + os << pretty_print(j, options); + + //std::cout << pretty_print(j, options) << "\n"; + CHECK(os.str() == expected); + } + + SECTION("multi_line") + { + std::string expected = R"({ + "foo": [ + "bar", + "baz", + [1,2,3] + ], + "qux": [ + 1, + 2, + 3, + null, + 123, + 45.3, + 342334, + 234 + ] +})"; + + json j = json::parse(s); + + json_options options; + options.spaces_around_comma(spaces_option::no_spaces) + .object_array_line_splits(line_split_kind::multi_line); + + std::ostringstream os; + os << pretty_print(j, options); + + //std::cout << pretty_print(j, options) << "\n"; + CHECK(os.str() == expected); + } + + SECTION("same_line with line length limit") + { + std::string expected = R"({ + "foo": ["bar","baz", + [1,2,3] + ], + "qux": [1,2,3,null, + 123,45.3,342334, + 234 + ] +})"; + + json j = json::parse(s); + + json_options options; + options.line_length_limit(20) + .spaces_around_comma(spaces_option::no_spaces) + .object_array_line_splits(line_split_kind::same_line); + + std::ostringstream os; + os << pretty_print(j, options); + + //std::cout << pretty_print(j, options) << "\n"; + CHECK(os.str() == expected); + } + + SECTION("new_line with line length limit") // Revisit 234 + { + std::string expected = R"({ + "foo": [ + "bar","baz", + [1,2,3] + ], + "qux": [ + 1,2,3,null,123, + 45.3,342334,234 + ] +})"; + + json j = json::parse(s); + + json_options options; + options.line_length_limit(20) + .spaces_around_comma(spaces_option::no_spaces) + .object_array_line_splits(line_split_kind::new_line); + + std::ostringstream os; + os << pretty_print(j, options); + + //std::cout << pretty_print(j, options) << "\n"; + CHECK(os.str() == expected); + } +} + +TEST_CASE("array_object with/without line_length_limit") +{ + std::string s = R"( +[ + { + "author": "Graham Greene", + "title": "The Comedians" + }, + { + "author": "Koji Suzuki", + "title": "ring" + }, + { + "author": "Haruki Murakami", + "title": "A Wild Sheep Chase" + } +] + )"; + SECTION("same_line") + { + std::string expected = R"([{"author": "Graham Greene","title": "The Comedians"},{"author": "Koji Suzuki","title": "ring"},{"author": "Haruki Murakami", + "title": "A Wild Sheep Chase"}])"; + + json j = json::parse(s); + + json_options options; + options.line_length_limit(120) + .spaces_around_comma(spaces_option::no_spaces) + .array_object_line_splits(line_split_kind::same_line); + + std::ostringstream os; + os << pretty_print(j, options); + + //std::cout << pretty_print(j, options) << "\n"; + CHECK(os.str() == expected); + } + + SECTION("new_line") + { + std::string expected = R"([ + {"author": "Graham Greene","title": "The Comedians"}, + {"author": "Koji Suzuki","title": "ring"}, + {"author": "Haruki Murakami","title": "A Wild Sheep Chase"} +])"; + + json j = json::parse(s); + + json_options options; + options.line_length_limit(120) + .spaces_around_comma(spaces_option::no_spaces) + .array_object_line_splits(line_split_kind::new_line); + + std::ostringstream os; + os << pretty_print(j, options); + + //std::cout << pretty_print(j, options) << "\n"; + CHECK(os.str() == expected); + } + + SECTION("multi_line (default)") + { + std::string expected = R"([ + { + "author": "Graham Greene", + "title": "The Comedians" + }, + { + "author": "Koji Suzuki", + "title": "ring" + }, + { + "author": "Haruki Murakami", + "title": "A Wild Sheep Chase" + } +])"; + + json j = json::parse(s); + + json_options options; + options.spaces_around_comma(spaces_option::no_spaces); + + std::ostringstream os; + os << pretty_print(j, options); + + //std::cout << pretty_print(j, options) << "\n"; + CHECK(os.str() == expected); + } + SECTION("same_line with line length limit") + { + std::string expected = R"([{"author": "Graham Greene", + "title": "The Comedians"}, + {"author": "Koji Suzuki", + "title": "ring"}, + {"author": "Haruki Murakami", + "title": "A Wild Sheep Chase"}])"; + + json j = json::parse(s); + + json_options options; + options.line_length_limit(20) + .spaces_around_comma(spaces_option::no_spaces) + .array_object_line_splits(line_split_kind::same_line); + + std::ostringstream os; + os << pretty_print(j, options); + + //std::cout << pretty_print(j, options) << "\n"; + CHECK(os.str() == expected); + } + SECTION("new_line with line length limit") + { + std::string expected = R"([ + {"author": "Graham Greene", + "title": "The Comedians"}, + {"author": "Koji Suzuki", + "title": "ring"}, + {"author": "Haruki Murakami", + "title": "A Wild Sheep Chase"} +])"; + json j = json::parse(s); + + json_options options; + options.line_length_limit(20) + .spaces_around_comma(spaces_option::no_spaces) + .array_object_line_splits(line_split_kind::new_line); + + std::ostringstream os; + os << pretty_print(j, options); + CHECK(os.str() == expected); + + //std::cout << pretty_print(j, options) << "\n"; + } +} + +TEST_CASE("json_options tests") +{ + SECTION("pad_inside_array_brackets") + { + std::string s = R"({ + "foo": [ 1, 2 ] +})"; + + json j = json::parse(s); + + json_options options; + options.pad_inside_array_brackets(true); + + std::ostringstream os; + j.dump(os, options, indenting::indent); + CHECK(os.str() == s); + } + SECTION("pad_inside_object_braces") + { + std::string s = R"([{ "foo": 1 }])"; + + json j = json::parse(s); + + json_options options; + options.pad_inside_object_braces(true) + .array_object_line_splits(line_split_kind::same_line); + + std::ostringstream os; + j.dump(os, options, indenting::indent); + CHECK(os.str() == s); + } +} diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_parse_error_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_parse_error_tests.cpp new file mode 100644 index 0000000000..1089292b48 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_parse_error_tests.cpp @@ -0,0 +1,239 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +void test_parse_error(const std::string& text, std::error_code ec) +{ + REQUIRE_THROWS(json::parse(text)); + try + { + json::parse(text); + } + catch (const ser_error& e) + { + if (e.code() != ec) + { + std::cout << text << std::endl; + std::cout << e.code().value() << " " << e.what() << std::endl; + } + CHECK(ec == e.code()); + } +} + +void test_parse_ec(const std::string& text, std::error_code expected) +{ + std::error_code ec; + + std::istringstream is(text); + json_decoder decoder; + json_reader reader(is,decoder); + + reader.read(ec); + //std::cerr << text << std::endl; + //std::cerr << ec.message() + // << " at line " << reader.line() + // << " and column " << reader.column() << std::endl; + + CHECK(ec); + CHECK(ec == expected); +} + +TEST_CASE("test_parse_missing_separator") +{ + std::string jtext = R"({"field1"{}})"; + + test_parse_error(jtext, jsoncons::json_errc::expected_colon); + test_parse_ec(jtext, jsoncons::json_errc::expected_colon); +} + +TEST_CASE("test_invalid_value") +{ + std::string jtext = R"({"field1":ru})"; + + test_parse_error(jtext,jsoncons::json_errc::expected_value); + test_parse_ec(jtext, jsoncons::json_errc::expected_value); +} + + +TEST_CASE("test_unexpected_end_of_file") +{ + std::string jtext = R"({"field1":{})"; + + test_parse_error(jtext, jsoncons::json_errc::unexpected_eof); + test_parse_ec(jtext, jsoncons::json_errc::unexpected_eof); +} + +TEST_CASE("test_value_not_found") +{ + std::string jtext = R"({"name":})"; + + test_parse_error(jtext, jsoncons::json_errc::expected_value); + test_parse_ec(jtext, jsoncons::json_errc::expected_value); +} + +TEST_CASE("test_escaped_characters") +{ + std::string input("[\"\\n\\b\\f\\r\\t\"]"); + std::string expected("\n\b\f\r\t"); + + json o = json::parse(input); + CHECK(expected == o[0].as()); +} + + +TEST_CASE("test_expected_colon") +{ + test_parse_error("{\"name\" 10}", jsoncons::json_errc::expected_colon); + test_parse_error("{\"name\" true}", jsoncons::json_errc::expected_colon); + test_parse_error("{\"name\" false}", jsoncons::json_errc::expected_colon); + test_parse_error("{\"name\" null}", jsoncons::json_errc::expected_colon); + test_parse_error("{\"name\" \"value\"}", jsoncons::json_errc::expected_colon); + test_parse_error("{\"name\" {}}", jsoncons::json_errc::expected_colon); + test_parse_error("{\"name\" []}", jsoncons::json_errc::expected_colon); +} + +TEST_CASE("test_expected_name") +{ + test_parse_error("{10}", jsoncons::json_errc::expected_name); + test_parse_error("{true}", jsoncons::json_errc::expected_name); + test_parse_error("{false}", jsoncons::json_errc::expected_name); + test_parse_error("{null}", jsoncons::json_errc::expected_name); + test_parse_error("{{}}", jsoncons::json_errc::expected_name); + test_parse_error("{[]}", jsoncons::json_errc::expected_name); +} + +TEST_CASE("test_expected_value") +{ + test_parse_error("[tru]", jsoncons::json_errc::invalid_value); + test_parse_error("[fa]", jsoncons::json_errc::invalid_value); + test_parse_error("[n]", jsoncons::json_errc::invalid_value); +} + +TEST_CASE("test_parse_primitive_pass") +{ + json val; + CHECK_NOTHROW((val=json::parse("null"))); + CHECK(val == json::null()); + CHECK_NOTHROW((val=json::parse("false"))); + CHECK(val == json(false)); + CHECK_NOTHROW((val=json::parse("true"))); + CHECK(val == json(true)); + CHECK_NOTHROW((val=json::parse("10"))); + CHECK(val == json(10)); + CHECK_NOTHROW((val=json::parse("1.999"))); + CHECK(val == json(1.999)); + CHECK_NOTHROW((val=json::parse("\"string\""))); + CHECK(val == json("string")); +} + +TEST_CASE("test_parse_empty_structures") +{ + json val; + CHECK_NOTHROW((val=json::parse("{}"))); + CHECK_NOTHROW((val=json::parse("[]"))); + CHECK_NOTHROW((val=json::parse("{\"object\":{},\"array\":[]}"))); + CHECK_NOTHROW((val=json::parse("[[],{}]"))); +} + +TEST_CASE("test_parse_primitive_fail") +{ + test_parse_error("null {}", jsoncons::json_errc::extra_character); + test_parse_error("n ", jsoncons::json_errc::invalid_value); + test_parse_error("nu ", jsoncons::json_errc::invalid_value); + test_parse_error("nul ", jsoncons::json_errc::invalid_value); + test_parse_error("false {}", jsoncons::json_errc::extra_character); + test_parse_error("fals ", jsoncons::json_errc::invalid_value); + test_parse_error("true []", jsoncons::json_errc::extra_character); + test_parse_error("tru ", jsoncons::json_errc::invalid_value); + test_parse_error("10 {}", jsoncons::json_errc::extra_character); + test_parse_error("1a ", jsoncons::json_errc::invalid_number); + test_parse_error("1.999 []", jsoncons::json_errc::extra_character); + test_parse_error("1e0-1", jsoncons::json_errc::invalid_number); + test_parse_error("\"string\"{}", jsoncons::json_errc::extra_character); + test_parse_error("\"string\"[]", jsoncons::json_errc::extra_character); +} + +TEST_CASE("test_multiple") +{ + std::string in="{\"a\":1,\"b\":2,\"c\":3}{\"a\":4,\"b\":5,\"c\":6}"; + //std::cout << in << std::endl; + + std::istringstream is(in); + + jsoncons::json_decoder decoder; + json_reader reader(is,decoder); + + REQUIRE_FALSE(reader.eof()); + reader.read_next(); + CHECK_FALSE(reader.eof()); + json val = decoder.get_result(); + CHECK(1 == val["a"].as()); + + REQUIRE_FALSE(reader.eof()); + reader.read_next(); + CHECK(reader.eof()); + json val2 = decoder.get_result(); + CHECK(4 == val2["a"].as()); +} + +TEST_CASE("test_uinteger_overflow") +{ + uint64_t m = (std::numeric_limits::max)(); + std::string s1 = std::to_string(m); + std::string s2 = s1; + s2.push_back('0'); + + json j1 = json::parse(s1); + CHECK(j1.is_uint64()); + CHECK(m == j1.as()); + + json j2 = json::parse(s2); + CHECK_FALSE(j2.is_uint64()); + CHECK(j2.is_bignum()); + CHECK(s2 == j2.as()); +} +TEST_CASE("test_negative_integer_overflow") +{ + int64_t m = (std::numeric_limits::lowest)(); + std::string s1 = std::to_string(m); + std::string s2 = s1; + s2.push_back('0'); + + json j1 = json::parse(s1); + CHECK(m == j1.as()); + + json j2 = json::parse(s2); + CHECK_FALSE(j2.is_int64()); + CHECK(j2.is_bignum()); + CHECK(s2 == j2.as()); +} + +TEST_CASE("test_positive_integer_overflow") +{ + int64_t m = (std::numeric_limits::max)(); + std::string s1 = std::to_string(m); + std::string s2 = s1; + s2.push_back('0'); + + json j1 = json::parse(s1); + CHECK(m == j1.as()); + + json j2 = json::parse(s2); + CHECK_FALSE(j2.is_int64()); + CHECK(j2.is_bignum()); + CHECK(s2 == j2.as()); +} + + + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_parser_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_parser_tests.cpp new file mode 100644 index 0000000000..a215f46738 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_parser_tests.cpp @@ -0,0 +1,279 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +TEST_CASE("Test cyrillic.json") +{ + std::string path = "./input/cyrillic.json"; + std::fstream is(path); + if (!is) + { + std::cout << "Cannot open " << path << std::endl; + } + REQUIRE(is); + json j = json::parse(is); +} + +TEST_CASE("test_object2") +{ +json source = json::parse(R"( +{ + "a" : "2", + "c" : [4,5,6] +} +)"); + + std::cout << source << std::endl; +} + +TEST_CASE("test_object_with_three_members") +{ + std::string input = "{\"A\":\"Jane\", \"B\":\"Roe\",\"C\":10}"; + json val = json::parse(input); + + CHECK(true == val.is_object()); + CHECK(3 == val.size()); +} + +TEST_CASE("test_double") +{ + json val = json::parse("42.229999999999997"); +} + +TEST_CASE("test_array_of_integer") +{ + std::string s = "[1,2,3]"; + json j1 = json::parse(s); + CHECK(true == j1.is_array()); + CHECK(3 == j1.size()); + + std::istringstream is(s); + json j2 = json::parse(is); + CHECK(true == j2.is_array()); + CHECK(3 == j2.size()); +} + +TEST_CASE("test_skip_bom") +{ + std::string s = "\xEF\xBB\xBF[1,2,3]"; + json j1 = json::parse(s); + CHECK(true == j1.is_array()); + CHECK(3 == j1.size()); + + std::istringstream is(s); + json j2 = json::parse(is); + CHECK(true == j2.is_array()); + CHECK(3 == j2.size()); +} + +TEST_CASE("test_parse_empty_object") +{ + jsoncons::json_decoder decoder; + json_parser parser; + + parser.reset(); + + static std::string s("{}"); + + parser.update(s.data(),s.length()); + parser.parse_some(decoder); + parser.finish_parse(decoder); + CHECK(parser.done()); + + json j = decoder.get_result(); +} + +TEST_CASE("test_parse_array") +{ + jsoncons::json_decoder decoder; + json_parser parser; + + parser.reset(); + + static std::string s("[]"); + + parser.update(s.data(),s.length()); + parser.parse_some(decoder); + parser.finish_parse(decoder); + CHECK(parser.done()); + + json j = decoder.get_result(); +} + +TEST_CASE("test_parse_string") +{ + jsoncons::json_decoder decoder; + json_parser parser; + + parser.reset(); + + static std::string s("\"\""); + + parser.update(s.data(),s.length()); + parser.parse_some(decoder); + parser.finish_parse(decoder); + CHECK(parser.done()); + + json j = decoder.get_result(); +} + +TEST_CASE("test_parse_integer") +{ + jsoncons::json_decoder decoder; + json_parser parser; + + parser.reset(); + + static std::string s("10"); + + parser.update(s.data(),s.length()); + parser.parse_some(decoder); + parser.finish_parse(decoder); + CHECK(parser.done()); + + json j = decoder.get_result(); +} + +TEST_CASE("test_parse_integer_space") +{ + jsoncons::json_decoder decoder; + json_parser parser; + + parser.reset(); + + static std::string s("10 "); + + parser.update(s.data(),s.length()); + parser.parse_some(decoder); + parser.finish_parse(decoder); + CHECK(parser.done()); + + json j = decoder.get_result(); +} + +TEST_CASE("test_parse_double_space") +{ + jsoncons::json_decoder decoder; + json_parser parser; + + parser.reset(); + + static std::string s("10.0 "); + + parser.update(s.data(),s.length()); + parser.parse_some(decoder); + parser.finish_parse(decoder); + CHECK(parser.done()); + + json j = decoder.get_result(); +} + +TEST_CASE("test_parse_false") +{ + jsoncons::json_decoder decoder; + json_parser parser; + + parser.reset(); + + static std::string s("false"); + + parser.update(s.data(),s.length()); + parser.parse_some(decoder); + parser.finish_parse(decoder); + CHECK(parser.done()); + + json j = decoder.get_result(); +} + +TEST_CASE("test_parse_true") +{ + jsoncons::json_decoder decoder; + json_parser parser; + + parser.reset(); + + static std::string s("true"); + + parser.update(s.data(),s.length()); + parser.parse_some(decoder); + parser.finish_parse(decoder); + CHECK(parser.done()); + + json j = decoder.get_result(); +} + +TEST_CASE("test_parse_null") +{ + jsoncons::json_decoder decoder; + json_parser parser; + + parser.reset(); + + static std::string s("null"); + + parser.update(s.data(),s.length()); + parser.parse_some(decoder); + parser.finish_parse(decoder); + CHECK(parser.done()); + + json j = decoder.get_result(); +} + +TEST_CASE("test_parse_array_string") +{ + jsoncons::json_decoder decoder; + json_parser parser; + + parser.reset(); + + static std::string s1("[\"\""); + + parser.update(s1.data(),s1.length()); + parser.parse_some(decoder); + CHECK_FALSE(parser.done()); + static std::string s2("]"); + parser.update(s2.data(), s2.length()); + parser.parse_some(decoder); + parser.finish_parse(decoder); + CHECK(parser.done()); + + json j = decoder.get_result(); +} + +TEST_CASE("test_incremental_parsing") +{ + jsoncons::json_decoder decoder; + json_parser parser; + + parser.reset(); + + parser.update("[fal",4); + parser.parse_some(decoder); + CHECK_FALSE(parser.done()); + CHECK(parser.source_exhausted()); + parser.update("se]",3); + parser.parse_some(decoder); + + parser.finish_parse(decoder); + CHECK(parser.done()); + + json j = decoder.get_result(); + REQUIRE(j.is_array()); + CHECK_FALSE(j[0].as()); +} + + + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_reader_exception_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_reader_exception_tests.cpp new file mode 100644 index 0000000000..86bb9b822e --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_reader_exception_tests.cpp @@ -0,0 +1,252 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +TEST_CASE("test_filename_invalid") +{ + std::string in_file = "./input/json-exception--1.json"; + std::ifstream is(in_file); + + json_decoder decoder; + + try + { + json_reader reader(is,decoder); + reader.read_next(); + } + catch (const std::exception&) + { + } + //CHECK(false == decoder.is_valid()); +} + +TEST_CASE("test_exception_left_brace") +{ + std::string in_file = "./input/json-exception-1.json"; + std::ifstream is(in_file); + + json_decoder decoder; + try + { + json_reader reader(is,decoder); + reader.read_next(); + } + catch (const ser_error& e) + { + CHECK(e.code() == json_errc::expected_comma_or_right_bracket); + CHECK(14 == e.line()); + CHECK(30 == e.column()); + } + CHECK(false == decoder.is_valid()); +} +TEST_CASE("test_exception_right_brace") +{ + std::string in_file = "./input/json-exception-2.json"; + std::ifstream is(in_file); + + json_decoder decoder; + try + { + json_reader reader(is,decoder); + reader.read_next(); // must throw + CHECK(0 != 0); + } + catch (const ser_error& e) + { + //std::cout << e.what() << std::endl; + CHECK(e.code() == json_errc::expected_comma_or_right_brace); + CHECK(17 == e.line()); + CHECK(9 == e.column()); + } + CHECK(false == decoder.is_valid()); +} + +TEST_CASE("test_exception_array_eof") +{ + std::istringstream is("[100"); + + json_decoder decoder; + try + { + json_reader reader(is,decoder); + reader.read_next(); // must throw + CHECK(0 != 0); + } + catch (const ser_error& e) + { + CHECK(e.code() == json_errc::unexpected_eof); + CHECK(1 == e.line()); + CHECK(5 == e.column()); + } + CHECK(false == decoder.is_valid()); +} + +TEST_CASE("test_exception_unicode_eof") +{ + std::istringstream is("[\"\\u"); + + json_decoder decoder; + try + { + json_reader reader(is,decoder); + reader.read_next(); // must throw + CHECK(0 != 0); + } + catch (const ser_error& e) + { + //std::cout << e.what() << std::endl; + CHECK(e.code() == json_errc::unexpected_eof); + CHECK(1 == e.line()); + CHECK(5 == e.column()); + } + CHECK(false == decoder.is_valid()); +} + +TEST_CASE("test_exception_tru_eof") +{ + std::istringstream is("[tru"); + + json_decoder decoder; + try + { + json_reader reader(is,decoder); + reader.read_next(); // must throw + CHECK(0 != 0); + } + catch (const ser_error& e) + { + //std::cout << e.what() << std::endl; + CHECK(e.code() == json_errc::unexpected_eof); + CHECK(1 == e.line()); + CHECK(5 == e.column()); + } + CHECK(false == decoder.is_valid()); +} + +TEST_CASE("test_exception_fals_eof") +{ + std::istringstream is("[fals"); + + json_decoder decoder; + try + { + json_reader reader(is,decoder); + reader.read_next(); // must throw + CHECK(0 != 0); + } + catch (const ser_error& e) + { + //std::cout << e.what() << std::endl; + CHECK(e.code() == json_errc::unexpected_eof); + CHECK(1 == e.line()); + CHECK(6 == e.column()); + } + CHECK(false == decoder.is_valid()); +} + +TEST_CASE("test_exception_nul_eof") +{ + std::istringstream is("[nul"); + + json_decoder decoder; + try + { + json_reader reader(is,decoder); + reader.read_next(); // must throw + CHECK(0 != 0); + } + catch (const ser_error& e) + { + //std::cout << e.what() << std::endl; + CHECK(e.code() == json_errc::unexpected_eof); + CHECK(1 == e.line()); + CHECK(5 == e.column()); + } + CHECK(false == decoder.is_valid()); +} + +TEST_CASE("test_exception_true_eof") +{ + std::istringstream is("[true"); + + json_decoder decoder; + try + { + json_reader reader(is,decoder); + reader.read_next(); // must throw + CHECK(0 != 0); + } + catch (const ser_error& e) + { + CHECK(e.code() == json_errc::unexpected_eof); + CHECK(1 == e.line()); + CHECK(6 == e.column()); + } + CHECK(false == decoder.is_valid()); +} + +TEST_CASE("test_exception_false_eof") +{ + std::istringstream is("[false"); + + json_decoder decoder; + try + { + json_reader reader(is,decoder); + reader.read_next(); // must throw + CHECK(0 != 0); + } + catch (const ser_error& e) + { + CHECK(e.code() == json_errc::unexpected_eof); + CHECK(1 == e.line()); + CHECK(7 == e.column()); + } + CHECK(false == decoder.is_valid()); +} + +TEST_CASE("test_exception_null_eof") +{ + std::istringstream is("[null"); + + json_decoder decoder; + try + { + json_reader reader(is,decoder); + reader.read_next(); // must throw + CHECK(0 != 0); + } + catch (const ser_error& e) + { + CHECK(e.code() == json_errc::unexpected_eof); + CHECK(1 == e.line()); + CHECK(6 == e.column()); + } + CHECK(false == decoder.is_valid()); +} + +TEST_CASE("test_exception") +{ + std::string input("{\"field1\":\n\"value}"); + REQUIRE_THROWS_AS(json::parse(input),ser_error); + try + { + json::parse(input); + } + catch (const ser_error& e) + { + CHECK((e.code() == json_errc::unexpected_eof && e.line() == 2 && e.column() == 9)); + } +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_reader_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_reader_tests.cpp new file mode 100644 index 0000000000..a27c7a1ceb --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_reader_tests.cpp @@ -0,0 +1,226 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +void test_json_reader_error(const std::string& text, std::error_code ec) +{ + REQUIRE_THROWS(json::parse(text)); + try + { + json::parse(text); + } + catch (const ser_error& e) + { + if (e.code() != ec) + { + std::cout << text << std::endl; + std::cout << e.code().value() << " " << e.what() << std::endl; + } + CHECK(ec == e.code()); + } +} + +void test_json_reader_ec(const std::string& text, std::error_code expected) +{ + std::error_code ec; + + std::istringstream is(text); + json_decoder decoder; + json_reader reader(is,decoder); + + reader.read(ec); + //std::cerr << text << std::endl; + //std::cerr << ec.message() + // << " at line " << reader.line() + // << " and column " << reader.column() << std::endl; + + CHECK(ec); + CHECK(ec == expected); +} + +TEST_CASE("test_missing_separator") +{ + std::string jtext = R"({"field1"{}})"; + + test_json_reader_error(jtext, jsoncons::json_errc::expected_colon); + test_json_reader_ec(jtext, jsoncons::json_errc::expected_colon); +} + +TEST_CASE("test_read_invalid_value") +{ + std::string jtext = R"({"field1":ru})"; + + test_json_reader_error(jtext,jsoncons::json_errc::expected_value); + test_json_reader_ec(jtext, jsoncons::json_errc::expected_value); +} + +TEST_CASE("test_read_unexpected_end_of_file") +{ + std::string jtext = R"({"field1":{})"; + + test_json_reader_error(jtext, jsoncons::json_errc::unexpected_eof); + test_json_reader_ec(jtext, jsoncons::json_errc::unexpected_eof); +} + + +TEST_CASE("test_read_value_not_found") +{ + std::string jtext = R"({"name":})"; + + test_json_reader_error(jtext, jsoncons::json_errc::expected_value); + test_json_reader_ec(jtext, jsoncons::json_errc::expected_value); +} + +TEST_CASE("test_read_escaped_characters") +{ + std::string input("[\"\\n\\b\\f\\r\\t\"]"); + std::string expected("\n\b\f\r\t"); + + json o = json::parse(input); + CHECK(expected == o[0].as()); +} + + +TEST_CASE("test_read_expected_colon") +{ + test_json_reader_error("{\"name\" 10}", jsoncons::json_errc::expected_colon); + test_json_reader_error("{\"name\" true}", jsoncons::json_errc::expected_colon); + test_json_reader_error("{\"name\" false}", jsoncons::json_errc::expected_colon); + test_json_reader_error("{\"name\" null}", jsoncons::json_errc::expected_colon); + test_json_reader_error("{\"name\" \"value\"}", jsoncons::json_errc::expected_colon); + test_json_reader_error("{\"name\" {}}", jsoncons::json_errc::expected_colon); + test_json_reader_error("{\"name\" []}", jsoncons::json_errc::expected_colon); +} + +TEST_CASE("test_read_expected_name") +{ + test_json_reader_error("{10}", jsoncons::json_errc::expected_name); + test_json_reader_error("{true}", jsoncons::json_errc::expected_name); + test_json_reader_error("{false}", jsoncons::json_errc::expected_name); + test_json_reader_error("{null}", jsoncons::json_errc::expected_name); + test_json_reader_error("{{}}", jsoncons::json_errc::expected_name); + test_json_reader_error("{[]}", jsoncons::json_errc::expected_name); +} + +TEST_CASE("test_read_expected_value") +{ + test_json_reader_error("[tru]", jsoncons::json_errc::invalid_value); + test_json_reader_error("[fa]", jsoncons::json_errc::invalid_value); + test_json_reader_error("[n]", jsoncons::json_errc::invalid_value); +} + +TEST_CASE("test_read_primitive_pass") +{ + json val; + CHECK_NOTHROW((val=json::parse("null"))); + CHECK(val == json::null()); + CHECK_NOTHROW((val=json::parse("false"))); + CHECK(val == json(false)); + CHECK_NOTHROW((val=json::parse("true"))); + CHECK(val == json(true)); + CHECK_NOTHROW((val=json::parse("10"))); + CHECK(val == json(10)); + CHECK_NOTHROW((val=json::parse("1.999"))); + CHECK(val == json(1.999)); + CHECK_NOTHROW((val=json::parse("\"string\""))); + CHECK(val == json("string")); +} + +TEST_CASE("test_read_empty_structures") +{ + json val; + CHECK_NOTHROW((val=json::parse("{}"))); + CHECK_NOTHROW((val=json::parse("[]"))); + CHECK_NOTHROW((val=json::parse("{\"object\":{},\"array\":[]}"))); + CHECK_NOTHROW((val=json::parse("[[],{}]"))); +} + +TEST_CASE("test_read_primitive_fail") +{ + test_json_reader_error("null {}", jsoncons::json_errc::extra_character); + test_json_reader_error("n ", jsoncons::json_errc::invalid_value); + test_json_reader_error("nu ", jsoncons::json_errc::invalid_value); + test_json_reader_error("nul ", jsoncons::json_errc::invalid_value); + test_json_reader_error("false {}", jsoncons::json_errc::extra_character); + test_json_reader_error("fals ", jsoncons::json_errc::invalid_value); + test_json_reader_error("true []", jsoncons::json_errc::extra_character); + test_json_reader_error("tru ", jsoncons::json_errc::invalid_value); + test_json_reader_error("10 {}", jsoncons::json_errc::extra_character); + test_json_reader_error("1a ", jsoncons::json_errc::invalid_number); + test_json_reader_error("1.999 []", jsoncons::json_errc::extra_character); + test_json_reader_error("1e0-1", jsoncons::json_errc::invalid_number); + test_json_reader_error("\"string\"{}", jsoncons::json_errc::extra_character); + test_json_reader_error("\"string\"[]", jsoncons::json_errc::extra_character); +} + +TEST_CASE("test_read_multiple") +{ + std::string in="{\"a\":1,\"b\":2,\"c\":3}{\"a\":4,\"b\":5,\"c\":6}"; + //std::cout << in << std::endl; + + std::istringstream is(in); + + jsoncons::json_decoder decoder; + json_reader reader(is,decoder); + + REQUIRE_FALSE(reader.eof()); + reader.read_next(); + json val = decoder.get_result(); + CHECK(1 == val["a"].as()); + REQUIRE_FALSE(reader.eof()); + reader.read_next(); + json val2 = decoder.get_result(); + CHECK(4 == val2["a"].as()); + CHECK(reader.eof()); +} + +TEST_CASE("json_reader read from string test") +{ + std::string s = R"( +{ + "store": { + "book": [ + { + "category": "reference", + "author": "Margaret Weis", + "title": "Dragonlance Series", + "price": 31.96 + }, + { + "category": "reference", + "author": "Brent Weeks", + "title": "Night Angel Trilogy", + "price": 14.70 + } + ] + } +} +)"; + + json_decoder decoder; + json_reader reader(s, decoder); + reader.read(); + json j = decoder.get_result(); + + REQUIRE(j.is_object()); + REQUIRE(j.size() == 1); + REQUIRE(j[0].is_object()); + REQUIRE(j[0].size() == 1); + REQUIRE(j[0][0].is_array()); + REQUIRE(j[0][0].size() == 2); + CHECK(j[0][0][0]["category"].as() == std::string("reference")); + CHECK(j[0][0][1]["author"].as() == std::string("Brent Weeks")); +} + + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_swap_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_swap_tests.cpp new file mode 100644 index 0000000000..481b71bcf9 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_swap_tests.cpp @@ -0,0 +1,149 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +void check_swap(const json& j1, const json& j2) +{ + json j3 = j1; + json j4 = j2; + + j3.swap(j4); + CHECK(j1 == j4); + CHECK(j2 == j3); +} + +TEST_CASE("test_swap") +{ + json j1 = json::null(); + json j2 = false; + json j3 = -2000; + json j4 = 2000U; + json j5 = 2000.1234; + json j6 = "Small"; + json j7 = "String too large for small string"; + json j8 = json::parse("[1,2,3,4]"); + json j9; + json j10 = json::object(); + j10["Name"] = "John Smith"; + + check_swap(j1,j1); + check_swap(j1,j2); + check_swap(j1,j3); + check_swap(j1,j4); + check_swap(j1,j5); + check_swap(j1,j6); + check_swap(j1,j7); + check_swap(j1,j8); + check_swap(j1,j9); + check_swap(j1,j10); + + check_swap(j2,j1); + check_swap(j2,j2); + check_swap(j2,j3); + check_swap(j2,j4); + check_swap(j2,j5); + check_swap(j2,j6); + check_swap(j2,j7); + check_swap(j2,j8); + check_swap(j2,j9); + check_swap(j2,j10); + + check_swap(j3,j1); + check_swap(j3,j2); + check_swap(j3,j3); + check_swap(j3,j4); + check_swap(j3,j5); + check_swap(j3,j6); + check_swap(j3,j7); + check_swap(j3,j8); + check_swap(j3,j9); + check_swap(j3,j10); + + check_swap(j4,j1); + check_swap(j4,j2); + check_swap(j4,j3); + check_swap(j4,j4); + check_swap(j4,j5); + check_swap(j4,j6); + check_swap(j4,j7); + check_swap(j4,j8); + check_swap(j4,j9); + check_swap(j4,j10); + + check_swap(j5,j1); + check_swap(j5,j2); + check_swap(j5,j3); + check_swap(j5,j4); + check_swap(j5,j5); + check_swap(j5,j6); + check_swap(j5,j7); + check_swap(j5,j8); + check_swap(j5,j9); + check_swap(j5,j10); + + check_swap(j6,j1); + check_swap(j6,j2); + check_swap(j6,j3); + check_swap(j6,j4); + check_swap(j6,j5); + check_swap(j6,j6); + check_swap(j6,j7); + check_swap(j6,j8); + check_swap(j6,j9); + check_swap(j6,j10); + + check_swap(j7,j1); + check_swap(j7,j2); + check_swap(j7,j3); + check_swap(j7,j4); + check_swap(j7,j5); + check_swap(j7,j6); + check_swap(j7,j7); + check_swap(j7,j8); + check_swap(j7,j9); + check_swap(j7,j10); + + check_swap(j8,j1); + check_swap(j8,j2); + check_swap(j8,j3); + check_swap(j8,j4); + check_swap(j8,j5); + check_swap(j8,j6); + check_swap(j8,j7); + check_swap(j8,j8); + check_swap(j8,j9); + check_swap(j8,j10); + + check_swap(j9,j1); + check_swap(j9,j2); + check_swap(j9,j3); + check_swap(j9,j4); + check_swap(j9,j5); + check_swap(j9,j6); + check_swap(j9,j7); + check_swap(j9,j8); + check_swap(j9,j9); + check_swap(j9,j10); + + check_swap(j10,j1); + check_swap(j10,j2); + check_swap(j10,j3); + check_swap(j10,j4); + check_swap(j10,j5); + check_swap(j10,j6); + check_swap(j10,j7); + check_swap(j10,j8); + check_swap(j10,j9); + check_swap(j10,j10); +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_type_traits_container_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_type_traits_container_tests.cpp new file mode 100644 index 0000000000..5c87bd43c3 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_type_traits_container_tests.cpp @@ -0,0 +1,373 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +TEST_CASE("test_json_as_pair") +{ + json j = json::array{false,1}; + auto t = j.as>(); + CHECK(std::get<0>(t) == false); + CHECK(std::get<1>(t) == 1); +} + +TEST_CASE("test_tuple_to_json") +{ + auto t = std::make_tuple(false,1,"foo"); + json j(t); + + REQUIRE(j.is_array()); + REQUIRE(j.size() == 3); + CHECK(false == j[0].as()); + CHECK(1 == j[1].as()); + CHECK(std::string("foo") == j[2].as()); +} + +TEST_CASE("test_json_as_tuple") +{ + json j = json::array{false,1,"foo"}; + + auto t = j.as>(); + + CHECK(std::get<0>(t) == false); + CHECK(std::get<1>(t) == 1); + CHECK(std::get<2>(t) == std::string("foo")); +} + +TEST_CASE("test_characters") +{ + const json a = "short"; + const json b = "a long string"; + + CHECK(true == a.is()); + CHECK(true == b.is()); + + std::string s2 = a.as(); + std::string t2 = b.as(); + + json c = json::array{ "short","a long string" }; + auto u = c.as>(); +} + +// vector + +TEST_CASE("test_is_json_vector") +{ + json a = json::array{0,1,2,3,4}; + + CHECK(true == a.is>()); +} + +TEST_CASE("test_as_vector") +{ + json a = json::array{0,1,2,3,4}; + std::vector v = a.as>(); + + CHECK(v[0] == 0); + CHECK(v[1] == 1); + CHECK(v[2] == 2); + CHECK(v[3] == 3); + CHECK(v[4] == 4); +} + +TEST_CASE("test_assign_vector") +{ + std::vector v {0,1,2,3,4}; + json a = v; + + CHECK(a[0] == json(0)); + CHECK(a[1] == json(1)); + CHECK(a[2] == json(2)); + CHECK(a[3] == json(3)); + CHECK(a[4] == json(4)); +} + +TEST_CASE("test_as_vector_of_bool") +{ + json a = json::parse("[true,false,true]"); + + std::vector v = a.as>(); + + CHECK(v[0] == true); + CHECK(v[1] == false); + CHECK(v[2] == true); +} + +TEST_CASE("test_assign_vector_of_bool") +{ + std::vector v = {true,false,true}; + json a = v; + + CHECK(a[0] == json(true)); + CHECK(a[1] == json(false)); + CHECK(a[2] == json(true)); + + json b; + b = v; + + CHECK(b[0] == json(true)); + CHECK(b[1] == json(false)); + CHECK(b[2] == json(true)); +} + +TEST_CASE("test_construct_vector_of_bool") +{ + std::vector v = {true,false,true}; + json a = v; + + CHECK(a[0] == json(true)); + CHECK(a[1] == json(false)); + CHECK(a[2] == json(true)); +} + +TEST_CASE("test_construct_const_vector_of_bool") +{ + const std::vector v = {true,false,true}; + json a = v; + + CHECK(a[0] == json(true)); + CHECK(a[1] == json(false)); + CHECK(a[2] == json(true)); +} + +// valarray + +TEST_CASE("test_is_json_valarray") +{ + json a = json::array{0,1,2,3,4}; + + CHECK(true == a.is>()); +} + +TEST_CASE("test_as_valarray") +{ + json a = json::array{0,1,2,3,4}; + std::valarray v = a.as>(); + + CHECK(v[0] == 0); + CHECK(v[1] == 1); + CHECK(v[2] == 2); + CHECK(v[3] == 3); + CHECK(v[4] == 4); +} + +TEST_CASE("test_assign_valarray") +{ + std::valarray v {0,1,2,3,4}; + json a = v; + + CHECK(a[0] == json(0)); + CHECK(a[1] == json(1)); + CHECK(a[2] == json(2)); + CHECK(a[3] == json(3)); + CHECK(a[4] == json(4)); +} + +TEST_CASE("test_is_json_map") +{ + json a; + a["a"] = 0; + a["b"] = 1; + a["c"] = 2; + + CHECK(true == (a.is >())); +} + +TEST_CASE("test_is_json_map2") +{ + json a; + a["a"] = "0"; + a["b"] = "1"; + a["c"] = "2"; + + CHECK(true == (a["a"].is_string())); + + json b("0"); + CHECK(true == (b.is())); + + CHECK(true == (a["a"].is())); + + CHECK(true == (a.is >())); +} + +TEST_CASE("test_as_map") +{ + json o; + o["first"] = "first"; + o["second"] = "second"; + + auto m = o.as>(); + CHECK(std::string("first") == m.at("first")); + CHECK(std::string("second") == m.at("second")); + + json o2(m); + CHECK(o == o2); + + json o3; + o3 = m; + CHECK(o == o3); +} + +TEST_CASE("test_as_map2") +{ + json o; + o["first"] = 1; + o["second"] = true; + o["third"] = jsoncons::null_type(); + + auto m = o.as>(); + CHECK(std::string("1") == m.at("first")); + CHECK(std::string("true") == m.at("second")); + CHECK(std::string("null") == m.at("third")); + + json o2(m); + CHECK(std::string("1") == o2["first"].as()); +} + +TEST_CASE("test_from_stl_container") +{ + std::vector a_vector{1, 2, 3, 4}; + json j_vector(a_vector); + CHECK((1 == j_vector[0].as())); + CHECK(2 == j_vector[1].as()); + CHECK(3 == j_vector[2].as()); + CHECK(4 == j_vector[3].as()); + + std::vector a_vector2{1ul, 2ul, 3ul, 4ul}; + json j_vec2(a_vector2); + CHECK(1 == j_vec2[0].as()); + CHECK(2 == j_vec2[1].as()); + CHECK(3 == j_vec2[2].as()); + CHECK(4 == j_vec2[3].as()); + + std::deque a_deque{1.123, 2.234, 3.456, 4.567}; + json j_deque(a_deque); + CHECK(1.123 == j_deque[0].as()); + CHECK(2.234 == j_deque[1].as()); + CHECK(3.456 == j_deque[2].as()); + CHECK(4.567 == j_deque[3].as()); + + std::list a_list{true, true, false, true}; + json j_list(a_list); + CHECK(true == j_list[0].as()); + CHECK(true == j_list[1].as()); + CHECK(false == j_list[2].as()); + CHECK(true == j_list[3].as()); + + std::forward_lista_flist {12345678909876, 23456789098765, 34567890987654, 45678909876543}; + json j_flist(a_flist); + CHECK(static_cast(12345678909876) == j_flist[0].as()); + CHECK(static_cast(23456789098765) == j_flist[1].as()); + CHECK(static_cast(34567890987654) == j_flist[2].as()); + CHECK(static_cast(45678909876543) == j_flist[3].as()); + + std::array a_array {{1, 2, 3, 4}}; + json j_array(a_array); + CHECK(1 == j_array[0].as()); + CHECK(2 == j_array[1].as()); + CHECK(3 == j_array[2].as()); + CHECK(4 == j_array[3].as()); + + std::set a_set{"one", "two", "three", "four", "one"}; + json j_set(a_set); // only one entry for "one" is used + // ["four", "one", "three", "two"] + + std::unordered_set a_uset{"one", "two", "three", "four", "one"}; + json j_uset(a_uset); // only one entry for "one" is used + // maybe ["two", "three", "four", "one"] + + std::multiset a_mset{"one", "two", "one", "four"}; + json j_mset(a_mset); // only one entry for "one" is used + // maybe ["one", "two", "four"] + + std::unordered_multiset a_umset {"one", "two", "one", "four"}; + json j_umset(a_umset); // both entries for "one" are used + // maybe ["one", "two", "one", "four"] + + std::map a_map{ {"one", 1}, {"two", 2}, {"three", 3} }; + json j_map(a_map); + CHECK(1 == j_map["one"].as()); + CHECK(2 == j_map["two"].as()); + CHECK(3 == j_map["three"].as()); + + std::unordered_map a_umap{ {"one", 1.2}, {"two", 2.3}, {"three", 3.4} }; + json j_umap(a_umap); + CHECK(1.2 == j_umap["one"].as()); + CHECK(2.3 == j_umap["two"].as()); + CHECK(3.4 == j_umap["three"].as()); + + std::multimap a_mmap{ {"one", true}, {"two", true}, {"three", false}, {"three", true} }; + json j_mmap(a_mmap); // one entry for key "three" + CHECK(true == j_mmap.find("one")->value().as()); + CHECK(true == j_mmap.find("two")->value().as()); + CHECK(false == j_mmap.find("three")->value().as()); + + std::unordered_multimap a_ummap { {"one", true}, {"two", true}, /*{"three", false},*/ {"three", true} }; + json j_ummap(a_ummap); // two entries for key "three" + CHECK(true == j_ummap.find("one")->value().as()); + CHECK(true == j_ummap.find("two")->value().as()); + CHECK(true == j_ummap.find("three")->value().as()); +} + +//own vector will always be of an even length +struct own_vector : std::vector { using std::vector::vector; }; + +namespace jsoncons { +template +struct json_type_traits { + static bool is(const Json& j) noexcept + { + return j.is_object() && j.size() % 2 == 0; + } + static own_vector as(const Json& j) + { + own_vector v; + for (auto& item : j.object_range()) + { + std::string s(item.key()); + v.push_back(std::strtol(s.c_str(),nullptr,10)); + v.push_back(item.value().template as()); + } + return v; + } + static Json to_json(const own_vector& val){ + Json j; + for(size_t i=0;i +struct is_json_type_traits_declared : public std::true_type +{}; +} // jsoncons + +TEST_CASE("own_vector json_type_traits") +{ + json j = json::object{ {"1",2},{"3",4} }; + REQUIRE(j.is()); + auto v = j.as(); + REQUIRE(v.size() == 4); + json j2 = v; + CHECK(j2 == j); +} diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_type_traits_macros_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_type_traits_macros_tests.cpp new file mode 100644 index 0000000000..76490605e0 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_type_traits_macros_tests.cpp @@ -0,0 +1,153 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#if defined(_MSC_VER) +#include "windows.h" // test no inadvertant macro expansions +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +namespace json_type_traits_macros_tests { + + struct book + { + std::string author; + std::string title; + double price; + }; + struct book2 + { + std::string author; + std::string title; + double price; + std::string isbn; + }; + class book3 + { + std::string author_; + std::string title_; + double price_; + public: + book3() = default; + + book3(const std::string& author, + const std::string& title, + double price) + : author_(author), title_(title), price_(price) + { + } + + book3(const book3&) = default; + book3(book3&&) = default; + book3& operator=(const book3&) = default; + book3& operator=(book3&&) = default; + + const std::string& author() const + { + return author_; + } + + const std::string& title() const + { + return title_; + } + + double price() const + { + return price_; + } + }; + +} // namespace jsoncons_member_traits_decl_tests + +namespace ns = json_type_traits_macros_tests; + +JSONCONS_GETTER_CTOR_TRAITS_DECL(ns::book3, author, title, price) +JSONCONS_MEMBER_TRAITS_DECL(ns::book,author,title,price) +JSONCONS_MEMBER_TRAITS_DECL(ns::book2,author,title,price,isbn) + +TEST_CASE("JSONCONS_MEMBER_TRAITS_DECL tests") +{ + std::string an_author = "Haruki Murakami"; + std::string a_title = "Kafka on the Shore"; + double a_price = 25.17; + + ns::book book{an_author, a_title, a_price}; + + SECTION("book") + { + std::string s; + + encode_json(book, s); + + json j = decode_json(s); + + REQUIRE(j.is() == true); + REQUIRE(j.is() == false); + + CHECK(j["author"].as() == an_author); + CHECK(j["title"].as() == a_title); + CHECK(j["price"].as() == Approx(a_price).epsilon(0.001)); + + json j2(book); + + CHECK(j == j2); + + ns::book val = j.as(); + + CHECK(val.author == book.author); + CHECK(val.title == book.title); + CHECK(val.price == Approx(book.price).epsilon(0.001)); + } +} + +TEST_CASE("JSONCONS_GETTER_CTOR_TRAITS_DECL tests") +{ + std::string an_author = "Haruki Murakami"; + std::string a_title = "Kafka on the Shore"; + double a_price = 25.17; + + SECTION("is") + { + json j; + j["author"] = an_author; + j["title"] = a_title; + j["price"] = a_price; + + bool val = j.is(); + CHECK(val == true); + } + SECTION("to_json") + { + ns::book3 book(an_author,a_title,a_price); + + json j(book); + + CHECK(j["author"].as() == an_author); + CHECK(j["title"].as() == a_title); + CHECK(j["price"].as() == Approx(a_price).epsilon(0.001)); + } + + SECTION("as") + { + json j; + j["author"] = an_author; + j["title"] = a_title; + j["price"] = a_price; + + ns::book3 book = j.as(); + + CHECK(book.author() == an_author); + CHECK(book.title() == a_title); + CHECK(book.price() == Approx(a_price).epsilon(0.001)); + } +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_type_traits_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_type_traits_tests.cpp new file mode 100644 index 0000000000..321218da89 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_type_traits_tests.cpp @@ -0,0 +1,141 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#if defined(_MSC_VER) +#include "windows.h" // test no inadvertant macro expansions +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; +// own vector will always be of an even length +struct own_vector : std::vector { using std::vector::vector; }; + +namespace jsoncons { +template +struct json_type_traits { + static bool is(const Json&) noexcept { return true; } + static own_vector as(const Json&) { return own_vector(); } + static Json to_json(const own_vector& val) { + Json j; + for (uint64_t i = 0; i(p); + + root["Test"] = q; +} + +TEST_CASE("test_uint8_t") +{ + uint8_t x = 10; + + json o; + o["u"] = x; + + CHECK(o["u"].is_number()); + + uint8_t y = o["u"].as(); + + CHECK(y == 10); +} + +TEST_CASE("test_float_assignment") +{ + float x = 10.5; + + json o; + o["float"] = x; + + CHECK(o["float"].is_number()); + + float y = o["float"].as(); + + CHECK(10.5 == Approx(y).epsilon(0.00001)); +} + +TEST_CASE("test_float") +{ + float x = 10.5; + + json o(x); + + CHECK(o.is()); + + float y = o.as(); + + CHECK(10.5 == Approx(y).epsilon(0.00001)); +} + +TEST_CASE("test_unsupported_type") +{ + json o; + + //o["u"] = Info; + // compile error +} + +TEST_CASE("test_as_json_value") +{ + json a; + + a["first"] = "first"; + a["second"] = "second"; + + CHECK(true == a.is()); + + json b = a.as(); + CHECK("first" == b["first"].as()); + CHECK("second" == b["second"].as()); +} + +TEST_CASE("test_byte_string_as_vector") +{ + json a(byte_string{'H','e','l','l','o'}); + + REQUIRE(a.is_byte_string()); + + auto bs = a.as(); + + REQUIRE(5 == bs.size()); + CHECK('H' == bs[0]); + CHECK('e' == bs[1]); + CHECK('l' == bs[2]); + CHECK('l' == bs[3]); + CHECK('o' == bs[4]); +} +/* +TEST_CASE("test_own_vector") +{ + jsoncons::json j = own_vector({0,9,8,7}); + std::cout << j; +} +*/ + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_variant_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_variant_tests.cpp new file mode 100644 index 0000000000..b7e163dc3a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/json_variant_tests.cpp @@ -0,0 +1,209 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include + +using namespace jsoncons; + +TEST_CASE("test_variant") +{ + json::variant var1(int64_t(-100), semantic_tag::none); + CHECK(storage_type::int64_val == var1.get_storage_type()); + json::variant var2(uint64_t(100), semantic_tag::none); + CHECK(storage_type::uint64_val == var2.get_storage_type()); + json::variant var3("Small string", 12, semantic_tag::none); + CHECK(storage_type::short_string_val == var3.get_storage_type()); + json::variant var4("Too long to fit in small string", 31, semantic_tag::none); + CHECK(storage_type::long_string_val == var4.get_storage_type()); + json::variant var5(true, semantic_tag::none); + CHECK(storage_type::bool_val == var5.get_storage_type()); + json::variant var6(semantic_tag::none); + CHECK(storage_type::empty_object_val == var6.get_storage_type()); + json::variant var7{ null_type(), semantic_tag::none }; + CHECK(storage_type::null_val == var7.get_storage_type()); + json::variant var8{ json::object(json::allocator_type()), semantic_tag::none }; + CHECK(storage_type::object_val == var8.get_storage_type()); + json::variant var9(123456789.9, semantic_tag::none); + CHECK(storage_type::double_val == var9.get_storage_type()); +} + +TEST_CASE("test_move_constructor") +{ + int64_t val1 = -100; + json::variant var1(val1, semantic_tag::none); + json::variant var2(std::move(var1)); + //CHECK(storage_type::null_val == var1.get_storage_type()); + CHECK(storage_type::int64_val == var2.get_storage_type()); + CHECK(var2.int64_data_cast()->value() == val1); + + uint64_t val3 = 9999; + json::variant var3(val3, semantic_tag::none); + json::variant var4(std::move(var3)); + //CHECK(storage_type::null_val == var3.get_storage_type()); + CHECK(storage_type::uint64_val == var4.get_storage_type()); + CHECK(var4.uint64_data_cast()->value() == val3); + + double val5 = 123456789.9; + json::variant var5(val5, semantic_tag::none); + json::variant var6(std::move(var5)); + //CHECK(storage_type::null_val == var5.get_storage_type()); + CHECK(storage_type::double_val == var6.get_storage_type()); + CHECK(var6.double_data_cast()->value() == val5); + + std::string val7("Too long for small string"); + json::variant var7(val7.data(), val7.length(), semantic_tag::none); + json::variant var8(std::move(var7)); + //CHECK(storage_type::null_val == var7.get_storage_type()); + CHECK(storage_type::long_string_val == var8.get_storage_type()); + CHECK(val7 == var8.string_data_cast()->data()); + CHECK(val7.length() == var8.string_data_cast()->length()); + + std::string val9("Small string"); + json::variant var9(val9.data(), val9.length(), semantic_tag::none); + json::variant var10(std::move(var9)); + //CHECK(storage_type::null_val == var9.get_storage_type()); + CHECK(storage_type::short_string_val == var10.get_storage_type()); + CHECK(val9 == var10.short_string_data_cast()->data()); + CHECK(val9.length() == var10.short_string_data_cast()->length()); + + bool val11 = true; + json::variant var11(val11, semantic_tag::none); + json::variant var12(std::move(var11)); + //CHECK(storage_type::null_val == var11.get_storage_type()); + CHECK(storage_type::bool_val == var12.get_storage_type()); + CHECK(var12.bool_data_cast()->value() == val11); + + std::string val13("Too long for small string"); + json::variant var13(val13.data(), val13.length(), semantic_tag::none); + json::variant var14(std::move(var13)); + //CHECK(storage_type::null_val == var13.get_storage_type()); + CHECK(storage_type::long_string_val == var14.get_storage_type()); + CHECK(val13 == var14.string_data_cast()->data()); + + json::object val15 = { {"first",1},{"second",2} }; + json::variant var15(val15, semantic_tag::none); + json::variant var16(std::move(var15)); + CHECK(storage_type::null_val == var15.get_storage_type()); + CHECK(storage_type::object_val == var16.get_storage_type()); + CHECK(val15 == var16.object_data_cast()->value()); + + json::array val17 = {1,2,3,4}; + json::variant var17(val17, semantic_tag::none); + json::variant var18(std::move(var17)); + CHECK(storage_type::null_val == var17.get_storage_type()); + CHECK(storage_type::array_val == var18.get_storage_type()); + CHECK(val17 == var18.array_data_cast()->value()); +} + +TEST_CASE("test_copy_constructor") +{ + int64_t val1 = 123456789; + json::variant var1(val1, semantic_tag::none); + json::variant var2(var1); + CHECK(storage_type::int64_val == var1.get_storage_type()); + CHECK(storage_type::int64_val == var2.get_storage_type()); + CHECK(var2.int64_data_cast()->value() == val1); + + uint64_t val3 = 123456789; + json::variant var3(val3, semantic_tag::none); + json::variant var4(var3); + CHECK(storage_type::uint64_val == var3.get_storage_type()); + CHECK(storage_type::uint64_val == var4.get_storage_type()); + CHECK(var4.uint64_data_cast()->value() == val3); + + double val5 = 123456789.9; + json::variant var5(val5, semantic_tag::none); + json::variant var6(var5); + CHECK(storage_type::double_val == var5.get_storage_type()); + CHECK(storage_type::double_val == var6.get_storage_type()); + CHECK(var6.double_data_cast()->value() == val5); + + std::string val9 = "Small string"; + json::variant var9(val9.data(), val9.length(), semantic_tag::none); + json::variant var10(var9); + CHECK(storage_type::short_string_val == var9.get_storage_type()); + CHECK(storage_type::short_string_val == var10.get_storage_type()); + CHECK(var10.short_string_data_cast()->data() == val9); + + bool val11 = true; + json::variant var11(val11, semantic_tag::none); + json::variant var12(var11); + CHECK(storage_type::bool_val == var11.get_storage_type()); + CHECK(storage_type::bool_val == var12.get_storage_type()); + CHECK(var12.bool_data_cast()->value() == val11); + + std::string val13 = "Too long for small string"; + json::variant var13(val13.data(), val13.length(), semantic_tag::none); + json::variant var14(var13); + CHECK(storage_type::long_string_val == var13.get_storage_type()); + CHECK(storage_type::long_string_val == var14.get_storage_type()); + CHECK(var14.string_data_cast()->data() == val13); + + json::object val15 = { {"first",1},{"second",2} }; + json::variant var15(val15, semantic_tag::none); + json::variant var16(var15); + CHECK(storage_type::object_val == var15.get_storage_type()); + CHECK(storage_type::object_val == var16.get_storage_type()); + CHECK(val15 == var16.object_data_cast()->value()); + + json::array val17 = {1,2,3,4}; + json::variant var17(val17, semantic_tag::none); + json::variant var18(var17); + CHECK(storage_type::array_val == var17.get_storage_type()); + CHECK(storage_type::array_val == var18.get_storage_type()); + CHECK(val17 == var18.array_data_cast()->value()); +} + +TEST_CASE("test_equals") +{ + json::variant var1(semantic_tag::none); + json::variant var2{ json::object(), semantic_tag::none }; + CHECK((var1 == var1 && var2 == var2)); + CHECK((var1 == var2 && var2 == var1)); + + json::variant var3{semantic_tag::none }; + CHECK((var3 == var1 && var1 == var3)); + json::variant var4{ json::object({{"first",1},{"second",2}}), semantic_tag::none }; + json::variant var5{ json::object({ { "first",1 },{ "second",2 } }), semantic_tag::none }; + CHECK((var3 != var4 && var4 != var3)); + CHECK((var2 != var4 && var4 != var2)); + CHECK(var4 == var4); + CHECK(var4 == var5); + CHECK(var5 == var4); + + json::variant var6(int64_t(100), semantic_tag::none); + json::variant var7(uint64_t(100), semantic_tag::none); + CHECK((var6 == var7 && var7 == var6)); + + json::variant var8(100.0, semantic_tag::none); + CHECK((var8 == var8 && var6 == var8 && var8 == var6 && var7 == var8 && var8 == var7)); + + std::string val9("small string"); + std::string val11("small string 2"); + json::variant var9(val9.data(), val9.length(), semantic_tag::none); + json::variant var10(val9.data(),val9.length(), semantic_tag::none); + json::variant var11(val11.data(),val11.length(), semantic_tag::none); + + std::string val12("too long for small string"); + std::string val14("too long for small string 2"); + json::variant var12(val12.data(),val12.length(), semantic_tag::none); + json::variant var13(val12.data(),val12.length(), semantic_tag::none); + json::variant var14(val14.data(),val14.length(), semantic_tag::none); + CHECK((var9 == var10 && var10 == var9)); + CHECK((var9 != var11 && var11 != var9)); + CHECK((var12 == var13 && var13 == var12)); + CHECK((var12 != var14 && var14 != var12)); + + json::variant var15(val9.data(),val9.length(), semantic_tag::none, std::allocator()); + CHECK((var9 == var15 && var15 == var9)); + + json::variant var16(static_cast(0), semantic_tag::none); + json::variant var17(static_cast(0), semantic_tag::none); + CHECK(var16 == var17); + CHECK(var17 == var16); +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/jsoncons_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/jsoncons_tests.cpp new file mode 100644 index 0000000000..f7e0c3317b --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/jsoncons_tests.cpp @@ -0,0 +1,230 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +TEST_CASE("test_1") +{ + basic_json j; + + std::basic_ostringstream os; + + std::cout << sizeof(json) << std::endl; + + //os << j << U"\n"; +} + +TEST_CASE("test_shrink_to_fit") +{ + json val = json::make_array(3); + val.reserve(100); + val[0].reserve(100); + val[0]["key"] = "value"; + val.shrink_to_fit(); + CHECK(3 == val.size()); + CHECK(1 == val[0].size()); +} + +TEST_CASE("test_for_each_value") +{ + std::string input = "{\"A\":\"Jane\", \"B\":\"Roe\",\"C\":10}"; + json val = json::parse(input); + + json::object_iterator it = val.object_range().begin(); + + CHECK(it->value().is_string()); + ++it; + CHECK(it->value().is_string()); + ++it; + CHECK(it->value().get_storage_type() == jsoncons::storage_type::uint64_val); + ++it; + CHECK((it == val.object_range().end())); +} + +TEST_CASE("test_assignment") +{ + json root; + + root["double_1"] = 10.0; + + json double_1 = root["double_1"]; + + CHECK(double_1.as() == Approx(10.0).epsilon(0.000001)); + + root["myobject"] = json(); + root["myobject"]["double_2"] = 7.0; + root["myobject"]["bool_2"] = true; + root["myobject"]["int_2"] = 0LL; + root["myobject"]["string_2"] = "my string"; + root["myarray"] = json::array(); + + json double_2 = root["myobject"]["double_2"]; + + CHECK(double_2.as() == Approx(7.0).epsilon(0.000001)); + CHECK(double_2.as() == 7); + CHECK(root["myobject"]["bool_2"].as()); + CHECK(root["myobject"]["int_2"].as() == 0); + CHECK(root["myobject"]["string_2"].as() == std::string("my string")); + + CHECK(root["myobject"]["bool_2"].as()); + CHECK(root["myobject"]["int_2"].as() == 0); + CHECK(root["myobject"]["string_2"].as() == std::string("my string")); + +} + +TEST_CASE("test_array") +{ + json root; + + root["addresses"]; + + std::vector addresses; + json address1; + address1["city"] = "San Francisco"; + address1["state"] = "CA"; + address1["zip"] = "94107"; + address1["country"] = "USA"; + addresses.push_back(address1); + + json address2; + address2["city"] = "Sunnyvale"; + address2["state"] = "CA"; + address2["zip"] = "94085"; + address2["country"] = "USA"; + addresses.push_back(address2); + + root["addresses"] = addresses; + + CHECK(root["addresses"].size() == 2); + +} + +TEST_CASE("test_null") +{ + json nullval = json::null(); + CHECK(nullval.is_null()); + CHECK(nullval.is()); + + json obj; + obj["field"] = json::null(); + CHECK(obj["field"] == json::null()); +} + +TEST_CASE("test_to_string") +{ + std::ostringstream os; + os << "{" + << "\"string\":\"value\"" + << ",\"null\":null" + << ",\"bool1\":false" + << ",\"bool2\":true" + << ",\"integer\":12345678" + << ",\"neg-integer\":-87654321" + << ",\"double\":123456.01" + << ",\"neg-double\":-654321.01" + << ",\"exp\":2.00600e+03" + << ",\"minus-exp\":1.00600e-010" + << ",\"escaped-string\":\"\\\\\\n\"" + << "}"; + + + json root = json::parse(os.str()); + + CHECK(root["null"].is_null()); + CHECK(root["null"].is()); + CHECK_FALSE(root["bool1"].as()); + CHECK(root["bool2"].as()); + CHECK(root["integer"].as() == 12345678); + CHECK(root["integer"].as() == 12345678); + CHECK(root["neg-integer"].as() == -87654321); + CHECK(root["double"].as() == Approx(123456.01).epsilon(0.0000001)); + CHECK(root["escaped-string"].as() == std::string("\\\n")); + + CHECK_FALSE(root["bool1"].as()); + CHECK(root["bool2"].as()); + CHECK(root["integer"].as() == 12345678); + CHECK(root["integer"].as() == 12345678); + CHECK(root["neg-integer"].as() == -87654321); + CHECK(root["double"].as() == Approx(123456.01).epsilon(0.0000001)); + CHECK(root["escaped-string"].as() == std::string("\\\n")); +} + +TEST_CASE("test_u0000") +{ + std::string inputStr("[\"\\u0040\\u0040\\u0000\\u0011\"]"); + //std::cout << "Input: " << inputStr << std::endl; + json arr = json::parse(inputStr); + + std::string s = arr[0].as(); + REQUIRE(4 == s.length()); + CHECK(static_cast(s[0]) == 0x40); + CHECK(static_cast(s[1]) == 0x40); + CHECK(static_cast(s[2]) == 0x00); + CHECK(static_cast(s[3]) == 0x11); + + std::ostringstream os; + os << arr; + std::string s2 = os.str(); + + //std::cout << std::hex << "Output: " << os.str() << std::endl; + +} + +TEST_CASE("test_uHHHH") +{ + std::string inputStr("[\"\\u007F\\u07FF\\u0800\"]"); + json arr = json::parse(inputStr); + + std::string s = arr[0].as(); + REQUIRE(s.length() == 6); + CHECK(static_cast(s[0]) == 0x7f); + CHECK(static_cast(s[1]) == 0xdf); + CHECK(static_cast(s[2]) == 0xbf); + CHECK(static_cast(s[3]) == 0xe0); + CHECK(static_cast(s[4]) == 0xa0); + CHECK(static_cast(s[5]) == 0x80); + + std::ostringstream os; + json_options options; + options.escape_all_non_ascii(true); + arr.dump(os, options); + std::string outputStr = os.str(); + + json arr2 = json::parse(outputStr); + std::string s2 = arr2[0].as(); + REQUIRE(s2.length() == 6); + CHECK(static_cast(s2[0]) == 0x7f); + CHECK(static_cast(s2[1]) == 0xdf); + CHECK(static_cast(s2[2]) == 0xbf); + CHECK(static_cast(s2[3]) == 0xe0); + CHECK(static_cast(s2[4]) == 0xa0); + CHECK(static_cast(s2[5]) == 0x80); + +} + +TEST_CASE("test_multiline_comments") +{ + std::string path = "./input/json-multiline-comment.json"; + std::fstream is(path); + if (!is) + { + std::cout << "Cannot open " << path << std::endl; + return; + } + json j = json::parse(is); + + CHECK(j.is_array()); + CHECK(j.is()); + CHECK(j.size() == 0); +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/jsonpatch/jsonpatch_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/jsonpatch/jsonpatch_tests.cpp new file mode 100644 index 0000000000..3d4de8375c --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/jsonpatch/jsonpatch_tests.cpp @@ -0,0 +1,496 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#if defined(_MSC_VER) +#include "windows.h" // test no inadvertant macro expansions +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; +using namespace jsoncons::literals; + +void check_patch(json& target, const json& patch, std::error_code expected_ec, const json& expected) +{ + std::error_code ec; + jsonpatch::apply_patch(target, patch, ec); + if (ec != expected_ec || expected != target) + { + std::cout << "target:\n" << target << std::endl; + } + CHECK(ec == expected_ec); + CHECK(target == expected); +} + +TEST_CASE("add_an_object_member") +{ + json target = R"( + { "foo": "bar"} + )"_json; + + json patch = R"( + [ + { "op": "add", "path": "/baz", "value": "qux" } + ] + )"_json; + + json expected = R"( + {"baz":"qux","foo":"bar"} + )"_json; + + check_patch(target,patch,std::error_code(),expected); +} + +TEST_CASE("add_an_array_element") +{ + json target = R"( + { "foo": [ "bar", "baz" ] } + )"_json; + + json patch = R"( + [ + { "op": "add", "path": "/foo/1", "value": "qux" } + ] + )"_json; + + json expected = R"( + { "foo": [ "bar", "qux", "baz" ] } + )"_json; + + check_patch(target,patch,std::error_code(),expected); +} + +TEST_CASE("remove_an_object_member") +{ + json target = R"( + { + "baz": "qux", + "foo": "bar" + } + )"_json; + + json patch = R"( + [ + { "op": "remove", "path": "/baz" } + ] + )"_json; + + json expected = R"( + { "foo": "bar" } + )"_json; + + check_patch(target,patch,std::error_code(),expected); +} + +TEST_CASE("remove_an_array_element") +{ + json target = R"( + { "foo": [ "bar", "qux", "baz" ] } + )"_json; + + json patch = R"( + [ + { "op": "remove", "path": "/foo/1" } + ] + )"_json; + + json expected = R"( + { "foo": [ "bar", "baz" ] } + )"_json; + + check_patch(target,patch,std::error_code(),expected); +} + +TEST_CASE("replace_a_value") +{ + json target = R"( + { + "baz": "qux", + "foo": "bar" + } + )"_json; + + json patch = R"( + [ + { "op": "replace", "path": "/baz", "value": "boo" } + ] + )"_json; + + json expected = R"( + { + "baz": "boo", + "foo": "bar" + } + )"_json; + + check_patch(target,patch,std::error_code(),expected); +} + +TEST_CASE("move_a_value") +{ + json target = R"( + { + "foo": { + "bar": "baz", + "waldo": "fred" + }, + "qux": { + "corge": "grault" + } + } + )"_json; + + json patch = R"( + [ + { "op": "move", "from": "/foo/waldo", "path": "/qux/thud" } + ] + )"_json; + + json expected = R"( + { + "foo": { + "bar": "baz" + }, + "qux": { + "corge": "grault", + "thud": "fred" + } + } + )"_json; + + check_patch(target,patch,std::error_code(),expected); +} + +TEST_CASE("move_an_array_element") +{ + json target = R"( + { "foo": [ "all", "grass", "cows", "eat" ] } + )"_json; + + json patch = R"( + [ + { "op": "move", "from": "/foo/1", "path": "/foo/3" } + ] + )"_json; + + json expected = R"( + { "foo": [ "all", "cows", "eat", "grass" ] } + )"_json; + + check_patch(target,patch,std::error_code(),expected); +} + +TEST_CASE("add_to_nonexistent_target") +{ + json target = R"( + { "foo": "bar" } + )"_json; + + json patch = R"( + [ + { "op": "add", "path": "/baz/bat", "value": "qux" } + ] + )"_json; + + json expected = target; + + check_patch(target,patch,jsonpatch::jsonpatch_errc::add_failed,expected); +} + +TEST_CASE("testing_a_value_success") +{ + json target = R"( + { + "baz": "qux", + "foo": [ "a", 2, "c" ] + } + )"_json; + + json patch = R"( + [ + { "op": "test", "path": "/baz", "value": "qux" }, + { "op": "test", "path": "/foo/1", "value": 2 } + ] + )"_json; + + json expected = target; + + check_patch(target,patch,std::error_code(),expected); +} + +TEST_CASE("testing_a_value_error") +{ + json target = R"( + { "baz": "qux" } + + )"_json; + + json patch = R"( + [ + { "op": "test", "path": "/baz", "value": "bar" } + ] + )"_json; + + json expected = target; + + check_patch(target,patch,jsonpatch::jsonpatch_errc::test_failed,expected); +} + +TEST_CASE("adding_nested_member_object") +{ + json target = R"( + { "foo": "bar" } + + )"_json; + + json patch = R"( + [ + { "op": "add", "path": "/child", "value": { "grandchild": { } } } + ] + )"_json; + + json expected = R"( + { + "foo": "bar", + "child": { + "grandchild": { + } + } + } + + )"_json; + + check_patch(target,patch,std::error_code(),expected); +} + +TEST_CASE("tilde_escape_ordering") +{ + json target = R"( + { + "/": 9, + "~1": 10 + } + + )"_json; + + json patch = R"( + [ + {"op": "test", "path": "/~01", "value": 10} + ] + )"_json; + + json expected = R"( + { + "/": 9, + "~1": 10 + } + + )"_json; + + check_patch(target,patch,std::error_code(),expected); +} + +TEST_CASE("comparing_strings_and_numbers") +{ + json target = R"( + { + "/": 9, + "~1": 10 + } + + )"_json; + + json patch = R"( + [ + {"op": "test", "path": "/~01", "value": "10"} + ] + )"_json; + + json expected = target; + + check_patch(target,patch,jsonpatch::jsonpatch_errc::test_failed,expected); +} + +TEST_CASE("adding_an_array_value") +{ + json target = R"( + { "foo": ["bar"] } + + )"_json; + + json patch = R"( + [ + { "op": "add", "path": "/foo/-", "value": ["abc", "def"] } + ] + )"_json; + + json expected = R"( + { "foo": ["bar", ["abc", "def"]] } + + )"_json; + + check_patch(target,patch,std::error_code(),expected); +} + +TEST_CASE("test_add_add") +{ + json target = R"( + { "foo": "bar"} + )"_json; + + json patch = R"( + [ + { "op": "add", "path": "/baz", "value": "qux" }, + { "op": "add", "path": "/foo", "value": [ "bar", "baz" ] } + ] + )"_json; + + json expected = R"( + { "baz":"qux", "foo": [ "bar", "baz" ]} + )"_json; + + check_patch(target,patch,std::error_code(),expected); +} + +TEST_CASE("test_add_add_add_fail") +{ + json target = R"( + { "foo": "bar"} + )"_json; + + json patch = R"( + [ + { "op": "add", "path": "/baz", "value": "qux" }, + { "op": "add", "path": "/foo", "value": [ "bar", "baz" ] }, + { "op": "add", "path": "/baz/bat", "value": "qux" } // nonexistent target + ] + )"_json; + + json expected = target; + + check_patch(target,patch,jsonpatch::jsonpatch_errc::add_failed,expected); +} + +TEST_CASE("test_add_remove_remove_fail") +{ + json target = R"( + { + "baz": "boo", + "foo": [ "bar", "qux", "baz" ] + } + )"_json; + + json patch = R"( + [ + { "op": "add", "path": "/baz", "value": "qux" }, + { "op": "remove", "path": "/foo/2" }, + { "op": "remove", "path": "/foo/2" } // nonexistent target + ] + )"_json; + + json expected = target; + + check_patch(target,patch,jsonpatch::jsonpatch_errc::remove_failed,expected); +} + +TEST_CASE("test_move_copy_replace_remove_fail") +{ + json target = R"( + { + "baz": ["boo"], + "foo": [ "bar", "qux", "baz" ] + } + )"_json; + + json patch = R"( + [ + { "op": "add", "path": "/baz/-", "value": "xyz" }, + { "op": "move", "from": "/foo/1", "path" : "/baz/-" }, + { "op": "copy", "from": "/baz/0", "path" : "/foo/-" }, + { "op": "replace", "path": "/foo/2", "value" : "qux" }, + { "op": "remove", "path": "/foo/3" } // nonexistent target + ] + )"_json; + + json expected = target; + + check_patch(target,patch,jsonpatch::jsonpatch_errc::remove_failed,expected); + +} + +TEST_CASE("test_diff1") +{ + json source = R"( + {"/": 9, "~1": 10, "foo": "bar"} + )"_json; + + json target = R"( + { "baz":"qux", "foo": [ "bar", "baz" ]} + )"_json; + + auto patch = jsonpatch::from_diff(source, target); + + check_patch(source,patch,std::error_code(),target); +} + +TEST_CASE("test_diff2") +{ + json source = R"( + { + "/": 3, + "foo": "bar" + } + )"_json; + + json target = R"( + { + "/": 9, + "~1": 10 + } + )"_json; + + auto patch = jsonpatch::from_diff(source, target); + + check_patch(source,patch,std::error_code(),target); +} + +TEST_CASE("add_when_new_items_in_target_array1") +{ + jsoncons::json source = R"( + {"/": 9, "foo": [ "bar"]} + )"_json; + + jsoncons::json target = R"( + { "baz":"qux", "foo": [ "bar", "baz" ]} + )"_json; + + jsoncons::json patch = jsoncons::jsonpatch::from_diff(source, target); + + check_patch(source,patch,std::error_code(),target); +} + +TEST_CASE("add_when_new_items_in_target_array2") +{ + jsoncons::json source = R"( + {"/": 9, "foo": [ "bar", "bar"]} + )"_json; + + jsoncons::json target = R"( + { "baz":"qux", "foo": [ "bar", "baz" ]} + )"_json; + + jsoncons::json patch = jsoncons::jsonpatch::from_diff(source, target); + + check_patch(source,patch,std::error_code(),target); +} + + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/jsonpath/JSONPathTestSuite_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/jsonpath/JSONPathTestSuite_tests.cpp new file mode 100644 index 0000000000..1c09931ddd --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/jsonpath/JSONPathTestSuite_tests.cpp @@ -0,0 +1,116 @@ +// Copyright 2013-2018 Daniel Parker +// Distributed under Boost license + +#if defined(_MSC_VER) +#include "windows.h" // test no inadvertant macro expansions +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) && _MSC_VER >= 1900 +#include +namespace fs = std::experimental::filesystem; +#else +//#include +//namespace fs = std::filesystem; +#endif + +using namespace jsoncons; +using namespace jsoncons::jsonpath; + +#if defined(_MSC_VER) && _MSC_VER >= 1900 +TEST_CASE("JSONPath Test Suite") +{ + ojson document; + std::map query_dictionary; + std::map expected_dictionary; + + std::string path = "./input/JSONPathTestSuite"; + for (auto& p : fs::directory_iterator(path)) + { + if (fs::exists(p) && fs::is_regular_file(p)) + { + if (p.path().filename() == "document.json") + { + try + { + std::ifstream is(p.path().c_str()); + document = ojson::parse(is); + } + catch(const std::exception& e) + { + std::cerr << e.what() << std::endl; + return; + } + } + else if (p.path().extension() == ".jsonpath") + { + std::string s; + char buffer[4096]; + std::ifstream is(p.path().c_str()); + while (is.read(buffer, sizeof(buffer))) + { + s.append(buffer, sizeof(buffer)); + } + s.append(buffer, (size_t)is.gcount()); + query_dictionary[p.path().stem()] = s; + } + else if (p.path().extension() == ".json") + { + try + { + ojson j; + std::ifstream is(p.path().c_str()); + j = ojson::parse(is); + expected_dictionary[p.path().stem()] = j; + } + catch (const jsoncons::ser_error& e) + { + std::cerr << e.what() << std::endl; + return; + } + } + } + } + + for (auto pair : query_dictionary) + { + auto it = expected_dictionary.find(pair.first); + if (it != expected_dictionary.end()) + { + try + { + ojson result = json_query(document, pair.second); + CHECK(it->second == result); + } + catch (const jsoncons::jsonpath::jsonpath_error& e) + { + ojson result = json_query(document, pair.second); + std::cerr << pair.first << " " << pair.second << " " << e.what() << std::endl; + } + catch (const std::exception& e) + { + std::cerr << e.what() << std::endl; + } + } + else + { + std::cout << "Expected value for " << pair.first << "not found \n"; + std::cout << pair.second << '\n'; + ojson result = json_query(document,pair.second); + std::cout << pretty_print(result) << std::endl; + } + } +} +#endif + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/jsonpath/jsonpath_error_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/jsonpath/jsonpath_error_tests.cpp new file mode 100644 index 0000000000..6664e708dd --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/jsonpath/jsonpath_error_tests.cpp @@ -0,0 +1,156 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#if defined(_MSC_VER) +#include "windows.h" // test no inadvertant macro expansions +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +struct jsonpath_fixture +{ + static const char* store_text() + { + static const char* text = "{ \"store\": {\"book\": [ { \"category\": \"reference\",\"author\": \"Nigel Rees\",\"title\": \"Sayings of the Century\",\"price\": 8.95},{ \"category\": \"fiction\",\"author\": \"Evelyn Waugh\",\"title\": \"Sword of Honour\",\"price\": 12.99},{ \"category\": \"fiction\",\"author\": \"Herman Melville\",\"title\": \"Moby Dick\",\"isbn\": \"0-553-21311-3\",\"price\": 8.99},{ \"category\": \"fiction\",\"author\": \"J. R. R. Tolkien\",\"title\": \"The Lord of the Rings\",\"isbn\": \"0-395-19395-8\",\"price\": 22.99}],\"bicycle\": {\"color\": \"red\",\"price\": 19.95}}}"; + return text; + } + static const char* store_text_empty_isbn() + { + static const char* text = "{ \"store\": {\"book\": [ { \"category\": \"reference\",\"author\": \"Nigel Rees\",\"title\": \"Sayings of the Century\",\"price\": 8.95},{ \"category\": \"fiction\",\"author\": \"Evelyn Waugh\",\"title\": \"Sword of Honour\",\"price\": 12.99},{ \"category\": \"fiction\",\"author\": \"Herman Melville\",\"title\": \"Moby Dick\",\"isbn\": \"0-553-21311-3\",\"price\": 8.99},{ \"category\": \"fiction\",\"author\": \"J. R. R. Tolkien\",\"title\": \"The Lord of the Rings\",\"isbn\": \"\",\"price\": 22.99}],\"bicycle\": {\"color\": \"red\",\"price\": 19.95}}}"; + return text; + } + static const char* book_text() + { + static const char* text = "{ \"category\": \"reference\",\"author\": \"Nigel Rees\",\"title\": \"Sayings of the Century\",\"price\": 8.95}"; + return text; + } + + json book() + { + json root = json::parse(jsonpath_fixture::store_text()); + json book = root["store"]["book"]; + return book; + } + + json bicycle() + { + json root = json::parse(jsonpath_fixture::store_text()); + json bicycle = root["store"]["bicycle"]; + return bicycle; + } +}; + +void test_error_code(const json& root, const std::string& path, std::error_code value, size_t line, size_t column) +{ + REQUIRE_THROWS_AS(jsonpath::json_query(root,path),jsonpath::jsonpath_error); + try + { + json result = jsonpath::json_query(root,path); + } + catch (const jsonpath::jsonpath_error& e) + { + if (e.code() != value) + { + std::cout << path << "\n"; + } + CHECK(e.code() == value); + CHECK(e.line() == line); + CHECK(e.column() == column); + } +} + +/*TEST_CASE("test_root_error") +{ + json root = json::parse(jsonpath_fixture::store_text()); + test_error_code(root, "..*", jsonpath_errc::expected_root,1,1);` +}*/ + +TEST_CASE("test_right_bracket_error") +{ + + json root = json::parse(jsonpath_fixture::store_text()); + test_error_code(root, "$['store']['book'[*]", jsonpath::jsonpath_errc::unexpected_end_of_input,1,21); +} + +TEST_CASE("jsonpath missing dot") +{ + json root = json::parse(jsonpath_fixture::store_text()); + test_error_code(root, "$.store.book[?(@category == 'fiction')][?(@.price < 15)].title", jsonpath::jsonpath_errc::expected_separator,1,17); +} + +TEST_CASE("test_dot_dot_dot") +{ + + json root = json::parse(jsonpath_fixture::store_text()); + test_error_code(root, "$.store...price", jsonpath::jsonpath_errc::expected_name,1,10); +} + +TEST_CASE("test_dot_star_name") +{ + + json root = json::parse(jsonpath_fixture::store_text()); + test_error_code(root, "$.store.*price", jsonpath::jsonpath_errc::expected_separator,1,10); +} +TEST_CASE("test_filter_error") +{ + json root = json::parse(jsonpath_fixture::store_text()); + std::string path = "$..book[?(.price<10)]"; + test_error_code(root, path, jsonpath::jsonpath_errc::parse_error_in_filter,1,17); +} + +TEST_CASE("jsonpath slice errors") +{ + json root = json::parse(R"( +[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19] +)"); + + SECTION("$[") + { + std::string path = "$["; + test_error_code(root, path, jsonpath::jsonpath_errc::unexpected_end_of_input,1,3); + } + SECTION("$[1") + { + std::string path = "$[1"; + test_error_code(root, path, jsonpath::jsonpath_errc::unexpected_end_of_input,1,4); + } + SECTION("$[1:") + { + std::string path = "$[1:"; + test_error_code(root, path, jsonpath::jsonpath_errc::unexpected_end_of_input,1,5); + } + SECTION("$[1:1") + { + std::string path = "$[1:1"; + test_error_code(root, path, jsonpath::jsonpath_errc::unexpected_end_of_input,1,6); + } + + SECTION("$[-:]") + { + std::string path = "$[-:]"; + test_error_code(root, path, jsonpath::jsonpath_errc::expected_slice_start,1,4); + } + + SECTION("$[-1:-]") + { + std::string path = "$[-1:-]"; + test_error_code(root, path, jsonpath::jsonpath_errc::expected_slice_end,1,7); + } + + SECTION("$[-1:-1:-]") + { + std::string path = "$[-1:-1:-]"; + test_error_code(root, path, jsonpath::jsonpath_errc::expected_slice_step,1,10); + } +} + + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/jsonpath/jsonpath_filter_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/jsonpath/jsonpath_filter_tests.cpp new file mode 100644 index 0000000000..b946b563de --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/jsonpath/jsonpath_filter_tests.cpp @@ -0,0 +1,488 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#if defined(_MSC_VER) +#include "windows.h" // test no inadvertant macro expansions +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; +using namespace jsoncons::jsonpath; +using namespace jsoncons::jsonpath::detail; + +struct jsonpath_filter_fixture +{ + static const char* store_text() + { + static const char* text = "{ \"store\": {\"book\": [ { \"category\": \"reference\",\"author\": \"Nigel Rees\",\"title\": \"Sayings of the Century\",\"price\": 8.95},{ \"category\": \"fiction\",\"author\": \"Evelyn Waugh\",\"title\": \"Sword of Honour\",\"price\": 12.99},{ \"category\": \"fiction\",\"author\": \"Herman Melville\",\"title\": \"Moby Dick\",\"isbn\": \"0-553-21311-3\",\"price\": 8.99},{ \"category\": \"fiction\",\"author\": \"J. R. R. Tolkien\",\"title\": \"The Lord of the Rings\",\"isbn\": \"0-395-19395-8\",\"price\": 22.99}],\"bicycle\": {\"color\": \"red\",\"price\": 19.95}}}"; + return text; + } + static const char* book_text() + { + static const char* text = "{ \"category\": \"reference\",\"author\": \"Nigel Rees\",\"title\": \"Sayings of the Century\",\"price\": 8.95}"; + return text; + } + + json book() + { + json root = json::parse(jsonpath_filter_fixture::store_text()); + json book = root["store"]["book"]; + return book; + } + + json bicycle() + { + json root = json::parse(jsonpath_filter_fixture::store_text()); + json bicycle = root["store"]["bicycle"]; + return bicycle; + } +}; + +TEST_CASE("test_div") +{ + const char* pend; + jsonpath_filter_parser parser; + + json context = json::array(); + context.push_back(3); + + std::string s1 = "(3/1)"; + auto expr1 = parser.parse(context,s1.c_str(), s1.c_str()+ s1.length(), &pend); + auto result1 = expr1.eval(context); + CHECK(json(3) == result1); + + std::string s2 = "(3/@.length)"; + auto expr2 = parser.parse(context,s2.c_str(), s2.c_str()+ s2.length(), &pend); + auto result2 = expr2.eval(context); + CHECK(json(3) == result2); + + std::string s3 = "(5/2)"; + auto expr3 = parser.parse(context,s3.c_str(), s3.c_str()+ s3.length(), &pend); + auto result3 = expr3.eval(context); + CHECK(json(2.5) == result3); + + std::string s4 = "(@.length/3)"; + auto expr4 = parser.parse(context,s4.c_str(), s4.c_str()+ s4.length(), &pend); + auto result4 = expr4.eval(context); + CHECK(0.333333 == Approx(result4.as()).epsilon(0.001)); + + std::string s5 = "(@.0/@.length)"; + auto expr5 = parser.parse(context,s5.c_str(), s5.c_str()+ s5.length(), &pend); + auto result5 = expr5.eval(context); + CHECK(json(3) == result5); +} + +TEST_CASE("test_mult") +{ + const char* pend; + jsonpath_filter_parser parser; + + json context = json::array(); + context.push_back(1); + context.push_back(2); + + std::string s1 = "(3*1)"; + auto expr1 = parser.parse(context, s1.c_str(), s1.c_str()+ s1.length(), &pend); + auto result1 = expr1.eval(context); + CHECK(json(3) == result1); + + std::string s2 = "(3*@.length)"; + auto expr2 = parser.parse(context, s2.c_str(), s2.c_str()+ s2.length(), &pend); + auto result2 = expr2.eval(context); + CHECK(json(6) == result2); + + std::string s3 = "(5*2)"; + auto expr3 = parser.parse(context, s3.c_str(), s3.c_str()+ s3.length(), &pend); + auto result3 = expr3.eval(context); + CHECK(json(10) == result3); + + std::string s4 = "(@.length*3)"; + auto expr4 = parser.parse(context, s4.c_str(), s4.c_str()+ s4.length(), &pend); + auto result4 = expr4.eval(context); + CHECK(json(6) == result4); + + std::string s5 = "(@.length*@.1)"; + auto expr5 = parser.parse(context, s5.c_str(), s5.c_str()+ s5.length(), &pend); + auto result5 = expr5.eval(context); + CHECK(json(4) == result5); +} + +TEST_CASE("test_minus") +{ + const char* pend; + jsonpath_filter_parser parser; + + json context = json::array(); + context.push_back(10.0); + + std::string s1 = "(3-1)"; + auto expr1 = parser.parse(context, s1.c_str(), s1.c_str()+ s1.length(), &pend); + auto result1 = expr1.eval(context); + CHECK(json(2) == result1); + + std::string s2 = "(3-@.length)"; + auto expr2 = parser.parse(context, s2.c_str(), s2.c_str()+ s2.length(), &pend); + auto result2 = expr2.eval(context); + CHECK(json(2) == result2); + + std::string s3 = "(3.5-1.0)"; + auto expr3 = parser.parse(context, s3.c_str(), s3.c_str()+ s3.length(), &pend); + auto result3 = expr3.eval(context); + CHECK(json(2.5) == result3); + + std::string s4 = "(@.length-3)"; + auto expr4 = parser.parse(context, s4.c_str(), s4.c_str()+ s4.length(), &pend); + auto result4 = expr4.eval(context); + CHECK(json(-2) ==result4); + + std::string s5 = "(@.length-@.0)"; + auto expr5 = parser.parse(context, s5.c_str(), s5.c_str()+ s5.length(), &pend); + auto result5 = expr5.eval(context); + CHECK(json(-9) ==result5); +} + +TEST_CASE("test_lt") +{ + const char* pend; + jsonpath_filter_parser parser; + + json context = json::array(); + context.push_back(100); + context.push_back(1); + + std::string s1 = "(3 < 1)"; + auto expr1 = parser.parse(context, s1.c_str(), s1.c_str()+ s1.length(), &pend); + auto result1 = expr1.eval(context); + CHECK(result1 == json(false)); + + std::string s2 = "(3 < @.length)"; + auto expr2 = parser.parse(context, s2.c_str(), s2.c_str()+ s2.length(), &pend); + auto result2 = expr2.eval(context); + CHECK(result2 == json(false)); + + std::string s3 = "(@.length < 3)"; + auto expr3 = parser.parse(context, s3.c_str(), s3.c_str()+ s3.length(), &pend); + auto result3 = expr3.eval(context); + CHECK(result3 == json(true)); + + std::string s4 = "(@.length < @.length)"; + auto expr4 = parser.parse(context, s4.c_str(), s4.c_str()+ s4.length(), &pend); + auto result4 = expr4.eval(context); + CHECK(result4 == json(false)); + + std::string s5 = "(@.length < @.0)"; + auto expr5 = parser.parse(context, s5.c_str(), s5.c_str()+ s5.length(), &pend); + auto result5 = expr5.eval(context); + CHECK(json(true) == result5); + + std::string s6 = "(@.length < @.1)"; + auto expr6 = parser.parse(context, s6.c_str(), s6.c_str()+ s6.length(), &pend); + auto result6 = expr6.eval(context); + CHECK(json(false) == result6); +} + +TEST_CASE("test_lte") +{ + const char* pend; + jsonpath_filter_parser parser; + + json context = json::array(); + context.push_back(1); + + std::string s1 = "(3 <= 1)"; + auto expr1 = parser.parse(context, s1.c_str(), s1.c_str()+ s1.length(), &pend); + auto result1 = expr1.eval(context); + CHECK(result1 == json(false)); + + std::string s2 = "(3 <= @.length)"; + auto expr2 = parser.parse(context, s2.c_str(), s2.c_str()+ s2.length(), &pend); + auto result2 = expr2.eval(context); + CHECK(result2 == json(false)); +} + +TEST_CASE("test_gt") +{ + const char* pend; + jsonpath_filter_parser parser; + + json context = json::array(); + context.push_back(1); + + std::string s1 = "(3 > 1)"; + auto expr1 = parser.parse(context, s1.c_str(), s1.c_str()+ s1.length(), &pend); + auto result1 = expr1.eval(context); + CHECK(result1 == json(true)); + + std::string s2 = "(3 > @.length)"; + auto expr2 = parser.parse(context, s2.c_str(), s2.c_str()+ s2.length(), &pend); + auto result2 = expr2.eval(context); + CHECK(result2 == json(true)); +} + +TEST_CASE("test_gte") +{ + const char* pend; + jsonpath_filter_parser parser; + + json context = json::array(); + context.push_back(1); + + std::string s1 = "(3 >= 1)"; + auto expr1 = parser.parse(context, s1.c_str(), s1.c_str()+ s1.length(), &pend); + auto result1 = expr1.eval(context); + CHECK(result1 == json(true)); + + std::string s2 = "(3 >= @.length)"; + auto expr2 = parser.parse(context, s2.c_str(), s2.c_str()+ s2.length(), &pend); + auto result2 = expr2.eval(context); + CHECK(result2 == json(true)); +} + +TEST_CASE("test_eq") +{ + const char* pend; + jsonpath_filter_parser parser; + + json context = json::array(); + context.push_back(1); + + std::string s1 = "(3 == 1)"; + auto expr1 = parser.parse(context, s1.c_str(), s1.c_str()+ s1.length(), &pend); + auto result1 = expr1.eval(context); + CHECK(result1 == json(false)); + + std::string s2 = "(3 == @.length)"; + auto expr2 = parser.parse(context, s2.c_str(), s2.c_str()+ s2.length(), &pend); + auto result2 = expr2.eval(context); + CHECK(result2 == json(false)); + + std::string s3 = "(1 == 1)"; + auto expr3 = parser.parse(context, s3.c_str(), s3.c_str()+ s3.length(), &pend); + auto result3 = expr3.eval(context); + CHECK(result3 == json(true)); + + std::string s4 = "(1 == @.length)"; + auto expr4 = parser.parse(context, s4.c_str(), s4.c_str()+ s4.length(), &pend); + auto result4 = expr4.eval(context); + CHECK(result4 == json(true)); +} + +TEST_CASE("test_precedence") +{ + const char* pend; + jsonpath_filter_parser parser; + + json context = json::array(); + context.push_back(1); + context.push_back(2); + + std::string s1 = "(@.0 == 1 && @.1 == 2)"; + auto expr1 = parser.parse(context, s1.c_str(), s1.c_str()+ s1.length(), &pend); + auto result1 = expr1.eval(context); + CHECK(result1 == json(true)); + + std::string s2 = "((@.0 == 1) && (@.1 == 2))"; + auto expr2 = parser.parse(context, s2.c_str(), s2.c_str()+ s2.length(), &pend); + auto result2 = expr2.eval(context); + CHECK(result2 == json(true)); + + std::string s3 = "(@.0 == 2 && @.1 == 2)"; + auto expr3 = parser.parse(context, s3.c_str(), s3.c_str()+ s3.length(), &pend); + auto result3 = expr3.eval(context); + CHECK(result3 == json(false)); + + std::string s4 = "((@.0 == 1) && (@.1 == 1))"; + auto expr4 = parser.parse(context, s4.c_str(), s4.c_str()+ s4.length(), &pend); + auto result4 = expr4.eval(context); + CHECK(result4 == json(false)); +} + +TEST_CASE("test_ne") +{ + const char* pend; + jsonpath_filter_parser parser; + + json context = json::array(); + context.push_back(1); + + std::string s1 = "(3 != 1)"; + auto expr1 = parser.parse(context, s1.c_str(), s1.c_str()+ s1.length(), &pend); + auto result1 = expr1.eval(context); + CHECK(result1 == json(true)); + + std::string s2 = "(3 != @.length)"; + auto expr2 = parser.parse(context, s2.c_str(), s2.c_str()+ s2.length(), &pend); + auto result2 = expr2.eval(context); + CHECK(result2 == json(true)); + + std::string s3 = "(1 != 1)"; + auto expr3 = parser.parse(context, s3.c_str(), s3.c_str()+ s3.length(), &pend); + auto result3 = expr3.eval(context); + CHECK(result3 == json(false)); + + std::string s4 = "(1 != @.length)"; + auto expr4 = parser.parse(context, s4.c_str(), s4.c_str()+ s4.length(), &pend); + auto result4 = expr4.eval(context); + CHECK(result4 == json(false)); +} + +TEST_CASE("test_jsonpath_filter") +{ + const char* pend; + jsonpath_filter_parser parser; + json parent = json::array(); + parent.push_back(1); + parent.push_back(2); + + std::string expr1 = "(1 + 1)"; + auto res1 = parser.parse(parent, expr1.c_str(), expr1.c_str()+ expr1.length(), &pend); + auto result1 = res1.eval(parent); + CHECK(json(2) == result1); + + std::string expr2 = "(1 - 1)"; + auto res2 = parser.parse(parent, expr2.c_str(), expr2.c_str()+ expr2.length(), &pend); + auto result2 = res2.eval(parent); + CHECK(json(0) == result2); + + std::string expr3 = "(@.length - 1)"; + auto res3 = parser.parse(parent, expr3.c_str(), expr3.c_str()+ expr3.length(), &pend); + auto result3 = res3.eval(parent); + CHECK(json(1) == result3); + +} + +TEST_CASE("test_jsonpath_filter_exclaim") +{ + const char* pend; + jsonpath_filter_parser parser; + json parent = json::array(); + parent.push_back(1); + parent.push_back(2); + + std::string expr1 = "(!(1 + 1))"; + auto res1 = parser.parse(parent, expr1.c_str(), expr1.c_str()+ expr1.length(), &pend); + auto result1 = res1.eval(parent); + CHECK(result1 == json(false)); + + std::string expr2 = "(!0)"; + auto res2 = parser.parse(parent, expr2.c_str(), expr2.c_str()+ expr2.length(), &pend); + auto result2= res2.eval(parent); + CHECK(result2 == json(true)); +} + + +TEST_CASE("test_jsonpath_index_expression") +{ + json root = json::parse(jsonpath_filter_fixture::store_text()); + //std::cout << pretty_print(root) << std::endl; + //std::cout << "$..book[(@.length-1)]" << std::endl; + + json result = json_query(root,"$..book[(@.length-1)]"); + + CHECK(1 == result.size()); + CHECK(root["store"]["book"][3] == result[0]); + + // std::cout << pretty_print(result) << std::endl; +} + +TEST_CASE("test_jsonpath_filter_negative_numbers") +{ + const char* pend; + jsonpath_filter_parser parser; + json parent = json::array(); + parent.push_back(1); + parent.push_back(2); + + std::string expr1 = "(-1 + 1)"; + auto res1 = parser.parse(parent, expr1.c_str(), expr1.c_str()+ expr1.length(), &pend); + auto result1 = res1.eval(parent); + CHECK(json(0) == result1); + + std::string expr2 = "(1 + -1)"; + auto res2 = parser.parse(parent, expr2.c_str(), expr2.c_str()+ expr2.length(), &pend); + auto result2 = res2.eval(parent); + CHECK(json(0) == result2); + + std::string expr3 = "(-1 - -1)"; + auto res3 = parser.parse(parent, expr3.c_str(), expr3.c_str()+ expr3.length(), &pend); + auto result3 = res3.eval(parent); + CHECK(json(0) == result3); + + std::string expr4 = "(-1 - -3)"; + auto res4 = parser.parse(parent, expr4.c_str(), expr4.c_str()+ expr4.length(), &pend); + auto result4 = res4.eval(parent); + CHECK(json(2) == result4); + + std::string expr5 = "((-2 < -1) && (-3 > -4))"; + auto res5 = parser.parse(parent, expr5.c_str(), expr5.c_str()+ expr5.length(), &pend); + auto result5 = res5.eval(parent); + CHECK(json(true) == result5); + + std::string expr6 = "((-2 < -1) || (-4 > -3))"; + auto res6 = parser.parse(parent, expr6.c_str(), expr6.c_str()+ expr6.length(), &pend); + auto result6 = res6.eval(parent); + CHECK(json(true) == result6); + + std::string expr7 = "(-2 < -1 && -3 > -4)"; + auto res7 = parser.parse(parent, expr7.c_str(), expr7.c_str()+ expr7.length(), &pend); + auto result7 = res7.eval(parent); + CHECK(json(true) == result7); + + std::string expr8 = "(-2 < -1 || -4 > -3)"; + auto res8 = parser.parse(parent, expr8.c_str(), expr8.c_str()+ expr8.length(), &pend); + auto result8 = res8.eval(parent); + CHECK(json(true) == result8); +} + +TEST_CASE("test_jsonpath_filter_uni") +{ + const char* pend; + jsonpath_filter_parser parser; + json parent = json::array(); + parent.push_back(1); + parent.push_back(2); + + std::string expr1 = "(0)"; + auto res = parser.parse(parent, expr1.c_str(), expr1.c_str()+ expr1.length(), &pend); + auto result1 = res.eval(parent); + + //std::cout << (int)result1.data_type() << std::endl; + CHECK(result1 == json(0)); + + CHECK(json(0) == result1); +} + +#if !(defined(__GNUC__) && (__GNUC__ == 4 && __GNUC_MINOR__ < 9)) +// GCC 4.8 has broken regex support: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53631 +TEST_CASE("test_jsonpath_filter_regex") +{ + const char* pend; + jsonpath_filter_parser parser; + json parent = json::array(); + parent.push_back(1); + parent.push_back(2); + + std::string expr1 = "('today I go' =~ /today.*?/)"; + auto res1 = parser.parse(parent, expr1.c_str(), expr1.c_str()+ expr1.length(), &pend); + auto result1 = res1.eval(parent); + CHECK(result1 == json(true)); + + std::string expr2 = "('today I go' =~ /Today.*?/)"; + auto res2 = parser.parse(parent, expr2.c_str(), expr2.c_str()+ expr2.length(), &pend); + auto result2 = res2.eval(parent); + CHECK(result2 == json(false)); + + std::string expr3 = "('today I go' =~ /Today.*?/i)"; + auto res3 = parser.parse(parent, expr3.c_str(), expr3.c_str()+ expr3.length(), &pend); + auto result3 = res3.eval(parent); + CHECK(result3 == json(true)); +} +#endif + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/jsonpath/jsonpath_function_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/jsonpath/jsonpath_function_tests.cpp new file mode 100644 index 0000000000..d46c09129e --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/jsonpath/jsonpath_function_tests.cpp @@ -0,0 +1,182 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#if defined(_MSC_VER) +#include "windows.h" // test no inadvertant macro expansions +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +TEST_CASE("jsonpath function tests") +{ + const json store = json::parse(R"( + { + "store": { + "book": [ + { + "category": "reference", + "author": "Nigel Rees", + "title": "Sayings of the Century", + "price": 8.95 + }, + { + "category": "fiction", + "author": "Evelyn Waugh", + "title": "Sword of Honour", + "price": 12.99 + }, + { + "category": "fiction", + "author": "Herman Melville", + "title": "Moby Dick", + "isbn": "0-553-21311-3", + "price": 8.99 + }, + { + "category": "fiction", + "author": "J. R. R. Tolkien", + "title": "The Lord of the Rings", + "isbn": "0-395-19395-8", + "price": 22.99 + } + ], + "bicycle": { + "color": "red", + "price": 19.95 + } + } + } + )"); + + SECTION("count") + { + json result = jsonpath::json_query(store,"count($.store.book[*])"); + + size_t expected = 4; + + REQUIRE(result.size() == 1); + CHECK(result[0].as() == expected); + } +#if 0 + SECTION("keys") + { + json result = json_query(store,"keys($.store.book[0])[*]"); + + json expected = json::parse("[\"author\",\"category\",\"price\",\"title\"]"); + + REQUIRE(result.size() == 4); + CHECK(result == expected); + } + SECTION("sum") + { + json result = json_query(store,"sum($.store.book[*].price)"); + double expected = 53.92; + REQUIRE(result.size() == 1); + CHECK(result[0].as() == Approx(expected).epsilon(0.000001)); + } + SECTION("sum in filter") + { + json result = json_query(store,"$.store.book[?(@.price > sum($.store.book[*].price) / count($.store.book[*]))].title"); + std::string expected = "The Lord of the Rings"; + REQUIRE(result.size() == 1); + CHECK(result[0].as() == expected); + } + SECTION("avg") + { + json result = json_query(store,"avg($.store.book[*].price)"); + + double expected = 13.48; + + REQUIRE(result.size() == 1); + CHECK(result[0].as() == Approx(expected).epsilon(0.000001)); + } + SECTION("avg in filter") + { + json result = json_query(store,"$.store.book[?(@.price > avg($.store.book[*].price))].title"); + std::string expected = "The Lord of the Rings"; + REQUIRE(result.size() == 1); + CHECK(result[0].as() == expected); + } + + SECTION("prod") + { + json result = json_query(store,"prod($.store.book[*].price)"); + + double expected = 24028.731766049998; + + REQUIRE(result.size() == 1); + CHECK(result[0].as() == Approx(expected).epsilon(0.000001)); + } + + SECTION("min") + { + json result = json_query(store,"min($.store.book[*].price)"); + + double expected = 8.95; + + REQUIRE(result.size() == 1); + CHECK(result[0].as() == Approx(expected).epsilon(0.000001)); + } + + SECTION("max") + { + json result = json_query(store,"max($.store.book[*].price)"); + + double expected = 22.99; + + REQUIRE(result.size() == 1); + CHECK(result[0].as() == Approx(expected).epsilon(0.000001)); + } + + SECTION("max in filter") + { + std::string path = "$.store.book[?(@.price < max($.store.book[*].price))].title"; + + json expected = json::parse(R"( + ["Sayings of the Century","Sword of Honour","Moby Dick"] + )"); + + json result = json_query(store,path); + + CHECK(result == expected); + } +#if !(defined(__GNUC__) && (__GNUC__ == 4 && __GNUC_MINOR__ < 9)) +// GCC 4.8 has broken regex support: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53631 + SECTION("tokenize") + { + json j("The cat sat on the mat"); + json result = json_query(j,"tokenize($,'\\\\s+')[*]"); + + json expected = json::parse("[\"The\",\"cat\",\"sat\",\"on\",\"the\",\"mat\"]"); + + CHECK(result == expected); + } + SECTION("tokenize in filter") + { + json j = json::parse("[\"The cat sat on the mat\",\"The cat on the mat\"]"); + json result = json_query(j,"$[?(tokenize(@,'\\\\s+')[2]=='sat')]"); + + CHECK(result[0] == j[0]); + } + SECTION("tokenize in filter 2") + { + json result = json_query(store,"$.store.book[?(tokenize(@.author,'\\\\s+')[1] == 'Waugh')].title"); + std::string expected = "Sword of Honour"; + REQUIRE(result.size() == 1); + CHECK(result[0].as() == expected); + } +#endif +#endif +} + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/jsonpath/jsonpath_normalized_path_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/jsonpath/jsonpath_normalized_path_tests.cpp new file mode 100644 index 0000000000..fd90c3a4c9 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/jsonpath/jsonpath_normalized_path_tests.cpp @@ -0,0 +1,251 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#if defined(_MSC_VER) +#include "windows.h" // test no inadvertant macro expansions +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; +using namespace jsoncons::jsonpath; + +// https://jsonpath.herokuapp.com/ + +TEST_CASE("store normalized path tests") +{ + const json store = json::parse(R"( + { + "store": { + "book": [ + { + "category": "reference", + "author": "Nigel Rees", + "title": "Sayings of the Century", + "price": 8.95 + }, + { + "category": "fiction", + "author": "Evelyn Waugh", + "title": "Sword of Honour", + "price": 12.99 + }, + { + "category": "fiction", + "author": "Herman Melville", + "title": "Moby Dick", + "isbn": "0-553-21311-3", + "price": 8.99 + }, + { + "category": "fiction", + "author": "J. R. R. Tolkien", + "title": "The Lord of the Rings", + "isbn": "0-395-19395-8", + "price": 22.99 + } + ], + "bicycle": { + "color": "red", + "price": 19.95 + } + }, + "expensive": 10 + } + )"); + + SECTION("$.store.book[0].category") + { + const json expected = json::parse(R"( + [ + "$['store']['book'][0]['category']" + ] + )"); + + std::string path = "$.store.book[0].category"; + + json result = json_query(store,"$.store.book[0].category",result_type::path); + CHECK(result == expected); + } + SECTION("test_string_index") + { + + const json expected = json::parse(R"( + [ + "$['store']['book'][0]['category'][0]", + "$['store']['book'][0]['category'][2]" + ] + )"); + + std::string path = "$.store.book.0.category[0,2]"; + + json result = json_query(store,path,result_type::path); + //CHECK(result == expected); // revisit + + //json result2 = json_query(store,path,result_type::value); + //std::cout << pretty_print(result2) << std::endl; + } + + SECTION("test_array_length") + { + + const json expected = json::parse(R"( + [ + "$['store']['book']['length']" + ] + )"); + + std::string path = "$.store.book.length"; + json result = json_query(store,path,result_type::path); + CHECK(result == expected); + + std::string path2 = "$.store.book['length']"; + json result2 = json_query(store, path, result_type::path); + CHECK(result2 == expected); + } + + SECTION("test_price_filter") + { + + const json expected = json::parse(R"( + [ + "$['store']['book'][0]['title']", + "$['store']['book'][2]['title']" + ] + )"); + + std::string path = "$.store.book[?(@.price < 10)].title"; + json result = json_query(store,path,result_type::path); + CHECK(result == expected); + } + + SECTION("test_length_expression") + { + + const json expected = json::parse(R"( + [ + "$['store']['book'][3]['title']" + ] + )"); + + std::string path = "$.store.book[(@.length-1)].title"; + json result = json_query(store,path,result_type::path); + CHECK(result == expected); + } +} + +TEST_CASE("normalized path test") +{ + json test = json::parse(R"( + { + "books": [ + {"title": "b1", "chapters":[{"subtitle":"b1c1"}]}, + {"title": "b2", "chapters":[{"subtitle":"b2c1"}]} + ] + } )"); + + json expected = json::parse(R"([{"subtitle":"b2c1"}])"); + std::string expected_path = "$['books'][1]['chapters'][0]"; + + SECTION("$.books[*].chapters[?(@.subtitle == 'b2c1')]") + { + std::string path = "$.books[*].chapters[?(@.subtitle == 'b2c1')]"; + json result = json_query(test, path); + + json path_result = json_query(test, path, result_type::path); + CHECK(result == expected); + + REQUIRE(path_result.size() == 1); + CHECK(path_result[0].as() == expected_path); + } + SECTION("$..books[*].chapters[?(@.subtitle == 'b2c1')]") + { + std::string path = "$..books[*].chapters[?(@.subtitle == 'b2c1')]"; + json result = json_query(test, path); + CHECK(result == expected); + + json path_result = json_query(test, path, result_type::path); + + REQUIRE(path_result.size() == 1); + CHECK(path_result[0].as() == expected_path); + } + SECTION("$..[?(@.subtitle == 'b2c1')]") + { + std::string path = "$..[?(@.subtitle == 'b2c1')]"; + json result = json_query(test, path); + CHECK(result == expected); + + json path_result = json_query(test, path, result_type::path); + + REQUIRE(path_result.size() == 1); + CHECK(path_result[0].as() == expected_path); + } +} + +TEST_CASE("jsonpath object union normalized path test") +{ + json test = json::parse(R"( + { + "books": [ + {"title": "b1", "chapters":[{"subtitle":"b1c1"}]}, + {"title": "b2", "chapters":[{"subtitle":"b2c1"}]} + ] + } )"); + + + SECTION("$..[chapters[?(@.subtitle == 'b2c1')],chapters[?(@.subtitle == 'b2c1')]]") + { + json expected = json::parse(R"([{"subtitle":"b2c1"}])"); + json expected_path = json::parse(R"(["$['books'][1]['chapters[?(@.subtitle == 'b2c1')]']"])"); + + std::string path = "$..[chapters[?(@.subtitle == 'b2c1')],chapters[?(@.subtitle == 'b2c1')]]"; + json result = json_query(test, path); + CHECK(result == expected); + + json path_result = json_query(test, path, result_type::path); + + CHECK(path_result == expected_path); + } +} + +TEST_CASE("jsonpath array union normalized path test") +{ + json root = json::parse(R"( +[[1,2,3,4,1,2,3,4],[0,1,2,3,4,5,6,7,8,9],[0,1,2,3,4,5,6,7,8,9]] +)"); + + SECTION("$[0,1,2]") + { + json expected = json::parse(R"([[0,1,2,3,4,5,6,7,8,9],[1,2,3,4,1,2,3,4]])"); + json expected_path = json::parse(R"( ["$[1]","$[0]"])"); + + std::string path = "$[0,1,2]"; + json result = json_query(root, path); + CHECK(result == expected); + + json path_result = json_query(root, path, result_type::path); + CHECK(path_result == expected_path); + } + + SECTION("$[0][0:4,2:8]") + { + json expected = json::parse(R"([1,2,3,4])"); + json expected_path = json::parse(R"(["$[0][0]","$[0][1]","$[0][2]","$[0][3]"])"); + + std::string path = "$[0][0:4,2:8]"; + json result = json_query(root, path); + CHECK(result == expected); + + json path_result = json_query(root, path, result_type::path); + CHECK(path_result == expected_path); + } +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/jsonpath/jsonpath_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/jsonpath/jsonpath_tests.cpp new file mode 100644 index 0000000000..4ec8cdd003 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/jsonpath/jsonpath_tests.cpp @@ -0,0 +1,1845 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#if defined(_MSC_VER) +#include "windows.h" // test no inadvertant macro expansions +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // std::unordered_set + +using namespace jsoncons; + +TEST_CASE("jsonpath name tests") +{ + ojson example = ojson::parse(R"( + { + "\\\\" : "1", + "*" : "2", + "\\\"" : "3" + } + )"); + + SECTION("test 1") + { + ojson expected = ojson::array(); + expected.push_back(example.at("\\\\")); + + ojson result1 = jsonpath::json_query(example,"$.\\\\"); + ojson result2 = jsonpath::json_query(example, "$. \\\\ "); + ojson result3 = jsonpath::json_query(example,"$[\\\\]"); + ojson result4 = jsonpath::json_query(example, "$['\\\\\\\\']"); + ojson result5 = jsonpath::json_query(example, "$[\"\\\\\\\\\"]"); + + CHECK(result1 == expected); + CHECK(result2 == expected); + CHECK(result3 == expected); + CHECK(result4 == expected); + CHECK(result5 == expected); + + REQUIRE_THROWS_AS(jsonpath::json_query(example,"$.'\\'"),jsonpath::jsonpath_error); + } + + SECTION("test 2") + { + ojson expected = ojson::array(); + expected.push_back(example.at("\\\\")); + expected.push_back(example.at("*")); + expected.push_back(example.at("\\\"")); + + ojson result1 = jsonpath::json_query(example,"$.*"); + ojson result2 = jsonpath::json_query(example, "$. * "); + ojson result3 = jsonpath::json_query(example, "$[*]"); + ojson result4 = jsonpath::json_query(example, "$ [*] "); + ojson result5 = jsonpath::json_query(example, "$ [ * ] "); + + CHECK(result1 == expected); + CHECK(result2 == expected); + CHECK(result3 == expected); + CHECK(result4 == expected); + CHECK(result5 == expected); + } + + SECTION("test 3") + { + ojson expected = ojson::array(); + expected.push_back(example.at("*")); + + ojson result1 = jsonpath::json_query(example, "$['*']"); + ojson result2 = jsonpath::json_query(example, "$ [\"*\"] "); + + CHECK(result1 == expected); + CHECK(result2 == expected); + } +} + +TEST_CASE("jsonpath store tests") +{ + json store = json::parse(R"( + { + "store": { + "book": [ + { + "category": "reference", + "author": "Nigel Rees", + "title": "Sayings of the Century", + "price": 8.95 + }, + { + "category": "fiction", + "author": "Evelyn Waugh", + "title": "Sword of Honour", + "price": 12.99 + }, + { + "category": "fiction", + "author": "Herman Melville", + "title": "Moby Dick", + "isbn": "0-553-21311-3", + "price": 8.99 + }, + { + "category": "fiction", + "author": "J. R. R. Tolkien", + "title": "The Lord of the Rings", + "isbn": "0-395-19395-8", + "price": 22.99 + } + ], + "bicycle": { + "color": "red", + "price": 19.95 + } + } + } + )"); + + + SECTION("Absolute path") + { + json result1 = jsonpath::json_query(store,"$"); + json result2 = jsonpath::json_query(store,"$.*"); + json result3 = jsonpath::json_query(store,"$..*"); + + REQUIRE(result1.size() == 1); + CHECK(result1[0] == store); + REQUIRE(result2.size() == 1); + CHECK(result2[0] == store["store"]); + REQUIRE(result3.size() == 1); + CHECK(result3[0] == store["store"]); + + json result4 = jsonpath::json_query(store,"$ "); + json result5 = jsonpath::json_query(store,"$ \n.\n * "); + json result6 = jsonpath::json_query(store,"$ .. * "); + + REQUIRE(result4.size() == 1); + CHECK(result4[0] == store); + REQUIRE(result5.size() == 1); + CHECK(result5[0] == store["store"]); + REQUIRE(result6.size() == 1); + CHECK(result6[0] == store["store"]); + } + + SECTION("test_path") + { + json book_list = store["store"]["book"]; + json bicycle = store["store"]["bicycle"]; + + json result1 = jsonpath::json_query(store,"$.store.book"); + json result2 = jsonpath::json_query(store,"$. store . book "); + json result3 = jsonpath::json_query(store,"store.book"); + json result4 = jsonpath::json_query(store," store . book "); + json result5 = jsonpath::json_query(store,"$.'store'.'book'"); + json result6 = jsonpath::json_query(store,"\"store\".\"book\""); + + json expected = json::array(); + expected.push_back(book_list); + + CHECK(result1 == expected); + CHECK(result2 == expected); + CHECK(result3 == expected); + CHECK(result4 == expected); + CHECK(result5 == expected); + CHECK(result6 == expected); + } + + //std::cout << pretty_print(result) << std::endl; + SECTION("test_jsonpath_store_book2") + { + json book_list = store["store"]["book"]; + + json result = jsonpath::json_query(store,"$['store']['book']"); + + json expected = json::array(); + expected.push_back(book_list); + + CHECK(result == expected); + // std::c/out << pretty_print(result) << std::endl; + } + + SECTION("$.store[book[0].title,book[1].title,book[3].title]") + { + json result = jsonpath::json_query(store,"$.store[book[0].title,book[1].title,book[3].title]"); + json expected = json::parse(R"(["Sayings of the Century","Sword of Honour","The Lord of the Rings"])"); + CHECK(result == expected); + } + + SECTION("$.store[book[3].title,book[?(@.price > 10)].title]") + { + json result = jsonpath::json_query(store,"$.store[book[3].title,book[?(@.price > 10)].title]"); + json expected = json::parse(R"(["Sword of Honour","The Lord of the Rings"])"); + CHECK(result == expected); + } + + SECTION("test_jsonpath_bracket_with_double_quotes") + { + json book_list = store["store"]["book"]; + + json result = jsonpath::json_query(store,"$[\"store\"][\"book\"]"); + + json expected = json::array(); + expected.push_back(book_list); + + CHECK(result == expected); + // std::c/out << pretty_print(result) << std::endl; + } + SECTION("test_jsonpath_store_book_bicycle") + { + /* SECTION("one") + { + + json result = jsonpath::json_query(store,"$['store']['book']"); + json expected = json::array(); + expected.push_back(book_list); + CHECK(result == expected); + }*/ + + SECTION("two") + { + json book_list = store["store"]["book"]; + json bicycle = store["store"]["bicycle"]; + + json result = jsonpath::json_query(store,"$['store']['book','bicycle']"); + json expected1 = json::array(); + expected1.push_back(book_list); + expected1.push_back(bicycle); + json expected2 = json::array(); + expected2.push_back(bicycle); + expected2.push_back(book_list); + CHECK((result == expected1 || result == expected2)); + } + + //std::cout << pretty_print(result) << std::endl; + } + + SECTION("test_jsonpath_store_book_bicycle_unquoted") + { + json book_list = store["store"]["book"]; + json bicycle = store["store"]["bicycle"]; + + + json result = jsonpath::json_query(store,"$[store][book,bicycle]"); + + json expected1 = json::array(); + expected1.push_back(book_list); + expected1.push_back(bicycle); + json expected2 = json::array(); + expected2.push_back(bicycle); + expected2.push_back(book_list); + CHECK((result == expected1 || result == expected2)); + + //std::cout << pretty_print(result) << std::endl; + } + + SECTION("test_jsonpath_store_book_union") + { + json result = jsonpath::json_query(store,"$['store']..['author','title']"); + + json expected = json::parse(R"( + [ + "Nigel Rees", + "Sayings of the Century", + "Evelyn Waugh", + "Sword of Honour", + "Herman Melville", + "Moby Dick", + "J. R. R. Tolkien", + "The Lord of the Rings" + ] + )"); + } + + SECTION("test_jsonpath_store_book_star") + { + json book_list = store["store"]["book"]; + + json result = jsonpath::json_query(store,"$['store']['book'][*]"); + json expected = book_list; + + //std::cout << pretty_print(result) << std::endl; + CHECK(result == expected); + } + + SECTION("test_store_dotdot_price") + { + json book_list = store["store"]["book"]; + json bicycle = store["store"]["bicycle"]; + + json result = jsonpath::json_query(store,"$.store..price"); + + json expected = json::array(); + expected.push_back(bicycle["price"]); + for (size_t i = 0; i < book_list.size(); ++i) + { + expected.push_back(book_list[i]["price"]); + } + + //std::cout << pretty_print(result) << std::endl; + + CHECK(result == expected); + } + + SECTION("test_jsonpath_recursive_descent") + { + json result1 = jsonpath::json_query(store,"$..book[2]"); + //std::cout << pretty_print(result1) << std::endl; + CHECK(result1.size() == 1); + + CHECK(result1[0] == store["store"]["book"][2]); + + json result1a = jsonpath::json_query(store,"$..book.2"); + //std::cout << pretty_print(result1a) << std::endl; + CHECK(result1a.size() == 1); + CHECK(result1a[0] == store["store"]["book"][2]); + + json result2 = jsonpath::json_query(store,"$..book[-1:]"); + //std::cout << pretty_print(result2) << std::endl; + CHECK(result2.size() == 1); + CHECK(result2[0] == store["store"]["book"][3]); + + SECTION("$..book[0,1]") + { + json result = jsonpath::json_query(store,"$..book[0,1]"); + + json expected1 = json::array{store["store"]["book"][0],store["store"]["book"][1]}; + json expected2 = json::array{store["store"]["book"][1],store["store"]["book"][0]}; + //std::cout << pretty_print(result) << std::endl; + CHECK(result.size() == 2); + CHECK((result == expected1 || result == expected2)); + } + + json result4 = jsonpath::json_query(store,"$..book[:2]"); + //std::cout << pretty_print(result4) << std::endl; + CHECK(result4.size() == 2); + CHECK(result4[0] == store["store"]["book"][0]); + CHECK(result4[1] == store["store"]["book"][1]); + + json result5 = jsonpath::json_query(store,"$..book[1:2]"); + //std::cout << pretty_print(result5) << std::endl; + CHECK(result5.size() == 1); + CHECK(result5[0] == store["store"]["book"][1]); + + json result6 = jsonpath::json_query(store,"$..book[-2:]"); + //std::cout << pretty_print(result6) << std::endl; + CHECK(result6.size() == 2); + CHECK(result6[0] == store["store"]["book"][2]); + CHECK(result6[1] == store["store"]["book"][3]); + + json result7 = jsonpath::json_query(store,"$..book[2:]"); + //std::cout << pretty_print(result7) << std::endl; + CHECK(result7.size() == 2); + CHECK(result7[0] == store["store"]["book"][2]); + CHECK(result7[1] == store["store"]["book"][3]); + } + + SECTION("test_jsonpath_filter1") + { + json book_list = store["store"]["book"]; + + json result = jsonpath::json_query(store,"$..book[?(@.price<10)]"); + //std::cout << pretty_print(result) << std::endl; + json books = book_list; + json expected = json::array(); + for (size_t i = 0; i < books.size(); ++i) + { + double price = books[i]["price"].as(); + if (price < 10) + { + expected.push_back(books[i]); + } + } + CHECK(result == expected); + } + + SECTION("test_jsonpath_filter2") + { + json book_list = store["store"]["book"]; + + json result = jsonpath::json_query(store,"$..book[?(10 > @.price)]"); + + //std::cout << pretty_print(result) << std::endl; + json books = book_list; + json expected = json::array(); + for (size_t i = 0; i < books.size(); ++i) + { + double price = books[i]["price"].as(); + if (10 > price) + { + expected.push_back(books[i]); + } + } + CHECK(result == expected); + } + + SECTION("test_jsonpath_filter_category_eq_reference") + { + json book_list = store["store"]["book"]; + + json result = jsonpath::json_query(store,"$..book[?(@.category == 'reference')]"); + + //std::cout << pretty_print(result) << std::endl; + json books = book_list; + json expected = json::array(); + for (size_t i = 0; i < books.size(); ++i) + { + double price = books[i]["price"].as(); + (void)price; + + if (books[i]["category"].as() == "reference") + { + expected.push_back(books[i]); + } + } + CHECK(result == expected); + } + + SECTION("test_jsonpath_filter3") + { + json book_list = store["store"]["book"]; + + json result = jsonpath::json_query(store,"$..book[?((@.price > 8) && (@.price < 12))]"); + + json books = book_list; + + json expected = json::array(); + for (size_t i = 0; i < books.size(); ++i) + { + double price = books[i]["price"].as(); + if (price > 8 && price < 12) + { + expected.push_back(books[i]); + } + } + //std::cout << pretty_print(result) << std::endl; + //std::cout << pretty_print(expected) << std::endl; + + CHECK(result == expected); + } + + SECTION("test_jsonpath_book_isbn") + { + json book_list = store["store"]["book"]; + + json books = book_list; + for (size_t i = 0; i < books.size(); ++i) + { + bool has_isbn = books[i].contains("isbn"); + if (has_isbn) + { + json result = jsonpath::json_query(books[i],"$.isbn"); + json expected = json::array(); + expected.push_back(books[i]["isbn"]); + CHECK(result == expected); + //std::cout << pretty_print(result) << std::endl; + } + } + } + + SECTION("test_jsonpath_book_empty_isbn") + { + json book_list = store["store"]["book"]; + + const char* empty_isbn = "{ \"store\": {\"book\": [ { \"category\": \"reference\",\"author\": \"Nigel Rees\",\"title\": \"Sayings of the Century\",\"price\": 8.95},{ \"category\": \"fiction\",\"author\": \"Evelyn Waugh\",\"title\": \"Sword of Honour\",\"price\": 12.99},{ \"category\": \"fiction\",\"author\": \"Herman Melville\",\"title\": \"Moby Dick\",\"isbn\": \"0-553-21311-3\",\"price\": 8.99},{ \"category\": \"fiction\",\"author\": \"J. R. R. Tolkien\",\"title\": \"The Lord of the Rings\",\"isbn\": \"\",\"price\": 22.99}],\"bicycle\": {\"color\": \"red\",\"price\": 19.95}}}"; + json root2 = json::parse(empty_isbn); + + json books = book_list; + for (size_t i = 0; i < books.size(); ++i) + { + bool has_isbn = books[i].contains("isbn"); + if (has_isbn) + { + json result = jsonpath::json_query(books[i],"$.isbn"); + json expected = json::array(); + expected.push_back(books[i]["isbn"]); + CHECK(result == expected); + //std::cout << pretty_print(result) << std::endl; + } + } + } + + SECTION("test_jsonpath_filter4") + { + json book_list = store["store"]["book"]; + + json result = jsonpath::json_query(store,"$..book[?(@.isbn)]"); + + json books = book_list; + + json expected = json::array(); + for (size_t i = 0; i < books.size(); ++i) + { + if (books[i].contains("isbn")) + { + expected.push_back(books[i]); + } + } + //std::cout << pretty_print(result) << std::endl; + //std::cout << pretty_print(expected) << std::endl; + + CHECK(result == expected); + } + SECTION("test_jsonpath_array_length") + { + json result = jsonpath::json_query(store,"$..book.length"); + + //std::cout << pretty_print(result) << std::endl; + + CHECK(1 == result.size()); + CHECK(store["store"]["book"].size() == result[0].as()); + } + + SECTION("test_jsonpath_book_category") + { + json book_list = store["store"]["book"]; + + json book = book_list[0]; + + json result = jsonpath::json_query(book,"$.category"); + + CHECK(1 == result.size()); + CHECK("reference" == result[0].as()); + } + + SECTION("test_jsonpath_book_filter_false") + { + json result = jsonpath::json_query(store,"$..book[?(false)]"); + //std::cout << pretty_print(result) << std::endl; + + json expected = json::array(); + + CHECK(result == expected); + } + + SECTION("test_jsonpath_book_filter_false_and_false") + { + json result = jsonpath::json_query(store,"$..book[?(false && false)]"); + //std::cout << pretty_print(result) << std::endl; + + json expected = json::array(); + + CHECK(result == expected); + } + + SECTION("test_jsonpath_book_filter_false_or_false") + { + json result = jsonpath::json_query(store,"$..book[?(false || false)]"); + //std::cout << pretty_print(result) << std::endl; + + json expected = json::array(); + + CHECK(result == expected); + } + + SECTION("test_jsonpath_book_filter_false_or_true") + { + json book_list = store["store"]["book"]; + + json result = jsonpath::json_query(store,"$..book[?(false || true)]"); + //std::cout << pretty_print(result) << std::endl; + + CHECK(result == book_list); + } + + SECTION("test_jsonpath_store_book_authors") + { + json book_list = store["store"]["book"]; + + json result = jsonpath::json_query(store,"$.store.book[?(@.price < 10)].author"); + + json expected = json::array(); + for (size_t i = 0; i < book_list.size(); ++i) + { + json book = book_list[i]; + if (book["price"].as() < 10) + { + expected.push_back(book["author"]); + } + } + + //json expected = book_list; + + //std::cout << pretty_print(result) << std::endl; + + CHECK(result == expected); + } + + SECTION("test_jsonpath_store_book_tests") + { + json book_list = store["store"]["book"]; + + json result1 = jsonpath::json_query(store,"$.store.book[ ?(@.category == @.category) ]"); + CHECK(book_list == result1); + + json result2 = jsonpath::json_query(store,"$.store.book[ ?(@.category == @['category']) ]"); + CHECK(book_list == result2); + + json result3 = jsonpath::json_query(store,"$.store.book[ ?(@ == @) ]"); + CHECK(book_list == result3); + + json result4 = jsonpath::json_query(store,"$.store.book[ ?(@.category != @.category) ]"); + json expected4 = json::array(); + CHECK(result4 == expected4); + } + + SECTION("test_jsonpath_store_book_tests2") + { + json result1 = jsonpath::json_query(store,"$.store.book[ ?((@.author == 'Nigel Rees') || (@.author == 'Evelyn Waugh')) ].author"); + json expected1 = json::array(); + expected1.push_back("Nigel Rees"); + expected1.push_back("Evelyn Waugh"); + CHECK(result1 == expected1); + + json result1b = jsonpath::json_query(store,"$.store.book[ ?((@.author == 'Nigel Rees') || (@.author == 'Evelyn Waugh')) ].title"); + json expected1b = json::array(); + expected1b.push_back("Sayings of the Century"); + expected1b.push_back("Sword of Honour"); + //std::cout << result1b << std::endl; + CHECK(expected1b == result1b); + + json result2 = jsonpath::json_query(store,"$.store.book[ ?(((@.author == 'Nigel Rees') || (@.author == 'Evelyn Waugh')) && (@.price < 15)) ].author"); + json expected2 = json::array(); + expected2.push_back("Nigel Rees"); + expected2.push_back("Evelyn Waugh"); + CHECK(result2 == expected2); + + json result3 = jsonpath::json_query(store,"$.store.book[ ?(((@.author == 'Nigel Rees') || (@.author == 'Evelyn Waugh')) && (@.category == 'reference')) ].author"); + json expected3 = json::array(); + expected3.push_back("Nigel Rees"); + CHECK(result3 == expected3); + + json result4 = jsonpath::json_query(store,"$.store.book[ ?(((@.author == 'Nigel Rees') || (@.author == 'Evelyn Waugh')) && (@.category != 'fiction')) ].author"); + json expected4 = json::array(); + expected4.push_back("Nigel Rees"); + CHECK(result4 == expected4); + + json result5 = jsonpath::json_query(store,"$.store.book[?('a' == 'a')].author"); + json expected5 = json::array(); + expected5.push_back("Nigel Rees"); + expected5.push_back("Evelyn Waugh"); + expected5.push_back("Herman Melville"); + expected5.push_back("J. R. R. Tolkien"); + CHECK(result5 == expected5); + + json result6 = jsonpath::json_query(store,"$.store.book[?('a' == 'b')].author"); + json expected6 = json::array(); + CHECK(result6 == expected6); + } + + #if !(defined(__GNUC__) && (__GNUC__ == 4 && __GNUC_MINOR__ < 9)) + // GCC 4.8 has broken regex support: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53631 + SECTION("test_jsonpath_store_book_regex") + { + json result3 = jsonpath::json_query(store,"$.store.book[ ?(@.category =~ /fic.*?/)].author"); + json expected3 = json::array(); + expected3.push_back("Evelyn Waugh"); + expected3.push_back("Herman Melville"); + expected3.push_back("J. R. R. Tolkien"); + CHECK(result3 == expected3); + + json result4 = jsonpath::json_query(store,"$.store.book[ ?(@.author =~ /Evelyn.*?/)].author"); + json expected4 = json::array(); + expected4.push_back("Evelyn Waugh"); + CHECK(result4 == expected4); + + json result5 = jsonpath::json_query(store,"$.store.book[ ?(!(@.author =~ /Evelyn.*?/))].author"); + json expected5 = json::array(); + expected5.push_back("Nigel Rees"); + expected5.push_back("Herman Melville"); + expected5.push_back("J. R. R. Tolkien"); + CHECK(result5 == expected5); + } + #endif + + SECTION("test_jsonpath_everything") + { + json book_list = store["store"]["book"]; + json bicycle = store["store"]["bicycle"]; + + json result = jsonpath::json_query(store,"$.store.*"); + //std::cout << result << std::endl; + + json expected = json::array(); + expected.push_back(bicycle); + expected.push_back(book_list); + + CHECK(result == expected); + } + + SECTION("test_jsonpath_everything_in_store") + { + json result = jsonpath::json_query(store,"$..*"); + //std::cout << result << std::endl; + + json expected = json::array(); + expected.push_back(store["store"]); + + CHECK(result == expected); + } + + SECTION("test_array_slice_operator") + { + SECTION("Array slice") + { + + json result1 = jsonpath::json_query(store,"$..book[1:2].author"); + json expected1 = json::parse(R"( + [ + "Evelyn Waugh" + ] + )"); + CHECK(result1 == expected1); + + json result2 = jsonpath::json_query(store,"$..book[1:3:2].author"); + json expected2 = expected1; + CHECK(result2 == expected2); + + json result3 = jsonpath::json_query(store,"$..book[1:4:2].author"); + json expected3 = json::parse(R"( + [ + "Evelyn Waugh", + "J. R. R. Tolkien" + ] + )"); + CHECK(result3 == expected3); + } + + SECTION("Union") + { + std::unordered_set expected = {"Evelyn Waugh","J. R. R. Tolkien","Nigel Rees"}; + + json result1 = jsonpath::json_query(store,"$..book[1:4:2,0].author"); + CHECK(result1.size() == expected.size()); + for (const auto& item : result1.array_range()) + { + CHECK(expected.count(item.as()) == 1); + } + + json result2 = jsonpath::json_query(store,"$..book[1::2,0].author"); + CHECK(result2.size() == expected.size()); + for (const auto& item : result2.array_range()) + { + CHECK(expected.count(item.as()) == 1); + } + } + } + + SECTION("test_max_pre") + { + std::string path = "$.store.book[*].price"; + json result = jsonpath::json_query(store,path); + + //std::cout << result << std::endl; + } + + SECTION("test_max") + { + std::string path = "$.store.book[?(@.price < max($.store.book[*].price))].title"; + + json expected = json::parse(R"( + ["Sayings of the Century","Sword of Honour","Moby Dick"] + )"); + + json result = jsonpath::json_query(store,path); + CHECK(result == expected); + + //std::cout << result << std::endl; + } + + SECTION("test_min") + { + std::string path = "$.store.book[?(@.price > min($.store.book[*].price))].title"; + + json expected = json::parse(R"( + ["Sword of Honour","Moby Dick","The Lord of the Rings"] + )"); + + json result = jsonpath::json_query(store,path); + CHECK(result == expected); + } + + SECTION("test_sum_filter_func") + { + std::string path = "$.store.book[?(@.price > sum($.store.book[*].price) / 4)].title"; // unexpected exception if '$.store.book.length' instead '4' + + json expected = json::parse(R"( + ["The Lord of the Rings"] + )"); + + json result = jsonpath::json_query(store,path); + CHECK(result == expected); + } + + SECTION("test_prod_func") + { + std::string path = "$.store.bicycle[?(479373 < prod($..price) && prod($..price) < 479374)].color"; + + json expected = json::parse(R"( + ["red"] + )"); + + json result = jsonpath::json_query(store,path); + CHECK(result == expected); + } + + SECTION("test_ws1") + { + json result = jsonpath::json_query(store,"$..book[ ?(( @.price > 8 ) && (@.price < 12)) ].author"); + + json expected = json::parse(R"( + [ + "Nigel Rees", + "Herman Melville" + ] + )"); + + CHECK(result == expected); + } + +} + +// store tests + +TEST_CASE("test_jsonpath_last_of_two_arrays") +{ + json val = json::parse(R"( +{ "store": { + "book": [ + { "author": "Nigel Rees" + }, + { "author": "Evelyn Waugh" + }, + { "author": "Herman Melville" + } + ] + }, + "Roman": { + "book": [ + { "author": "Tolstoy L" + }, + { "author": "Tretyakovskiy R" + }, + { "author": "Kulik M" + } + ] + } +} + )"); + + json expected = json::parse(R"( +[ + { "author": "Kulik M"}, + { "author": "Herman Melville"} +] + )"); + + json result = jsonpath::json_query(val, "$..book[(@.length - 1)]"); + + CHECK(result == expected); +} + +TEST_CASE("test_jsonpath_next_to_last_of_two_arrays") +{ + json val = json::parse(R"( +{ "store": { + "book": [ + { "author": "Nigel Rees" + }, + { "author": "Evelyn Waugh" + }, + { "author": "Herman Melville" + } + ] + }, + "Roman": { + "book": [ + { "author": "Tolstoy L" + }, + { "author": "Tretyakovskiy R" + }, + { "author": "Kulik M" + } + ] + } +} + )"); + + json expected = json::parse(R"( +[ + { "author": "Tretyakovskiy R"}, + { "author": "Evelyn Waugh"} +] + )"); + + json result = jsonpath::json_query(val, "$..book[(@.length - 2)]"); + + CHECK(result == expected); + + json expected2 = json::parse(R"( +[ + "Tolstoy L", + "Nigel Rees" +] + )"); + std::string path2 = "$..[0].author"; + json result2 = jsonpath::json_query(val, path2); + CHECK(result2 == expected2); + +} + +TEST_CASE("test_jsonpath_aggregation") +{ + json val = json::parse(R"( +{ + "firstName": "John", + "lastName" : "doe", + "age" : 26, + "address" : { + "streetAddress": "naist street", + "city" : "Nara", + "postalCode" : "630-0192" + }, + "phoneNumbers": [ + { + "type" : "iPhone", + "number": "0123-4567-8888" + }, + { + "type" : "home", + "number": "0123-4567-8910" + } + ] +} + )"); + + SECTION("$['firstName','lastName']") + { + json expected1 = json::parse(R"( + ["John","doe"] + )"); + json expected2 = json::parse(R"( + ["doe","John"] + )"); + + json result2 = jsonpath::json_query(val, "$['firstName','lastName']"); + CHECK((result2 == expected1 || result2 == expected2)); + + json result3 = jsonpath::json_query(val, "$[\"firstName\",\"lastName\"]"); + CHECK((result3 == expected1 || result3 == expected2)); + } + + SECTION("$..['firstName','city']") + { + json expected1 = json::parse(R"(["John","Nara"])"); + json expected2 = json::parse(R"(["Nara","John"])"); + std::string path = "$..['firstName','city']"; + + json result = jsonpath::json_query(val, path); + CHECK((result == expected1 || result == expected2)); + } +} + +TEST_CASE("test_jsonpath_aggregation2") +{ + json val = json::parse(R"( +{ "store": { + "book": [ + { "author": "Nigel Rees" + }, + { "author": "Evelyn Waugh" + }, + { "author": "Herman Melville" + } + ] + } +} + )"); + + json result = jsonpath::json_query(val, "$..book[(@.length - 1),(@.length - 2)]"); + + json expected1 = json::parse(R"([{"author": "Herman Melville"},{"author": "Evelyn Waugh"}])"); + json expected2 = json::parse(R"([{"author": "Evelyn Waugh"},{"author": "Herman Melville"}])"); + CHECK((result == expected1 || result == expected2)); +} + +TEST_CASE("test_jsonpath_aggregation3") +{ + json val = json::parse(R"( +{ + "firstName": "John", + "lastName" : "doe", + "age" : 26, + "address" : { + "streetAddress": "naist street", + "city" : "Nara", + "postalCode" : "630-0192" + }, + "phoneNumbers": [ + { + "type" : "iPhone", + "number": "0123-4567-8888" + }, + { + "type" : "home", + "number": "0123-4567-8910" + } + ] +} + )"); + + std::unordered_set expected = {"iPhone","0123-4567-8888","home","0123-4567-8910"}; + + json result = jsonpath::json_query(val, "$..['type','number']"); + CHECK(result.size() == expected.size()); + for (const auto& item : result.array_range()) + { + CHECK(expected.count(item.as()) == 1); + } +} + +TEST_CASE("test_jsonpath_aggregation4") +{ + json val = json::parse(R"( +{ + "firstName": "John", + "lastName" : "doe", + "age" : 26, + "address" : { + "streetAddress": "naist street", + "city" : "Nara", + "postalCode" : "630-0192" + }, + "phoneNumbers": [ + { + "type" : "iPhone", + "number": "0123-4567-8888" + }, + { + "type" : "home", + "number": "0123-4567-8910" + } + ] +} + )"); + + json test1 = jsonpath::json_query(val, "$.phoneNumbers"); + //std::cout << test1 << std::endl; + json test2 = jsonpath::json_query(val, "$[phoneNumbers]"); + //std::cout << test2 << std::endl; + json test3 = jsonpath::json_query(val, "$..['type']"); + //std::cout << test3 << std::endl; + + std::unordered_set expected = {"iPhone","0123-4567-8888","home","0123-4567-8910"}; + + json result2 = jsonpath::json_query(val, "$.phoneNumbers..['type','number']"); + CHECK(result2.size() == expected.size()); + for (const auto& item : result2.array_range()) + { + CHECK(expected.count(item.as()) == 1); + } +} + +TEST_CASE("test_jsonpath_string_indexation") +{ + json val; + val["about"] = "I\xe2\x82\xacJ"; + + json expected1 = json::array(1,"I"); + json result1 = jsonpath::json_query(val, "$..about[0]"); + CHECK(result1 == expected1); + + json expected2 = json::array(1,"\xe2\x82\xac"); + json result2 = jsonpath::json_query(val, "$..about[1]"); + CHECK(result2 == expected2); + + json expected3 = json::array(1,"J"); + json result3 = jsonpath::json_query(val, "$..about[2]"); + CHECK(result3 == expected3); + + json expected4 = json::array(1,3); + json result4 = jsonpath::json_query(val, "$..about.length"); + CHECK(result4 == expected4); +} + +TEST_CASE("test_union_array_elements") +{ + json val = json::parse(R"( +{ "store": { + "book": [ + { "author": "Nigel Rees" + }, + { "author": "Evelyn Waugh" + }, + { "author": "Herman Melville" + } + ] + }, + "Roman": { + "book": [ + { "author": "Tolstoy L" + }, + { "author": "Tretyakovskiy R" + }, + { "author": "Kulik M" + } + ] + } +} + )"); + + json expected1 = json::parse(R"( +[ + { "author": "Kulik M"}, + { "author": "Herman Melville"} +] + )"); + json result1 = jsonpath::json_query(val, "$..book[-1]"); + CHECK(result1 == expected1); + + std::unordered_set expected = {"Kulik M","Tolstoy L","Herman Melville","Nigel Rees"}; + + json expected2 = json::parse(R"( +[ + { + "author": "Kulik M" + }, + { + "author": "Tolstoy L" + }, + { + "author": "Herman Melville" + }, + { + "author": "Nigel Rees" + } +] + )"); + json result2 = jsonpath::json_query(val, "$..book[-1,-3]"); + + CHECK(result2.size() == expected.size()); + for (const auto& item : result2.array_range()) + { + CHECK(expected.count(item["author"].as()) == 1); + } + + //CHECK(result2 == expected2); + //json expected3 = expected2; + json result3 = jsonpath::json_query(val, "$..book[-1,(@.length - 3)]"); + CHECK(result3.size() == expected.size()); + for (const auto& item : result3.array_range()) + { + CHECK(expected.count(item["author"].as()) == 1); + } + //CHECK(result3 == expected3); + //json expected4 = expected2; + json result4 = jsonpath::json_query(val, "$..book[(@.length - 1),-3]"); + CHECK(result4.size() == expected.size()); + for (const auto& item : result4.array_range()) + { + CHECK(expected.count(item["author"].as()) == 1); + } + //CHECK(result4 == expected4); +} + +TEST_CASE("test_replace") +{ + json j; + try + { + j = json::parse(R"( +{"store": +{"book": [ +{"category": "reference", +"author": "Margaret Weis", +"title": "Dragonlance Series", +"price": 31.96}, {"category": "reference", +"author": "Brent Weeks", +"title": "Night Angel Trilogy", +"price": 14.70 +}]}} +)"); + } + catch (const ser_error& e) + { + std::cout << e.what() << std::endl; + } + + //std::cout << "!!!test_replace" << std::endl; + //std::cout << ("1\n") << pretty_print(j) << std::endl; + + CHECK(31.96 == Approx(j["store"]["book"][0]["price"].as()).epsilon(0.001)); + + jsonpath::json_replace(j,"$..book[?(@.price==31.96)].price", 30.9); + + CHECK(30.9 == Approx(j["store"]["book"][0]["price"].as()).epsilon(0.001)); + + //std::cout << ("2\n") << pretty_print(j) << std::endl; +} + + +TEST_CASE("test_select_two") +{ + json j = json::parse(R"( +[ + { + "a": 5, + "b": 500, + "c": 5000 + }, + { + "a": 6, + "b": 600, + "c": 6000 + }, + { + "a": 7, + "b": 700, + "c": 7000 + } +] +)"); + + json result = jsonpath::json_query(j,"$..*[?((@.a == 5 && @.b == 500) || (@.a == 6 && @.b == 600))]"); + + json expected = json::parse(R"( +[ + { + "a": 5, + "b": 500, + "c": 5000 + }, + { + "a": 6, + "b": 600, + "c": 6000 + } +] +)"); + + CHECK(result == expected); +} + +TEST_CASE("test_select_length_4") +{ + json j = json::parse(R"( +[ + { + "result": [ + 1, + 2, + 3, + 4 + ] + } +] + +)"); + + json result = jsonpath::json_query(j,"$..[?(@.result.length == 4)]"); + + json expected = json::parse(R"( +[{"result":[1,2,3,4]}] + )"); + + CHECK(result == expected); +} + +TEST_CASE("complex json") +{ + const json complex_json = json::parse(R"( + [ + { + "root": { + "id" : 10, + "second": [ + { + "names": [ + 2 + ], + "complex": [ + { + "names": [ + 1 + ], + "panels": [ + { + "result": [ + 1 + ] + }, + { + "result": [ + 1, + 2, + 3, + 4 + ] + }, + { + "result": [ + 1 + ] + } + ] + } + ] + } + ] + } + }, + { + "root": { + "id" : 20, + "second": [ + { + "names": [ + 2 + ], + "complex": [ + { + "names": [ + 1 + ], + "panels": [ + { + "result": [ + 1 + ] + }, + { + "result": [ + 1, + 2, + 3, + 4 + ] + }, + { + "result": [ + 1 + ] + } + ] + } + ] + } + ] + } + } + ] + )"); + + SECTION("test_select_length_4_2") + { + json result = jsonpath::json_query(complex_json,"$..[?(@.result.length == 4)]"); + json expected = json::parse(R"( + [{"result":[1,2,3,4]},{"result":[1,2,3,4]}] + )"); + + CHECK(result == expected); + } + SECTION("test_select_length_4_2_plus") + { + + json result = jsonpath::json_query(complex_json,"$..[?(@.id == 10)]..[?(@.result.length == 4)]"); + //std::cout << result << std::endl; + + json expected = json::parse(R"( + [{"result":[1,2,3,4]}] + )"); + + CHECK(result == expected); + } + + SECTION("test_select_length_4_2_plus_plus") + { + + json result = jsonpath::json_query(complex_json,"$..[?(@.result.length == 4)][?(@.result[0] == 3 || @.result[1] == 3 || @.result[2] == 3 || @.result[3] == 3)]"); + //std::cout << result << std::endl; + + json expected = json::parse(R"( + [{"result":[1,2,3,4]},{"result":[1,2,3,4]}] + )"); + + CHECK(result == expected); + } +} + + +TEST_CASE("test_nested") +{ + json j = json::parse(R"( +{ + "id" : 10, + "b": {"id" : 10} +} +)"); + + json result = jsonpath::json_query(j,"$..[?(@.id == 10)]"); + + json expected = json::parse(R"( +[ + { + "id" : 10, + "b" : { + "id" : 10 + } + }, + { + "id" : 10 + } +] +)"); + + CHECK(result == expected); +} + +TEST_CASE("test_array_nested") +{ + json j = json::parse(R"( +{ + "a" : [ + { + "id" : 10, + "b": {"id" : 10} + } + ] +} +)"); + + json result = jsonpath::json_query(j,"$..[?(@.id == 10)]"); + + json expected = json::parse(R"( +[ + { + "id" : 10, + "b" : { + "id" : 10 + } + }, + { + "id" : 10 + } +] +)"); + + CHECK(result == expected); +} + +TEST_CASE("test_array_array_nested") +{ + json j = json::parse(R"( +{ + "a" : [[ + { + "id" : 10, + "b": {"id" : 10} + } + ]] +} +)"); + + json result = jsonpath::json_query(j,"$..[?(@.id == 10)]"); + + json expected = json::parse(R"( +[ + { + "id" : 10, + "b" : { + "id" : 10 + } + }, + { + "id" : 10 + } +] +)"); + + CHECK(result == expected); +} + +TEST_CASE("jsonpath test 1") +{ + json j = json::parse(R"( +[ + { + "category": "reference", + "author": "Nigel Rees", + "title": "Sayings of the Century", + "price": 8.95 + }, + { + "category": "fiction", + "author": "Evelyn Waugh", + "title": "Sword of Honour", + "price": 12.99 + }, + { + "category": "fiction", + "author": "Herman Melville", + "title": "Moby Dick", + "isbn": "0-553-21311-3", + "price": 8.99 + }, + { + "category": "fiction", + "author": "J. R. R. Tolkien", + "title": "The Lord of the Rings", + "isbn": "0-395-19395-8", + "price": 22.99 + } +] +)"); + + SECTION("$.0.category") + { + json result = jsonpath::json_query(j,"$.0.category"); + REQUIRE(result.size() == 1); + CHECK(result[0].as() == std::string("reference")); + } + SECTION("$.0.'category'") + { + json result = jsonpath::json_query(j,"$.0.'category'"); + REQUIRE(result.size() == 1); + CHECK(result[0].as() == std::string("reference")); + } + SECTION("$[0].category") + { + json result = jsonpath::json_query(j,"$[0].category"); + REQUIRE(result.size() == 1); + CHECK(result[0].as() == std::string("reference")); + } + SECTION("0.category") + { + json result = jsonpath::json_query(j,"0.category"); + REQUIRE(result.size() == 1); + CHECK(result[0].as() == std::string("reference")); + } + + SECTION("0['category']") + { + json result = jsonpath::json_query(j,"0['category']"); + REQUIRE(result.size() == 1); + CHECK(result[0].as() == std::string("reference")); + } + SECTION("0[\"category\"]") + { + json result = jsonpath::json_query(j,"0[\"category\"]"); + REQUIRE(result.size() == 1); + CHECK(result[0].as() == std::string("reference")); + } + SECTION("count($.*)") + { + json result = jsonpath::json_query(j,"count($.*)"); + REQUIRE(result.size() == 1); + CHECK(result[0].as() == 4); + } + + SECTION("$.*") + { + json result = jsonpath::json_query(j,"$.*"); + REQUIRE(result.size() == 4); + CHECK(result == j); + } + + SECTION("$[-3].category") + { + json result = jsonpath::json_query(j,"$[-3].category"); + REQUIRE(result.size() == 1); + CHECK(result[0].as() == std::string("fiction")); + } + + SECTION("$[-2:].category") + { + json expected = json::parse(R"([ "Moby Dick", "The Lord of the Rings"])"); + json result = jsonpath::json_query(j,"$[-2:].title"); + REQUIRE(result.size() == 2); + CHECK(result == expected); + } + + SECTION("$[-1,-3,-4].category") + { + std::unordered_set expected{"The Lord of the Rings", "Sword of Honour", "Sayings of the Century"}; + json result = jsonpath::json_query(j,"$[-1,-3,-4].title"); + + CHECK(result.size() == expected.size()); + for (const auto& item : result.array_range()) + { + CHECK(expected.count(item.as()) == 1); + } + } + + SECTION("count($.*)") + { + json result = jsonpath::json_query(j,"count($.*)"); + REQUIRE(result.size() == 1); + CHECK(result[0].as() == 4); + } + + SECTION("count($[*])") + { + json result = jsonpath::json_query(j,"count($[*])"); + REQUIRE(result.size() == 1); + CHECK(result[0].as() == 4); + } + SECTION("keys($[1])") + { + json expected = json::array{"author","category","price","title"}; + + json result = jsonpath::json_query(j,"keys($[1])[*]"); + CHECK(result == expected); + } +#if !(defined(__GNUC__) && (__GNUC__ == 4 && __GNUC_MINOR__ < 9)) +// GCC 4.8 has broken regex support: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53631 + SECTION("$[?(tokenize(@.author,'\\\\s+')[1] == 'Waugh')].title") + { + json expected = json::array{"Sword of Honour"}; + + json result = jsonpath::json_query(j,"$[?(tokenize(@.author,'\\\\s+')[1] == 'Waugh')].title"); + + CHECK(result == expected); + } + + SECTION("tokenize($[0].author,'\\\\s+')") + { + json expected = json::parse("[[\"Nigel\",\"Rees\"]]"); + + json result = jsonpath::json_query(j,"tokenize($[0].author,'\\\\s+')"); + + CHECK(result == expected); + } +#endif +} +TEST_CASE("jsonpath array union test") +{ + json root = json::parse(R"( +[[1,2,3,4,1,2,3,4],[0,1,2,3,4,5,6,7,8,9],[0,1,2,3,4,5,6,7,8,9]] +)"); + SECTION("Test 1") + { + json expected = json::parse(R"( +[[0,1,2,3,4,5,6,7,8,9],[1,2,3,4,1,2,3,4]] +)"); + json result = jsonpath::json_query(root,"$[0,1,2]"); + CHECK(result == expected); + } + + SECTION("Test 2") + { + json expected = json::parse(R"( +[1,2,3,4] +)"); + json result = jsonpath::json_query(root, "$[0][0:4,2:8]"); + CHECK(result == expected); + } + + SECTION("Test 3") + { + json expected = json::parse(R"( +[1,4] +)"); + json result = jsonpath::json_query(root, "$[0][0,0,0,3]"); + CHECK(result == expected); + } + + SECTION("Test 4") + { + json expected = json::parse(R"( +[1,2] +)"); + //json result1 = jsonpath::json_query(root,"$[0.0,1.1,2.2]"); + json result2 = jsonpath::json_query(root,"$[0[0],1[1],2[2]]"); + + //CHECK(result1 == expected); + CHECK(result2 == expected); + } +} + +TEST_CASE("jsonpath object union test 1") +{ + const json root = json::parse(R"( +[{ + "firstName": "John", + "lastName" : "Smith", + "age" : 26, + "address" : { + "streetAddress": "naist street", + "city" : "Nara", + "postalCode" : "630-0192" + }, + "phoneNumbers": [ + { + "type" : "iPhone", + "number": "0123-4567-8888" + }, + { + "type" : "home", + "number": "0123-4567-8910" + } + ] +}, +{ + "firstName": "John", + "lastName" : "Doe", + "age" : 30, + "address" : { + "streetAddress": "naist street", + "city" : "Nara", + "postalCode" : "630-0192" + }, + "phoneNumbers": [ + { + "type" : "iPhone", + "number": "0123-4567-8888" + }, + { + "type" : "home", + "number": "0123-4567-8910" + } + ] +}] + +)"); + + SECTION("$..[firstName,address.city]") + { + json expected = json::parse(R"(["John","Nara"])"); + std::string path = "$..[firstName,address.city]"; + json result = jsonpath::json_query(root,path); + CHECK(result == expected); + } + SECTION("$..[firstName,*.city]") + { + json expected = json::parse(R"(["John","Nara"])"); + std::string path = "$..[firstName,*.city]"; + json result = jsonpath::json_query(root,path); + CHECK(result == expected); + } + SECTION("$..[firstName,address[city]]") + { + json expected = json::parse(R"(["John","Nara"])"); + std::string path = "$..[firstName,address[city]]"; + json result = jsonpath::json_query(root,path); + CHECK(result == expected); + } + SECTION("$..[firstName,address['city']]") + { + json expected = json::parse(R"(["John","Nara"])"); + std::string path = "$..[firstName,address['city']]"; + json result = jsonpath::json_query(root,path); + CHECK(result == expected); + } + SECTION("$..[firstName,address.'city']") + { + json expected = json::parse(R"(["John","Nara"])"); + std::string path = "$..[firstName,address.'city']"; + json result = jsonpath::json_query(root,path); + CHECK(result == expected); + } + SECTION(R"($..[firstName,address."city"])") + { + json expected = json::parse(R"(["John","Nara"])"); + std::string path = R"($..[firstName,address."city"])"; + json result = jsonpath::json_query(root,path); + CHECK(result == expected); + } + SECTION(R"($..[firstName,address["city"]])") + { + json expected = json::parse(R"(["John","Nara"])"); + std::string path = R"($..[firstName,address["city"]])"; + json result = jsonpath::json_query(root,path); + CHECK(result == expected); + } + SECTION(R"($..['firstName','address'["city"]])") + { + json expected = json::parse(R"(["John","Nara"])"); + std::string path = R"($..['firstName','address'["city"]])"; + json result = jsonpath::json_query(root,path); + CHECK(result == expected); + } + SECTION(R"($..["firstName","address"["city"]])") + { + json expected = json::parse(R"(["John","Nara"])"); + std::string path = R"($..["firstName","address"["city"]])"; + json result = jsonpath::json_query(root,path); + CHECK(result == expected); + } + SECTION(R"($..["firstName","address"["city"]])") + { + json expected = json::parse(R"(["John","Nara"])"); + std::string path = R"($..[?(@.firstName == 'John')])"; + json result = jsonpath::json_query(root,path); + //std::cout << pretty_print(result) << "\n\n"; + //CHECK(result == expected); + } + SECTION(R"($..[?(@.firstName == 'John')][?(@.lastName == 'Doe')])") + { + json expected = json::parse(R"(["John","Nara"])"); + std::string path = R"($..[?(@.firstName == 'John')][?(@.lastName == 'Doe')])"; + json result = jsonpath::json_query(root,path); + REQUIRE(result.size() == 1); + CHECK(result[0] == root[1]); + } +} + +TEST_CASE("jsonpath object union test") +{ + const json root = json::parse(R"( +[{ + "firstName": "John", + "lastName" : "Smith" +}, +{ + "firstName": "John", + "lastName" : "Doe" +} +] + +)"); + + SECTION(R"($..["firstName","address"["city"]])") + { + json expected = json::parse(R"([{"firstName":"John","lastName":"Smith"},{"firstName":"John","lastName":"Doe"}])"); + std::string path = R"($..[?(@.firstName == 'John')])"; + json result = jsonpath::json_query(root,path); + //std::cout << result << "\n\n"; + CHECK(result == expected); + } + + SECTION(R"($..["firstName","address"["city"]])") + { + json expected = json::parse(R"([{"firstName":"John","lastName":"Doe"}])"); + std::string path = R"($[?(@.firstName == 'John')][?(@.lastName == 'Doe')])"; + json result = jsonpath::json_query(root,path); + //std::cout << result << "\n\n"; + CHECK(result == expected); + } +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/jsonpointer/jsonpointer_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/jsonpointer/jsonpointer_tests.cpp new file mode 100644 index 0000000000..dfb6575a29 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/jsonpointer/jsonpointer_tests.cpp @@ -0,0 +1,316 @@ +// Copyright 2017 Daniel Parker +// Distributed under Boost license + +#if defined(_MSC_VER) +#include "windows.h" // test no inadvertant macro expansions +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; +using namespace jsoncons::literals; + +void check_get_with_const_ref(const json& example, const std::string& pointer, const json& expected) +{ + + std::error_code ec; + const json& result = jsonpointer::get(example,pointer,ec); + CHECK_FALSE(ec); + CHECK(result == expected); +} + +void check_contains(const json& example, const std::string& pointer, bool expected) +{ + bool result = jsonpointer::contains(example,pointer); + CHECK(result == expected); +} + +void check_insert_or_assign(json& example, const std::string& path, const json& value, const json& expected) +{ + std::error_code ec; + jsonpointer::insert_or_assign(example, path, value, ec); + CHECK_FALSE(ec); + CHECK(example == expected); +} + +void check_replace(json& example, const std::string& path, const json& value, const json& expected) +{ + std::error_code ec; + jsonpointer::replace(example, path, value, ec); + CHECK_FALSE(ec); + CHECK(example == expected); +} + +void check_remove(json& example, const std::string& path, const json& expected) +{ + std::error_code ec; + jsonpointer::remove(example, path, ec); + CHECK_FALSE(ec); + CHECK(example == expected); +} + +TEST_CASE("get_with_const_ref_test") +{ +// Example from RFC 6901 +const json example = json::parse(R"( + { + "foo": ["bar", "baz"], + "": 0, + "a/b": 1, + "c%d": 2, + "e^f": 3, + "g|h": 4, + "i\\j": 5, + "k\"l": 6, + " ": 7, + "m~n": 8 + } +)"); + + check_contains(example,"",true); + check_contains(example,"/foo",true); + check_contains(example,"/foo/0",true); + check_contains(example,"/",true); + check_contains(example,"/a~1b",true); + check_contains(example,"/c%d",true); + check_contains(example,"/e^f",true); + check_contains(example,"/g|h",true); + check_contains(example,"/i\\j",true); + check_contains(example,"/k\"l",true); + check_contains(example,"/ ",true); + check_contains(example,"/m~0n",true); + + check_get_with_const_ref(example,"",example); + check_get_with_const_ref(example,"/foo",json::parse("[\"bar\", \"baz\"]")); + check_get_with_const_ref(example,"/foo/0",json("bar")); + check_get_with_const_ref(example,"/",json(0)); + check_get_with_const_ref(example,"/a~1b",json(1)); + check_get_with_const_ref(example,"/c%d",json(2)); + check_get_with_const_ref(example,"/e^f",json(3)); + check_get_with_const_ref(example,"/g|h",json(4)); + check_get_with_const_ref(example,"/i\\j",json(5)); + check_get_with_const_ref(example,"/k\"l",json(6)); + check_get_with_const_ref(example,"/ ",json(7)); + check_get_with_const_ref(example,"/m~0n",json(8)); +} + +TEST_CASE("get_with_ref_test") +{ +// Example from RFC 6901 +json example = json::parse(R"( + { + "foo": ["bar", "baz"] + } +)"); + + std::error_code ec; + json& result = jsonpointer::get(example,"/foo/0",ec); + CHECK_FALSE(ec); + + result = "bat"; + + //std::cout << example << std::endl; +} + +TEST_CASE("get_with_nonexistent_target") +{ + json example = R"( + { "foo": "bar" } + )"_json; + + check_contains(example,"/baz",false); +} + +// insert_or_assign + +TEST_CASE("test_add_object_member") +{ + json example = json::parse(R"( + { "foo": "bar"} + )"); + + const json expected = json::parse(R"( + { "foo": "bar", "baz" : "qux"} + )"); + + check_insert_or_assign(example,"/baz", json("qux"), expected); +} + +TEST_CASE("test_add_array_element") +{ + json example = json::parse(R"( + { "foo": [ "bar", "baz" ] } + )"); + + const json expected = json::parse(R"( + { "foo": [ "bar", "qux", "baz" ] } + )"); + + check_insert_or_assign(example,"/foo/1", json("qux"), expected); +} + +TEST_CASE("test_add_array_value") +{ + json example = json::parse(R"( + { "foo": ["bar"] } + )"); + + const json expected = json::parse(R"( + { "foo": ["bar", ["abc", "def"]] } + )"); + + check_insert_or_assign(example,"/foo/-", json::array({"abc", "def"}), expected); +} + +// remove + +TEST_CASE("test_remove_object_member") +{ + json example = json::parse(R"( + { "foo": "bar", "baz" : "qux"} + )"); + + const json expected = json::parse(R"( + { "foo": "bar"} + )"); + + check_remove(example,"/baz", expected); +} + +TEST_CASE("test_remove_array_element") +{ + json example = json::parse(R"( + { "foo": [ "bar", "qux", "baz" ] } + )"); + + const json expected = json::parse(R"( + { "foo": [ "bar", "baz" ] } + )"); + + check_remove(example,"/foo/1", expected); +} + +// replace + +TEST_CASE("test_replace_object_value") +{ + json example = json::parse(R"( + { + "baz": "qux", + "foo": "bar" + } + )"); + + const json expected = json::parse(R"( + { + "baz": "boo", + "foo": "bar" + } + )"); + + check_replace(example,"/baz", json("boo"), expected); +} +TEST_CASE("test_replace_array_value") +{ + json example = json::parse(R"( + { "foo": [ "bar", "baz" ] } + )"); + + const json expected = json::parse(R"( + { "foo": [ "bar", "qux" ] } + )"); + + check_replace(example,"/foo/1", json("qux"), expected); +} + +TEST_CASE("jsonpointer path tests") +{ + SECTION("/a~1b") + { + jsonpointer::address p("/a~1b"); + + auto it = p.begin(); + auto end = p.end(); + + CHECK((*it++ == "a/b")); + CHECK(it == end); + } + SECTION("/a~1b") + { + jsonpointer::address p("/m~0n"); + + auto it = p.begin(); + auto end = p.end(); + + CHECK((*it++ == "m~n")); + CHECK(it == end); + } + SECTION("/0/1") + { + jsonpointer::address p("/0/1"); + + auto it = p.begin(); + auto end = p.end(); + + CHECK((*it++ == "0")); + CHECK((*it++ == "1")); + CHECK(it == end); + } +} + +TEST_CASE("jsonpointer concatenation") +{ + // Example from RFC 6901 + json example = json::parse(R"( + { + "a/b": ["bar", "baz"], + "m~n": ["foo", "qux"] + } + )"); + + SECTION("path append a/b") + { + jsonpointer::address p; + p /= "a/b"; + p /= "0"; + + auto it = p.begin(); + auto end = p.end(); + + CHECK((*it++ == "a/b")); + CHECK((*it++ == "0")); + CHECK(it == end); + + std::error_code ec; + json j = jsonpointer::get(example, p, ec); + std::cout << j << "\n"; + } + + SECTION("concatenate two paths") + { + jsonpointer::address p1; + p1 /= "m~n"; + jsonpointer::address p2; + p2 /= "1"; + jsonpointer::address p = p1 + p2; + + auto it = p.begin(); + auto end = p.end(); + + CHECK((*it++ == "m~n")); + CHECK((*it++ == "1")); + CHECK(it == end); + + json j = jsonpointer::get(example, p); + std::cout << j << "\n"; + } +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/msgpack/decode_msgpack_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/msgpack/decode_msgpack_tests.cpp new file mode 100644 index 0000000000..843050aa28 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/msgpack/decode_msgpack_tests.cpp @@ -0,0 +1,129 @@ +// Copyright 2016 Daniel Parker +// Distributed under Boost license + +#if defined(_MSC_VER) +#include "windows.h" // test no inadvertant macro expansions +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; +using namespace jsoncons::msgpack; + +void check_decode_msgpack(const std::vector& v, const json& expected) +{ + json result = decode_msgpack(v); + REQUIRE(result == expected); +} + +TEST_CASE("decode_number_msgpack_test") +{ + // positive fixint 0x00 - 0x7f + check_decode_msgpack({0x00},json(0U)); + check_decode_msgpack({0x01},json(1U)); + check_decode_msgpack({0x0a},json(10U)); + check_decode_msgpack({0x17},json(23U)); + check_decode_msgpack({0x18},json(24U)); + check_decode_msgpack({0x7f},json(127U)); + + check_decode_msgpack({0xcc,0xff},json(255U)); + check_decode_msgpack({0xcd,0x01,0x00},json(256U)); + check_decode_msgpack({0xcd,0xff,0xff},json(65535U)); + check_decode_msgpack({0xce,0,1,0x00,0x00},json(65536U)); + check_decode_msgpack({0xce,0xff,0xff,0xff,0xff},json(4294967295U)); + check_decode_msgpack({0xcf,0,0,0,1,0,0,0,0},json(4294967296U)); + check_decode_msgpack({0xcf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff},json((std::numeric_limits::max)())); + + check_decode_msgpack({0x01},json(1)); + check_decode_msgpack({0x0a},json(10)); + check_decode_msgpack({0x17},json(23)); + check_decode_msgpack({0x18},json(24)); + check_decode_msgpack({0x7f},json(127)); + + check_decode_msgpack({0xcc,0xff},json(255)); + check_decode_msgpack({0xcd,0x01,0x00},json(256)); + check_decode_msgpack({0xcd,0xff,0xff},json(65535)); + check_decode_msgpack({0xce,0,1,0x00,0x00},json(65536)); + check_decode_msgpack({0xce,0xff,0xff,0xff,0xff},json(4294967295)); + check_decode_msgpack({0xd3,0,0,0,1,0,0,0,0},json(4294967296)); + check_decode_msgpack({0xd3,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff},json((std::numeric_limits::max)())); + + // negative fixint 0xe0 - 0xff + check_decode_msgpack({0xe0},json(-32)); + check_decode_msgpack({0xff},json(-1)); // + + // negative integers + check_decode_msgpack({0xd1,0xff,0},json(-256)); + check_decode_msgpack({0xd1,0xfe,0xff},json(-257)); + check_decode_msgpack({0xd2,0xff,0xff,0,0},json(-65536)); + check_decode_msgpack({0xd2,0xff,0xfe,0xff,0xff},json(-65537)); + check_decode_msgpack({0xd3,0xff,0xff,0xff,0xff,0,0,0,0},json(-4294967296)); + check_decode_msgpack({0xd3,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff},json(-4294967297)); + + // null, true, false + check_decode_msgpack({0xc0},json::null()); // + check_decode_msgpack({0xc3},json(true)); // + check_decode_msgpack({0xc2},json(false)); // + + // floating point + check_decode_msgpack({0xcb,0,0,0,0,0,0,0,0},json(0.0)); + check_decode_msgpack({0xcb,0xbf,0xf0,0,0,0,0,0,0},json(-1.0)); + check_decode_msgpack({0xcb,0xc1,0x6f,0xff,0xff,0xe0,0,0,0},json(-16777215.0)); + + // string + check_decode_msgpack({0xa0},json("")); + check_decode_msgpack({0xa1,' '},json(" ")); + check_decode_msgpack({0xbf,'1','2','3','4','5','6','7','8','9','0', + '1','2','3','4','5','6','7','8','9','0', + '1','2','3','4','5','6','7','8','9','0', + '1'}, + json("1234567890123456789012345678901")); + check_decode_msgpack({0xd9,0x20,'1','2','3','4','5','6','7','8','9','0', + '1','2','3','4','5','6','7','8','9','0', + '1','2','3','4','5','6','7','8','9','0', + '1','2'}, + json("12345678901234567890123456789012")); + +} + +TEST_CASE("decode_msgpack_arrays_and_maps") +{ + // fixarray + check_decode_msgpack({0x90},json::array()); + check_decode_msgpack({0x80},json::object()); + + check_decode_msgpack({0x91,'\0'},json::parse("[0]")); + check_decode_msgpack({0x92,'\0','\0'},json::array({0,0})); + check_decode_msgpack({0x92,0x91,'\0','\0'}, json::parse("[[0],0]")); + check_decode_msgpack({0x91,0xa5,'H','e','l','l','o'},json::parse("[\"Hello\"]")); + + check_decode_msgpack({0x81,0xa2,'o','c',0x91,'\0'}, json::parse("{\"oc\": [0]}")); + check_decode_msgpack({0x81,0xa2,'o','c',0x94,'\0','\1','\2','\3'}, json::parse("{\"oc\": [0, 1, 2, 3]}")); +} + +TEST_CASE("Compare msgpack packed item and jsoncons item") +{ + std::vector bytes; + msgpack::msgpack_bytes_encoder encoder(bytes); + encoder.begin_array(2); // Must be definite length array + encoder.string_value("foo"); + encoder.byte_string_value(byte_string{'b','a','r'}); + encoder.end_array(); + encoder.flush(); + + json expected = json::array(); + + expected.emplace_back("foo"); + expected.emplace_back(byte_string{ 'b','a','r' }); + + json j = msgpack::decode_msgpack(bytes); + + REQUIRE(j == expected); +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/msgpack/encode_msgpack_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/msgpack/encode_msgpack_tests.cpp new file mode 100644 index 0000000000..97071eb1c6 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/msgpack/encode_msgpack_tests.cpp @@ -0,0 +1,127 @@ +// Copyright 2016 Daniel Parker +// Distributed under Boost license + +#if defined(_MSC_VER) +#include "windows.h" // test no inadvertant macro expansions +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +void check_encode_msgpack(const std::vector& expected, + const json& j) +{ + std::vector result; + msgpack::encode_msgpack(j, result); + if (result.size() != expected.size()) + { + std::cout << std::hex << (int)expected[0] << " " << std::hex << (int)result[0] << std::endl; + } + REQUIRE(result.size() == expected.size()); + for (size_t i = 0; i < expected.size(); ++i) + { + if (expected[i] != result[i]) + { + std::cout << "Different " << i << "\n"; + for (size_t k = 0; k < expected.size(); ++k) + { + std::cout << std::hex << (int)expected[k] << " " << std::hex << (int)result[k] << std::endl; + } + } + REQUIRE(result[i] == expected[i]); + } +} + +TEST_CASE("encode_msgpack_test") +{ + // positive fixint 0x00 - 0x7f + check_encode_msgpack({0x00},json(0U)); + check_encode_msgpack({0x01},json(1U)); + check_encode_msgpack({0x0a},json(10U)); + check_encode_msgpack({0x17},json(23U)); + check_encode_msgpack({0x18},json(24U)); + check_encode_msgpack({0x7f},json(127U)); + + check_encode_msgpack({0xcc,0xff},json(255U)); + check_encode_msgpack({0xcd,0x01,0x00},json(256U)); + check_encode_msgpack({0xcd,0xff,0xff},json(65535U)); + check_encode_msgpack({0xce,0,1,0x00,0x00},json(65536U)); + check_encode_msgpack({0xce,0xff,0xff,0xff,0xff},json(4294967295U)); + check_encode_msgpack({0xcf,0,0,0,1,0,0,0,0},json(4294967296U)); + check_encode_msgpack({0xcf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff},json((std::numeric_limits::max)())); + + check_encode_msgpack({0x01},json(1)); + check_encode_msgpack({0x0a},json(10)); + check_encode_msgpack({0x17},json(23)); + check_encode_msgpack({0x18},json(24)); + check_encode_msgpack({0x7f},json(127)); + + check_encode_msgpack({0xcc,0xff},json(255)); + check_encode_msgpack({0xcd,0x01,0x00},json(256)); + check_encode_msgpack({0xcd,0xff,0xff},json(65535)); + check_encode_msgpack({0xce,0,1,0x00,0x00},json(65536)); + check_encode_msgpack({0xce,0xff,0xff,0xff,0xff},json(4294967295)); + check_encode_msgpack({0xcf,0,0,0,1,0,0,0,0},json(4294967296)); + check_encode_msgpack({0xcf,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff},json((std::numeric_limits::max)())); + + // negative fixint 0xe0 - 0xff + check_encode_msgpack({0xe0},json(-32)); + check_encode_msgpack({0xff},json(-1)); // + + // negative integers + check_encode_msgpack({0xd1,0xff,0},json(-256)); + check_encode_msgpack({0xd1,0xfe,0xff},json(-257)); + check_encode_msgpack({0xd2,0xff,0xff,0,0},json(-65536)); + check_encode_msgpack({0xd2,0xff,0xfe,0xff,0xff},json(-65537)); + check_encode_msgpack({0xd3,0xff,0xff,0xff,0xff,0,0,0,0},json(-4294967296)); + check_encode_msgpack({0xd3,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff},json(-4294967297)); + + // null, true, false + check_encode_msgpack({0xc0},json::null()); // + check_encode_msgpack({0xc3},json(true)); // + check_encode_msgpack({0xc2},json(false)); // + + // floating point + check_encode_msgpack({0xca,0,0,0,0},json(0.0)); + check_encode_msgpack({0xca,0xbf,0x80,0,0},json(-1.0)); + check_encode_msgpack({0xca,0xcb,0x7f,0xff,0xff},json(-16777215.0)); + + // string + check_encode_msgpack({0xa0},json("")); + check_encode_msgpack({0xa1,' '},json(" ")); + check_encode_msgpack({0xbf,'1','2','3','4','5','6','7','8','9','0', + '1','2','3','4','5','6','7','8','9','0', + '1','2','3','4','5','6','7','8','9','0', + '1'}, + json("1234567890123456789012345678901")); + check_encode_msgpack({0xd9,0x20,'1','2','3','4','5','6','7','8','9','0', + '1','2','3','4','5','6','7','8','9','0', + '1','2','3','4','5','6','7','8','9','0', + '1','2'}, + json("12345678901234567890123456789012")); + + +} + +TEST_CASE("encode_msgpack_arrays_and_maps") +{ + // fixarray + check_encode_msgpack({0x90},json::array()); + check_encode_msgpack({0x80},json::object()); + + check_encode_msgpack({0x91,'\0'},json::parse("[0]")); + check_encode_msgpack({0x92,'\0','\0'},json::array({0,0})); + check_encode_msgpack({0x92,0x91,'\0','\0'}, json::parse("[[0],0]")); + check_encode_msgpack({0x91,0xa5,'H','e','l','l','o'},json::parse("[\"Hello\"]")); + + check_encode_msgpack({0x81,0xa2,'o','c',0x91,'\0'}, json::parse("{\"oc\": [0]}")); + check_encode_msgpack({0x81,0xa2,'o','c',0x94,'\0','\1','\2','\3'}, json::parse("{\"oc\": [0, 1, 2, 3]}")); +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/msgpack/msgpack_encoder_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/msgpack/msgpack_encoder_tests.cpp new file mode 100644 index 0000000000..aee9765ca5 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/msgpack/msgpack_encoder_tests.cpp @@ -0,0 +1,108 @@ +// Copyright 2016 Daniel Parker +// Distributed under Boost license + +#if defined(_MSC_VER) +#include "windows.h" // test no inadvertant macro expansions +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +TEST_CASE("serialize array to msgpack") +{ + std::vector v; + msgpack::msgpack_bytes_encoder encoder(v); + //encoder.begin_object(1); + encoder.begin_array(3); + encoder.bool_value(true); + encoder.bool_value(false); + encoder.null_value(); + encoder.end_array(); + //encoder.end_object(); + encoder.flush(); + + try + { + json result = msgpack::decode_msgpack(v); + std::cout << result << std::endl; + } + catch (const std::exception& e) + { + std::cout << e.what() << std::endl; + } +} + +TEST_CASE("Too many and too few items in MessagePack object or array") +{ + std::error_code ec{}; + std::vector v; + msgpack::msgpack_bytes_encoder encoder(v); + + SECTION("Too many items in array") + { + CHECK(encoder.begin_array(3)); + CHECK(encoder.bool_value(true)); + CHECK(encoder.bool_value(false)); + CHECK(encoder.null_value()); + CHECK(encoder.begin_array(2)); + CHECK(encoder.string_value("cat")); + CHECK(encoder.string_value("feline")); + CHECK(encoder.end_array()); + REQUIRE_THROWS_WITH(encoder.end_array(), msgpack::msgpack_error_category_impl().message((int)msgpack::msgpack_errc::too_many_items).c_str()); + encoder.flush(); + } + SECTION("Too few items in array") + { + CHECK(encoder.begin_array(5)); + CHECK(encoder.bool_value(true)); + CHECK(encoder.bool_value(false)); + CHECK(encoder.null_value()); + CHECK(encoder.begin_array(2)); + CHECK(encoder.string_value("cat")); + CHECK(encoder.string_value("feline")); + CHECK(encoder.end_array()); + REQUIRE_THROWS_WITH(encoder.end_array(), msgpack::msgpack_error_category_impl().message((int)msgpack::msgpack_errc::too_few_items).c_str()); + encoder.flush(); + } + SECTION("Too many items in object") + { + CHECK(encoder.begin_object(3)); + CHECK(encoder.name("a")); + CHECK(encoder.bool_value(true)); + CHECK(encoder.name("b")); + CHECK(encoder.bool_value(false)); + CHECK(encoder.name("c")); + CHECK(encoder.null_value()); + CHECK(encoder.name("d")); + CHECK(encoder.begin_array(2)); + CHECK(encoder.string_value("cat")); + CHECK(encoder.string_value("feline")); + CHECK(encoder.end_array()); + REQUIRE_THROWS_WITH(encoder.end_object(), msgpack::msgpack_error_category_impl().message((int)msgpack::msgpack_errc::too_many_items).c_str()); + encoder.flush(); + } + SECTION("Too few items in object") + { + CHECK(encoder.begin_object(5)); + CHECK(encoder.name("a")); + CHECK(encoder.bool_value(true)); + CHECK(encoder.name("b")); + CHECK(encoder.bool_value(false)); + CHECK(encoder.name("c")); + CHECK(encoder.null_value()); + CHECK(encoder.name("d")); + CHECK(encoder.begin_array(2)); + CHECK(encoder.string_value("cat")); + CHECK(encoder.string_value("feline")); + CHECK(encoder.end_array()); + REQUIRE_THROWS_WITH(encoder.end_object(), msgpack::msgpack_error_category_impl().message((int)msgpack::msgpack_errc::too_few_items).c_str()); + encoder.flush(); + } +} diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/msgpack/msgpack_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/msgpack/msgpack_tests.cpp new file mode 100644 index 0000000000..99a0ae9dcd --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/msgpack/msgpack_tests.cpp @@ -0,0 +1,147 @@ +// Copyright 2016 Daniel Parker +// Distributed under Boost license + +#if defined(_MSC_VER) +#include "windows.h" // test no inadvertant macro expansions +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; +using namespace jsoncons::msgpack; + +TEST_CASE("msgpack_test") +{ + json j1; + j1["zero"] = 0; + j1["one"] = 1; + j1["two"] = 2; + j1["null"] = null_type(); + j1["true"] = true; + j1["false"] = false; + j1["max int64_t"] = (std::numeric_limits::max)(); + j1["max uint64_t"] = (std::numeric_limits::max)(); + j1["min int64_t"] = (std::numeric_limits::lowest)(); + j1["max int32_t"] = (std::numeric_limits::max)(); + j1["max uint32_t"] = (std::numeric_limits::max)(); + j1["min int32_t"] = (std::numeric_limits::lowest)(); + j1["max int16_t"] = (std::numeric_limits::max)(); + j1["max uint16_t"] = (std::numeric_limits::max)(); + j1["min int16_t"] = (std::numeric_limits::lowest)(); + j1["max int8_t"] = (std::numeric_limits::max)(); + j1["max uint8_t"] = (std::numeric_limits::max)(); + j1["min int8_t"] = (std::numeric_limits::lowest)(); + j1["max double"] = (std::numeric_limits::max)(); + j1["min double"] = (std::numeric_limits::lowest)(); + j1["max float"] = (std::numeric_limits::max)(); + j1["zero float"] = 0.0; + j1["min float"] = (std::numeric_limits::lowest)(); + j1["String too long for small string optimization"] = "String too long for small string optimization"; + + json ja = json::array(); + ja.push_back(0); + ja.push_back(1); + ja.push_back(2); + ja.push_back(null_type()); + ja.push_back(true); + ja.push_back(false); + ja.push_back((std::numeric_limits::max)()); + ja.push_back((std::numeric_limits::max)()); + ja.push_back((std::numeric_limits::lowest)()); + ja.push_back((std::numeric_limits::max)()); + ja.push_back((std::numeric_limits::max)()); + ja.push_back((std::numeric_limits::lowest)()); + ja.push_back((std::numeric_limits::max)()); + ja.push_back((std::numeric_limits::max)()); + ja.push_back((std::numeric_limits::lowest)()); + ja.push_back((std::numeric_limits::max)()); + ja.push_back((std::numeric_limits::max)()); + ja.push_back((std::numeric_limits::lowest)()); + ja.push_back((std::numeric_limits::max)()); + ja.push_back((std::numeric_limits::lowest)()); + ja.push_back((std::numeric_limits::max)()); + ja.push_back(0.0); + ja.push_back((std::numeric_limits::lowest)()); + ja.push_back("String too long for small string optimization"); + + j1["An array"] = ja; + + std::vector v; + encode_msgpack(j1, v); + + json j2 = decode_msgpack(v); + + CHECK(j1 == j2); +} + +TEST_CASE("msgpack_test2") +{ + wjson j1; + j1[L"zero"] = 0; + j1[L"one"] = 1; + j1[L"two"] = 2; + j1[L"null"] = null_type(); + j1[L"true"] = true; + j1[L"false"] = false; + j1[L"max int64_t"] = (std::numeric_limits::max)(); + j1[L"max uint64_t"] = (std::numeric_limits::max)(); + j1[L"min int64_t"] = (std::numeric_limits::lowest)(); + j1[L"max int32_t"] = (std::numeric_limits::max)(); + j1[L"max uint32_t"] = (std::numeric_limits::max)(); + j1[L"min int32_t"] = (std::numeric_limits::lowest)(); + j1[L"max int16_t"] = (std::numeric_limits::max)(); + j1[L"max uint16_t"] = (std::numeric_limits::max)(); + j1[L"min int16_t"] = (std::numeric_limits::lowest)(); + j1[L"max int8_t"] = (std::numeric_limits::max)(); + j1[L"max uint8_t"] = (std::numeric_limits::max)(); + j1[L"min int8_t"] = (std::numeric_limits::lowest)(); + j1[L"max double"] = (std::numeric_limits::max)(); + j1[L"min double"] = (std::numeric_limits::lowest)(); + j1[L"max float"] = (std::numeric_limits::max)(); + j1[L"zero float"] = 0.0; + j1[L"min float"] = (std::numeric_limits::lowest)(); + j1[L"S"] = L"S"; + j1[L"String too long for small string optimization"] = L"String too long for small string optimization"; + + wjson ja = wjson::array(); + ja.push_back(0); + ja.push_back(1); + ja.push_back(2); + ja.push_back(null_type()); + ja.push_back(true); + ja.push_back(false); + ja.push_back((std::numeric_limits::max)()); + ja.push_back((std::numeric_limits::max)()); + ja.push_back((std::numeric_limits::lowest)()); + ja.push_back((std::numeric_limits::max)()); + ja.push_back((std::numeric_limits::max)()); + ja.push_back((std::numeric_limits::lowest)()); + ja.push_back((std::numeric_limits::max)()); + ja.push_back((std::numeric_limits::max)()); + ja.push_back((std::numeric_limits::lowest)()); + ja.push_back((std::numeric_limits::max)()); + ja.push_back((std::numeric_limits::max)()); + ja.push_back((std::numeric_limits::lowest)()); + ja.push_back((std::numeric_limits::max)()); + ja.push_back((std::numeric_limits::lowest)()); + ja.push_back((std::numeric_limits::max)()); + ja.push_back(0.0); + ja.push_back((std::numeric_limits::lowest)()); + ja.push_back(L"S"); + ja.push_back(L"String too long for small string optimization"); + + j1[L"An array"] = ja; + + std::vector v; + encode_msgpack(j1, v); + + //wjson j2 = decode_msgpack(v); + + //CHECK(j1 == j2); +} diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/ojson_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/ojson_tests.cpp new file mode 100644 index 0000000000..5d1fdc11bd --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/ojson_tests.cpp @@ -0,0 +1,102 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +TEST_CASE("test_index") +{ + ojson o = ojson::parse(R"( + { + "street_number" : "100", + "street_name" : "Queen St W", + "city" : "Toronto", + "country" : "Canada" + } + )"); + + CHECK("100" == o[0].as()); + CHECK("Queen St W" == o[1].as()); + CHECK("Toronto" ==o[2].as()); + CHECK("Canada" ==o[3].as()); + + CHECK("100" == o.at(0).as()); + CHECK("Queen St W" == o.at(1).as()); + CHECK("Toronto" ==o.at(2).as()); + CHECK("Canada" ==o.at(3).as()); +} + +TEST_CASE("test_object") +{ + ojson o = ojson::parse(R"( + { + "street_number" : "100", + "street_name" : "Queen St W", + "city" : "Toronto", + "country" : "Canada" + } + )"); + + o.insert_or_assign("postal_code", "M5H 2N2"); + + ojson o2 = o; + CHECK(o == o2); + + ojson o3 = o; + o3["street_name"] = "Queen St W"; + //CHECK(o == o3); + + //BOOST_CHECK_EQUAL("Queen St W",o["street_name"].as()); + //CHECK(2 == o["city"].as()); + //CHECK(4 == o["street_number"].as()); + + auto it = o.find("country"); + CHECK_FALSE((it == o.object_range().end())); + o.insert_or_assign(it,"province","Ontario"); + + o.insert_or_assign("unit_type","O"); + + o.erase("unit_type"); +} + +TEST_CASE("test_object_emplace") +{ + ojson o = ojson::parse(R"( + { + "street_number" : "100", + "street_name" : "Queen St W", + "city" : "Toronto", + "country" : "Canada" + } + )"); + + o.try_emplace("postal_code", "M5H 2N2"); + + ojson o2 = o; + CHECK(o == o2); + + ojson o3 = o; + o3["street_name"] = "Queen St W"; + //CHECK(o == o3); + + //BOOST_CHECK_EQUAL("Queen St W",o["street_name"].as()); + //CHECK(2 == o["city"].as()); + //CHECK(4 == o["street_number"].as()); + + auto it = o.find("country"); + CHECK_FALSE((it == o.object_range().end())); + o.try_emplace(it,"province","Ontario"); + + o.try_emplace("unit_type","O"); + + o.erase("unit_type"); +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/order_preserving_json_object_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/order_preserving_json_object_tests.cpp new file mode 100644 index 0000000000..6dd362666f --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/order_preserving_json_object_tests.cpp @@ -0,0 +1,290 @@ +// Copyright 2019 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +TEST_CASE("json sorted_unique_range_tag") +{ + typedef std::pair item_type; + std::vector items; + items.emplace_back("a", 1); + items.emplace_back("b", 2); + items.emplace_back("c", 3); + items.emplace_back("d", 4); + items.emplace_back("e", 5); + items.emplace_back("f", 6); + items.emplace_back("g", 7); + + json j; + j.insert(sorted_unique_range_tag(), items.begin(), items.end()); + + SECTION("iterate") + { + REQUIRE(j.size() == 7); + + auto it = j.object_range().begin(); + CHECK(it->key() == std::string("a")); + CHECK(it->value().as() == 1); + CHECK((++it)->key() == std::string("b")); + CHECK(it->value().as() == 2); + CHECK((++it)->key() == std::string("c")); + CHECK(it->value().as() == 3); + CHECK((++it)->key() == std::string("d")); + CHECK(it->value().as() == 4); + CHECK((++it)->key() == std::string("e")); + CHECK(it->value().as() == 5); + CHECK((++it)->key() == std::string("f")); + CHECK(it->value().as() == 6); + CHECK((++it)->key() == std::string("g")); + CHECK(it->value().as() == 7); + } + + SECTION("find") + { + auto it1 = j.find("a"); + REQUIRE(bool(it1 != j.object_range().end())); + CHECK(it1->value().as() == 1); + + auto it2 = j.find("b"); + REQUIRE(bool(it2 != j.object_range().end())); + CHECK(it2->value().as() == 2); + + auto it3 = j.find("c"); + REQUIRE(bool(it3 != j.object_range().end())); + CHECK(it3->value().as() == 3); + + auto it4 = j.find("d"); + REQUIRE(bool(it4 != j.object_range().end())); + CHECK(it4->value().as() == 4); + } +} + +TEST_CASE("ojson sorted_unique_range_tag") +{ + typedef std::pair item_type; + std::vector items; + items.emplace_back("a", 1); + items.emplace_back("b", 2); + items.emplace_back("c", 3); + items.emplace_back("d", 4); + items.emplace_back("e", 5); + items.emplace_back("f", 6); + items.emplace_back("g", 7); + + ojson j; + j.insert(sorted_unique_range_tag(), items.begin(), items.end()); + + SECTION("iterate") + { + REQUIRE(j.size() == 7); + + auto it = j.object_range().begin(); + CHECK(it->key() == std::string("a")); + CHECK(it->value().as() == 1); + CHECK((++it)->key() == std::string("b")); + CHECK(it->value().as() == 2); + CHECK((++it)->key() == std::string("c")); + CHECK(it->value().as() == 3); + CHECK((++it)->key() == std::string("d")); + CHECK(it->value().as() == 4); + CHECK((++it)->key() == std::string("e")); + CHECK(it->value().as() == 5); + CHECK((++it)->key() == std::string("f")); + CHECK(it->value().as() == 6); + CHECK((++it)->key() == std::string("g")); + CHECK(it->value().as() == 7); + } + + SECTION("find") + { + auto it1 = j.find("a"); + REQUIRE(bool(it1 != j.object_range().end())); + CHECK(it1->value().as() == 1); + + auto it2 = j.find("b"); + REQUIRE(bool(it2 != j.object_range().end())); + CHECK(it2->value().as() == 2); + + auto it3 = j.find("c"); + REQUIRE(bool(it3 != j.object_range().end())); + CHECK(it3->value().as() == 3); + + auto it4 = j.find("d"); + REQUIRE(bool(it4 != j.object_range().end())); + CHECK(it4->value().as() == 4); + } +} + +TEST_CASE("order preserving insert") +{ + json_object o; + + typedef std::pair item_type; + std::vector items; + items.emplace_back("b", 1); + items.emplace_back("a", 2); + items.emplace_back("c", 3); + items.emplace_back("a", 4); + items.emplace_back("a", 5); + items.emplace_back("d", 6); + items.emplace_back("a", 7); + + o.insert(std::make_move_iterator(items.begin()), std::make_move_iterator(items.end()), + [](item_type&& item){return ojson::key_value_type(std::forward(item.first),std::forward(item.second));}); + + SECTION("iterate") + { + REQUIRE(o.size() == 4); + + auto it = o.begin(); + CHECK(it->key() == std::string("b")); + CHECK(it->value().as() == 1); + CHECK((++it)->key() == std::string("a")); + CHECK(it->value().as() == 2); + CHECK((++it)->key() == std::string("c")); + CHECK(it->value().as() == 3); + CHECK((++it)->key() == std::string("d")); + CHECK(it->value().as() == 6); + } + + SECTION("find") + { + auto it1 = o.find("a"); + REQUIRE(bool(it1 != o.end())); + CHECK(it1->value().as() == 2); + + auto it2 = o.find("b"); + REQUIRE(bool(it2 != o.end())); + CHECK(it2->value().as() == 1); + + auto it3 = o.find("c"); + REQUIRE(bool(it3 != o.end())); + CHECK(it3->value().as() == 3); + + auto it4 = o.find("d"); + REQUIRE(bool(it4 != o.end())); + CHECK(it4->value().as() == 6); + } +} + +TEST_CASE("order preserving insert_or_assign") +{ + json_object o; + + o.insert_or_assign("b", 1); + o.insert_or_assign("a", 2); + o.insert_or_assign("c", 3); + o.insert_or_assign("a", 4); + o.insert_or_assign("a", 5); + + SECTION("insert_or_assign") + { + REQUIRE(o.size() == 3); + + auto it = o.find("a"); + REQUIRE(bool(it != o.end())); + CHECK(it->value().as() == 5); + + auto it2 = o.begin(); + CHECK(it2->key() == std::string("b")); + CHECK(it2->value().as() == 1); + CHECK((++it2)->key() == std::string("a")); + CHECK(it2->value().as() == 5); + CHECK((++it2)->key() == std::string("c")); + CHECK(it2->value().as() == 3); + } + + SECTION("insert_or_assign at pos") + { + auto it = o.find("a"); + auto it2 = o.insert_or_assign(it,"d",3); + CHECK_FALSE((it2 == o.end())); + + auto it3 = o.begin(); + CHECK(it3->key() == std::string("b")); + CHECK(it3->value().as() == 1); + CHECK((++it3)->key() == std::string("d")); + CHECK(it3->value().as() == 3); + CHECK((++it3)->key() == std::string("a")); + CHECK(it3->value().as() == 5); + CHECK((++it3)->key() == std::string("c")); + CHECK(it3->value().as() == 3); + + //for (auto kv : o) + //{ + // std::cout << kv.key() << ": " << kv.value() << "\n"; + //} + } + + SECTION("try_emplace") + { + REQUIRE(o.size() == 3); + + o.try_emplace("d",7); + o.try_emplace("d",8); + + auto it3 = o.begin(); + CHECK(it3->key() == std::string("b")); + CHECK(it3->value().as() == 1); + CHECK((++it3)->key() == std::string("a")); + CHECK(it3->value().as() == 5); + CHECK((++it3)->key() == std::string("c")); + CHECK(it3->value().as() == 3); + CHECK((++it3)->key() == std::string("d")); + CHECK(it3->value().as() == 7); + } + + SECTION("try_emplace at pos") + { + auto it = o.find("a"); + auto it2 = o.try_emplace(it,"d",7); + o.try_emplace(it2, "d", 8); + + auto it3 = o.begin(); + CHECK(it3->key() == std::string("b")); + CHECK(it3->value().as() == 1); + CHECK((++it3)->key() == std::string("d")); + CHECK(it3->value().as() == 7); + CHECK((++it3)->key() == std::string("a")); + CHECK(it3->value().as() == 5); + CHECK((++it3)->key() == std::string("c")); + CHECK(it3->value().as() == 3); + } + + SECTION("erase") + { + REQUIRE(o.size() == 3); + + o.erase("a"); + REQUIRE(o.size() == 2); + + auto it2 = o.begin(); + CHECK(it2->key() == std::string("b")); + CHECK(it2->value().as() == 1); + CHECK((++it2)->key() == std::string("c")); + CHECK(it2->value().as() == 3); + } + + SECTION("erase range") + { + REQUIRE(o.size() == 3); + + o.erase(o.begin(),o.begin()+2); + REQUIRE(o.size() == 1); + + auto it2 = o.begin(); + CHECK(it2->key() == std::string("c")); + CHECK(it2->value().as() == 3); + } +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/parse_string_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/parse_string_tests.cpp new file mode 100644 index 0000000000..6e5191d1e3 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/parse_string_tests.cpp @@ -0,0 +1,133 @@ +// Copyright 2016 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +struct jsonpath_filter_fixture +{ +}; + +class lenient_error_handler : public parse_error_handler +{ +public: + lenient_error_handler(std::error_code value) + : value_(value) + { + } +private: + std::error_code value_; + + bool do_error(std::error_code ec, const ser_context&) noexcept + { + return ec == value_; // if returns true, use default processing + } +}; + +TEST_CASE("test_parse_small_string1") +{ + std::string input = "\"String\""; + + json_decoder decoder; + try + { + json_reader reader(input,decoder); + reader.read_next(); + } + catch (const std::exception&) + { + } + CHECK(decoder.is_valid()); +} + +TEST_CASE("test_parse_small_string2") +{ + std::string input = "\"Str\\\"ing\""; + + json_decoder decoder; + try + { + json_reader reader(input, decoder); + reader.read_next(); + } + catch (const std::exception&) + { + } + CHECK(decoder.is_valid()); +} + +TEST_CASE("test_parse_small_string4") +{ + std::string input = "\"Str\\\"ing\""; + + for (size_t i = 2; i < input.length(); ++i) + { + std::istringstream is(input); + json_decoder decoder; + try + { + json_reader reader(is, decoder); + reader.buffer_length(i); + reader.read_next(); + } + catch (const std::exception&) + { + } + CHECK(decoder.is_valid()); + CHECK(std::string("Str\"ing") == decoder.get_result().as()); + } +} +TEST_CASE("test_parse_big_string1") +{ + std::string input = "\"Big Str\\\"ing\""; + + for (size_t i = 2; i < input.length(); ++i) + { + std::istringstream is(input); + json_decoder decoder; + try + { + json_reader reader(is, decoder); + reader.buffer_length(i); + reader.read_next(); + } + catch (const std::exception&) + { + } + CHECK(decoder.is_valid()); + CHECK(std::string("Big Str\"ing") == decoder.get_result().as()); + } +} + +TEST_CASE("test_parse_big_string2") +{ + std::string input = "\"Big\t Str\\\"ing\""; + + //for (size_t i = 2; i < input.length(); ++i) + //{ + std::istringstream is(input); + json_decoder decoder; + lenient_error_handler err_handler(json_errc::illegal_character_in_string); + try + { + json_reader reader(is, decoder, err_handler); + //reader.buffer_length(i); + reader.read_next(); + } + catch (const std::exception&) + { + } + CHECK(decoder.is_valid()); + CHECK(std::string("Big\t Str\"ing") == decoder.get_result().as()); + //} +} + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/short_string_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/short_string_tests.cpp new file mode 100644 index 0000000000..151c50ad2f --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/short_string_tests.cpp @@ -0,0 +1,32 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +TEST_CASE("test_small_string") +{ + json s("ABCD"); + CHECK(s.get_storage_type() == jsoncons::storage_type::short_string_val); + CHECK(s.as() == std::string("ABCD")); + + json t(s); + CHECK(t.get_storage_type() == jsoncons::storage_type::short_string_val); + CHECK(t.as() == std::string("ABCD")); + + json q; + q = s; + CHECK(q.get_storage_type() == jsoncons::storage_type::short_string_val); + CHECK(q.as() == std::string("ABCD")); +} + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/staj_iterator_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/staj_iterator_tests.cpp new file mode 100644 index 0000000000..818967be0a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/staj_iterator_tests.cpp @@ -0,0 +1,82 @@ +// Copyright 2018 Daniel Parker +// Distributed under Boost license + +#if defined(_MSC_VER) +#include "windows.h" // test no inadvertant macro expansions +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +TEST_CASE("array_iterator test") +{ + std::string s = R"( + [ + { + "enrollmentNo" : 100, + "firstName" : "Tom", + "lastName" : "Cochrane", + "mark" : 55 + }, + { + "enrollmentNo" : 101, + "firstName" : "Catherine", + "lastName" : "Smith", + "mark" : 95 + }, + { + "enrollmentNo" : 102, + "firstName" : "William", + "lastName" : "Skeleton", + "mark" : 60 + } + ] + )"; + + std::istringstream is(s); + + json_cursor reader(is); + + staj_array_iterator it(reader); + + for (const auto& val : it) + { + std::cout << val << "\n"; + } + +} + +TEST_CASE("object_iterator test") +{ + std::string s = R"( + { + "enrollmentNo" : 100, + "firstName" : "Tom", + "lastName" : "Cochrane", + "mark" : 55 + } + )"; + + std::istringstream is(s); + + json_cursor reader(is); + + staj_object_iterator it(reader); + + for (const auto& item : it) + { + std::cout << item.first << ": " << item.second << "\n"; + } +} + + + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/stateful_allocator_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/stateful_allocator_tests.cpp new file mode 100644 index 0000000000..42aa80f39d --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/stateful_allocator_tests.cpp @@ -0,0 +1,189 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +class pool +{ +private: + struct node_type + { + char* memory_ptr_; + node_type* next_ptr_; + }; + struct node_typeA + { + node_type data; + char c[1]; + }; + typedef std::aligned_storage::type storage_type; + + size_t offset_, size_; + node_type* head_; + node_type* curr_; + + node_type* add_node() + { + size_t mem_size = sizeof(storage_type) + size_ - 1; + node_type* storage = reinterpret_cast(alloc(mem_size)); + node_type* p = new(storage)node_type(); + auto pa = reinterpret_cast(storage); + p->memory_ptr_ = new(&pa->c)char[size_]; + p->next_ptr_ = nullptr; + return storage; + } + + void* alloc(size_t n) {return malloc(n);} + void dealloc(void* storage) {free(storage);} +public: + pool(size_t size) + : offset_(0), size_(size), allocate_count_(0), deallocate_count_(0), construct_count_(0), destroy_count_(0) + { + head_ = curr_ = add_node(); + } + ~pool() + { + while (head_) + { + node_type* curr2_ = head_->next_ptr_; + dealloc(head_); + head_ = curr2_; + } + } + void* allocate(size_t n) + { + void *pv; + if (n > (size_ - offset_)) + { + if (size_ < n) + { + size_ = n; + } + curr_->next_ptr_ = add_node(); + curr_ = curr_->next_ptr_; + offset_ = 0; + } + pv = reinterpret_cast(curr_->memory_ptr_ + offset_); + + size_t mem_size = sizeof(storage_type) + n - 1; + + offset_ += mem_size; + return pv; + } + + size_t allocate_count_; + size_t deallocate_count_; + size_t construct_count_; + size_t destroy_count_; +}; + +template +class pool_allocator +{ +public: + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef T value_type; + template + struct rebind + { + typedef pool_allocator other; + }; + pool_allocator(pool* pp) throw() + : pool_ptr_(pp) + { + } + pool_allocator(const pool_allocator& s) throw() + : pool_ptr_(s.pool_ptr_) + { + } + template + pool_allocator(const pool_allocator &s) throw() + : pool_ptr_(s.pool_ptr_) + { + } + ~pool_allocator() throw() + { + } + pointer address(reference x) const + { + return &x; + } + const_pointer address(const_reference x) const + { + return &x; + } + pointer allocate(size_type n, const void* = 0) + { + ++pool_ptr_->allocate_count_; + return static_cast(pool_ptr_->allocate(n * sizeof(T))); + } + void deallocate(pointer, size_type) + { + ++pool_ptr_->deallocate_count_; + } + size_type max_size() const throw() + { + return size_t(-1) / sizeof(T); + } + template + void construct(pointer p, Args&&... args) + { + ::new(p) T(std::forward(args)...); + ++pool_ptr_->construct_count_; + } + void destroy(pointer p) + { + (void)p; + p->~T(); + ++pool_ptr_->destroy_count_; + } + pool* pool_ptr_; +}; + +template +bool operator==(const pool_allocator &s0, const pool_allocator &s1) +{ + return s0.pool_ptr_ == s1.pool_ptr_; +} +template +bool operator!=(const pool_allocator &s0, const pool_allocator &s1) +{ + return s0.pool_ptr_ != s1.pool_ptr_; +} +#if !defined(__GNUC__) +// basic_string doesn't satisfy C++11 allocator requirements +TEST_CASE("test_string_allocation") +{ + + pool a_pool(1024); + pool_allocator allocator(&a_pool); + + typedef basic_json> myjson; + + { + myjson j("String too long for short string", allocator); + } + std::cout << "Allocate count = " << a_pool.allocate_count_ + << ", construct count = " << a_pool.construct_count_ + << ", destroy count = " << a_pool.destroy_count_ + << ", deallocate count = " << a_pool.deallocate_count_ << std::endl; + CHECK(a_pool.allocate_count_ == a_pool.deallocate_count_); + CHECK(a_pool.construct_count_ == a_pool.destroy_count_); + +} +#endif + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/string_to_double_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/string_to_double_tests.cpp new file mode 100644 index 0000000000..c632e3d10e --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/string_to_double_tests.cpp @@ -0,0 +1,55 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +TEST_CASE("test_string_to_double") +{ + std::cout << "sizeof(json): " << sizeof(json) << std::endl; + + const char* s1 = "0.0"; + json j1 = json::parse(s1); + double expected1 = 0.0; + CHECK( j1.as() == expected1); + + const char* s2 = "0.123456789"; + json j2 = json::parse(s2); + double expected2 = 0.123456789; + CHECK( j2.as() == expected2); + + const char* s3 = "123456789.123456789"; + json j3 = json::parse(s3); + char* end3 = nullptr; + double expected3 = strtod(s3,&end3); + CHECK( j3.as() == expected3); +} + +TEST_CASE("test_exponent") +{ + jsoncons::detail::string_to_double reader; + const char* begin = "1.15507e-173"; + char* endptr = nullptr; + const double value1 = 1.15507e-173; + const double value2 = strtod(begin, &endptr ); + const double value3 = reader(begin,endptr-begin); + + CHECK(value1 == value2); + CHECK(value2 == value3); + + const char* s1 = "1.15507e+173"; + json j1 = json::parse(s1); + double expected1 = 1.15507e+173; + CHECK( j1.as() == expected1); + +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/string_view_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/string_view_tests.cpp new file mode 100644 index 0000000000..d7515798bd --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/string_view_tests.cpp @@ -0,0 +1,28 @@ +// Copyright 2019 Daniel Parker +// Distributed under Boost license + +#include +#include + +#if defined(JSONCONS_HAS_STRING_VIEW) + +#include + +using namespace jsoncons; + +TEST_CASE("string_view tests") +{ + std::cout << "string_view tests\n"; + json j = json::parse(R"( + { + "a" : "2", + "c" : [4,5,6] + } + )"); + + auto s = j["a"].as(); + CHECK(bool(s == "2")); +} + +#endif + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/tests_main.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/tests_main.cpp new file mode 100644 index 0000000000..1d646dc52f --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/tests_main.cpp @@ -0,0 +1,3 @@ +#define CATCH_CONFIG_MAIN +#include + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/ubjson/decode_ubjson_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/ubjson/decode_ubjson_tests.cpp new file mode 100644 index 0000000000..3b0d070e0a --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/ubjson/decode_ubjson_tests.cpp @@ -0,0 +1,181 @@ +// Copyright 2016 Daniel Parker +// Distributed under Boost license + +#if defined(_MSC_VER) +#include "windows.h" // test no inadvertant macro expansions +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +void check_decode_ubjson(const std::vector& v, const json& expected) +{ + json j1 = ubjson::decode_ubjson(v); + REQUIRE(j1 == expected); + + std::string s; + for (auto c : v) + { + s.push_back(c); + } + std::istringstream is(s); + json j2 = ubjson::decode_ubjson(is); + REQUIRE(j2 == expected); +} + +void check_decode_ubjson(const std::vector& expected, const std::vector& result) +{ + if (result.size() != expected.size()) + { + std::cout << std::hex << (int)expected[0] << " " << std::hex << (int)result[0] << std::endl; + } + REQUIRE(result.size() == expected.size()); + for (size_t i = 0; i < expected.size(); ++i) + { + if (expected[i] != result[i]) + { + std::cout << "Different " << i << "\n"; + for (size_t k = 0; k < expected.size(); ++k) + { + std::cout << std::hex << std::setprecision(2) << std::setw(2) + << std::noshowbase << std::setfill('0') << static_cast(result[k]); + } + } + REQUIRE(result[i] == expected[i]); + } +} + +TEST_CASE("decode_number_ubjson_test") +{ + SECTION("null, true, false") + { + check_decode_ubjson({'Z'},json::null()); + check_decode_ubjson({'T'},json(true)); + check_decode_ubjson({'F'},json(false)); + } + SECTION("uint8") + { + check_decode_ubjson({'U',0x00},json(0U)); + check_decode_ubjson({'U',0x01},json(1U)); + check_decode_ubjson({'U',0x0a},json(10U)); + check_decode_ubjson({'U',0x17},json(23U)); + check_decode_ubjson({'U',0x18},json(24U)); + check_decode_ubjson({'U',0x7f},json(127U)); + check_decode_ubjson({'U',0xff},json(255U)); + } + SECTION("int8,int16,int32,int64") + { + check_decode_ubjson({'i',0xff},json(-1)); + check_decode_ubjson({'I',0x01,0x00},json(256)); + check_decode_ubjson({'l',0,0,0xff,0xff},json(65535)); + check_decode_ubjson({'l',0,1,0x00,0x00},json(65536)); + check_decode_ubjson({'L',0,0,0,0,0xff,0xff,0xff,0xff},json(4294967295)); + check_decode_ubjson({'L',0,0,0,1,0,0,0,0},json(4294967296)); + check_decode_ubjson({'L',0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff},json((std::numeric_limits::max)())); + // negative integers + check_decode_ubjson({'I',0xff,0},json(-256)); + check_decode_ubjson({'I',0xfe,0xff},json(-257)); + check_decode_ubjson({'l',0xff,0xff,0,0},json(-65536)); + check_decode_ubjson({'l',0xff,0xfe,0xff,0xff},json(-65537)); + check_decode_ubjson({'L',0xff,0xff,0xff,0xff,0,0,0,0},json(-4294967296)); + check_decode_ubjson({'L',0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff},json(-4294967297)); + } + + SECTION("float32,float64") + { + check_decode_ubjson({'D',0,0,0,0,0,0,0,0},json(0.0)); + check_decode_ubjson({'D',0xbf,0xf0,0,0,0,0,0,0},json(-1.0)); + check_decode_ubjson({'D',0xc1,0x6f,0xff,0xff,0xe0,0,0,0},json(-16777215.0)); + } + + SECTION("array") + { + check_decode_ubjson({'[',']'},json::parse("[]")); + check_decode_ubjson({'[', 'Z', 'T', 'F', ']'},json::parse("[null,true,false]")); + check_decode_ubjson({'[','#','i',0},json::parse("[]")); + check_decode_ubjson({'[','#','i',1,'I',0xff,0},json::parse("[-256]")); + } + SECTION("ubjson array optimized with type and count") + { + check_decode_ubjson({'[','$','I','#','i',2, + 0x01,0x00, // 256 + 0xff,0}, // -256 + json::parse("[256,-256]")); + } + SECTION("ubjson object optimized with type and count") + { + check_decode_ubjson({'{','$','I','#','i',2, + 'i',5,'f','i','r','s','t', + 0x01,0x00, // 256 + 'i',6,'s','e','c','o','n','d', + 0xff,0}, // -256 + json::parse("{\"first\":256,\"second\":-256}")); + } +} + +TEST_CASE("decode_ubjson_arrays_and_maps") +{ + check_decode_ubjson({'[','#','U',0x00},json::array()); + check_decode_ubjson({ '{','#','U',0x00 }, json::object()); + + check_decode_ubjson({'[','#','U',0x01,'U',0x00},json::parse("[0]")); + check_decode_ubjson({'[','#','U',0x02,'U',0x00,'U',0x00},json::parse("[0,0]")); + check_decode_ubjson({'[','#','U',0x02, + '[','#','U',0x01,'U',0x00, + 'U',0x00},json::parse("[[0],0]")); + check_decode_ubjson({'[','#','U',0x01,'S','U',0x05,'H','e','l','l','o'},json::parse("[\"Hello\"]")); + check_decode_ubjson({'{','#','U',0x01,'U',0x02,'o','c','[','#','U',0x01,'U',0x00}, json::parse("{\"oc\": [0]}")); + check_decode_ubjson({'{','#','U',0x01,'U',0x02,'o','c','[','#','U',0x04,'U',0x00,'U',0x01,'U',0x02,'U',0x03}, json::parse("{\"oc\": [0,1,2,3]}")); +} + +TEST_CASE("decode indefinite length ubjson arrays and maps") +{ + std::vector v; + ubjson::ubjson_bytes_encoder encoder(v); + + SECTION("[\"Hello\"]") + { + encoder.begin_array(); + encoder.string_value("Hello"); + encoder.end_array(); + + check_decode_ubjson({'[','S','U',0x05,'H','e','l','l','o',']'}, v); + } + + SECTION("{\"oc\": [0]}") + { + encoder.begin_object(); + encoder.name("oc"); + encoder.begin_array(); + encoder.uint64_value(0); + encoder.end_array(); + encoder.end_object(); + + check_decode_ubjson({'{','U',0x02,'o','c','[','U',0x00,']','}'}, v); + } + + SECTION("{\"oc\": [0,1,2,3]}") + { + encoder.begin_object(); + encoder.name("oc"); + encoder.begin_array(); + encoder.uint64_value(0); + encoder.uint64_value(1); + encoder.uint64_value(2); + encoder.uint64_value(3); + encoder.end_array(); + encoder.end_object(); + + check_decode_ubjson({'{','U',0x02,'o','c','[','U',0x00,'U',0x01,'U',0x02,'U',0x03,']','}'}, v); + } +} + + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/ubjson/encode_ubjson_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/ubjson/encode_ubjson_tests.cpp new file mode 100644 index 0000000000..9fdcc178a2 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/ubjson/encode_ubjson_tests.cpp @@ -0,0 +1,177 @@ +// Copyright 2016 Daniel Parker +// Distributed under Boost license + +#if defined(_MSC_VER) +#include "windows.h" // test no inadvertant macro expansions +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +void check_encode_ubjson(const std::vector& expected, const json& j) +{ + std::vector result; + ubjson::encode_ubjson(j, result); + if (result.size() != expected.size()) + { + std::cout << std::hex << (int)expected[0] << " " << std::hex << (int)result[0] << std::endl; + } + REQUIRE(result.size() == expected.size()); + for (size_t i = 0; i < expected.size(); ++i) + { + if (expected[i] != result[i]) + { + std::cout << "Different " << i << "\n"; + for (size_t k = 0; k < expected.size(); ++k) + { + std::cout << std::hex << (int)expected[k] << " " << std::hex << (int)result[k] << std::endl; + } + } + REQUIRE(result[i] == expected[i]); + } +} + +void check_encode_ubjson(const std::vector& expected, const std::vector& result) +{ + if (result.size() != expected.size()) + { + std::cout << std::hex << (int)expected[0] << " " << std::hex << (int)result[0] << std::endl; + } + REQUIRE(result.size() == expected.size()); + for (size_t i = 0; i < expected.size(); ++i) + { + if (expected[i] != result[i]) + { + std::cout << "Different " << i << "\n"; + for (size_t k = 0; k < expected.size(); ++k) + { + std::cout << std::hex << (int)expected[k] << " " << std::hex << (int)result[k] << std::endl; + } + } + REQUIRE(result[i] == expected[i]); + } +} + +TEST_CASE("encode_ubjson_test") +{ + check_encode_ubjson({'U',0x00},json(0U)); + check_encode_ubjson({'U',0x01},json(1U)); + check_encode_ubjson({'U',0x0a},json(10U)); + check_encode_ubjson({'U',0x17},json(23U)); + check_encode_ubjson({'U',0x18},json(24U)); + check_encode_ubjson({'U',0x7f},json(127U)); + check_encode_ubjson({'U',0xff},json(255U)); + check_encode_ubjson({'I',0x01,0x00},json(256U)); + check_encode_ubjson({'l',0,1,0x00,0x00},json(65536U)); + check_encode_ubjson({'L',0,0,0,1,0,0,0,0},json(4294967296U)); + + check_encode_ubjson({'U',0x01},json(1)); + check_encode_ubjson({'U',0x0a},json(10)); + check_encode_ubjson({'U',0x17},json(23)); + check_encode_ubjson({'U',0x18},json(24)); + check_encode_ubjson({'U',0x7f},json(127)); + + check_encode_ubjson({'U',0xff},json(255)); + check_encode_ubjson({'I',0x01,0x00},json(256)); + check_encode_ubjson({'l',0,1,0x00,0x00},json(65536)); + check_encode_ubjson({'L',0,0,0,1,0,0,0,0},json(4294967296)); + check_encode_ubjson({'L',0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff},json((std::numeric_limits::max)())); + + check_encode_ubjson({'i',0xe0},json(-32)); + check_encode_ubjson({'i',0xff},json(-1)); // + + // negative integers + check_encode_ubjson({'I',0xff,0},json(-256)); + check_encode_ubjson({'I',0xfe,0xff},json(-257)); + check_encode_ubjson({'l',0xff,0xff,0,0},json(-65536)); + check_encode_ubjson({'l',0xff,0xfe,0xff,0xff},json(-65537)); + check_encode_ubjson({'L',0xff,0xff,0xff,0xff,0,0,0,0},json(-4294967296)); + check_encode_ubjson({'L',0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff},json(-4294967297)); + + // null, true, false + check_encode_ubjson({'Z'},json::null()); // + check_encode_ubjson({'T'},json(true)); // + check_encode_ubjson({'F'},json(false)); // + + // floating point + check_encode_ubjson({'d',0,0,0,0},json(0.0)); + check_encode_ubjson({'d',0xbf,0x80,0,0},json(-1.0)); + check_encode_ubjson({'d',0xcb,0x7f,0xff,0xff},json(-16777215.0)); + + // string + check_encode_ubjson({'S','U',0x00},json("")); + check_encode_ubjson({'S','U',0x01,' '},json(" ")); + check_encode_ubjson({'S','U',0x1f,'1','2','3','4','5','6','7','8','9','0', + '1','2','3','4','5','6','7','8','9','0', + '1','2','3','4','5','6','7','8','9','0', + '1'}, + json("1234567890123456789012345678901")); + check_encode_ubjson({'S','U',0x20,'1','2','3','4','5','6','7','8','9','0', + '1','2','3','4','5','6','7','8','9','0', + '1','2','3','4','5','6','7','8','9','0', + '1','2'}, + json("12345678901234567890123456789012")); +} +TEST_CASE("encode_ubjson_arrays_and_maps") +{ + check_encode_ubjson({'[','#','U',0x00},json::array()); + check_encode_ubjson({'{','#','U',0x00},json::object()); + check_encode_ubjson({'[','#','U',0x01,'U',0x00},json::parse("[0]")); + check_encode_ubjson({'[','#','U',0x02,'U',0x00,'U',0x00},json::parse("[0,0]")); + check_encode_ubjson({'[','#','U',0x02, + '[','#','U',0x01,'U',0x00, + 'U',0x00},json::parse("[[0],0]")); + check_encode_ubjson({'[','#','U',0x01,'S','U',0x05,'H','e','l','l','o'},json::parse("[\"Hello\"]")); + check_encode_ubjson({'{','#','U',0x01,'U',0x02,'o','c','[','#','U',0x01,'U',0x00}, json::parse("{\"oc\": [0]}")); + check_encode_ubjson({'{','#','U',0x01,'U',0x02,'o','c','[','#','U',0x04,'U',0x00,'U',0x01,'U',0x02,'U',0x03}, json::parse("{\"oc\": [0,1,2,3]}")); +} + +TEST_CASE("encode indefinite length ubjson arrays and maps") +{ + std::vector v; + ubjson::ubjson_bytes_encoder encoder(v); + + SECTION("[\"Hello\"]") + { + encoder.begin_array(); + encoder.string_value("Hello"); + encoder.end_array(); + + check_encode_ubjson({'[','S','U',0x05,'H','e','l','l','o',']'}, v); + } + + SECTION("{\"oc\": [0]}") + { + encoder.begin_object(); + encoder.name("oc"); + encoder.begin_array(); + encoder.uint64_value(0); + encoder.end_array(); + encoder.end_object(); + + check_encode_ubjson({'{','U',0x02,'o','c','[','U',0x00,']','}'}, v); + } + + SECTION("{\"oc\": [0,1,2,3]}") + { + encoder.begin_object(); + encoder.name("oc"); + encoder.begin_array(); + encoder.uint64_value(0); + encoder.uint64_value(1); + encoder.uint64_value(2); + encoder.uint64_value(3); + encoder.end_array(); + encoder.end_object(); + + check_encode_ubjson({'{','U',0x02,'o','c','[','U',0x00,'U',0x01,'U',0x02,'U',0x03,']','}'}, v); + } +} + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/ubjson/ubjson_encoder_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/ubjson/ubjson_encoder_tests.cpp new file mode 100644 index 0000000000..713008e528 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/ubjson/ubjson_encoder_tests.cpp @@ -0,0 +1,107 @@ +// Copyright 2016 Daniel Parker +// Distributed under Boost license + +#if defined(_MSC_VER) +#include "windows.h" // test no inadvertant macro expansions +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; +using namespace jsoncons::ubjson; + +TEST_CASE("serialize array to ubjson") +{ + std::vector v; + ubjson::ubjson_bytes_encoder encoder(v); + encoder.begin_array(3); + encoder.bool_value(true); + encoder.bool_value(false); + encoder.null_value(); + encoder.end_array(); + encoder.flush(); + + try + { + json result = decode_ubjson(v); + std::cout << result << std::endl; + } + catch (const std::exception& e) + { + std::cout << e.what() << std::endl; + } +} + +TEST_CASE("Too many and too few items in UBJSON object or array") +{ + std::error_code ec{}; + std::vector v; + ubjson::ubjson_bytes_encoder encoder(v); + + SECTION("Too many items in array") + { + CHECK(encoder.begin_array(3)); + CHECK(encoder.bool_value(true)); + CHECK(encoder.bool_value(false)); + CHECK(encoder.null_value()); + CHECK(encoder.begin_array(2)); + CHECK(encoder.string_value("cat")); + CHECK(encoder.string_value("feline")); + CHECK(encoder.end_array()); + REQUIRE_THROWS_WITH(encoder.end_array(), ubjson_error_category_impl().message((int)ubjson_errc::too_many_items).c_str()); + encoder.flush(); + } + SECTION("Too few items in array") + { + CHECK(encoder.begin_array(5)); + CHECK(encoder.bool_value(true)); + CHECK(encoder.bool_value(false)); + CHECK(encoder.null_value()); + CHECK(encoder.begin_array(2)); + CHECK(encoder.string_value("cat")); + CHECK(encoder.string_value("feline")); + CHECK(encoder.end_array()); + REQUIRE_THROWS_WITH(encoder.end_array(), ubjson_error_category_impl().message((int)ubjson_errc::too_few_items).c_str()); + encoder.flush(); + } + SECTION("Too many items in object") + { + CHECK(encoder.begin_object(3)); + CHECK(encoder.name("a")); + CHECK(encoder.bool_value(true)); + CHECK(encoder.name("b")); + CHECK(encoder.bool_value(false)); + CHECK(encoder.name("c")); + CHECK(encoder.null_value()); + CHECK(encoder.name("d")); + CHECK(encoder.begin_array(2)); + CHECK(encoder.string_value("cat")); + CHECK(encoder.string_value("feline")); + CHECK(encoder.end_array()); + REQUIRE_THROWS_WITH(encoder.end_object(), ubjson_error_category_impl().message((int)ubjson_errc::too_many_items).c_str()); + encoder.flush(); + } + SECTION("Too few items in object") + { + CHECK(encoder.begin_object(5)); + CHECK(encoder.name("a")); + CHECK(encoder.bool_value(true)); + CHECK(encoder.name("b")); + CHECK(encoder.bool_value(false)); + CHECK(encoder.name("c")); + CHECK(encoder.null_value()); + CHECK(encoder.name("d")); + CHECK(encoder.begin_array(2)); + CHECK(encoder.string_value("cat")); + CHECK(encoder.string_value("feline")); + CHECK(encoder.end_array()); + REQUIRE_THROWS_WITH(encoder.end_object(), ubjson_error_category_impl().message((int)ubjson_errc::too_few_items).c_str()); + encoder.flush(); + } +} diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/unicode_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/unicode_tests.cpp new file mode 100644 index 0000000000..252db14489 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/unicode_tests.cpp @@ -0,0 +1,59 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +#if 0 + +BOOST_AUTO_TEST_CASE( test_surrogate_pair ) +{ + std::string input = "[\"\\u8A73\\u7D30\\u95B2\\u89A7\\uD800\\uDC01\\u4E00\"]"; + json value = json::parse(input); + json_options options; + options.escape_all_non_ascii(true); + std::string output; + value.dump(output,options); + + CHECK(input == output); +} + +TEST_CASE("test_wide_surrogate_pair") +{ + std::wstring input = L"[\"\\u8A73\\u7D30\\u95B2\\u89A7\\uD800\\uDC01\\u4E00\"]"; + wjson value = wjson::parse(input); + wjson_options options; + options.escape_all_non_ascii(true); + std::wstring output; + value.dump(output,options); + + CHECK(input == output); +} + +BOOST_AUTO_TEST_CASE( test1 ) +{ + std::istringstream is("{\"unicode_string_1\":\"\\uD800\\uDC00\"}"); + + json root = json::parse(is); + CHECK(root.is_object()); + CHECK(root.is()); + + root["double_1"] = 10.0; + + json double_1 = root["double_1"]; + + BOOST_CHECK_CLOSE(double_1.as(), 10.0, 0.000001); + + BOOST_CHECK_CLOSE(double_1.as(), 10.0, 0.000001); + + json copy(root); +} +#endif + diff --git a/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/wjson_tests.cpp b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/wjson_tests.cpp new file mode 100644 index 0000000000..0a4d24dcd2 --- /dev/null +++ b/cpp/src/core/thirdparty/jsoncons-0.126.0/tests/src/wjson_tests.cpp @@ -0,0 +1,53 @@ +// Copyright 2013 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +TEST_CASE("test_wjson") +{ + wjson root; + root[L"field1"] = L"test"; + root[L"field2"] = 3.9; + root[L"field3"] = true; + + CHECK(root[L"field1"].as() == L"test"); + CHECK(root[L"field2"].as() == 3.9); + CHECK(root[L"field3"].as() == true); + + std::wstring s1 = root[L"field1"].as(); + CHECK(s1 == L"test"); +} + +TEST_CASE("test_wjson_escape_u") +{ + std::wstring input = L"[\"\\uABCD\"]"; + std::wistringstream is(input); + + wjson root = wjson::parse(is); + + std::wstring s = root[0].as(); + CHECK( s.length() == 1 ); + CHECK( s[0] == 0xABCD ); +} + +TEST_CASE("wjson serialization tests") +{ + jsoncons::wjson testBlock; + testBlock[L"foo"] = true; + testBlock[L"bar"] = false; + testBlock[L"baz"] = true; + std::wstring testStr; + testBlock.dump(testStr); + + CHECK(testStr == L"{\"bar\":false,\"baz\":true,\"foo\":true}"); +} + diff --git a/cpp/src/core/thirdparty/versions.txt b/cpp/src/core/thirdparty/versions.txt new file mode 100644 index 0000000000..59a496f5e5 --- /dev/null +++ b/cpp/src/core/thirdparty/versions.txt @@ -0,0 +1,6 @@ +ARROW_VERSION=apache-arrow-0.14.0 +BOOST_VERSION=1.70.0 +GTEST_VERSION=1.8.1 +LAPACK_VERSION=v3.8.0 +OPENBLAS_VERSION=v0.3.6 +FAISS_VERSION=branch-0.2.0 \ No newline at end of file diff --git a/cpp/src/core/todo b/cpp/src/core/todo new file mode 100644 index 0000000000..eeb0a69915 --- /dev/null +++ b/cpp/src/core/todo @@ -0,0 +1,2 @@ +1. Support L2 and IP +2. replace with RapidJson \ No newline at end of file