From 455549a5c8982f3ba5ab8a56e37a50fed635ef91 Mon Sep 17 00:00:00 2001 From: changliao1025 Date: Wed, 21 Feb 2024 22:23:36 -0800 Subject: [PATCH 1/4] minor issue fix for configuration --- README.md | 12 +++++++++++- pyhexwatershed/classes/_hpc.py | 5 +++++ pyhexwatershed/classes/pycase.py | 19 ++++++++++++++++--- streamlit_app.py | 0 4 files changed, 32 insertions(+), 4 deletions(-) delete mode 100644 streamlit_app.py diff --git a/README.md b/README.md index c0a2fed..b9918dc 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,8 @@ Copyright © 2022, Battelle Memorial Institute There are a number of publications that describe the algorithms used in `HexWatershed` in detail. If you make use of `HexWatershed` in your work, please consider including a reference to the following: -* Liao, Chang, Cooper, M. G. PyFlowline a mesh independent river network generator for hydrologic models. Journal of Open Source Software. https://doi.org/10.21105/joss.05446 + +#### `Scientific Publications` * Liao, Chang, Zhou, T., Xu, D., Tan, Z., Bisht, G., Cooper, M. G., et al. (2023). Topological relationship-based flow direction modeling: Stream burning and depression filling. Journal of Advances in Modeling Earth Systems, 15, e2022MS003487. https://doi.org/10.1029/2022MS003487 @@ -56,9 +57,18 @@ https://doi.org/10.1016/j.advwatres.2021.104099. * Liao, C., Tesfa, T., Duan, Z., & Leung, L. R. (2020). Watershed delineation on a hexagonal mesh grid. Environmental Modelling & Software, 128, 104702. https://doi.org/10.1016/j.envsoft.2020.104702 + +#### `Software` + +* Liao, Chang, Cooper, M. G. PyFlowline a mesh independent river network generator for hydrologic models. Journal of Open Source Software. https://doi.org/10.21105/joss.05446 + * Liao. C. (2022) Pyflowline: a mesh independent river network generator for hydrologic models. Zenodo. https://doi.org/10.5281/zenodo.6407299 * Liao. C. (2022). HexWatershed: a mesh independent flow direction model for hydrologic models (0.1.1). Zenodo. https://doi.org/10.5281/zenodo.6425881 +For a full list of references including applications of HexWatershed in other projects, please refer to the `documentation`. + + + diff --git a/pyhexwatershed/classes/_hpc.py b/pyhexwatershed/classes/_hpc.py index 491be8a..5eb04c5 100644 --- a/pyhexwatershed/classes/_hpc.py +++ b/pyhexwatershed/classes/_hpc.py @@ -44,6 +44,11 @@ def _pyhexwatershed_create_hpc_job(self, sSlurm_in=None): sLine = 'oPyhexwatershed.pPyFlowline.aBasin[0].dThreshold_small_river=' \ + "{:0f}".format(self.pPyFlowline.aBasin[0].dThreshold_small_river)+ '\n' ofs_pyhexwatershed.write(sLine) + sLine = 'oPyhexwatershed.pPyFlowline.aBasin[0].sFilename_flowline_filter=' \ + + "'"+ self.pPyFlowline.aBasin[0].sFilename_flowline_filter + "'" +'\n' + ofs_pyhexwatershed.write(sLine) + + sLine = 'oPyhexwatershed.pyhexwatershed_setup()' + '\n' ofs_pyhexwatershed.write(sLine) diff --git a/pyhexwatershed/classes/pycase.py b/pyhexwatershed/classes/pycase.py index 05e3051..af70da6 100644 --- a/pyhexwatershed/classes/pycase.py +++ b/pyhexwatershed/classes/pycase.py @@ -72,6 +72,7 @@ class hexwatershedcase(object): sFilename_model_configuration='' sFilename_mesh='' sFilename_mesh_info='' + sFilename_mesh_boundary='' sFilename_flowline_info='' sFilename_basins='' sFilename_hexwatershed_bin='' @@ -219,6 +220,15 @@ def __init__(self, aConfig_in): if 'sFilename_mesh_netcdf' in aConfig_in: self.sFilename_mesh_netcdf = aConfig_in['sFilename_mesh_netcdf'] + if 'sFilename_mesh_boundary' in aConfig_in: + self.sFilename_mesh_boundary = aConfig_in[ 'sFilename_mesh_boundary'] + + if self.iFlag_mesh_boundary==1: + if not os.path.isfile(self.sFilename_mesh_boundary ): + print("The mesh boundary file does not exist, you should update this parameter before running the model!") + #exit() + pass + if self.iFlag_user_provided_binary == 1: print('The model will use the user provided binary file') if 'sFilename_hexwatershed_bin' in aConfig_in: @@ -477,7 +487,8 @@ def pyhexwatershed_run_hexwatershed(self): self.generate_bash_script() os.chdir(self.sWorkspace_output_hexwatershed) sCommand = "./run_hexwatershed.bat" - print(sCommand) + #print(sCommand) + sys.stdout.flush() p = subprocess.Popen(sCommand, shell= True) p.wait() elif system == 'Linux': @@ -486,7 +497,8 @@ def pyhexwatershed_run_hexwatershed(self): self.pyhexwatershed_generate_bash_script() os.chdir(self.sWorkspace_output_hexwatershed) sCommand = "./run_hexwatershed.sh" - print(sCommand) + #print(sCommand) + sys.stdout.flush() p = subprocess.Popen(sCommand, shell= True) p.wait() elif system == 'Darwin': @@ -495,7 +507,8 @@ def pyhexwatershed_run_hexwatershed(self): self.generate_bash_script() os.chdir(self.sWorkspace_output_hexwatershed) sCommand = "./run_hexwatershed.sh" - print(sCommand) + #print(sCommand) + sys.stdout.flush() p = subprocess.Popen(sCommand, shell= True) p.wait() else: diff --git a/streamlit_app.py b/streamlit_app.py deleted file mode 100644 index e69de29..0000000 From 03a41a1644d38171afbf4906af299e15bc0623d2 Mon Sep 17 00:00:00 2001 From: changliao1025 Date: Mon, 15 Apr 2024 10:54:28 -0700 Subject: [PATCH 2/4] remove hexwatershed source code from repo --- external/hexwatershed/CMakeLists.txt | 95 -- external/hexwatershed/bin/hexwatershed | Bin 427928 -> 0 bytes external/hexwatershed/src/.DS_Store | Bin 6148 -> 0 bytes external/hexwatershed/src/.idea/modules.xml | 8 - external/hexwatershed/src/.idea/src.iml | 8 - external/hexwatershed/src/.idea/workspace.xml | 91 -- external/hexwatershed/src/compset/compset.cpp | 198 --- external/hexwatershed/src/compset/compset.h | 173 --- .../src/compset/compset_depression.cpp | 705 --------- .../src/compset/compset_direction.cpp | 525 ------- .../src/compset/compset_initialize.cpp | 199 --- .../hexwatershed/src/compset/compset_run.cpp | 825 ----------- .../hexwatershed/src/compset/compset_save.cpp | 543 ------- .../src/compset/compset_stream.cpp | 430 ------ external/hexwatershed/src/conversion.cpp | 230 --- external/hexwatershed/src/conversion.h | 67 - external/hexwatershed/src/data.cpp | 224 --- external/hexwatershed/src/data.h | 52 - external/hexwatershed/src/domain/domain.cpp | 119 -- external/hexwatershed/src/domain/domain.h | 146 -- .../hexwatershed/src/domain/domain_read.cpp | 381 ----- external/hexwatershed/src/edge.cpp | 148 -- external/hexwatershed/src/edge.h | 43 - external/hexwatershed/src/flowline.cpp | 93 -- external/hexwatershed/src/flowline.h | 49 - external/hexwatershed/src/geology.cpp | 71 - external/hexwatershed/src/geology.h | 17 - external/hexwatershed/src/global.cpp | 126 -- external/hexwatershed/src/global.h | 140 -- external/hexwatershed/src/hexagon.cpp | 138 -- external/hexwatershed/src/hexagon.h | 149 -- external/hexwatershed/src/json/JSONBase.cpp | 64 - external/hexwatershed/src/json/JSONBase.h | 29 - external/hexwatershed/src/json/basin.cpp | 71 - external/hexwatershed/src/json/basin.h | 30 - external/hexwatershed/src/json/cell.cpp | 230 --- external/hexwatershed/src/json/cell.h | 65 - external/hexwatershed/src/json/link.cpp | 55 - external/hexwatershed/src/json/link.h | 22 - external/hexwatershed/src/json/links.cpp | 38 - external/hexwatershed/src/json/links.h | 21 - external/hexwatershed/src/json/mesh.cpp | 38 - external/hexwatershed/src/json/mesh.h | 22 - external/hexwatershed/src/json/multibasin.cpp | 41 - external/hexwatershed/src/json/multibasin.h | 22 - external/hexwatershed/src/json/vertex.cpp | 95 -- external/hexwatershed/src/json/vertex.h | 48 - external/hexwatershed/src/main.cpp | 99 -- external/hexwatershed/src/parameter.cpp | 35 - external/hexwatershed/src/parameter.h | 51 - external/hexwatershed/src/segment.cpp | 101 -- external/hexwatershed/src/segment.h | 65 - external/hexwatershed/src/subbasin.cpp | 126 -- external/hexwatershed/src/subbasin.h | 48 - external/hexwatershed/src/system.cpp | 476 ------- external/hexwatershed/src/system.h | 87 -- external/hexwatershed/src/watershed.cpp | 1259 ----------------- external/hexwatershed/src/watershed.h | 116 -- .../export_json_to_geojson_polygon.py | 15 +- .../auxiliary/merge_cell_to_polygon.py | 83 ++ pyhexwatershed/classes/_visual.py | 39 +- pyhexwatershed/classes/pycase.py | 69 +- 62 files changed, 176 insertions(+), 9377 deletions(-) delete mode 100755 external/hexwatershed/CMakeLists.txt delete mode 100755 external/hexwatershed/bin/hexwatershed delete mode 100755 external/hexwatershed/src/.DS_Store delete mode 100755 external/hexwatershed/src/.idea/modules.xml delete mode 100755 external/hexwatershed/src/.idea/src.iml delete mode 100755 external/hexwatershed/src/.idea/workspace.xml delete mode 100755 external/hexwatershed/src/compset/compset.cpp delete mode 100755 external/hexwatershed/src/compset/compset.h delete mode 100755 external/hexwatershed/src/compset/compset_depression.cpp delete mode 100755 external/hexwatershed/src/compset/compset_direction.cpp delete mode 100755 external/hexwatershed/src/compset/compset_initialize.cpp delete mode 100755 external/hexwatershed/src/compset/compset_run.cpp delete mode 100755 external/hexwatershed/src/compset/compset_save.cpp delete mode 100755 external/hexwatershed/src/compset/compset_stream.cpp delete mode 100755 external/hexwatershed/src/conversion.cpp delete mode 100755 external/hexwatershed/src/conversion.h delete mode 100755 external/hexwatershed/src/data.cpp delete mode 100755 external/hexwatershed/src/data.h delete mode 100755 external/hexwatershed/src/domain/domain.cpp delete mode 100755 external/hexwatershed/src/domain/domain.h delete mode 100755 external/hexwatershed/src/domain/domain_read.cpp delete mode 100755 external/hexwatershed/src/edge.cpp delete mode 100755 external/hexwatershed/src/edge.h delete mode 100755 external/hexwatershed/src/flowline.cpp delete mode 100755 external/hexwatershed/src/flowline.h delete mode 100755 external/hexwatershed/src/geology.cpp delete mode 100755 external/hexwatershed/src/geology.h delete mode 100755 external/hexwatershed/src/global.cpp delete mode 100755 external/hexwatershed/src/global.h delete mode 100755 external/hexwatershed/src/hexagon.cpp delete mode 100755 external/hexwatershed/src/hexagon.h delete mode 100755 external/hexwatershed/src/json/JSONBase.cpp delete mode 100755 external/hexwatershed/src/json/JSONBase.h delete mode 100755 external/hexwatershed/src/json/basin.cpp delete mode 100755 external/hexwatershed/src/json/basin.h delete mode 100755 external/hexwatershed/src/json/cell.cpp delete mode 100755 external/hexwatershed/src/json/cell.h delete mode 100755 external/hexwatershed/src/json/link.cpp delete mode 100755 external/hexwatershed/src/json/link.h delete mode 100755 external/hexwatershed/src/json/links.cpp delete mode 100755 external/hexwatershed/src/json/links.h delete mode 100755 external/hexwatershed/src/json/mesh.cpp delete mode 100755 external/hexwatershed/src/json/mesh.h delete mode 100755 external/hexwatershed/src/json/multibasin.cpp delete mode 100755 external/hexwatershed/src/json/multibasin.h delete mode 100755 external/hexwatershed/src/json/vertex.cpp delete mode 100755 external/hexwatershed/src/json/vertex.h delete mode 100755 external/hexwatershed/src/main.cpp delete mode 100755 external/hexwatershed/src/parameter.cpp delete mode 100755 external/hexwatershed/src/parameter.h delete mode 100755 external/hexwatershed/src/segment.cpp delete mode 100755 external/hexwatershed/src/segment.h delete mode 100755 external/hexwatershed/src/subbasin.cpp delete mode 100755 external/hexwatershed/src/subbasin.h delete mode 100755 external/hexwatershed/src/system.cpp delete mode 100755 external/hexwatershed/src/system.h delete mode 100755 external/hexwatershed/src/watershed.cpp delete mode 100755 external/hexwatershed/src/watershed.h create mode 100644 pyhexwatershed/algorithms/auxiliary/merge_cell_to_polygon.py diff --git a/external/hexwatershed/CMakeLists.txt b/external/hexwatershed/CMakeLists.txt deleted file mode 100755 index 0f21b59..0000000 --- a/external/hexwatershed/CMakeLists.txt +++ /dev/null @@ -1,95 +0,0 @@ -cmake_minimum_required(VERSION 3.10) -project(hexwatershed CXX) - -set(CMAKE_CXX_STANDARD 11) -message("CMAKE_CURRENT_SOURCE_DIR is = ${CMAKE_CURRENT_SOURCE_DIR}") -include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../src) -set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -set(CMAKE_VERBOSE_MAKEFILE ON) - -set(hexwatershed_srcs - ${CMAKE_CURRENT_SOURCE_DIR}/../src/compset/compset_depression.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../src/compset/compset_direction.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../src/compset/compset_initialize.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../src/compset/compset_run.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../src/compset/compset_save.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../src/compset/compset_stream.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../src/compset/compset.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../src/compset/compset.h - ${CMAKE_CURRENT_SOURCE_DIR}/../src/domain/domain_read.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../src/domain/domain.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../src/domain/domain.h - ${CMAKE_CURRENT_SOURCE_DIR}/../src/json/cell.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../src/json/cell.h - ${CMAKE_CURRENT_SOURCE_DIR}/../src/json/mesh.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../src/json/mesh.h - ${CMAKE_CURRENT_SOURCE_DIR}/../src/json/basin.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../src/json/basin.h - ${CMAKE_CURRENT_SOURCE_DIR}/../src/json/multibasin.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../src/json/multibasin.h - ${CMAKE_CURRENT_SOURCE_DIR}/../src/json/JSONBase.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../src/json/JSONBase.h - ${CMAKE_CURRENT_SOURCE_DIR}/../src/conversion.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../src/conversion.h - ${CMAKE_CURRENT_SOURCE_DIR}/../src/data.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../src/data.h - ${CMAKE_CURRENT_SOURCE_DIR}/../src/edge.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../src/edge.h - ${CMAKE_CURRENT_SOURCE_DIR}/../src/flowline.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../src/flowline.h - ${CMAKE_CURRENT_SOURCE_DIR}/../src/geology.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../src/geology.h - ${CMAKE_CURRENT_SOURCE_DIR}/../src/global.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../src/global.h - ${CMAKE_CURRENT_SOURCE_DIR}/../src/hexagon.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../src/hexagon.h - ${CMAKE_CURRENT_SOURCE_DIR}/../src/main.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../src/parameter.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../src/parameter.h - ${CMAKE_CURRENT_SOURCE_DIR}/../src/segment.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../src/segment.h - ${CMAKE_CURRENT_SOURCE_DIR}/../src/subbasin.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../src/subbasin.h - ${CMAKE_CURRENT_SOURCE_DIR}/../src/system.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../src/system.h - ${CMAKE_CURRENT_SOURCE_DIR}/../src/json/vertex.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../src/json/vertex.h - ${CMAKE_CURRENT_SOURCE_DIR}/../src/watershed.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../src/watershed.h - ) - -add_executable(hexwatershed ${hexwatershed_srcs}) - -set(default_build_type Release) -if(EXISTS "${CMAKE_SOURCE_DIR}/../.git") - set(default_build_type Release) -endif() - -if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - message(STATUS "Setting build type to '${default_build_type}' as none was specified.") - set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE - STRING "Choose the type of build." FORCE) - # Set the possible values of build type for cmake-gui - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS - "Debug" "Release" "MinSizeRel" "RelWithDebInfo") -endif() - -message("build type = ${default_build_type}") - -target_compile_options(hexwatershed PUBLIC -std=c++11) - -set(INSTALL_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../bin) -install(TARGETS hexwatershed RUNTIME DESTINATION ${INSTALL_DIR}) - -find_package(OpenMP) - -if (OPENMP_FOUND) - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") - set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}") -endif() - -set(RAPIDJSON_NCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../rapidjson) - -include_directories(${RAPIDJSON_NCLUDE_DIR}) - -target_link_libraries(hexwatershed -std=c++11) diff --git a/external/hexwatershed/bin/hexwatershed b/external/hexwatershed/bin/hexwatershed deleted file mode 100755 index 296ec6937bf06b523ab47dad90cfbf89a38a7096..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 427928 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 diff --git a/external/hexwatershed/src/.DS_Store b/external/hexwatershed/src/.DS_Store deleted file mode 100755 index 5008ddfcf53c02e82d7eee2e57c38e5672ef89f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 - - - - - - - \ No newline at end of file diff --git a/external/hexwatershed/src/.idea/src.iml b/external/hexwatershed/src/.idea/src.iml deleted file mode 100755 index bc2cd87..0000000 --- a/external/hexwatershed/src/.idea/src.iml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/external/hexwatershed/src/.idea/workspace.xml b/external/hexwatershed/src/.idea/workspace.xml deleted file mode 100755 index 97843c0..0000000 --- a/external/hexwatershed/src/.idea/workspace.xml +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1552423063892 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/external/hexwatershed/src/compset/compset.cpp b/external/hexwatershed/src/compset/compset.cpp deleted file mode 100755 index 1444585..0000000 --- a/external/hexwatershed/src/compset/compset.cpp +++ /dev/null @@ -1,198 +0,0 @@ - -/** - * @file flowline.cpp - * @author Chang Liao (chang.liao@pnnl.gov) - * @brief - * @version 0.1 - * @date 2019-06-11Created by Chang Liao on 4/26/18. - * - * @copyright Copyright (c) 2019 - * - */ - -#include "./compset.h" - -namespace hexwatershed -{ - - compset::compset() - { - - - } - - compset::~compset() - { - } - - int compset::compset_read_model() - { - int error_code =1; - return error_code; - } - int compset::compset_setup_model() - { - int error_code =1; - return error_code; - } - - int compset::compset_run_model() - - { - int error_code =1; - int iFlag_global = cParameter.iFlag_global; - int iFlag_multiple_outlet = cParameter.iFlag_multiple_outlet; - int iFlag_debug =cParameter.iFlag_debug; - std::string sFilename; - error_code = compset_priority_flood_depression_filling(); - if (error_code != 1) - { - return error_code; - } - sLog = "Finished depression filling"; - ofs_log << sLog << std::endl; - ofs_log.flush(); - std::cout << sLog << std::endl; - compset_calculate_flow_direction(); - sLog = "Finished flow direction"; - ofs_log << sLog << std::endl; - ofs_log.flush(); - std::flush(std::cout); - std::cout << sLog << std::endl; - - compset_calculate_flow_accumulation(); - sLog = "Finished flow accumulation"; - ofs_log << sLog << std::endl; - ofs_log.flush(); - std::cout << sLog << std::endl; - - if (iFlag_global !=1) - { - if (iFlag_multiple_outlet != 1) - { - compset_define_stream_grid(); - sLog = "Finished defining stream grid"; - ofs_log << sLog << std::endl; - ofs_log.flush(); - std::cout << sLog << std::endl; - - iFlag_debug = 0; - compset_define_watershed_boundary(); - sLog = "Finished defining watershed boundary"; - ofs_log << sLog << std::endl; - ofs_log.flush(); - std::cout << sLog << std::endl; - - //start from here, we can actually run all the algorithm using the watershed object - compset_define_stream_confluence(); - sLog = "Finished defining confluence"; - ofs_log << sLog << std::endl; - ofs_log.flush(); - std::cout << sLog << std::endl; - - compset_define_stream_segment(); - sLog = "Finished defining stream segment"; - ofs_log << sLog << std::endl; - ofs_log.flush(); - std::cout << sLog << std::endl; - - compset_build_stream_topology(); - sLog = "Finished defining stream topology"; - ofs_log << sLog << std::endl; - ofs_log.flush(); - std::cout << sLog << std::endl; - - compset_define_stream_order(); - sLog = "Finished defining stream order"; - ofs_log << sLog << std::endl; - ofs_log.flush(); - std::cout << sLog << std::endl; - - compset_define_subbasin(); - sLog = "Finished defining subbasin"; - ofs_log << sLog << std::endl; - ofs_log.flush(); - std::cout << sLog << std::endl; - - compset_calculate_watershed_characteristics(); - sLog = "Finished watershed characteristics"; - ofs_log << sLog << std::endl; - ofs_log.flush(); - std::cout << sLog << std::endl; - std::flush(std::cout); - - //now all the watersheds are processed, we can transfer back to main object - compset_transfer_watershed_to_domain(); - compset_update_cell_elevation(); - compset_update_vertex_elevation(); - } - else - { - //multiple outlet case, do we need these information? - compset_define_stream_grid(); - sLog = "Finished defining stream grid"; - ofs_log << sLog << std::endl; - ofs_log.flush(); - std::cout << sLog << std::endl; - iFlag_debug = 0; - compset_define_watershed_boundary(); - sLog = "Finished defining watershed boundary"; - ofs_log << sLog << std::endl; - ofs_log.flush(); - std::cout << sLog << std::endl; - //start from here, we can actually run all the algorithm using the watershed object - compset_define_stream_confluence(); - sLog = "Finished defining confluence"; - ofs_log << sLog << std::endl; - ofs_log.flush(); - std::cout << sLog << std::endl; - compset_define_stream_segment(); - sLog = "Finished defining stream segment"; - ofs_log << sLog << std::endl; - ofs_log.flush(); - std::cout << sLog << std::endl; - compset_build_stream_topology(); - sLog = "Finished defining stream topology"; - ofs_log << sLog << std::endl; - ofs_log.flush(); - std::cout << sLog << std::endl; - compset_define_stream_order(); - sLog = "Finished defining stream order"; - ofs_log << sLog << std::endl; - ofs_log.flush(); - std::cout << sLog << std::endl; - compset_define_subbasin(); - sLog = "Finished defining subbasin"; - ofs_log << sLog << std::endl; - ofs_log.flush(); - std::cout << sLog << std::endl; - compset_calculate_watershed_characteristics(); - sLog = "Finished watershed characteristics"; - ofs_log << sLog << std::endl; - ofs_log.flush(); - std::cout << sLog << std::endl; - std::flush(std::cout); - //now all the watersheds are processed, we can transfer back to main object - compset_transfer_watershed_to_domain(); - compset_update_cell_elevation(); - compset_update_vertex_elevation(); - } - } - else - { - //global simulation - } - - std::flush(std::cout); - - - return error_code; - } - - int compset::compset_cleanup_model () - { - int error_code =1; - return error_code; - } - -} // namespace hexwatershed diff --git a/external/hexwatershed/src/compset/compset.h b/external/hexwatershed/src/compset/compset.h deleted file mode 100755 index ed01897..0000000 --- a/external/hexwatershed/src/compset/compset.h +++ /dev/null @@ -1,173 +0,0 @@ -/** - * @file edge.h - * @author Chang Liao (chang.liao@pnnl.gov) - * @brief Header file of the case class - * @version 0.1 - * @date 2019-08-02 - * @citation Liao, C., Tesfa, T., Duan, Z., & Leung, L. R. (2020). - * Watershed delineation on a hexagonal mesh grid. Environmental Modelling & Software, 104702. - * https://www.sciencedirect.com/science/article/pii/S1364815219308278 - * @github page https://github.com/changliao1025/hexwatershed - * @copyright Copyright (c) 2019 - * - */ -#pragma once -#include -#include -#include -#include -#include -#include // abs, floor - -#include "../system.h" -#include "../hexagon.h" -#include "../flowline.h" -#include "../conversion.h" -#include "../watershed.h" -#include "../parameter.h" - - -#include "../json/JSONBase.h" -#include "../json/mesh.h" -#include "../json/cell.h" -#include "../json/basin.h" -#include "../json/multibasin.h" - -using namespace std; -using namespace rapidjson; -using namespace jsonmodel; - -enum eMesh_type { - eM_hexagon, - eM_square, - eM_latlon, - eM_triangle, - eM_mpas, -}; - -enum eVariable { - eV_elevation, - eV_flow_direction, - eV_flow_accumulation, - eV_stream_grid, - eV_confluence, - eV_watershed, - eV_subbasin, - eV_segment, - eV_slope_between, - eV_slope_within, - eV_stream_order, - eV_wetness_index, -}; - -namespace hexwatershed -{ - - - class compset { - public: - compset (); - - ~compset (); - - int nWatershed_total; - int nSegment_total; //the total number of stream segment - int nConfluence_total; //the total number of stream confluence - - - std::string sWorkspace_input; - std::string sWorkspace_output; - - std::string sWorkspace_output_pyflowline; - std::string sWorkspace_output_hexwatershed; - - std::string sFilename_configuration; - std::string sFilename_log; - std::string sLog; - std::string sFilename_mesh_info; - - std::string sFilename_domain_json; - std::string sFilename_json; - std::string sFilename_animation_json; - - //vtk support - std::string sFilename_vtk; - std::string sFilename_vtk_debug; - - //others - std::string sDate_default; - std::string sDate; - - std::ofstream ofs_log; // used for IO starlog file - - //std::map mParameter; //for input data and parameters - std::vector vCell; //all the cells based on shapefile - std::vector vCell_active; //all calls has elevation (not missing value) - std::vector vCell_priority_flood; //all calls has elevation (not missing value) - //watershed cWatershed; - std::vector vWatershed; - std::vector vElevation; //vector to store the DEM raster data - std::vector vFlowline; - // this may be merged with global id - std::vector vVertex_active; //for vtk support, it store all the vertex in 3D - - std::string sFilename_netcdf_output; //if model use netcdf, we can put all results into one single netcdf file, - // except the txt based results. - std::string sFilename_hexagon_netcdf; - parameter cParameter; - std::vector aCell; - std::vector aBasin; - std::vector vContinent_boundary; - //std::vector vInstance; - - int compset_initialize_model (); - int compset_setup_model (); - int compset_read_model(); - int compset_run_model (); - int compset_save_model (); - int compset_cleanup_model (); - - int compset_assign_stream_burning_cell(); - int compset_priority_flood_depression_filling (); - int compset_stream_burning_with_topology (long lCellID_center); - int compset_stream_burning_without_topology (long lCellID_center); - int compset_breaching_stream_elevation (long lCellID_center); - int compset_calculate_flow_direction (); - int compset_calculate_flow_accumulation (); - int compset_define_stream_grid (); - int compset_define_watershed_boundary (); - int compset_define_stream_confluence (); - int compset_define_stream_segment (); - int compset_tag_confluence_upstream (int iWatershed, long lCellID_confluence); - - int compset_build_stream_topology(); - int compset_define_stream_order(); - int compset_define_subbasin (); - int compset_calculate_watershed_characteristics (); - - int compset_save_watershed_characteristics (); - - - int compset_transfer_watershed_to_domain(); - - int compset_save_vtk (std::string sFilename_in); - int compset_save_json(std::string sFilename_in); - int compset_save_domain_json(std::string sFilename_in); - int compset_save_animation_json(std::string sFilename_in); - std::vector compset_obtain_boundary (std::vector vCell_in); - long compset_find_index_by_cell_id(long lCellID); - - - int find_continent_boundary(long lCellID_in); - int find_land_ocean_interface_neighbors(long lCellID_in); - - int priority_flood_depression_filling(std::vector vCell_in); - int compset_update_cell_elevation(); - int compset_update_vertex_elevation(); - - int compset_check_digital_elevation_model_depression (std::vector vCell_in); - - std::array compset_find_lowest_cell_in_priority_queue (std::vector vCell_in); - - }; -} // namespace hexwatershed diff --git a/external/hexwatershed/src/compset/compset_depression.cpp b/external/hexwatershed/src/compset/compset_depression.cpp deleted file mode 100755 index a275592..0000000 --- a/external/hexwatershed/src/compset/compset_depression.cpp +++ /dev/null @@ -1,705 +0,0 @@ - -/** - * @file depression.h - * @author Chang Liao (chang.liao@pnnl.gov) - * @brief The depression header file - * @version 0.1 - * @date 2019-08-02 - * @citation Liao, C., Tesfa, T., Duan, Z., & Leung, L. R. (2020). - * Watershed delineation on a hexagonal mesh grid. Environmental Modelling & Software, 104702. - * https://www.sciencedirect.com/science/article/pii/S1364815219308278 - * @github page https://github.com/changliao1025/hexwatershed - * @copyright Copyright (c) 2019 - * - */ -#include "./compset.h" - -namespace hexwatershed -{ - - /** - * private functions. check whether there is local depression in the dem or not. in fact, a more rigorous method should pass in dem instead of the hexagon vector - but because we will not change any member variable here, it should be safe to pass in the vector - * @param vCell_in - * @return - */ - int compset::compset_check_digital_elevation_model_depression(std::vector vCell_in) - { - int error_code = 1; - int iNeighbor; - int nNeighbor_land; - int nEdge; - long lCellID_neighbor; - long lCellIndex_self, lCelllIndex_search; - float dElevation_min; - float dElevation_self; - std::vector vNeighbor_land; - std::vector::iterator iIterator; - std::vector vElevation_neighbor; - //std::vector::iterator iIterator1; - //std::vector::iterator iIterator2; - - //#pragma omp parallel for private(lCellIndex_self, iIterator, iNeighbor, vNeighbor_land, \ - dElevation_self, vElevation_neighbor, \ - lCellID_neighbor, dElevation_min, lCelllIndex_search) - for (lCellIndex_self = 0; lCellIndex_self < vCell_in.size(); lCellIndex_self++) - { - if (error_code == 1) - { - nNeighbor_land = vCell_in.at(lCellIndex_self).nNeighbor_land; - nEdge = vCell_in.at(lCellIndex_self).nEdge; - if (nNeighbor_land == nEdge) - { - vNeighbor_land = vCell_in.at(lCellIndex_self).vNeighbor_land; - dElevation_self = vCell_in.at(lCellIndex_self).dElevation_mean; - vElevation_neighbor.clear(); - for (iNeighbor = 0; iNeighbor < nNeighbor_land; iNeighbor++) - { - lCellID_neighbor = vNeighbor_land[iNeighbor]; - //find it - for (lCelllIndex_search = 0; lCelllIndex_search < vCell_in.size(); lCelllIndex_search++) - { - if (vCell_in.at(lCelllIndex_search).lCellID == lCellID_neighbor) - { - vElevation_neighbor.push_back(vCell_in.at(lCelllIndex_search).dElevation_mean); - } - else - { - //continue; - } - } - } - //if it is the lowest? - dElevation_min = *(std::min_element(vElevation_neighbor.begin(), vElevation_neighbor.end())); - if (dElevation_self < dElevation_min) - { - error_code = 0; - } - } - else - { - //edge do nothing - } - } - else - { - //continue; - } - } - return error_code; - } - - /** - * retrieve the boundary of the hexagon grid boundary - * it is not ordered - * @param vCell_in :the hexagon grid - * @return - */ - std::vector compset::compset_obtain_boundary(std::vector vCell_in) - { - int error_code = 1; - int iMesh_type = this->cParameter.iMesh_type; - std::vector::iterator iIterator1; - - std::vector vCell_out; - - for (iIterator1 = vCell_in.begin(); iIterator1 != vCell_in.end(); iIterator1++) - { - if (iMesh_type ==1 || iMesh_type ==4 ) - { - if ((*iIterator1).nNeighbor_land < (*iIterator1).nVertex) //or vertex - { - vCell_out.push_back(*iIterator1); - } - } - else - { - if ((*iIterator1).nNeighbor_land < 8) // - { - vCell_out.push_back(*iIterator1); - } - } - - } - - return vCell_out; - } - /** - * find the hexagon with the lowest elevation - * @param vCell_in :the hexagon grid - * @return - */ - std::array compset::compset_find_lowest_cell_in_priority_queue(std::vector vCell_in) - { - long lCellIndex_active = 0; - long lCellID_global = -1; - long lIndex = 0; - long lCellIndex_boundary = 0; - float dElevation_lowest; - - std::vector::iterator iIterator1; - std::array aIndex_out; - if (vCell_in.size() < 2) - { - //something is wrong - } - else - { - //set the first as lowest - dElevation_lowest = vCell_in[0].dElevation_mean; - lCellID_global = vCell_in[0].lCellID; - lCellIndex_active = vCell_in[0].lCellIndex; - lCellIndex_boundary = 0; - for (iIterator1 = vCell_in.begin(); iIterator1 != vCell_in.end(); iIterator1++) - { - if ((*iIterator1).dElevation_mean < dElevation_lowest) - { - dElevation_lowest = (*iIterator1).dElevation_mean; - lCellID_global = (*iIterator1).lCellID; - lCellIndex_active = (*iIterator1).lCellIndex; - lCellIndex_boundary = lIndex; - } - lIndex = lIndex + 1; - } - //be careful - aIndex_out.at(0) = lCellIndex_boundary; - aIndex_out.at(1) = lCellIndex_active; - aIndex_out.at(2) = lCellID_global; - } - return aIndex_out; - } - - /** - * DEM depression filling - * @return - */ - int compset::compset_priority_flood_depression_filling() - { - int error_code = 1; - int iFlag_finished = 0; - int iFlag_has_stream; - int iFlag_global = cParameter.iFlag_global; - int iFlag_multiple_outlet = cParameter.iFlag_multiple_outlet; - int iFlag_flowline = cParameter.iFlag_flowline; - int iFlag_stream_burning_topology= cParameter.iFlag_stream_burning_topology; - int iFlag_stream_burning_treated_neighbor; - int nOutlet = cParameter.nOutlet; - - long lCellID_outlet ; - long lCellIndex_outlet; - - float dBreach_threshold = cParameter.dBreach_threshold; - int iFlag_stream_burned; - int iFlag_stream_burned_center; - int iFlag_stream_burned_neighbor; - int iFlag_depression_filling_treated; - int iFlag_depression_filling_treated_neighbor; - int iFlag_found; - int iOption_filling = 1; //2 switch - - long lCellIndex_boundary; - long lCellIndex_active; - long lCellIndex_neighbor; - long iAttempt = 0; - long lCellID_center; - long lCellID_neighbor; - long lCellID_self; - long lCellID_temp; - long lCellID_next; - long lCellIndex_next; - - long lCellID_downstream; - long lCellID_downstream_neighbor; - float dElevation_mean_center; - float dElevation_mean_neighbor; - float dElevation_history; - float dDifference_dummy; - std::array aIndex; - - std::vector vCell_boundary; - std::vector::iterator iIterator1; - std::vector::iterator iIterator; - std::vector::iterator iIterator_self; - - - if (iFlag_global==0) - { - if (iFlag_multiple_outlet == 0) - { - std::cout<<"This is a local simulation with only one outlet."<= 3)//careful - { - priority_flood_depression_filling (vContinent_boundary); - } - - //reset to the next continent - vContinent_boundary.clear(); - - } - } - } - - } - else //pure dem based - { - //find each watershed - for (iIterator_self = vCell_active.begin (); iIterator_self != vCell_active.end (); iIterator_self++) - { - if ((*iIterator_self).iFlag_depression_filling_treated != 1) - { - if ((*iIterator_self).nNeighbor_land < (*iIterator_self).nVertex) - { - - vContinent_boundary.clear(); - find_continent_boundary((*iIterator_self).lCellID); - - for (iIterator = vContinent_boundary.begin(); iIterator != vContinent_boundary.end(); iIterator++) - { - lCellIndex_active = (*iIterator).lCellIndex; - vCell_active.at(lCellIndex_active).iFlag_depression_filling_treated = 1; - } - - //start flooding - if (vContinent_boundary.size () >= 3)//careful - { - priority_flood_depression_filling (vContinent_boundary); - } - - //reset to the next continent - vContinent_boundary.clear(); - - } - } - } - - } - - } - - } - else - { - std::cout<<"This is a global simulation"<= 3)//careful - { - priority_flood_depression_filling (vContinent_boundary); - } - - //reset to the next continent - vContinent_boundary.clear(); - - } - } - } - - } - else //pure dem based - { - //find each watershed - for (iIterator_self = vCell_active.begin (); iIterator_self != vCell_active.end (); iIterator_self++) - { - if ((*iIterator_self).iFlag_depression_filling_treated != 1) - { - if ((*iIterator_self).nNeighbor_land < (*iIterator_self).nVertex) - { - - vContinent_boundary.clear(); - find_continent_boundary((*iIterator_self).lCellID); - - for (iIterator = vContinent_boundary.begin(); iIterator != vContinent_boundary.end(); iIterator++) - { - lCellIndex_active = (*iIterator).lCellIndex; - vCell_active.at(lCellIndex_active).iFlag_depression_filling_treated = 1; - } - - //start flooding - if (vContinent_boundary.size () >= 3)//careful - { - priority_flood_depression_filling (vContinent_boundary); - } - - //reset to the next continent - vContinent_boundary.clear(); - - } - } - } - - } - - } - - return error_code; - } - -/** - * @brief - * - * @param lCellID_in - * @return int - */ - int compset::find_land_ocean_interface_neighbors(long lCellID_in) - { - int error_code = 1; - int iNeighbor; - int iVertex; - int iFlag_depression_filling_treated; - std::vector aNeighbor; - //std::vector::iterator iIterator_self; - std::vector vNeighbor_land; - long lCellIndex_neighbor; - long lCellIndex = compset_find_index_by_cell_id(lCellID_in); - long lCellID_neighbor; - std::vector::iterator iIterator; - vNeighbor_land = vCell_active.at(lCellIndex).vNeighbor_land; - for (iIterator = vNeighbor_land.begin (); iIterator != vNeighbor_land.end (); iIterator++) - { - lCellID_neighbor = *iIterator; - lCellIndex_neighbor = compset_find_index_by_cell_id(lCellID_neighbor); - iNeighbor = vCell_active.at(lCellIndex_neighbor).nNeighbor_land; - iVertex = vCell_active.at(lCellIndex_neighbor).nVertex; - iFlag_depression_filling_treated = vCell_active.at(lCellIndex_neighbor).iFlag_depression_filling_treated ; - if ( iNeighbor vCellID_boundary; - std::vector aNeighbor; - int iFlag_finished = 0 ; - int iFlag_found_starting_point =0 ; - long lCellIndex_neighbor; - long lCellID_current = lCellID_in; - long lCellID_neighbor; - std::vector::iterator iIterator; - std::vector::iterator iIterator1; - - lCellIndex_neighbor = compset_find_index_by_cell_id(lCellID_in); - vCell_active.at(lCellIndex_neighbor).iFlag_depression_filling_treated = 1; - vContinent_boundary.push_back(vCell_active.at(lCellIndex_neighbor)); - - - - find_land_ocean_interface_neighbors(lCellID_current); - - - - - return error_code;; - - } - - - - int compset::priority_flood_depression_filling(std::vector vCell_boundary_in) - { - int error_code= 1; - int iFlag_stream_burning_treated_neighbor; - int iFlag_global = cParameter.iFlag_global; - int iFlag_multiple_outlet = cParameter.iFlag_multiple_outlet; - int iFlag_elevation_profile = cParameter.iFlag_elevation_profile; - long lCellID_lowest; - long lCellIndex_neighbor; - long lCellID_neighbor; - long lCellIndex_boundary; - long lCellIndex_active; - float dElevation_mean_center; - float dElevation_mean_neighbor; - float dElevation_profile0_center; - float dElevation_profile0_neighbor; - int iFlag_depression_filling_treated_neighbor; - std::array aIndex_search; - - while (vCell_boundary_in.size () > 3) - { - aIndex_search = compset_find_lowest_cell_in_priority_queue(vCell_boundary_in); - lCellIndex_boundary = aIndex_search[0]; //local index in boundary - lCellIndex_active = aIndex_search[1]; - lCellID_lowest = aIndex_search[2]; - dElevation_mean_center = (vCell_active.at (lCellIndex_active)).dElevation_mean; - dElevation_profile0_center = (vCell_active.at (lCellIndex_active)).dElevation_profile0; - //remove it from the table - vCell_boundary_in.erase (vCell_boundary_in.begin () + lCellIndex_boundary); - - for (int i = 0; i < (vCell_active.at (lCellIndex_active)).nNeighbor_land; i++) - { - lCellID_neighbor = (vCell_active.at (lCellIndex_active)).vNeighbor_land[i]; - lCellIndex_neighbor = compset_find_index_by_cell_id(lCellID_neighbor); - iFlag_depression_filling_treated_neighbor = vCell_active.at(lCellIndex_neighbor).iFlag_depression_filling_treated; - iFlag_stream_burning_treated_neighbor = vCell_active.at(lCellIndex_neighbor).iFlag_stream_burning_treated; - dElevation_mean_neighbor = vCell_active[lCellIndex_neighbor].dElevation_mean; - - if (iFlag_depression_filling_treated_neighbor != 1) - { - if(iFlag_stream_burning_treated_neighbor ==1 ) - { - vCell_active.at(lCellIndex_neighbor).iFlag_depression_filling_treated = 1; - vCell_boundary_in.push_back(vCell_active[lCellIndex_neighbor]); - } - else - { - vCell_priority_flood.push_back( vCell_active.at(lCellIndex_neighbor) ); - - if (dElevation_mean_neighbor <= dElevation_mean_center) - { - vCell_active[lCellIndex_neighbor].dElevation_mean = dElevation_mean_center + 0.001 + abs(dElevation_mean_neighbor) * 0.0001; - } - - //elevation profile case - if(iFlag_elevation_profile == 1) - { - dElevation_profile0_neighbor = vCell_active[lCellIndex_neighbor].dElevation_profile0; - if (dElevation_profile0_neighbor <= dElevation_profile0_center) - { - vCell_active[lCellIndex_neighbor].dElevation_profile0 = - dElevation_profile0_center + abs (dElevation_profile0_center) * 0.0001 + 0.0001; - } - } - - vCell_active.at(lCellIndex_neighbor).iFlag_depression_filling_treated = 1; - vCell_boundary_in.push_back(vCell_active[lCellIndex_neighbor]); - } - } - else - { - (vCell_active[lCellIndex_neighbor]).iFlag_depression_filling_treated =1; - - } - } - } - return error_code; - } - - - - -} diff --git a/external/hexwatershed/src/compset/compset_direction.cpp b/external/hexwatershed/src/compset/compset_direction.cpp deleted file mode 100755 index d352714..0000000 --- a/external/hexwatershed/src/compset/compset_direction.cpp +++ /dev/null @@ -1,525 +0,0 @@ -/** - * @file domain.cpp - * @author Chang Liao (chang.liao@pnnl.gov) - * @brief the realization of the domain class - * @version 0.1 - * @date 2019-08-02 - * - * @copyright Copyright (c) 2019 - * - */ -#include "compset.h" - -namespace hexwatershed -{ - - /** - * calculate the flow direction based on elevation, this step "should" only be run after the depression filling - * @return - */ - int compset::compset_calculate_flow_direction() - { - int error_code = 1; - int iFlag_stream_burned; - int iFlag_has_stream; - int iMesh_type = cParameter.iMesh_type; - - int iFlag_flowline = cParameter.iFlag_flowline; - int iFlag_stream_burning_topology = cParameter.iFlag_stream_burning_topology; - - int iFlag_global = cParameter.iFlag_global; - int iFlag_multiple_outlet = cParameter.iFlag_multiple_outlet; - int iFlag_elevation_profile = cParameter.iFlag_elevation_profile; - long iNeighborIndex; - long lCellID_lowest; - long lCellID_highest; - long lCellIndex_self; - long lCellID; - float dElevation_mean; - float dElevation_profile0; - float dElevation_diff; - float dDistance_neighbor; - float dDistance_downslope; - float dDistance_initial =0.0; - float dSlope_initial = 0.0; - float dSlope_downslope; // should be negative because downslope - float dSlope_upslope; // should be positive because upslope - float dSlope_new; - float dSlope_elevation_profile0; - - long lCellIndex_neighbor; - long lCellIndex_neighbor_lowest; - long lCellIndex_neighbor_highest; - long lCellID_downstream; - - std::vector vNeighbor_distance; - std::vector vNeighbor; - std::vector vNeighbor_land; - - std::vector::iterator iIterator; - std::vector::iterator iIterator_neighbor; - - if (iFlag_flowline == 1) // use the existing - { - - if (iFlag_stream_burning_topology == 0) - { - // rely on elevation - for (lCellIndex_self = 0; lCellIndex_self < vCell_active.size(); lCellIndex_self++) - { - vNeighbor = (vCell_active.at(lCellIndex_self)).vNeighbor; - vNeighbor_land = (vCell_active.at(lCellIndex_self)).vNeighbor_land; - vNeighbor_distance = (vCell_active.at(lCellIndex_self)).vNeighbor_distance; - lCellID_lowest = -1; - lCellID_highest = -1; - dElevation_mean = (vCell_active.at(lCellIndex_self)).dElevation_mean; - dSlope_downslope = dSlope_initial; - dSlope_upslope = dSlope_initial; - dDistance_downslope = dDistance_initial; - - // iterate through all neighbors - for (iIterator_neighbor = vNeighbor_land.begin(); iIterator_neighbor != vNeighbor_land.end(); iIterator_neighbor++) - { - - lCellIndex_neighbor = compset_find_index_by_cell_id(*iIterator_neighbor); - dElevation_diff = dElevation_mean - vCell_active.at(lCellIndex_neighbor).dElevation_mean; - // get distance - iIterator = std::find(vNeighbor.begin(), vNeighbor.end(), *iIterator_neighbor); - iNeighborIndex = std::distance(vNeighbor.begin(), iIterator); - dDistance_neighbor = vNeighbor_distance.at(iNeighborIndex); - dSlope_new = dElevation_diff / dDistance_neighbor; - if (dSlope_new > 0.0) - { - // this is a downslope - (vCell_active.at(lCellIndex_self)).vDownslope.push_back(*iIterator_neighbor); - if (dSlope_new > dSlope_downslope) - { - // this maybe a dominant downslope - dSlope_downslope = dSlope_new; - dDistance_downslope = dDistance_neighbor; - lCellID_lowest = *iIterator_neighbor; - } - } - else - { - // this should be a upslope - (vCell_active.at(lCellIndex_self)).vUpslope.push_back(*iIterator_neighbor); - if (dSlope_new < dSlope_upslope) - { - // this maybe a dominant upslope - dSlope_upslope = dSlope_new; - lCellID_highest = *iIterator_neighbor; - } - } - } - // mark the direction as the largest elevation differences - if (lCellID_lowest != -1) - { - (vCell_active.at(lCellIndex_self)).lCellID_downslope_dominant = lCellID_lowest; - // before define stream, we cannot establish upslope relationship - // calculate slope - if (dSlope_downslope < 0.0) - { - std::cout << "Slope should be positive!" << std::endl; - } - (vCell_active.at(lCellIndex_self)).dSlope_max_downslope = dSlope_downslope; - (vCell_active.at(lCellIndex_self)).dDistance_to_downslope = dDistance_downslope; - } - else - { - // outlet - if (dSlope_upslope > 0.0) - { - std::cout << "Upslope should be positive!" << std::endl; - } - (vCell_active.at(lCellIndex_self)).dSlope_max_downslope = -1 * dSlope_upslope; - //just use its own length - (vCell_active.at(lCellIndex_self)).dDistance_to_downslope = (vCell_active.at(lCellIndex_self)).dLength_edge_mean; - } - } - } - else - { - //#pragma omp parallel for private(lCellIndex_self, vNeighbor_land, lCellID_lowest, dElevation_mean, dSlope_initial, dSlope_new, iIterator_neighbor) - for (lCellIndex_self = 0; lCellIndex_self < vCell_active.size(); lCellIndex_self++) - { - vNeighbor = (vCell_active.at(lCellIndex_self)).vNeighbor; - vNeighbor_distance = (vCell_active.at(lCellIndex_self)).vNeighbor_distance; - iFlag_stream_burned = vCell_active[lCellIndex_self].iFlag_stream_burned; - vNeighbor_land = (vCell_active.at(lCellIndex_self)).vNeighbor_land; - lCellID_lowest = -1; - lCellID_highest = -1; - - dElevation_mean = (vCell_active.at(lCellIndex_self)).dElevation_mean; - dElevation_profile0 = (vCell_active.at(lCellIndex_self)).dElevation_profile0; - lCellID_downstream = (vCell_active.at(lCellIndex_self)).lCellID_downstream_burned; - lCellID = (vCell_active.at(lCellIndex_self)).lCellID; - - dSlope_downslope = dSlope_initial; - dSlope_upslope = dSlope_initial; - dDistance_downslope = dDistance_initial; - - iFlag_has_stream = 0; - for (iIterator_neighbor = vNeighbor_land.begin(); iIterator_neighbor != vNeighbor_land.end(); iIterator_neighbor++) - { - lCellIndex_neighbor = compset_find_index_by_cell_id(*iIterator_neighbor); - if (vCell_active.at(lCellIndex_neighbor).iFlag_stream_burned == 1) - { - iFlag_has_stream = 1; - break; - } - } - - if (iFlag_has_stream == 1) - { - // iterate through all neighbors - for (iIterator_neighbor = vNeighbor_land.begin(); iIterator_neighbor != vNeighbor_land.end(); iIterator_neighbor++) - { - lCellIndex_neighbor = compset_find_index_by_cell_id(*iIterator_neighbor); - if (vCell_active.at(lCellIndex_neighbor).iFlag_stream_burned == 1) - { - // it has a neighboring stream - dElevation_diff = dElevation_mean - vCell_active.at(lCellIndex_neighbor).dElevation_mean; - // get distance - iIterator = std::find(vNeighbor.begin(), vNeighbor.end(), (*iIterator_neighbor)); - iNeighborIndex = std::distance(vNeighbor.begin(), iIterator); - dDistance_neighbor = vNeighbor_distance.at(iNeighborIndex); - - dSlope_new = dElevation_diff / dDistance_neighbor; - if (dSlope_new > 0.0) // positive means stream elevation is lower - { - if (dSlope_new > dSlope_downslope) - { - dSlope_downslope = dSlope_new; - lCellID_lowest = *iIterator_neighbor; - lCellIndex_neighbor_lowest = lCellIndex_neighbor; - dDistance_downslope = dDistance_neighbor; - } - } - else - { - // this is an upslope stream grid, but may not the steepest one, so we can skip the lowest - } - (vCell_active.at(lCellIndex_self)).vDownslope.push_back(*iIterator_neighbor); - } - else - { - dElevation_diff = dElevation_mean - vCell_active.at(lCellIndex_neighbor).dElevation_mean; - // get distance - iIterator = std::find(vNeighbor.begin(), vNeighbor.end(), (*iIterator_neighbor)); - iNeighborIndex = std::distance(vNeighbor.begin(), iIterator); - dDistance_neighbor = vNeighbor_distance.at(iNeighborIndex); - dSlope_new = dElevation_diff / dDistance_neighbor; - if (dSlope_new > 0.0) // positive, a lower neighbor - { - // this is a downslope but not stream - (vCell_active.at(lCellIndex_self)).vDownslope.push_back(*iIterator_neighbor); - } - else - { - // this should be a upslope land grid - (vCell_active.at(lCellIndex_self)).vUpslope.push_back(*iIterator_neighbor); - if (dSlope_new < dSlope_upslope) - { - // this maybe a dominant downslope - dSlope_upslope = dSlope_new; - lCellID_highest = *iIterator_neighbor; - dDistance_downslope = dDistance_neighbor; - lCellIndex_neighbor_highest = lCellIndex_self; - } - } - } - } - } - else - { - // iterate through all neighbors - for (iIterator_neighbor = vNeighbor_land.begin(); iIterator_neighbor != vNeighbor_land.end(); iIterator_neighbor++) - { - lCellIndex_neighbor = compset_find_index_by_cell_id(*iIterator_neighbor); - dElevation_diff = dElevation_mean - vCell_active.at(lCellIndex_neighbor).dElevation_mean; - // get distance - iIterator = std::find(vNeighbor.begin(), vNeighbor.end(), (*iIterator_neighbor)); - iNeighborIndex = std::distance(vNeighbor.begin(), iIterator); - dDistance_neighbor = vNeighbor_distance.at(iNeighborIndex); - dSlope_new = dElevation_diff / dDistance_neighbor; - if (dSlope_new > 0.0) - { - // this is a downslope - (vCell_active.at(lCellIndex_self)).vDownslope.push_back(*iIterator_neighbor); - if (dSlope_new > dSlope_downslope) // downslope - { - dSlope_downslope = dSlope_new; - lCellID_lowest = *iIterator_neighbor; - dDistance_downslope = dDistance_neighbor; - lCellIndex_neighbor_lowest = lCellIndex_neighbor; - } - } - else - { - // this should be a upslope - (vCell_active.at(lCellIndex_self)).vUpslope.push_back(*iIterator_neighbor); - if (dSlope_new < dSlope_upslope) - { - // this maybe a dominant upslope - dSlope_upslope = dSlope_new; - lCellID_highest = *iIterator_neighbor; - lCellIndex_neighbor_highest = lCellIndex_self; - } - } - } - } - - if (iFlag_stream_burned == 1) - { - if (lCellID_downstream != -1) - { - for (iIterator_neighbor = vNeighbor_land.begin(); - iIterator_neighbor != vNeighbor_land.end(); - iIterator_neighbor++) - { - - lCellIndex_neighbor = compset_find_index_by_cell_id(*iIterator_neighbor); - if (vCell_active.at(lCellIndex_neighbor).lCellID == lCellID_downstream) // thi is the downstream - { - (vCell_active.at(lCellIndex_self)).lCellID_downslope_dominant = *iIterator_neighbor; - // only use this stream elevation to calcualte slope - dElevation_diff = dElevation_mean - vCell_active.at(lCellIndex_neighbor).dElevation_mean; // positive - // get distance - iIterator = std::find(vNeighbor.begin(), vNeighbor.end(), (*iIterator_neighbor)); - iNeighborIndex = std::distance(vNeighbor.begin(), iIterator); - dDistance_neighbor = vNeighbor_distance.at(iNeighborIndex); - dSlope_new = dElevation_diff / dDistance_neighbor; - (vCell_active.at(lCellIndex_self)).dSlope_max_downslope = dSlope_new; - (vCell_active.at(lCellIndex_self)).dDistance_to_downslope = dDistance_neighbor; - // elevation profile - if (iFlag_elevation_profile == 1) - { - dElevation_diff = dElevation_profile0 - vCell_active.at(lCellIndex_neighbor).dElevation_profile0; - dSlope_elevation_profile0 = dElevation_diff / (vCell_active.at(lCellIndex_self)).dLength_stream_burned; - if (dSlope_elevation_profile0 <= 0.0001) - { - dSlope_elevation_profile0 = 0.0001; - } - (vCell_active.at(lCellIndex_self)).dSlope_elevation_profile0 = dSlope_elevation_profile0; - } - break; - } - } - } - else - { - // this is possibly outlet, and it has no downstream slope calculated - for (iIterator_neighbor = vNeighbor_land.begin(); - iIterator_neighbor != vNeighbor_land.end(); - iIterator_neighbor++) - { - lCellIndex_neighbor = compset_find_index_by_cell_id(*iIterator_neighbor); - - if (vCell_active.at(lCellIndex_neighbor).lCellID_downstream_burned == lCellID) // reverse - { - //===================================== - // special case because we flip it - //================================== - dElevation_diff = dElevation_mean - vCell_active.at(lCellIndex_neighbor).dElevation_mean; - // get distance - iIterator = std::find(vNeighbor.begin(), vNeighbor.end(), (*iIterator_neighbor)); - iNeighborIndex = std::distance(vNeighbor.begin(), iIterator); - dDistance_neighbor = vNeighbor_distance.at(iNeighborIndex); - dSlope_new = dElevation_diff / dDistance_neighbor; - if (dSlope_new > 0.0) - { - std::cout << "Upslope should be negative!" << std::endl; - } - (vCell_active.at(lCellIndex_self)).dSlope_max_downslope = -1.0 * dSlope_new; // reverse - (vCell_active.at(lCellIndex_self)).dDistance_to_downslope = (vCell_active.at(lCellIndex_self)).dLength_edge_mean; - - if (iFlag_elevation_profile == 1) - { - dElevation_diff = vCell_active.at(lCellIndex_neighbor).dElevation_profile0 - dElevation_profile0; - dSlope_elevation_profile0 = dElevation_diff / (vCell_active.at(lCellIndex_self)).dLength_stream_burned; - if (dSlope_elevation_profile0 <= 0.0001) - { - dSlope_elevation_profile0 = 0.0001; - } - (vCell_active.at(lCellIndex_self)).dSlope_elevation_profile0 = dSlope_elevation_profile0; - } - - break; - } - } - } - } - else - { - // normal land grid neighbor, this cell maybe on the edge, if so, we can set it mannually as beach - if ( iMesh_type == 4) // this only apply to mpas that does not consider the vertex neighbors - { - if ((vCell_active.at(lCellIndex_self)).nNeighbor_land == (vCell_active.at(lCellIndex_self)).nVertex) - { - // mark the direction as the largest elevation differences - if (lCellID_lowest != -1) - { - (vCell_active.at(lCellIndex_self)).lCellID_downslope_dominant = lCellID_lowest; - // before define stream, we cannot establish upslope relationship - // calculate slope - if (dSlope_downslope < 0.0) - { - std::cout << "Downslope should be positive!" << std::endl; - } - (vCell_active.at(lCellIndex_self)).dSlope_max_downslope = dSlope_downslope; - (vCell_active.at(lCellIndex_self)).dDistance_to_downslope = dDistance_downslope; - - // elevation profile - if (iFlag_elevation_profile == 1) - { - dElevation_diff = dElevation_profile0 - vCell_active.at(lCellIndex_neighbor_lowest).dElevation_profile0; - dSlope_elevation_profile0 = dElevation_diff / (vCell_active.at(lCellIndex_self)).dLength_stream_burned; - if (dSlope_elevation_profile0 <= 0.0001) - { - dSlope_elevation_profile0 = 0.0001; - } - (vCell_active.at(lCellIndex_self)).dSlope_elevation_profile0 = dSlope_elevation_profile0; - } - } - else - { - // this cell is not on the edge, so it must has one - std::cout << "It should have one downslope!" << std::endl; - } - } - else - { // this is a edge node - (vCell_active.at(lCellIndex_self)).lCellID_downslope_dominant = -1; - if (dSlope_upslope > 0.0) - { - std::cout << "Upslope should be negative!" << std::endl; - } - (vCell_active.at(lCellIndex_self)).dSlope_max_downslope = -1.0 * dSlope_upslope; - (vCell_active.at(lCellIndex_self)).dDistance_to_downslope = (vCell_active.at(lCellIndex_self)).dLength_edge_mean; - - if (iFlag_elevation_profile == 1) // beach - { - (vCell_active.at(lCellIndex_self)).dSlope_elevation_profile0 = 0.0001; - } - } - } - else // for latlon and square mesh type - { - // - // mark the direction as the largest elevation differences - if (lCellID_lowest != -1) - { - (vCell_active.at(lCellIndex_self)).lCellID_downslope_dominant = lCellID_lowest; - // before define stream, we cannot establish upslope relationship - // calculate slope - if (dSlope_downslope < 0.0) - { - std::cout << "Downslope should be positive!" << std::endl; - } - (vCell_active.at(lCellIndex_self)).dSlope_max_downslope = dSlope_downslope; - (vCell_active.at(lCellIndex_self)).dDistance_to_downslope = dDistance_downslope; - - // elevation profile - if (iFlag_elevation_profile == 1) - { - dElevation_diff = dElevation_profile0 - vCell_active.at(lCellIndex_neighbor_lowest).dElevation_profile0; - dSlope_elevation_profile0 = dElevation_diff / (vCell_active.at(lCellIndex_self)).dLength_stream_burned; - if (dSlope_elevation_profile0 <= 0.0001) - { - dSlope_elevation_profile0 = 0.0001; - } - (vCell_active.at(lCellIndex_self)).dSlope_elevation_profile0 = dSlope_elevation_profile0; - } - } - else - { - // this cell may be on the edge, so it must has one - //std::cout << "It should have one downslope!" << std::endl; - } - } - } - } - } - } - else - { - // pure dem based - //#pragma omp parallel for private(lCellIndex_self, vNeighbor_land, lCellID_lowest, dElevation_mean, dSlope_initial, dSlope_new, iIterator_neighbor) - for (lCellIndex_self = 0; lCellIndex_self < vCell_active.size(); lCellIndex_self++) - { - vNeighbor = (vCell_active.at(lCellIndex_self)).vNeighbor; - vNeighbor_distance = (vCell_active.at(lCellIndex_self)).vNeighbor_distance; - vNeighbor_land = (vCell_active.at(lCellIndex_self)).vNeighbor_land; - lCellID_lowest = -1; - lCellID_highest = -1; - dElevation_mean = (vCell_active.at(lCellIndex_self)).dElevation_mean; - dSlope_downslope = dSlope_initial; - dSlope_upslope = dSlope_initial; - dDistance_downslope = dDistance_initial; - // iterate through all neighbors - for (iIterator_neighbor = vNeighbor_land.begin(); iIterator_neighbor != vNeighbor_land.end(); iIterator_neighbor++) - { - - lCellIndex_neighbor = compset_find_index_by_cell_id(*iIterator_neighbor); - dElevation_diff = dElevation_mean - vCell_active.at(lCellIndex_neighbor).dElevation_mean; - // get distance - iIterator = std::find(vNeighbor.begin(), vNeighbor.end(), (*iIterator_neighbor)); - iNeighborIndex = std::distance(vNeighbor.begin(), iIterator); - dDistance_neighbor = vNeighbor_distance.at(iNeighborIndex); - dSlope_new = dElevation_diff / dDistance_neighbor; - if (dSlope_new > 0.0) - { - // this is a downslope - (vCell_active.at(lCellIndex_self)).vDownslope.push_back(*iIterator_neighbor); - if (dSlope_new > dSlope_downslope) - { - // this maybe a dominant downslope - dSlope_downslope = dSlope_new; - dDistance_downslope = dDistance_neighbor; - lCellID_lowest = *iIterator_neighbor; - } - } - else - { - // this should be a upslope - (vCell_active.at(lCellIndex_self)).vUpslope.push_back(*iIterator_neighbor); - - if (dSlope_new < dSlope_upslope) - { - // this maybe a dominant downslope - dSlope_upslope = dSlope_new; - lCellID_highest = *iIterator_neighbor; - } - } - } - // mark the direction as the largest elevation differences - if (lCellID_lowest != -1) - { - (vCell_active.at(lCellIndex_self)).lCellID_downslope_dominant = lCellID_lowest; - - // before define stream, we cannot establish upslope relationship - if (dSlope_downslope < 0.0) - { - std::cout << "Slope should be positive!" << std::endl; - } - (vCell_active.at(lCellIndex_self)).dSlope_max_downslope = dSlope_downslope; - (vCell_active.at(lCellIndex_self)).dDistance_to_downslope = dDistance_downslope; - } - else - { - // outlet - // in this case, we will use the highest upslope as slope calculation - if (dSlope_upslope > 0.0) - { - std::cout << "Upslope should be positive!" << std::endl; - } - (vCell_active.at(lCellIndex_self)).dSlope_max_downslope = -1 * dSlope_upslope; - (vCell_active.at(lCellIndex_self)).dDistance_to_downslope = (vCell_active.at(lCellIndex_self)).dLength_edge_mean; - } - } - } - return error_code; - } // namespace hexwatershed - -} diff --git a/external/hexwatershed/src/compset/compset_initialize.cpp b/external/hexwatershed/src/compset/compset_initialize.cpp deleted file mode 100755 index afd10f6..0000000 --- a/external/hexwatershed/src/compset/compset_initialize.cpp +++ /dev/null @@ -1,199 +0,0 @@ -/** - * @file domain.cpp - * @author Chang Liao (chang.liao@pnnl.gov) - * @brief the realization of the domain class - * @version 0.1 - * @date 2019-08-02 - * - * @copyright Copyright (c) 2019 - * - */ -#include "./compset.h" - -namespace hexwatershed -{ - - /** - * initialize the model - * @return - */ - int compset::compset_initialize_model() - { - int error_code = 1; - - //get informaiton from the domain pass variable - long lVertexIndex = 0; - long lCellIndex=0; - long lCellIndex_outlet; - long ncell = this->aCell.size(); - - std::vector::iterator iIterator1; - std::vector::iterator iIterator2; - - vVertex_active.clear(); - vCell_active.clear(); - lVertexIndex =0; - //vCell_active.reserve(ncell); - - for (iIterator1 = aCell.begin(); iIterator1 != aCell.end(); iIterator1++) - { - hexagon pHexagon; - pHexagon.lCellIndex = lCellIndex; - pHexagon.lCellID = (*iIterator1).lCellID; - pHexagon.dElevation_mean = (*iIterator1).dElevation_mean; - pHexagon.dElevation_raw = (*iIterator1).dElevation_raw; - pHexagon.dElevation_profile0 = (*iIterator1).dElevation_profile0; - pHexagon.dLength_stream_burned = (*iIterator1).dLength_flowline; - pHexagon.dArea = (*iIterator1).dArea; - pHexagon.dAccumulation = pHexagon.dArea; - pHexagon.dLongitude_center_degree=(*iIterator1).dLongitude_center_degree; - pHexagon.dLatitude_center_degree=(*iIterator1).dLatitude_center_degree; - pHexagon.dLongitude_center_radian = convert_degree_to_radian(pHexagon.dLongitude_center_degree); - pHexagon.dLatitude_center_radian = convert_degree_to_radian(pHexagon.dLatitude_center_degree); - pHexagon.vNeighbor = (*iIterator1).aNeighbor; - pHexagon.vNeighbor_distance = (*iIterator1).aNeighbor_distance; - pHexagon.vNeighbor_land = (*iIterator1).aNeighbor_land; - //pHexagon.vNeighbor_ocean = (*iIterator1).aNeighbor_ocean; - //edge and vertex coordinates are not yet used - pHexagon.nNeighbor = (*iIterator1).nNeighbor; - pHexagon.nNeighbor_land = (*iIterator1).nNeighbor_land; - //pHexagon.nNeighbor_ocean = (*iIterator1).nNeighbor_ocean; - pHexagon.nEdge = (*iIterator1).nEdge; - pHexagon.nVertex = (*iIterator1).nVertex; - pHexagon.vVertex.clear(); - for (int i=0; i< pHexagon.nVertex; i++) - { - vertex pVertex = (*iIterator1).vVertex.at(i); - pVertex.dElevation = pHexagon.dElevation_mean; //this needs to be updated - iIterator2 = std::find(vVertex_active.begin(), vVertex_active.end(), pVertex); - if (iIterator2 != vVertex_active.end()) - { - //it is already indexed - pVertex.lVertexIndex = (*iIterator2).lVertexIndex; - } - else - { - pVertex.lVertexIndex = lVertexIndex; - lVertexIndex = lVertexIndex + 1; - vVertex_active.push_back(pVertex); - } - pHexagon.vVertex.push_back(pVertex); - - } - - pHexagon.iStream_segment_burned = (*iIterator1).iStream_segment_burned; - pHexagon.iStream_order_burned = (*iIterator1).iStream_order_burned; - pHexagon.lCellID_downstream_burned = (*iIterator1).lCellID_downstream_burned; - - if (pHexagon.iStream_segment_burned > 0) //check it starts with 1 - { - pHexagon.iFlag_stream_burned = 1; - } - - pHexagon.calculate_effective_resolution(); - //we require the - if (pHexagon.dLength_stream_burned < pHexagon.dLength_stream_conceptual) - { - pHexagon.dLength_stream_burned = pHexagon.dLength_stream_conceptual; - } - - vCell_active.push_back(pHexagon); - lCellIndex = lCellIndex +1 ; - } - - std::cout << "Finished initialization!" << std::endl; - std::flush(std::cout); - return error_code; - } - - int compset::compset_assign_stream_burning_cell() - { - int error_code = 1; - int iFlag_stream_burning_topology= cParameter.iFlag_stream_burning_topology; - int iMeshStrseg; - int iMeshStrord; - int iFlag_merged; - int iFlag_active; - long lCellID; - std::vector::iterator iIterator; - std::vector::iterator iIterator2; - - if (iFlag_stream_burning_topology == 0) - { - for (iIterator = vFlowline.begin(); iIterator != vFlowline.end(); iIterator++) - { - - lCellID = (*iIterator).lCellID; - //find in vector - //at this time, we do not yet know whether a stream is within watershed or not - //a mesh may have multiple nhd within - for (iIterator2 = vCell_active.begin(); iIterator2 != vCell_active.end(); iIterator2++) - { - if ((*iIterator2).lCellID == lCellID) - { - (*iIterator2).iFlag_stream_burned = 1; - } - } - } - } - else - { - - for (iIterator = vFlowline.begin(); iIterator != vFlowline.end(); iIterator++) - { - iFlag_active = (*iIterator).iFlag_active; - lCellID = (*iIterator).lCellID; - iMeshStrseg = (*iIterator).iStream_segment; - iMeshStrord = (*iIterator).iStream_order; - if (iFlag_active == 1) - { - //find in vector - //at this time, we do not yet know whether a stream is within watershed or not - //a mesh may have multiple nhd within - for (iIterator2 = vCell_active.begin(); iIterator2 != vCell_active.end(); iIterator2++) - { - if ((*iIterator2).lCellID == lCellID) - { - (*iIterator2).iFlag_stream_burned = 1; - //assign the stream order - if (iMeshStrord > (*iIterator2).iStream_order_burned) - { - //this code will be run at least once because default value is negative - (*iIterator2).iStream_order_burned = iMeshStrord; - //because the stream order is changed, the stream segment must be updated as well - (*iIterator2).iStream_segment_burned = iMeshStrseg; - } - else - { - /* code */ - } - } - } - } - else - { - //simplified - } - } - } - - return error_code; - } - - long compset::compset_find_index_by_cell_id(long lCellID_in) - { - long lCellIndex=-1; - - std::vector::iterator iIterator; - for (iIterator = vCell_active.begin(); iIterator != vCell_active.end(); iIterator++) - { - if ((*iIterator).lCellID == lCellID_in) - { - lCellIndex = (*iIterator).lCellIndex; - break; - } - } - - return lCellIndex; - } -} diff --git a/external/hexwatershed/src/compset/compset_run.cpp b/external/hexwatershed/src/compset/compset_run.cpp deleted file mode 100755 index dd38be2..0000000 --- a/external/hexwatershed/src/compset/compset_run.cpp +++ /dev/null @@ -1,825 +0,0 @@ -/** - * @file compset.cpp - * @author Chang Liao (chang.liao@pnnl.gov) - * @brief the realization of the compset class - * @version 0.1 - * @date 2019-08-02 - * - * @copyright Copyright (c) 2019 - * - */ -#include "./compset.h" - -namespace hexwatershed -{ - - /** - * calculate the flow accumulation based on flow direction - * @return - */ - int compset::compset_calculate_flow_accumulation() - { - int error_code = 1; - int iFlag_has_upslope = 0; - int iFlag_all_upslope_done; // assume all are done - long lFlag_total = 0; - long lCelllIndex_neighbor; - long lCellID_downslope_neighbor; - long lCellID_neighbor; - - std::vector::iterator iIterator_self; - // std::vector::iterator iIterator_neighbor; - std::vector vFlag(vCell_active.size()); - std::vector vFinished(vCell_active.size()); - std::fill(vFlag.begin(), vFlag.end(), 0); - std::fill(vFinished.begin(), vFinished.end(), 0); - - // the initial run - - lFlag_total = std::accumulate(vFlag.begin(), vFlag.end(), 0); - - while (lFlag_total != vCell_active.size()) - { - for (iIterator_self = vCell_active.begin(); iIterator_self != vCell_active.end(); iIterator_self++) - { - - if (vFlag.at((*iIterator_self).lCellIndex) == 1) - { - // this hexagon is finished - continue; - } - else - { - // check whether one or more of the neighbors flow to itself - iFlag_has_upslope = 0; - iFlag_all_upslope_done = 1; - for (int i = 0; i < (*iIterator_self).nNeighbor_land; i++) - { - lCellID_neighbor = (*iIterator_self).vNeighbor_land.at(i); - - lCelllIndex_neighbor = compset_find_index_by_cell_id(lCellID_neighbor); - - lCellID_downslope_neighbor = (vCell_active.at(lCelllIndex_neighbor)).lCellID_downslope_dominant; - - if (lCellID_downslope_neighbor == (*iIterator_self).lCellID) - { - // there is one upslope neighbor found - iFlag_has_upslope = 1; - if (vFlag.at(lCelllIndex_neighbor) == 1) - { - // std::cout << "==" << lCelllIndex_neighbor << std::endl; - } - else - { - iFlag_all_upslope_done = 0; - } - } - else - { - } - } - - // there are the ones have no upslope at all - - if (iFlag_has_upslope == 0) - { - vFlag.at((*iIterator_self).lCellIndex) = 1; - } - else - { - // these ones have upslope, - if (iFlag_all_upslope_done == 1) - { - // and they are finished scanning - for (int i = 0; i < (*iIterator_self).nNeighbor_land; i++) - { - lCellID_neighbor = (*iIterator_self).vNeighbor_land.at(i); - lCelllIndex_neighbor = compset_find_index_by_cell_id(lCellID_neighbor); - lCellID_downslope_neighbor = (vCell_active.at(lCelllIndex_neighbor)).lCellID_downslope_dominant; - - if (lCellID_downslope_neighbor == (*iIterator_self).lCellID) - { - // std::cout << "===" << lCelllIndex_neighbor << std::endl; - // std::cout << "====" << lCellID_downslope_neighbor << std::endl; - // this one accepts upslope and the upslope is done - (*iIterator_self).dAccumulation = - (*iIterator_self).dAccumulation + vCell_active.at(lCelllIndex_neighbor).dAccumulation; - } - else - { - // this neighbor does not flow here, sorry - } - } - vFlag.at((*iIterator_self).lCellIndex) = 1; - } - else - { - // we have wait temporally - } - } - } - } - lFlag_total = std::accumulate(vFlag.begin(), vFlag.end(), 0); - } - return error_code; - } - - /** - * define the stream network using flow accumulation value - * @return - */ - int compset::compset_define_stream_grid() - { - int error_code = 1; - long lCellIndex_self; - // in watershed hydrology, a threshold is usually used to define the network - // here we use similar method - float dAccumulation; - float dAccumulation_min = 0.0; - float dAccumulation_max = 0.0; - float dAccumulation_threshold; - long lCellID_outlet; - long lCellIndex_outlet; - int iFlag_global = cParameter.iFlag_global; - int iFlag_flowline = cParameter.iFlag_flowline; - int iFlag_multiple_outlet = cParameter.iFlag_multiple_outlet; - int iFlag_stream_grid_option; - std::vector::iterator iIterator_self; - iFlag_stream_grid_option = cParameter.iFlag_stream_grid_option; - if (iFlag_global != 1) - { - if (iFlag_flowline == 1) - { - if (iFlag_multiple_outlet == 0) - { - // use outlet id as largest - lCellID_outlet = aBasin.at(0).lCellID_outlet; - lCellIndex_outlet = compset_find_index_by_cell_id(lCellID_outlet); - dAccumulation_threshold = 0.05 * vCell_active.at(lCellIndex_outlet).dAccumulation; - - dAccumulation_min = vCell_active.at(lCellIndex_outlet).dAccumulation; - switch(iFlag_stream_grid_option) - { - case 1: //only burnt-in - for (lCellIndex_self = 0; lCellIndex_self < vCell_active.size(); lCellIndex_self++) - { - // should we set burnt in stream here? i think so - if ((vCell_active.at(lCellIndex_self)).iFlag_stream_burned == 1) - { - (vCell_active.at(lCellIndex_self)).iFlag_stream = 1; - (vCell_active.at(lCellIndex_self)).dLength_stream_conceptual = (vCell_active.at(lCellIndex_self)).dResolution_effective; - } - else - { - (vCell_active.at(lCellIndex_self)).iFlag_stream = 0; - // we still need its length for MOSART model. - (vCell_active.at(lCellIndex_self)).dLength_stream_conceptual = (vCell_active.at(lCellIndex_self)).dResolution_effective; - } - - } - break; - case 2: //only threshold - for (lCellIndex_self = 0; lCellIndex_self < vCell_active.size(); lCellIndex_self++) - { - if ((vCell_active.at(lCellIndex_self)).dAccumulation >= dAccumulation_threshold) - { - (vCell_active.at(lCellIndex_self)).iFlag_stream = 1; - (vCell_active.at(lCellIndex_self)).dLength_stream_conceptual = (vCell_active.at(lCellIndex_self)).dResolution_effective; - } - else - { - (vCell_active.at(lCellIndex_self)).iFlag_stream = 0; - // we still need its length for MOSART model. - (vCell_active.at(lCellIndex_self)).dLength_stream_conceptual = (vCell_active.at(lCellIndex_self)).dResolution_effective; - - } - } - break; - case 3: //combined - for (lCellIndex_self = 0; lCellIndex_self < vCell_active.size(); lCellIndex_self++) - { - - if ((vCell_active.at(lCellIndex_self)).dAccumulation >= dAccumulation_threshold) - { - (vCell_active.at(lCellIndex_self)).iFlag_stream = 1; - (vCell_active.at(lCellIndex_self)).dLength_stream_conceptual = (vCell_active.at(lCellIndex_self)).dResolution_effective; - } - else - { - // should we set burnt in stream here? i think so - if ((vCell_active.at(lCellIndex_self)).iFlag_stream_burned == 1) - { - (vCell_active.at(lCellIndex_self)).iFlag_stream = 1; - (vCell_active.at(lCellIndex_self)).dLength_stream_conceptual = (vCell_active.at(lCellIndex_self)).dResolution_effective; - } - else - { - (vCell_active.at(lCellIndex_self)).iFlag_stream = 0; - // we still need its length for MOSART model. - (vCell_active.at(lCellIndex_self)).dLength_stream_conceptual = (vCell_active.at(lCellIndex_self)).dResolution_effective; - } - } - } - break; - case 4: - for (lCellIndex_self = 0; lCellIndex_self < vCell_active.size(); lCellIndex_self++) - { - if ((vCell_active.at(lCellIndex_self)).iFlag_stream_burned == 1) - { - (vCell_active.at(lCellIndex_self)).iFlag_stream = 1; - dAccumulation= vCell_active.at(lCellIndex_self).dAccumulation; - if ( dAccumulation < dAccumulation_min) - { - dAccumulation_min = dAccumulation; - } - - } - } - //update threshold - - dAccumulation_threshold = dAccumulation_min; - for (lCellIndex_self = 0; lCellIndex_self < vCell_active.size(); lCellIndex_self++) - { - if ((vCell_active.at(lCellIndex_self)).dAccumulation >= dAccumulation_threshold) - { - (vCell_active.at(lCellIndex_self)).iFlag_stream = 1; - (vCell_active.at(lCellIndex_self)).dLength_stream_conceptual = (vCell_active.at(lCellIndex_self)).dResolution_effective; - } - else - { - (vCell_active.at(lCellIndex_self)).iFlag_stream = 0; - // we still need its length for MOSART model. - (vCell_active.at(lCellIndex_self)).dLength_stream_conceptual = (vCell_active.at(lCellIndex_self)).dResolution_effective; - } - } - break; - default: - //default it option 1 - for (lCellIndex_self = 0; lCellIndex_self < vCell_active.size(); lCellIndex_self++) - { - // should we set burnt in stream here? i think so - if ((vCell_active.at(lCellIndex_self)).iFlag_stream_burned == 1) - { - (vCell_active.at(lCellIndex_self)).iFlag_stream = 1; - (vCell_active.at(lCellIndex_self)).dLength_stream_conceptual = (vCell_active.at(lCellIndex_self)).dResolution_effective; - } - else - { - (vCell_active.at(lCellIndex_self)).iFlag_stream = 0; - // we still need its length for MOSART model. - (vCell_active.at(lCellIndex_self)).dLength_stream_conceptual = (vCell_active.at(lCellIndex_self)).dResolution_effective; - } - - } - break; - } - // openmp may not work for std container in earlier C++ - //#pragma omp parallel for private(lCellIndex_self) - - } - else // todo: multiple 'pre-defined' outlets - { - // define pre-define first - for (int iWatershed = 1; iWatershed <= cParameter.nOutlet; iWatershed++) - { - lCellID_outlet = aBasin.at(iWatershed - 1).lCellID_outlet; - lCellIndex_outlet = compset_find_index_by_cell_id(lCellID_outlet); - dAccumulation_threshold = 0.05 * vCell_active.at(lCellIndex_outlet).dAccumulation; - dAccumulation_min = vCell_active.at(lCellIndex_outlet).dAccumulation; - switch(iFlag_stream_grid_option) - { - case 1: //only burnt-in - for (lCellIndex_self = 0; lCellIndex_self < vCell_active.size(); lCellIndex_self++) - { - // should we set burnt in stream here? i think so - if ((vCell_active.at(lCellIndex_self)).iFlag_stream_burned == 1) - { - (vCell_active.at(lCellIndex_self)).iFlag_stream = 1; - (vCell_active.at(lCellIndex_self)).dLength_stream_conceptual = (vCell_active.at(lCellIndex_self)).dResolution_effective; - } - else - { - (vCell_active.at(lCellIndex_self)).iFlag_stream = 0; - // we still need its length for MOSART model. - (vCell_active.at(lCellIndex_self)).dLength_stream_conceptual = (vCell_active.at(lCellIndex_self)).dResolution_effective; - } - - } - break; - case 2: //only threshold - for (lCellIndex_self = 0; lCellIndex_self < vCell_active.size(); lCellIndex_self++) - { - if ((vCell_active.at(lCellIndex_self)).dAccumulation >= dAccumulation_threshold) - { - (vCell_active.at(lCellIndex_self)).iFlag_stream = 1; - (vCell_active.at(lCellIndex_self)).dLength_stream_conceptual = (vCell_active.at(lCellIndex_self)).dResolution_effective; - } - else - { - (vCell_active.at(lCellIndex_self)).iFlag_stream = 0; - // we still need its length for MOSART model. - (vCell_active.at(lCellIndex_self)).dLength_stream_conceptual = (vCell_active.at(lCellIndex_self)).dResolution_effective; - - } - } - break; - case 3: //combined - for (lCellIndex_self = 0; lCellIndex_self < vCell_active.size(); lCellIndex_self++) - { - - if ((vCell_active.at(lCellIndex_self)).dAccumulation >= dAccumulation_threshold) - { - (vCell_active.at(lCellIndex_self)).iFlag_stream = 1; - (vCell_active.at(lCellIndex_self)).dLength_stream_conceptual = (vCell_active.at(lCellIndex_self)).dResolution_effective; - } - else - { - // should we set burnt in stream here? i think so - if ((vCell_active.at(lCellIndex_self)).iFlag_stream_burned == 1) - { - (vCell_active.at(lCellIndex_self)).iFlag_stream = 1; - (vCell_active.at(lCellIndex_self)).dLength_stream_conceptual = (vCell_active.at(lCellIndex_self)).dResolution_effective; - } - else - { - (vCell_active.at(lCellIndex_self)).iFlag_stream = 0; - // we still need its length for MOSART model. - (vCell_active.at(lCellIndex_self)).dLength_stream_conceptual = (vCell_active.at(lCellIndex_self)).dResolution_effective; - } - } - } - break; - case 4: - for (lCellIndex_self = 0; lCellIndex_self < vCell_active.size(); lCellIndex_self++) - { - if ((vCell_active.at(lCellIndex_self)).iFlag_stream_burned == 1) - { - (vCell_active.at(lCellIndex_self)).iFlag_stream = 1; - dAccumulation= vCell_active.at(lCellIndex_self).dAccumulation; - if ( dAccumulation < dAccumulation_min) - { - dAccumulation_min = dAccumulation; - } - - } - } - //update threshold - - dAccumulation_threshold = dAccumulation_min; - for (lCellIndex_self = 0; lCellIndex_self < vCell_active.size(); lCellIndex_self++) - { - if ((vCell_active.at(lCellIndex_self)).dAccumulation >= dAccumulation_threshold) - { - (vCell_active.at(lCellIndex_self)).iFlag_stream = 1; - (vCell_active.at(lCellIndex_self)).dLength_stream_conceptual = (vCell_active.at(lCellIndex_self)).dResolution_effective; - } - else - { - (vCell_active.at(lCellIndex_self)).iFlag_stream = 0; - // we still need its length for MOSART model. - (vCell_active.at(lCellIndex_self)).dLength_stream_conceptual = (vCell_active.at(lCellIndex_self)).dResolution_effective; - } - } - break; - default: - //default it option 1 - for (lCellIndex_self = 0; lCellIndex_self < vCell_active.size(); lCellIndex_self++) - { - // should we set burnt in stream here? i think so - if ((vCell_active.at(lCellIndex_self)).iFlag_stream_burned == 1) - { - (vCell_active.at(lCellIndex_self)).iFlag_stream = 1; - (vCell_active.at(lCellIndex_self)).dLength_stream_conceptual = (vCell_active.at(lCellIndex_self)).dResolution_effective; - } - else - { - (vCell_active.at(lCellIndex_self)).iFlag_stream = 0; - // we still need its length for MOSART model. - (vCell_active.at(lCellIndex_self)).dLength_stream_conceptual = (vCell_active.at(lCellIndex_self)).dResolution_effective; - } - - } - break; - } - } - // then define normal grid as well - } - } - else - { - // find the maximum accumulation - dAccumulation_max = 0.0; - for (lCellIndex_self = 0; lCellIndex_self < vCell_active.size(); lCellIndex_self++) - { - if ((vCell_active.at(lCellIndex_self)).dAccumulation >= dAccumulation_max) - { - dAccumulation_max = (vCell_active.at(lCellIndex_self)).dAccumulation; - lCellIndex_outlet = (vCell_active.at(lCellIndex_self)).lCellIndex; - } - } - dAccumulation_threshold = 0.05 * vCell_active.at(lCellIndex_outlet).dAccumulation; - - for (lCellIndex_self = 0; lCellIndex_self < vCell_active.size(); lCellIndex_self++) - { - if ((vCell_active.at(lCellIndex_self)).dAccumulation >= dAccumulation_threshold) - { - (vCell_active.at(lCellIndex_self)).iFlag_stream = 1; - (vCell_active.at(lCellIndex_self)).dLength_stream_conceptual = (vCell_active.at(lCellIndex_self)).dResolution_effective; - } - else - { - (vCell_active.at(lCellIndex_self)).iFlag_stream = 0; - // we still need its length for MOSART model. - (vCell_active.at(lCellIndex_self)).dLength_stream_conceptual = (vCell_active.at(lCellIndex_self)).dResolution_effective; - } - } - } - } - else - { - // global scale simulation - } - - return error_code; - } - - /** - * define the watershed boundary using outlet - * @return - */ - int compset::compset_define_watershed_boundary() - { - int error_code = 1; - int iFound_outlet; - int iWatershed; - long lCellIndex_self; - long lCellIndex_current; - long lCellIndex_downslope; - long lCellIndex_outlet; - long lCellIndex_watershed; - long lCellID_downslope; - long lCellID_outlet; - - //float dDistance_to_watershed_outlet; - std::string sWatershed; - std::string sWorkspace_output_watershed; - - std::vector::iterator iterator_float; - std::vector::iterator iIterator_self; - int iFlag_global = cParameter.iFlag_global; - int iFlag_flowline = cParameter.iFlag_flowline; - int iFlag_multiple_outlet = cParameter.iFlag_multiple_outlet; - if (iFlag_global != 1) - { - if (iFlag_flowline == 1) - { - for (iWatershed = 1; iWatershed <= cParameter.nOutlet; iWatershed++) - { - lCellID_outlet = aBasin.at(iWatershed - 1).lCellID_outlet; - lCellIndex_outlet = compset_find_index_by_cell_id(lCellID_outlet); - watershed cWatershed; - sWatershed = convert_integer_to_string(iWatershed, 8); //increase to 8 to include 100 million rivers - cWatershed.sWorkspace_output_watershed = sWorkspace_output_hexwatershed + slash + sWatershed; - // make output - if (path_test(cWatershed.sWorkspace_output_watershed) == 0) - { - make_directory(cWatershed.sWorkspace_output_watershed); - } - cWatershed.sFilename_watershed_json = cWatershed.sWorkspace_output_watershed + slash + "watershed.json"; - cWatershed.sFilename_watershed_stream_edge_json = cWatershed.sWorkspace_output_watershed + slash + "stream_edge.json"; - cWatershed.sFilename_watershed_characteristics = cWatershed.sWorkspace_output_watershed + slash + "watershed.txt"; - cWatershed.sFilename_segment_characteristics = cWatershed.sWorkspace_output_watershed + slash + "segment.txt"; - cWatershed.sFilename_subbasin_characteristics = cWatershed.sWorkspace_output_watershed + slash + "subbasin.txt"; - cWatershed.vCell.clear(); - cWatershed.iWatershed = iWatershed; - cWatershed.lCellID_outlet = lCellID_outlet; - lCellIndex_watershed = 0; - // we may check the mesh id as well - vCell_active.at(lCellIndex_outlet).iFlag_outlet = 1; - for (lCellIndex_self = 0; lCellIndex_self < vCell_active.size(); lCellIndex_self++) - { - //if it is already in another watershed, skip it - if((vCell_active.at(lCellIndex_self)).iFlag_watershed==1) - { - continue; - } - //dDistance_to_watershed_outlet = (vCell_active.at(lCellIndex_self)).dDistance_to_downslope; - lCellID_downslope = (vCell_active.at(lCellIndex_self)).lCellID_downslope_dominant; - if (lCellID_downslope!=-1) - { - iFound_outlet = 0; - } - else - { - iFound_outlet =1 ; - } - lCellIndex_current = lCellIndex_self; - while (iFound_outlet != 1) - { - lCellID_downslope = (vCell_active.at(lCellIndex_current)).lCellID_downslope_dominant; - if (lCellID_outlet == lCellID_downslope) - { - iFound_outlet = 1; - (vCell_active.at(lCellIndex_self)).iFlag_watershed = 1; - //(vCell_active.at(lCellIndex_self)).dDistance_to_watershed_outlet = dDistance_to_watershed_outlet; - (vCell_active.at(lCellIndex_self)).iWatershed = iWatershed; - (vCell_active.at(lCellIndex_self)).lCellIndex_watershed = lCellIndex_watershed; - cWatershed.vCell.push_back(vCell_active.at(lCellIndex_self)); - lCellIndex_watershed = lCellIndex_watershed + 1; - } - else - { - if (lCellID_downslope != -1) - { - lCellIndex_current = compset_find_index_by_cell_id(lCellID_downslope); - if (lCellIndex_current >= 0) - { - if( vCell_active.at(lCellIndex_current).iWatershed == iWatershed ) //the downslope is already finished - { - //dDistance_to_watershed_outlet = dDistance_to_watershed_outlet + (vCell_active.at(lCellIndex_current)).dDistance_to_watershed_outlet; - (vCell_active.at(lCellIndex_self)).iFlag_watershed = 1; - //(vCell_active.at(lCellIndex_self)).dDistance_to_watershed_outlet = dDistance_to_watershed_outlet; - (vCell_active.at(lCellIndex_self)).iWatershed = iWatershed; - (vCell_active.at(lCellIndex_self)).lCellIndex_watershed = lCellIndex_watershed; - cWatershed.vCell.push_back(vCell_active.at(lCellIndex_self)); - lCellIndex_watershed = lCellIndex_watershed + 1; - iFound_outlet =1; - } - else - { - //dDistance_to_watershed_outlet = dDistance_to_watershed_outlet + (vCell_active.at(lCellIndex_current)).dDistance_to_downslope; - iFound_outlet = 0; - } - - } - else - { - iFound_outlet = 1; // a cell not going in this outlet may be going to a different one - } - - } - else - { - iFound_outlet = 1; // this cell is going out of domain and it does not belong to any user-defined watersheds. - } - } - } - } - - vCell_active.at(lCellIndex_outlet).iFlag_watershed = 1; - vCell_active.at(lCellIndex_outlet).iWatershed = iWatershed; - vCell_active.at(lCellIndex_outlet).lCellIndex_watershed = lCellIndex_watershed; - cWatershed.vCell.push_back(vCell_active.at(lCellIndex_outlet)); - vWatershed.push_back(cWatershed); - } - // how about other auto-defined watershed? - // todo - } - else - { - // without flowline - } - } - else - { - } - - return error_code; - } - - /** - * define the stream confluence point - * because we need to topology info, the vCell_active will be used - * @return - */ - int compset::compset_define_stream_confluence() - { - int error_code = 1; - int iWatershed; - int iFlag_global = cParameter.iFlag_global; - int iFlag_flowline = cParameter.iFlag_flowline; - int iFlag_multiple_outlet = cParameter.iFlag_multiple_outlet; - if (iFlag_global != 1) - { - if (iFlag_flowline == 1) - { - nSegment_total = 0; - nConfluence_total = 0; - for (iWatershed = 1; iWatershed <= cParameter.nOutlet; iWatershed++) - { - vWatershed.at(iWatershed - 1).watershed_define_stream_confluence(); - nConfluence_total = nConfluence_total + vWatershed.at(iWatershed - 1).nConfluence; - nSegment_total = nSegment_total + vWatershed.at(iWatershed - 1).nSegment; - } - } - } - else - { - } - - return error_code; - } - - /** - * define the stream segment, must use vCell_active - * @return - */ - int compset::compset_define_stream_segment() - { - int error_code = 1; - int iWatershed; - int iFlag_global = cParameter.iFlag_global; - int iFlag_flowline = cParameter.iFlag_flowline; - int iFlag_multiple_outlet = cParameter.iFlag_multiple_outlet; - if (iFlag_global != 1) - { - if (iFlag_flowline == 1) - { - for (iWatershed = 1; iWatershed <= cParameter.nOutlet; iWatershed++) - { - vWatershed.at(iWatershed - 1).watershed_define_stream_segment(); - } - } - } - - return error_code; - } - - int compset::compset_build_stream_topology() - { - int error_code = 1; - int iWatershed; - int iFlag_global = cParameter.iFlag_global; - int iFlag_flowline = cParameter.iFlag_flowline; - int iFlag_multiple_outlet = cParameter.iFlag_multiple_outlet; - if (iFlag_global != 1) - { - if (iFlag_flowline == 1) - { - for (iWatershed = 1; iWatershed <= cParameter.nOutlet; iWatershed++) - { - vWatershed.at(iWatershed - 1).watershed_build_stream_topology(); - } - } - } - return error_code; - } - int compset::compset_define_stream_order() - { - int error_code = 1; - int iWatershed; - int iFlag_global = cParameter.iFlag_global; - int iFlag_flowline = cParameter.iFlag_flowline; - int iFlag_multiple_outlet = cParameter.iFlag_multiple_outlet; - if (iFlag_global != 1) - { - if (iFlag_flowline == 1) - { - for (iWatershed = 1; iWatershed <= cParameter.nOutlet; iWatershed++) - { - vWatershed.at(iWatershed - 1).watershed_define_stream_order(); - } - } - } - return error_code; - } - /** - * define subbasin boundary, it requires cell topology, so the vCell_active is used - * @return - */ - int compset::compset_define_subbasin() - { - int error_code = 1; - int iWatershed; - - int iFlag_global = cParameter.iFlag_global; - int iFlag_flowline = cParameter.iFlag_flowline; - int iFlag_multiple_outlet = cParameter.iFlag_multiple_outlet; - if (iFlag_global != 1) - { - if (iFlag_flowline == 1) - { - for (iWatershed = 1; iWatershed <= cParameter.nOutlet; iWatershed++) - { - vWatershed.at(iWatershed - 1).watershed_define_subbasin(); - } - } - } - return error_code; - } - - /** - * @brief - * - * @return int - */ - - int compset::compset_calculate_watershed_characteristics() - { - int error_code = 1; - int iWatershed; - int iFlag_global = cParameter.iFlag_global; - int iFlag_flowline = cParameter.iFlag_flowline; - int iFlag_multiple_outlet = cParameter.iFlag_multiple_outlet; - if (iFlag_global != 1) - { - if (iFlag_flowline == 1) - { - for (iWatershed = 1; iWatershed <= cParameter.nOutlet; iWatershed++) - { - vWatershed.at(iWatershed - 1).calculate_watershed_characteristics(); - } - } - } - return error_code; - } - - int compset::compset_transfer_watershed_to_domain() - { - int error_code = 1; - int iWatershed; - int iFlag_global = cParameter.iFlag_global; - int iFlag_flowline = cParameter.iFlag_flowline; - int iFlag_multiple_outlet = cParameter.iFlag_multiple_outlet; - long lCellID1; - long lCellID2; - long lCellIndex; - std::vector::iterator iIterator1; - std::vector::iterator iIterator2; - for (iWatershed = 1; iWatershed <= cParameter.nOutlet; iWatershed++) - { - watershed cWatershed = vWatershed.at(iWatershed - 1); - for (iIterator1 = cWatershed.vCell.begin(); iIterator1 != cWatershed.vCell.end(); iIterator1++) - { - lCellID1 = (*iIterator1).lCellID; - for (iIterator2 = vCell_active.begin(); iIterator2 != vCell_active.end(); iIterator2++) - { - lCellID2 = (*iIterator2).lCellID; - if (lCellID1 == lCellID2) - { - lCellIndex = compset_find_index_by_cell_id(lCellID2); - vCell_active.at(lCellIndex).iSubbasin = (*iIterator1).iSubbasin; - vCell_active.at(lCellIndex).iSegment = (*iIterator1).iSegment; - vCell_active.at(lCellIndex).dDistance_to_subbasin_outlet = (*iIterator1).dDistance_to_subbasin_outlet; - //vCell_active.at(lCellIndex).dDistance_to_watershed_outlet = (*iIterator1).dDistance_to_watershed_outlet; - } - } - } - } - - return error_code; - } - /** - * @brief - * - * @return int - */ - int compset::compset_update_cell_elevation() - { - int error_code = 1; - std::vector::iterator iIterator1; - for (iIterator1 = vCell_active.begin(); iIterator1 != vCell_active.end(); ++iIterator1) - { - (*iIterator1).update_location(); - } - return error_code; - } - - /** - * @brief - * - * @return int - */ - int compset::compset_update_vertex_elevation() - { - int error_code = 1; - long lVertexIndex = 0; - std::vector::iterator iIterator1; - std::vector::iterator iIterator2; - std::vector::iterator iIterator3; - - for (iIterator2 = vVertex_active.begin(); iIterator2 != vVertex_active.end(); ++iIterator2) - { - - for (iIterator1 = vCell_active.begin(); iIterator1 != vCell_active.end(); ++iIterator1) - { - iIterator3 = std::find((*iIterator1).vVertex.begin(), (*iIterator1).vVertex.end(), (*iIterator2)); - - if (iIterator3 != (*iIterator1).vVertex.end()) - { - // found - (*iIterator2).dElevation = (*iIterator1).dElevation_mean; - // update location too - (*iIterator2).update_location(); - break; - } - else - { - } - } - } - - return error_code; - } - -} diff --git a/external/hexwatershed/src/compset/compset_save.cpp b/external/hexwatershed/src/compset/compset_save.cpp deleted file mode 100755 index c0ce7d3..0000000 --- a/external/hexwatershed/src/compset/compset_save.cpp +++ /dev/null @@ -1,543 +0,0 @@ -/** - * @file compset.cpp - * @author Chang Liao (chang.liao@pnnl.gov) - * @brief the realization of the compset class - * @version 0.1 - * @date 2019-08-02 - * - * @copyright Copyright (c) 2019 - * - */ -#include "./compset.h" - -namespace hexwatershed -{ - - /** - * save all the model outputs - * @return - */ - int compset::compset_save_model() - { - int error_code = 1; - int iFlag_global = cParameter.iFlag_global; - int iFlag_multiple_outlet = cParameter.iFlag_multiple_outlet; - - std::string sFilename; - if (iFlag_global != 1) - { - // now we will update some new result due to debug flag - compset_save_watershed_characteristics(); - } - else - { - } - - - - // update from watershed to main - - // main json file - sFilename = sFilename_json; - compset_save_json(sFilename); - - sFilename=sFilename_domain_json; - compset_save_domain_json(sFilename); - - sFilename = sFilename_animation_json; - compset_save_animation_json(sFilename); - sFilename = sFilename_vtk; - - compset_save_vtk(sFilename); - - ofs_log.close(); - std::cout << "Finished saving results!" << endl; - std::flush(std::cout); - - return error_code; - } - - int compset::compset_save_animation_json(std::string sFilename_in) - { - int error_code = 1; - - int iFlag_global = cParameter.iFlag_global; - int iFlag_multiple_outlet = cParameter.iFlag_multiple_outlet; - std::vector::iterator iIterator; - - jsonmodel::mesh cMesh; - - - if (iFlag_global != 1) - { - if (iFlag_multiple_outlet != 1) - { - //animation - for (iIterator = vCell_priority_flood.begin(); iIterator != vCell_priority_flood.end(); iIterator++) - { - cell pCell; - pCell.lCellID = (*iIterator).lCellID; - cMesh.aCell.push_back(pCell); - } - - cMesh.SerializeToFile(sFilename_in.c_str()); - } - } - return error_code; - } - int compset::compset_save_domain_json(std::string sFilename_in) - { - int error_code = 1; - int iWatershed; - int iFlag_global = cParameter.iFlag_global; - int iFlag_multiple_outlet = cParameter.iFlag_multiple_outlet; - std::vector::iterator iIterator; - - jsonmodel::mesh cMesh; - - if (iFlag_global != 1) - { - if (iFlag_multiple_outlet != 1) - { - for (iIterator = vCell_active.begin(); iIterator != vCell_active.end(); iIterator++) - { - - cell pCell; - pCell.dLongitude_center_degree = (*iIterator).dLongitude_center_degree; - pCell.dLatitude_center_degree = (*iIterator).dLatitude_center_degree; - pCell.dSlope_between = (*iIterator).dSlope_max_downslope; - pCell.dSlope_profile = (*iIterator).dSlope_elevation_profile0; - pCell.dDistance_to_downslope = (*iIterator).dDistance_to_downslope; - pCell.dDistance_to_subbasin_outlet = (*iIterator).dDistance_to_subbasin_outlet; - pCell.dDistance_to_watershed_outlet = (*iIterator).dDistance_to_watershed_outlet; - pCell.dElevation_mean = (*iIterator).dElevation_mean; - pCell.dElevation_raw = (*iIterator).dElevation_raw; - pCell.dElevation_profile0 = (*iIterator).dElevation_profile0; - pCell.dLength = (*iIterator).dLength_stream_conceptual; - pCell.dLength_flowline = (*iIterator).dLength_stream_burned; - pCell.dArea = (*iIterator).dArea; - pCell.lCellID = (*iIterator).lCellID; - pCell.iStream_segment = (*iIterator).iSegment; - pCell.iSubbasin = (*iIterator).iSubbasin; - pCell.iStream_segment_burned = (*iIterator).iStream_segment_burned; // flag for burned stream - - pCell.lCellID_downslope = (*iIterator).lCellID_downslope_dominant; - pCell.dAccumulation = (*iIterator).dAccumulation; - pCell.vVertex = (*iIterator).vVertex; - pCell.nVertex = pCell.vVertex.size(); - cMesh.aCell.push_back(pCell); - - } - - cMesh.SerializeToFile(sFilename_in.c_str()); - - } - } - return error_code; - } - int compset::compset_save_json(std::string sFilename_in) - { - int error_code = 1; - int iWatershed; - int iFlag_global = cParameter.iFlag_global; - int iFlag_multiple_outlet = cParameter.iFlag_multiple_outlet; - std::vector::iterator iIterator; - - jsonmodel::mesh cMesh; - - for (iWatershed = 1; iWatershed <= cParameter.nOutlet; iWatershed++) - { - vWatershed.at(iWatershed - 1).watershed_save_json(); - vWatershed.at(iWatershed - 1).watershed_save_stream_edge_json(); - } - - if (iFlag_global != 1) - { - if (iFlag_multiple_outlet != 1) - { - for (iIterator = vCell_active.begin(); iIterator != vCell_active.end(); iIterator++) - { - if ((*iIterator).iFlag_watershed == 1) - { - cell pCell; - pCell.dLongitude_center_degree = (*iIterator).dLongitude_center_degree; - pCell.dLatitude_center_degree = (*iIterator).dLatitude_center_degree; - pCell.dSlope_between = (*iIterator).dSlope_max_downslope; - pCell.dSlope_profile = (*iIterator).dSlope_elevation_profile0; - pCell.dDistance_to_downslope = (*iIterator).dDistance_to_downslope; - pCell.dDistance_to_subbasin_outlet = (*iIterator).dDistance_to_subbasin_outlet; - pCell.dDistance_to_watershed_outlet = (*iIterator).dDistance_to_watershed_outlet; - pCell.dElevation_mean = (*iIterator).dElevation_mean; - pCell.dElevation_raw = (*iIterator).dElevation_raw; - pCell.dElevation_profile0 = (*iIterator).dElevation_profile0; - pCell.dLength = (*iIterator).dLength_stream_conceptual; - pCell.dLength_flowline = (*iIterator).dLength_stream_burned; - pCell.dArea = (*iIterator).dArea; - pCell.lCellID = (*iIterator).lCellID; - pCell.iStream_segment = (*iIterator).iSegment; - pCell.iSubbasin = (*iIterator).iSubbasin; - pCell.iStream_segment_burned = (*iIterator).iStream_segment_burned; // flag for burned stream - - pCell.lCellID_downslope = (*iIterator).lCellID_downslope_dominant; - pCell.dAccumulation = (*iIterator).dAccumulation; - pCell.vVertex = (*iIterator).vVertex; - pCell.nVertex = pCell.vVertex.size(); - cMesh.aCell.push_back(pCell); - } - } - - cMesh.SerializeToFile(sFilename_in.c_str()); - - } - else - { - for (iIterator = vCell_active.begin(); iIterator != vCell_active.end(); iIterator++) - { - - cell pCell; - pCell.dLongitude_center_degree = (*iIterator).dLongitude_center_degree; - pCell.dLatitude_center_degree = (*iIterator).dLatitude_center_degree; - pCell.dSlope_between = (*iIterator).dSlope_max_downslope; - pCell.dSlope_profile = (*iIterator).dSlope_elevation_profile0; - - // pCell.dSlope_within = (*iIterator).dSlope_within; - pCell.dElevation_mean = (*iIterator).dElevation_mean; - pCell.dElevation_raw = (*iIterator).dElevation_raw; - pCell.dElevation_profile0 = (*iIterator).dElevation_profile0; - pCell.lCellID = (*iIterator).lCellID; - pCell.lCellID_downslope = (*iIterator).lCellID_downslope_dominant; - pCell.dArea = (*iIterator).dArea; - pCell.dAccumulation = (*iIterator).dAccumulation; - pCell.vVertex = (*iIterator).vVertex; - pCell.nVertex = pCell.vVertex.size(); - cMesh.aCell.push_back(pCell); - } - - cMesh.SerializeToFile(sFilename_in.c_str()); - } - } - else - { - for (iIterator = vCell_active.begin(); iIterator != vCell_active.end(); iIterator++) - { - - cell pCell; - pCell.dLongitude_center_degree = (*iIterator).dLongitude_center_degree; - pCell.dLatitude_center_degree = (*iIterator).dLatitude_center_degree; - pCell.dSlope_between = (*iIterator).dSlope_max_downslope; - - pCell.dSlope_within = (*iIterator).dSlope_within; - pCell.dElevation_raw = (*iIterator).dElevation_raw; - pCell.dElevation_mean = (*iIterator).dElevation_mean; - pCell.dElevation_profile0 = (*iIterator).dElevation_profile0; - pCell.dArea = (*iIterator).dArea; - pCell.dAccumulation = (*iIterator).dAccumulation; - pCell.lCellID = (*iIterator).lCellID; - - pCell.lCellID_downslope = (*iIterator).lCellID_downslope_dominant; - - pCell.vVertex = (*iIterator).vVertex; - pCell.nVertex = pCell.vVertex.size(); - cMesh.aCell.push_back(pCell); - } - - cMesh.SerializeToFile(sFilename_in.c_str()); - } - - return error_code; - } - /** - * save the watershed characteristics in the output - * @return - */ - int compset::compset_save_watershed_characteristics() - { - int error_code = 1; - int iWatershed; - for (iWatershed = 1; iWatershed <= cParameter.nOutlet; iWatershed++) - { - vWatershed.at(iWatershed - 1).save_watershed_characteristics(); - vWatershed.at(iWatershed - 1).save_segment_characteristics(); - vWatershed.at(iWatershed - 1).save_subbasin_characteristics(); - } - - return error_code; - } - - int compset::compset_save_vtk(std::string sFilename_in) - { - int error_code = 1; - int iVertex; - int iFlag_debug = cParameter.iFlag_debug; - long lValue; - long lCount; - long lCellID, lCellIndex; - long nVertex, nHexagon, nBoundary; - float dr, dx, dy, dz; - std::string sDummy; - std::string sLine; - std::string sPoint, sCell, sCell_size; - std::ofstream ofs_vtk; - std::vector::iterator iIterator; - std::vector::iterator iIterator2; - - float dRatio_vtk_z_exaggerate = 100.0; - - ofs_vtk.open(sFilename_in.c_str(), ios::out); - - sLine = "# vtk DataFile Version 2.0"; - ofs_vtk << sLine << std::endl; - sLine = "Flow direction unstructured grid"; - ofs_vtk << sLine << std::endl; - sLine = "ASCII"; - ofs_vtk << sLine << std::endl; - sLine = "DATASET UNSTRUCTURED_GRID"; - ofs_vtk << sLine << std::endl; - - if (iFlag_debug == 1) - { - // point - nHexagon = vCell_active.size(); - nVertex = vVertex_active.size(); - - // we consider both vertex and the center of hexagon - sPoint = convert_long_to_string(nVertex + nHexagon); - - sLine = "POINTS " + sPoint + " float"; - ofs_vtk << sLine << std::endl; - - // hexagon center first - for (iIterator = vCell_active.begin(); iIterator != vCell_active.end(); iIterator++) - { - - dx = (*iIterator).dx; - dy = (*iIterator).dy; - dz = (*iIterator).dz * dRatio_vtk_z_exaggerate; - sLine = convert_float_to_string(dx) + " " + convert_float_to_string(dy) + " " + convert_float_to_string(dz); - ofs_vtk << sLine << std::endl; - } - // then hexagon vertex - // because the vertex index start from 0, we need to add the nhexagon to have unique index - for (iIterator2 = vVertex_active.begin(); iIterator2 != vVertex_active.end(); iIterator2++) - { - dx = (*iIterator2).dx; - dy = (*iIterator2).dy; - dz = (*iIterator2).dz * dRatio_vtk_z_exaggerate; - - sLine = convert_float_to_string(dx) + " " + convert_float_to_string(dy) + " " + convert_float_to_string(dz); - ofs_vtk << sLine << std::endl; - } - - // then cell (polygon + polyline) - // we need to execlude boundary because they have no downslope for line feature - nBoundary = 0; - for (iIterator = vCell_active.begin(); iIterator != vCell_active.end(); iIterator++) - { - if ((*iIterator).lCellID_downslope_dominant == -1) - { - nBoundary = nBoundary + 1; - } - } - sCell = convert_long_to_string(nHexagon + (nHexagon - nBoundary)); - lCount = 0; - for (iIterator = vCell_active.begin(); iIterator != vCell_active.end(); iIterator++) - { - lCount = lCount + (*iIterator).nVertex + 1; - } - sCell_size = convert_long_to_string(lCount + (nHexagon - nBoundary) * 3); - - sLine = "CELLS " + sCell + " " + sCell_size; - ofs_vtk << sLine << std::endl; - // hexagon polygon - for (iIterator = vCell_active.begin(); iIterator != vCell_active.end(); iIterator++) - { - iVertex = (*iIterator).nVertex; - sLine = convert_integer_to_string(iVertex) + " "; - for (iIterator2 = (*iIterator).vVertex.begin(); iIterator2 != (*iIterator).vVertex.end(); iIterator2++) - { - sLine = sLine + convert_long_to_string((*iIterator2).lVertexIndex + nHexagon) + " "; - } - ofs_vtk << sLine << std::endl; - } - - // polyline - for (iIterator = vCell_active.begin(); iIterator != vCell_active.end(); iIterator++) - { - if ((*iIterator).lCellID_downslope_dominant != -1) - { - sLine = "2 "; - lCellID = (*iIterator).lCellID_downslope_dominant; - lCellIndex = compset_find_index_by_cell_id(lCellID); - sLine = sLine + convert_long_to_string((*iIterator).lCellIndex) + " " + convert_long_to_string(lCellIndex); - ofs_vtk << sLine << std::endl; - } - } - // cell type information - - sLine = "CELL_TYPES " + sCell; - ofs_vtk << sLine << std::endl; - for (iIterator = vCell_active.begin(); iIterator != vCell_active.end(); iIterator++) - { - sLine = "7"; - ofs_vtk << sLine << std::endl; - } - for (iIterator = vCell_active.begin(); iIterator != vCell_active.end(); iIterator++) - { - if ((*iIterator).lCellID_downslope_dominant != -1) - { - sLine = "3"; - ofs_vtk << sLine << std::endl; - } - } - // attributes - - sLine = "CELL_DATA " + sCell; // convert_long_to_string(nHexagon); //CELL_DATA - ofs_vtk << sLine << std::endl; - sLine = "SCALARS elevation float 1"; - ofs_vtk << sLine << std::endl; - sLine = "LOOKUP_TABLE default"; - - ofs_vtk << sLine << std::endl; - for (iIterator = vCell_active.begin(); iIterator != vCell_active.end(); iIterator++) - { - sLine = convert_float_to_string((*iIterator).dElevation_mean); - ofs_vtk << sLine << std::endl; - } - for (iIterator = vCell_active.begin(); iIterator != vCell_active.end(); iIterator++) - { - if ((*iIterator).lCellID_downslope_dominant != -1) - { - sLine = convert_float_to_string((*iIterator).dElevation_mean); - ofs_vtk << sLine << std::endl; - } - } - - ofs_vtk.close(); - } - else - { - nHexagon = vCell_active.size(); - nVertex = vVertex_active.size(); - - // we consider both vertex and the center of hexagon - sPoint = convert_long_to_string(nVertex + nHexagon); - - sLine = "POINTS " + sPoint + " float"; - ofs_vtk << sLine << std::endl; - - // hexagon center first - for (iIterator = vCell_active.begin(); iIterator != vCell_active.end(); iIterator++) - { - dx = (*iIterator).dx; - dy = (*iIterator).dy; - dz = (*iIterator).dz * dRatio_vtk_z_exaggerate; - sLine = convert_float_to_string(dx) + " " + convert_float_to_string(dy) + " " + convert_float_to_string(dz); - ofs_vtk << sLine << std::endl; - } - // then hexagon vertex - // because the vertex index start from 0, we need to add the nhexagon to have unique index - for (iIterator2 = vVertex_active.begin(); iIterator2 != vVertex_active.end(); iIterator2++) - { - - dx = (*iIterator2).dx; - dy = (*iIterator2).dy; - dz = (*iIterator2).dz * dRatio_vtk_z_exaggerate; - - sLine = convert_float_to_string(dx) + " " + convert_float_to_string(dy) + " " + convert_float_to_string(dz); - ofs_vtk << sLine << std::endl; - } - - // then cell (polygon + polyline) - // we need to execlude boundary because they have no downslope - nBoundary = 0; - for (iIterator = vCell_active.begin(); iIterator != vCell_active.end(); iIterator++) - { - if ((*iIterator).lCellID_downslope_dominant == -1) - { - nBoundary = nBoundary + 1; - } - } - sCell = convert_long_to_string(nHexagon + (nHexagon - nBoundary)); - - lCount = 0; - for (iIterator = vCell_active.begin(); iIterator != vCell_active.end(); iIterator++) - { - lCount = lCount + (*iIterator).nVertex + 1; - } - sCell_size = convert_long_to_string(lCount + (nHexagon - nBoundary) * 3); - - sLine = "CELLS " + sCell + " " + sCell_size; - ofs_vtk << sLine << std::endl; - // hexagon polygon - for (iIterator = vCell_active.begin(); iIterator != vCell_active.end(); iIterator++) - { - iVertex = (*iIterator).nVertex; - sLine = convert_integer_to_string(iVertex) + " "; - for (iIterator2 = (*iIterator).vVertex.begin(); iIterator2 != (*iIterator).vVertex.end(); iIterator2++) - { - sLine = sLine + convert_long_to_string((*iIterator2).lVertexIndex + nHexagon) + " "; - } - ofs_vtk << sLine << std::endl; - } - - // polyline - for (iIterator = vCell_active.begin(); iIterator != vCell_active.end(); iIterator++) - { - if ((*iIterator).lCellID_downslope_dominant != -1) - { - sLine = "2 "; - // cannot use cellindex anymore? - lCellID = (*iIterator).lCellID_downslope_dominant; - lCellIndex = compset_find_index_by_cell_id(lCellID); - sLine = sLine + convert_long_to_string((*iIterator).lCellIndex) + " " + convert_long_to_string(lCellIndex); - ofs_vtk << sLine << std::endl; - } - } - // cell type information - - sLine = "CELL_TYPES " + sCell; - ofs_vtk << sLine << std::endl; - for (iIterator = vCell_active.begin(); iIterator != vCell_active.end(); iIterator++) - { - sLine = "7"; - ofs_vtk << sLine << std::endl; - } - for (iIterator = vCell_active.begin(); iIterator != vCell_active.end(); iIterator++) - { - if ((*iIterator).lCellID_downslope_dominant != -1) - { - sLine = "3"; - ofs_vtk << sLine << std::endl; - } - } - - // attributes - - sLine = "CELL_DATA " + sCell; // convert_long_to_string(nHexagon); //CELL_DATA - ofs_vtk << sLine << std::endl; - sLine = "SCALARS elevation float 1"; - ofs_vtk << sLine << std::endl; - sLine = "LOOKUP_TABLE default"; - - ofs_vtk << sLine << std::endl; - for (iIterator = vCell_active.begin(); iIterator != vCell_active.end(); iIterator++) - { - sLine = convert_float_to_string((*iIterator).dElevation_mean); - ofs_vtk << sLine << std::endl; - } - for (iIterator = vCell_active.begin(); iIterator != vCell_active.end(); iIterator++) - { - if ((*iIterator).lCellID_downslope_dominant != -1) - { - sLine = convert_float_to_string((*iIterator).dElevation_mean); - ofs_vtk << sLine << std::endl; - } - } - - ofs_vtk.close(); - } - - return error_code; - } - -} diff --git a/external/hexwatershed/src/compset/compset_stream.cpp b/external/hexwatershed/src/compset/compset_stream.cpp deleted file mode 100755 index c15a378..0000000 --- a/external/hexwatershed/src/compset/compset_stream.cpp +++ /dev/null @@ -1,430 +0,0 @@ -/** - * @file compset.cpp - * @author Chang Liao (chang.liao@pnnl.gov) - * @brief the realization of the compset class - * @version 0.1 - * @date 2019-08-02 - * - * @copyright Copyright (c) 2019 - * - */ -#include "compset.h" - -namespace hexwatershed -{ - /** - * @brief - * - * @param lCellIndex_center - * @return int - */ - int compset::compset_stream_burning_without_topology(long lCellID_center_in) - { - int error_code = 1; - int iFlag_stream_burned; - int iFlag_stream_burned_neighbor; - int iFlag_stream_burning_treated; - int iFlag_stream_burning_treated_neighbor; - - int untreated; - long lCellID_neighbor; - long lCellID_neighbor2; - long lCellIndex_neighbor; - long lCellIndex_neighbor2; - float dBreach_threshold = cParameter.dBreach_threshold; - float dElevation_mean_center; - float dElevation_mean_neighbor; - std::vector::iterator iIterator_neighbor; - std::vector vNeighbor_land; - - long lCellIndex_center = compset_find_index_by_cell_id(lCellID_center_in); - - vCell_active.at(lCellIndex_center).iFlag_stream_burning_treated = 1; - vNeighbor_land = vCell_active.at(lCellIndex_center).vNeighbor_land; - - dElevation_mean_center = vCell_active.at(lCellIndex_center).dElevation_mean; - - // stream first - for (iIterator_neighbor = vNeighbor_land.begin(); iIterator_neighbor != vNeighbor_land.end(); iIterator_neighbor++) - { - lCellID_neighbor = (*iIterator_neighbor); - lCellIndex_neighbor = compset_find_index_by_cell_id(lCellID_neighbor); - iFlag_stream_burning_treated_neighbor = vCell_active.at(lCellIndex_neighbor).iFlag_stream_burning_treated; - iFlag_stream_burned_neighbor = vCell_active.at(lCellIndex_neighbor).iFlag_stream_burned; - - if (iFlag_stream_burned_neighbor == 1) - { - if (iFlag_stream_burning_treated_neighbor != 1) - { - dElevation_mean_neighbor = vCell_active.at(lCellIndex_neighbor).dElevation_mean; - if (dElevation_mean_neighbor < dElevation_mean_center) - { - vCell_active[lCellIndex_neighbor].dElevation_mean = dElevation_mean_center + 0.1 + abs(dElevation_mean_center) * 0.001; - } - else - { - if ((dElevation_mean_neighbor - dElevation_mean_center) > dBreach_threshold) - { - vCell_active[lCellIndex_neighbor].dElevation_mean = dElevation_mean_center + dBreach_threshold; - } - } - - vCell_active.at(lCellIndex_neighbor).iFlag_stream_burning_treated = 1; - } - } - } - - // go to the next iteration - for (iIterator_neighbor = vNeighbor_land.begin(); iIterator_neighbor != vNeighbor_land.end(); iIterator_neighbor++) - { - lCellID_neighbor = (*iIterator_neighbor); - lCellIndex_neighbor = compset_find_index_by_cell_id(lCellID_neighbor); - iFlag_stream_burned_neighbor = vCell_active.at(lCellIndex_neighbor).iFlag_stream_burned; - if (iFlag_stream_burned_neighbor == 1) - { - // recursive - untreated = 0; - for (int j = 0; j < vCell_active.at(lCellIndex_neighbor).nNeighbor_land; j++) - { - lCellID_neighbor2 = vCell_active.at(lCellIndex_neighbor).vNeighbor_land[j]; - lCellIndex_neighbor2 = compset_find_index_by_cell_id(lCellID_neighbor2); - - if (vCell_active.at(lCellIndex_neighbor2).iFlag_stream_burned == 1) - { - if (vCell_active.at(lCellIndex_neighbor2).iFlag_stream_burning_treated != 1) - { - untreated = untreated + 1; - } - } - } - if (untreated > 0) - { - compset_stream_burning_without_topology(lCellID_neighbor); - } - } - } - // land second - //it might have modified, so need update - dElevation_mean_center = vCell_active.at(lCellIndex_center).dElevation_mean; - // for (int i = 0; i < vCell_active.at (lCellIndex_center).nNeighbor_land; i++) - for (iIterator_neighbor = vNeighbor_land.begin(); iIterator_neighbor != vNeighbor_land.end(); iIterator_neighbor++) - { - lCellID_neighbor = (*iIterator_neighbor); - lCellIndex_neighbor = compset_find_index_by_cell_id(lCellID_neighbor); - iFlag_stream_burned_neighbor = vCell_active[lCellIndex_neighbor].iFlag_stream_burned; - iFlag_stream_burning_treated_neighbor = vCell_active[lCellIndex_neighbor].iFlag_stream_burning_treated; - if (iFlag_stream_burned_neighbor != 1) - { - if (iFlag_stream_burning_treated_neighbor != 1) - { - dElevation_mean_neighbor = vCell_active[lCellIndex_neighbor].dElevation_mean; - if (dElevation_mean_neighbor < dElevation_mean_center) - { - vCell_active[lCellIndex_neighbor].dElevation_mean = dElevation_mean_center + abs(dElevation_mean_center) * 0.01 + 0.01; - // we may increase the elevation again in the depression filling step - vCell_active[lCellIndex_neighbor].iFlag_stream_burning_treated = 1; - } - else - { - } - } - } - } - - return error_code; - } - - /** - * @brief - * - * @param lCellIndex_center - * @return int - */ - int compset::compset_stream_burning_with_topology(long lCellID_center_in) - { - int error_code = 1; - int iFlag_elevation_profile = cParameter.iFlag_elevation_profile; - int iOption_filling = 1; - int iFlag_finished; - - int iFlag_stream_burned; - int iFlag_stream_burned_neighbor; - - int iFlag_stream_burning_treated; - int iFlag_stream_burning_treated_neighbor; - - int iStream_order_center; - int iStream_order_neighbor; - long lIndex_outlet; - long lIndex_lowest; - long lCellIndex_active; - long lCellIndex_neighbor; - long lIndex_current; - long lIndex_center_next; - long lCellID_current; - long lCellID_downstream_burned; - - long lCellID_neighbor; - float dBreach_threshold = cParameter.dBreach_threshold; - float dElevation_mean_center; - float dElevation_mean_neighbor; - float dDifference_dummy; - float dElevation_profile0_center; - float dElevation_profile0_neighbor; - std::vector vNeighbor_land; - - std::vector::iterator iIterator_neighbor; - - long lCellIndex_center = compset_find_index_by_cell_id(lCellID_center_in); - - vCell_active.at(lCellIndex_center).iFlag_stream_burning_treated = 1; - vNeighbor_land = vCell_active.at(lCellIndex_center).vNeighbor_land; - dElevation_mean_center = vCell_active.at(lCellIndex_center).dElevation_mean; - dElevation_profile0_center = vCell_active.at(lCellIndex_center).dElevation_profile0; - - // stream elevation - iStream_order_center = vCell_active.at(lCellIndex_center).iStream_order_burned; - lCellID_current = vCell_active.at(lCellIndex_center).lCellID; - - - // stream first - - for (iIterator_neighbor = vNeighbor_land.begin(); iIterator_neighbor < vNeighbor_land.end(); iIterator_neighbor++) - { - lCellIndex_neighbor = compset_find_index_by_cell_id(*iIterator_neighbor); - lCellID_downstream_burned = vCell_active.at(lCellIndex_neighbor).lCellID_downstream_burned; - if (lCellID_downstream_burned == lCellID_current) - { - iStream_order_neighbor = vCell_active.at(lCellIndex_neighbor).iStream_order_burned; - dElevation_mean_neighbor = vCell_active.at(lCellIndex_neighbor).dElevation_mean; - - vCell_priority_flood.push_back( vCell_active.at(lCellIndex_neighbor) ); - - vCell_active.at(lCellIndex_neighbor).dElevation_downstream = dElevation_mean_center; // need update after modification - dDifference_dummy = dElevation_mean_neighbor - dElevation_mean_center; - if (dDifference_dummy >= 0) - { - - } - else - { - // this is a depression, but should we fill or breaching depends on parameter - if (abs(dDifference_dummy) < dBreach_threshold) - { - // if it is slight lower, we will increase it - if (iStream_order_neighbor == iStream_order_center) - { - vCell_active.at(lCellIndex_neighbor).dElevation_mean = dElevation_mean_center + abs(dElevation_mean_center) * 0.001 + 0.1; - } - else - { - vCell_active.at(lCellIndex_neighbor).dElevation_mean = dElevation_mean_center + abs(dElevation_mean_center) * 0.001 + 0.2; - - } - - } - else - { - // breaching needed//we will use breach algorithm - compset_breaching_stream_elevation(*iIterator_neighbor); - } - } - - // for elevation enabled case - if (iFlag_elevation_profile == 1) - { - dElevation_profile0_neighbor = vCell_active.at(lCellIndex_neighbor).dElevation_profile0; - if (dElevation_profile0_neighbor < dElevation_profile0_center) - { - vCell_active.at(lCellIndex_neighbor).dElevation_profile0 = - dElevation_profile0_center + abs(dElevation_profile0_center) * 0.001 + 1.0; - - } - } - - // update for next step - vCell_active.at(lCellIndex_neighbor).iFlag_stream_burning_treated = 1; // this should be enough - // burn recusively - lIndex_center_next = lCellIndex_neighbor; - - //std::cout << vCell_active.at(lCellIndex_neighbor).lCellID << ": " << vCell_active.at(lCellIndex_neighbor).dElevation_mean << std::endl; - // go to the new grid - if (vCell_active.at(lIndex_center_next).iFlag_headwater_burned != 1) - { - compset_stream_burning_with_topology(vCell_active.at(lCellIndex_neighbor).lCellID); - } - } - } - - //it might have modified, so need update - dElevation_mean_center = vCell_active.at(lCellIndex_center).dElevation_mean; - - // land second - for (iIterator_neighbor = vNeighbor_land.begin(); iIterator_neighbor != vNeighbor_land.end(); iIterator_neighbor++) - { - lCellID_neighbor = (*iIterator_neighbor); - lCellIndex_neighbor = compset_find_index_by_cell_id(lCellID_neighbor); - - iFlag_stream_burned_neighbor = vCell_active[lCellIndex_neighbor].iFlag_stream_burned; - iFlag_stream_burning_treated_neighbor = vCell_active[lCellIndex_neighbor].iFlag_stream_burning_treated; - - - - if (iFlag_stream_burned_neighbor != 1) - { - if (iFlag_stream_burning_treated_neighbor != 1) - { - - vCell_priority_flood.push_back( vCell_active.at(lCellIndex_neighbor) ); - - - dElevation_mean_neighbor = vCell_active[lCellIndex_neighbor].dElevation_mean; - - if (dElevation_mean_neighbor < dElevation_mean_center) - { - vCell_active.at(lCellIndex_neighbor).dElevation_mean = - dElevation_mean_center + abs(dElevation_mean_center) * 0.001 + 1.0; - - } - else - { - if ((dElevation_mean_neighbor - dElevation_mean_center) > dBreach_threshold) - { - vCell_active[lCellIndex_neighbor].dElevation_mean = dElevation_mean_center + dBreach_threshold; - - - } - } - vCell_active.at(lCellIndex_neighbor).iFlag_stream_burning_treated = 1; - - // if elevation profile is turned on - if (iFlag_elevation_profile == 1) - { - dElevation_profile0_neighbor = vCell_active[lCellIndex_neighbor].dElevation_profile0; - if (dElevation_profile0_neighbor < dElevation_profile0_center) - { - vCell_active.at(lCellIndex_neighbor).dElevation_profile0 = - dElevation_profile0_center + abs(dElevation_profile0_center) * 0.001 + 1.0; - } - } - } - } - } - - return error_code; - } - - /** - * @brief - * - * @param lCellID_active - * @return int - */ - int compset::compset_breaching_stream_elevation(long lCellID_active_in) - { - int error_code = 1; - // int iStream_order_neighbor; - // int iStream_order_center; - long lCellID; - long lCellIndex_active; - long lCellID2, lCellID3; - long lCellIndex2, lCellIndex3; - float dElevation_upstream; - float dElevation_downstream; - - long lCellID_downstream; - long lCellID_downstream2; - long lCellID_next; - - int iFlag_finished = 0; - int iFlag_found; - int iFlag_found1; - float dDifference_dummy; - float dElevation_before; - float dElevation_after; - float dElevation_dummy; - // std::vector::iterator iIterator2; - // std::vector::iterator iIterator3; - lCellIndex_active = compset_find_index_by_cell_id(lCellID_active_in); - while (iFlag_finished != 1) - { - lCellID = vCell_active.at(lCellIndex_active).lCellID; - lCellID_downstream = vCell_active.at(lCellIndex_active).lCellID_downstream_burned; - dElevation_upstream = vCell_active.at(lCellIndex_active).dElevation_mean; - // iStream_order_neighbor = vCell_active.at(lCellIndex_active).iStream_order_burned; - if (lCellID_downstream != -1) - { - iFlag_found = 0; - // for (iIterator2 = vCell_active.begin (); iIterator2 != vCell_active.end (); iIterator2++) - for (long lIndex2 = 0; lIndex2 < vCell_active.size(); lIndex2++) - { - lCellIndex2 = vCell_active.at(lIndex2).lCellIndex; - lCellID2 = vCell_active.at(lCellIndex2).lCellID; - if (lCellID2 == lCellID_downstream) - { - iFlag_found = 1; - dElevation_downstream = vCell_active.at(lCellIndex2).dElevation_mean; - // dElevation_before = dElevation_downstream; - // iStream_order_center = (*iIterator2).iStream_order_burned; - dDifference_dummy = dElevation_upstream - dElevation_downstream; - if (dDifference_dummy < 0) - { - vCell_active.at(lCellIndex2).dElevation_mean = dElevation_upstream; - vCell_active.at(lCellIndex_active).dElevation_mean = dElevation_downstream; - //std::cout << "Breached: CellID " << lCellID_active_in << "->" << lCellID_downstream - // << ", before: " - // << "upstream: " << dElevation_upstream << "downstream: " << dElevation_downstream - // << ", After: " - // << "upstream: " << vCell_active.at(lCellIndex_active).dElevation_mean << "downstream: " << vCell_active.at(lCellIndex2).dElevation_mean << std::endl; - // update - vCell_active.at(lCellIndex_active).dElevation_downstream = dElevation_upstream; - // find out the next downstream elevation - lCellID_downstream2 = vCell_active.at(lCellIndex2).lCellID_downstream_burned; - if (lCellID_downstream2 != -1) - { - iFlag_found1 = 0; - // for (iIterator3 = vCell_active.begin (); iIterator3 != vCell_active.end (); iIterator3++) - for (long lIndex3 = 0; lIndex3 < vCell_active.size(); lIndex3++) - { - lCellIndex3 = vCell_active.at(lIndex3).lCellIndex; - lCellID3 = vCell_active.at(lCellIndex3).lCellID; - if (lCellID3 == lCellID_downstream2) - { - iFlag_found1 = 1; - dDifference_dummy = vCell_active.at(lCellIndex2).dElevation_mean - vCell_active.at(lCellIndex3).dElevation_mean; - if (dDifference_dummy < 0.0) // another depression - { - lCellID_next = lCellID_downstream; - compset_breaching_stream_elevation(lCellID_next); - //} - } - iFlag_finished = 1; - break; - } - } - } - else - { - iFlag_finished = 1; - break; - } - } - else - { - // stop - iFlag_finished = 1; - } - } - } - } - else - { - iFlag_finished = 1; - break; - } - } - - return error_code; - } - -} diff --git a/external/hexwatershed/src/conversion.cpp b/external/hexwatershed/src/conversion.cpp deleted file mode 100755 index 12805b8..0000000 --- a/external/hexwatershed/src/conversion.cpp +++ /dev/null @@ -1,230 +0,0 @@ - -/** - * @file conversion.cpp - * @author Chang Liao (chang.liao@pnnl.gov) - * @brief Conversion between data types - * @version 0.1 - * @date 2019-06-11 - * - * @copyright Copyright (c) 2019 - * - */ - -#include "conversion.h" - -/** - * @brief it is used to convert integer to string - * - * @param iNumber_in : the integer number - * @return std::string - */ -std::string convert_integer_to_string(int iNumber_in) -{ - std::string str_out; - std::stringstream ss; - ss << iNumber_in; - str_out = ss.str(); - return str_out; -} - -std::string convert_long_to_string(long iNumber_in) -{ - std::string str_out; - std::stringstream ss; - ss << iNumber_in; - str_out = ss.str(); - return str_out; -} - -/** - * @brief convert an integer to a string with fixed length - * - * @param iNumber_in - * @param iWidth_in - * @return std::string - */ -std::string convert_integer_to_string(int iNumber_in, int iWidth_in) -{ - std::string str_out; - std::stringstream ss; - ss << setfill('0') << setw(iWidth_in) << iNumber_in; - str_out = ss.str(); - return str_out; -} - -/** - * @brief convert a float data type to string - * - * @param dNumber_in - * @return std::string - */ -std::string convert_double_to_string(double dNumber_in) -{ - std::string str_out; - std::stringstream ss; - ss << dNumber_in; - str_out = ss.str(); - return str_out; -} -std::string convert_float_to_string(float dNumber_in) -{ - std::string str_out; - std::stringstream ss; - ss << dNumber_in; - str_out = ss.str(); - return str_out; -} - -/** - * @brief convert a float data type to a string with fixed length - * - * @param iPrecision_in - * @param iWidth_in - * @param dNumber_in - * @return std::string - */ -std::string convert_double_to_string(int iPrecision_in, - int iWidth_in, - double dNumber_in) -{ - std::string str_out; - std::stringstream ss; - ss << std::fixed << std::setw(iWidth_in) << std::setprecision(iPrecision_in) << dNumber_in; - str_out = ss.str(); - return str_out; -} -std::string convert_float_to_string(int iPrecision_in, - int iWidth_in, - float dNumber_in) -{ - std::string str_out; - std::stringstream ss; - ss << std::fixed << std::setw(iWidth_in) << std::setprecision(iPrecision_in) << dNumber_in; - str_out = ss.str(); - return str_out; -} - -/** - * @brief convert temperature from kelvin to fahrenheit - * - * @param dTemperature_kelvin_in - * @return float - */ -float convert_from_kelvin_to_fahrenheit(float dTemperature_kelvin_in) -{ - float dTemperature_celsius = dTemperature_kelvin_in + kelvin_2_celsius; - float dTemperature_fahrenheit_out = dTemperature_celsius * 1.8 + 32.0; - return dTemperature_fahrenheit_out; -} -/** - * @brief convert temperature from fahrenheit to kelvin - * - * @param dTemperature_fahrenheit_in - * @return float - */ -float convert_from_fahrenheit_to_kelvin(float dTemperature_fahrenheit_in) -{ - float dTemperature_celsius = (dTemperature_fahrenheit_in - 32.0) / 1.8; - float dTemperature_kelvin_out = dTemperature_celsius - 273.15; - return dTemperature_kelvin_out; -} -/** - * @brief convert energy unit - * - * @param dJoule_per_meter_in - * @return float - */ -float convert_from_joule_per_meter_to_calorie_per_centimeter(float dJoule_per_meter_in) -{ - float dCalorie_per_meter = dJoule_per_meter_in * joule_2_calorie; - float dCalorie_per_centimeter_out = dCalorie_per_meter / 10000.0; - return dCalorie_per_centimeter_out; -} -/** - * @brief conver energy units - * - * @param dCalorie_per_centimeter_in - * @return float - */ -float convert_from_calorie_per_centimeter_to_joule_per_meter(float dCalorie_per_centimeter_in) -{ - float dCalorie_per_meter = dCalorie_per_centimeter_in * 10000; - float dJoule_per_meter_out = dCalorie_per_meter * calorie_2_joule; - return dJoule_per_meter_out; -} - -float convert_degree_to_radian(float dAngle_degree) -{ - float dAngle_radian = dAngle_degree / 180.0 * pi; - return dAngle_radian; -} - -/** - * @brief split a string using space - * - * @param sString_in - * @return std::vector - */ -std::vector split_string_by_space(std::string sString_in) -{ - std::size_t lLength = sString_in.length(); - if (lLength > 0) - { - std::istringstream iss(sString_in); - std::istream_iterator iterator_begin(iss), iterator_end; - std::vector vTokens_out(iterator_begin, iterator_end); // done! - return vTokens_out; - } - else - { - std::vector nothing; - return nothing; - } -} - - - -/** - * @brief split a string using user provide delimiter - * - * @param sString_in - * @param cDelimiter - * @return std::vector - */ -std::vector split_string_by_delimiter(std::string sString_in, - char cDelimiter) -{ - std::size_t lLength = sString_in.length(); - std::vector vTokens_out; - if (lLength > 0) - { - std::stringstream ss; - ss.str(sString_in); - std::string dummy; - while (std::getline(ss, dummy, cDelimiter)) - { - vTokens_out.push_back(dummy); - } - } - else - { - } - return vTokens_out; -} - -std::string ltrim(const std::string& s) -{ - size_t start = s.find_first_not_of(WHITESPACE); - return (start == std::string::npos) ? "" : s.substr(start); -} - -std::string rtrim(const std::string& s) -{ - size_t end = s.find_last_not_of(WHITESPACE); - return (end == std::string::npos) ? "" : s.substr(0, end + 1); -} - -std::string trim(const std::string& s) -{ - return rtrim(ltrim(s)); -} diff --git a/external/hexwatershed/src/conversion.h b/external/hexwatershed/src/conversion.h deleted file mode 100755 index b6d8560..0000000 --- a/external/hexwatershed/src/conversion.h +++ /dev/null @@ -1,67 +0,0 @@ -/** - * @file conversion.h - * @author Chang Liao (chang.liao@pnnl.gov) - * @brief The header file of the conversion source file - * @version 0.1 - * @date 2019-08-02 - * @citation Liao, C., Tesfa, T., Duan, Z., & Leung, L. R. (2020). - * Watershed delineation on a hexagonal mesh grid. Environmental Modelling & Software, 104702. - * https://www.sciencedirect.com/science/article/pii/S1364815219308278 - * @github page https://github.com/changliao1025/hexwatershed - * @copyright Copyright (c) 2019 - * - */ - - -#pragma once -//50================================================== -//c++ library -//50================================================== -#include -#include -#include -#include -#include -#include - -//50================================================== -//local header -//50================================================== -#include "global.h" -using namespace std; -//50================================================== - -const std::string WHITESPACE = " \n\r\t\f\v"; - -//50================================================== -//unit conversion -//50================================================== -float convert_from_kelvin_to_fahrenheit(float dTemperature_kelvin_in); -float convert_from_fahrenheit_to_kelvin(float dTemperature_fahrenheit_in); -float convert_from_joule_per_meter_to_calorie_per_centimeter(float dJoule_per_meter_in); -float convert_from_calorie_per_centimeter_to_joule_per_meter(float dCalorie_per_centimeter_in); - -std::string convert_integer_to_string(int iNumber_in); -std::string convert_long_to_string(long iNumber_in); -std::string convert_integer_to_string(int iNumber_in, - int iWidth_in); -std::string convert_double_to_string(double dNumber_in); -std::string convert_double_to_string(int iPrecision_in, - int iWidth_in, - double dNumber_in); - -std::string convert_float_to_string(float dNumber_in); -std::string convert_float_to_string(int iPrecision_in, - int iWidth_in, - float dNumber_in); - -float convert_degree_to_radian( float dAngle_degree); - -std::vector split_string_by_space(std::string sString_in); -std::vector split_string_by_delimiter(std::string sString_in, char cDelimiter_in); - -//string trim -std::string ltrim(const std::string& s); -std::string rtrim(const std::string& s); -std::string trim(const std::string& s); - diff --git a/external/hexwatershed/src/data.cpp b/external/hexwatershed/src/data.cpp deleted file mode 100755 index ba029e6..0000000 --- a/external/hexwatershed/src/data.cpp +++ /dev/null @@ -1,224 +0,0 @@ -/** - * @file data.cpp - * @author Chang Liao (chang.liao@pnnl.gov) - * @brief Deal with data read and write operations. - * @version 0.1 - * @date 2017-01-25 - * - * @copyright Copyright (c) 2019 - * - */ -#include "data.h" -data::data() -{ - -} -data::~data() -{ -} - - -/** - * @brief read_eco3d binary file (float type) - * - * @param sFilename_in - * @return float* - */ -float * data::read_binary(std::string sFilename_in) -{ - float * pData_out = nullptr; - long lLength1, lLength2; - float dummy; - std::ifstream ifs; - if (file_test(sFilename_in) == 1) - { - - ifs.open(sFilename_in.c_str(), ios::in | ios::binary); - if (ifs.good()) - { - ifs.seekg(0, ios::end); - lLength1 = long(ifs.tellg()); - ifs.seekg(0, ios::beg); - lLength2 = lLength1 / sizeof(float); - pData_out = new float[lLength2]; - for (long i = 0; i < lLength2; i++) - { - ifs.read(reinterpret_cast(&dummy), sizeof dummy); - pData_out[i] = dummy; - } - } - else - { - //std::cout << sError_open_failed << sFilename_in << std::endl; - } - - - ifs.close(); - } - else - { - //file missing - //std::cout << sError_file_missing << sFilename_in << std::endl; - } - - - return pData_out; -} - - -/** - * @brief read_eco3d binary into a two dimension array pointer - * - * @param sFilename_in - * @param lColumn_in - * @param lRow_in - * @return float** - */ -float ** data::read_binary(string sFilename_in, - long lColumn_in, - long lRow_in -) -{ - float dummy; - float * pdata_dummy = nullptr; - float ** pData_out = nullptr; - std::ifstream ifs; - if (file_test(sFilename_in) == 1) - { - ifs.open(sFilename_in.c_str(), ios::in | ios::binary); - if (ifs.good()) - { - pdata_dummy = new float[lColumn_in*lRow_in]; - for (long i = 0; i < lColumn_in*lRow_in; i++) - { - ifs.read(reinterpret_cast(&dummy), sizeof dummy); - pdata_dummy[i] = dummy; - } - pData_out = new float *[lRow_in]; - for (long i = 0; i < lRow_in; i++) - { - pData_out[i] = pdata_dummy + lColumn_in * i; - } - - } - else - { - //std::cout << sError_open_failed << sFilename_in << std::endl; - } - ifs.close(); - - } - else - { - //file missing - std::cout << sError_file_missing << sFilename_in << std::endl; - } -//delete[] pdata_dummy; - return pData_out; -} - - -/** - * @brief read_eco3d binary and save to a vector - * - * @param sFilename_in - * @return vector - */ -vector data::read_binary_vector(std::string sFilename_in) -{ - long lLength1, lLength2; - float dummy; - std::ifstream ifs; - std::vector vData_out; - vData_out.clear(); - if (file_test(sFilename_in) == 1) - { - ifs.open(sFilename_in.c_str(), ios::in | ios::binary); - if (ifs.good()) - { - ifs.seekg(0, ios::end); - lLength1 = long(ifs.tellg()); - ifs.seekg(0, ios::beg); - lLength2 = lLength1 / sizeof(float); - - for (long i = 0; i < lLength2; ++i) - { - ifs.read(reinterpret_cast(&dummy), sizeof dummy); - vData_out.push_back(dummy); - } - } - else - { - std::cout << sError_open_failed << sFilename_in << std::endl; - } - ifs.close(); - } - else - { - //file missing - std::cout << sError_file_missing << sFilename_in << std::endl; - } - return vData_out; -} - - - -/** - * @brief write vector to float binary file - - * - * @param sFilename_out - * @param vData_in - * @return int - */ -int data::write_binary_vector(std::string sFilename_out, std::vector vData_in) -{ - int error_code = 1; - float dDummy0, dDummy1; - //50================================================== - //covert from float to float first - //50================================================== - //the old approach will cause loss data warning - //std::vector vData_float(vData_in.begin(), vData_in.end()); - //the new approach - //in the next developement, I will use template instead of explict conversion - std::vector vData_float; - std::vector::iterator iIterator_double; - std::vector::iterator iIterator_float; - std::ofstream ofs; - for (iIterator_double = vData_in.begin(); iIterator_double != vData_in.end(); iIterator_double++) - { - dDummy0 = float(*iIterator_double); - vData_float.push_back(dDummy0); - } - //50================================================== - //check the data quality - //if all data are missing values, then we don't need it - //50================================================== - iIterator_float = std::max_element(vData_float.begin(), - vData_float.end()); - - dDummy1 = *iIterator_float; - if (dDummy1 == -9999.00) //we define -9999 as the missing value - { - std::cout << sLog_data_quality << std::endl; - error_code = 0; - } - else - { - - ofs.open(sFilename_out.c_str(), ios::out | ios::binary); - if (ofs.good()) - { - ofs.write(reinterpret_cast(&vData_float[0]), vData_float.size() * sizeof(float)); - error_code = 1; - } - else - { - std::cout << sError_open_failed << sFilename_out << std::endl; - error_code = 0; - } - ofs.close(); - } - return error_code; -} diff --git a/external/hexwatershed/src/data.h b/external/hexwatershed/src/data.h deleted file mode 100755 index 817df53..0000000 --- a/external/hexwatershed/src/data.h +++ /dev/null @@ -1,52 +0,0 @@ - -/** - * @file data.h - * @author Chang Liao (chang.liao@pnnl.gov) - * @brief The header of data I/O component source code. - * @version 0.1 - * @date 2017-01-25 - * @citation Liao, C., Tesfa, T., Duan, Z., & Leung, L. R. (2020). - * Watershed delineation on a hexagonal mesh grid. Environmental Modelling & Software, 104702. - * https://www.sciencedirect.com/science/article/pii/S1364815219308278 - * @github page https://github.com/changliao1025/hexwatershed - * @copyright Copyright (c) 2019 - * - */ -#pragma once - -//50================================================== -//C header -//50================================================== -//C++ header -#include -#include //the small sized array -#include //file stream -#include //for vector and stream -#include //c++ string -#include //vector -#include "system.h" -//50================================================== -using namespace std; -//50================================================== -class data -{ - public: - data(); - ~data(); - //50================================================== - //Traditional data IO - //50================================================== - static float * read_binary(std::string sFilename_in); - static float ** read_binary(std::string sFilename_in, - long lColumn_in, - long lRow_in); - static std::vector read_binary_vector(std::string sFilename_in); - static int write_binary_vector(std::string sFilename_in, - vector vData_in); - //50================================================== - //advanced data io using MPI - //dataIO using PETSc - //50================================================== - //Mat Read_Binary(string filErtame,int m,int n); - //50================================================== -}; diff --git a/external/hexwatershed/src/domain/domain.cpp b/external/hexwatershed/src/domain/domain.cpp deleted file mode 100755 index 6608cc4..0000000 --- a/external/hexwatershed/src/domain/domain.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/** - * @file domain.cpp - * @author Chang Liao (chang.liao@pnnl.gov) - * @brief the realization of the domain class - * @version 0.1 - * @date 2019-08-02 - * - * @copyright Copyright (c) 2019 - * - */ -#include "domain.h" - -namespace hexwatershed -{ - - domain::domain(){ - - }; - - domain::~domain(){}; - - /** - * - * @param sFilename_configuration_in: user provided model configuration file - * please refer to the user guide for I/O instruction - */ - domain::domain(std::string sFilename_configuration_in) - { - - // check the length of the configuration file - std::size_t iLength = sFilename_configuration_in.length(); - if (iLength < 5) - { - cCompset.cParameter.iFlag_configuration_file = 0; - } - else - { - std::cout << "The configuration file is:" << sFilename_configuration_in - << std::endl; - // check the existence of the configuration file - if (1 != file_test(sFilename_configuration_in)) // the file does not even exist - { - cCompset.cParameter.iFlag_configuration_file = 0; - } - else - { - cCompset.cParameter.sFilename_configuration = sFilename_configuration_in; - cCompset.cParameter.iFlag_configuration_file = 1; - } - } - - time_t now = time(0); - tm *ltm = localtime(&now); - - - - - int iYear = 1900 + ltm->tm_year; - int iMonth = 1 + ltm->tm_mon; - int iDay = ltm->tm_mday; - sDate_default = convert_integer_to_string(iYear, 4) + convert_integer_to_string(iMonth, 2) + convert_integer_to_string(iDay, 2); - sDate = "20200101"; - - std::cout << "Finished set up model" << std::endl; - std::flush(std::cout); - } - - int domain::domain_setup() - { - int error_code=1; - - cCompset.compset_setup_model(); - return error_code; - } - - int domain::domain_initialize () - { - int error_code=1; - - cCompset.compset_initialize_model(); - //the last outlet need to be set - - return error_code; - } - - /** - * run the model - * @return - */ - int domain::domain_run() - { - int error_code = 1; - error_code = cCompset.compset_run_model(); - - return error_code; - } - - int domain::domain_save () - { - int error_code=1; - cCompset.compset_save_model(); - return error_code; - } - - - /** - * clean up the model status - * @return - */ - int domain::domain_cleanup() - { - int error_code = 1; - cCompset.compset_cleanup_model (); - std::cout << "Finished clean up memory!" << endl; - - return error_code; - } - -} // namespace hexwatershed diff --git a/external/hexwatershed/src/domain/domain.h b/external/hexwatershed/src/domain/domain.h deleted file mode 100755 index b2ed154..0000000 --- a/external/hexwatershed/src/domain/domain.h +++ /dev/null @@ -1,146 +0,0 @@ -/** - * @file domain.h - * @author Chang Liao (chang.liao@pnnl.gov) - * @brief Header file of the domain class - * @version 0.1 - * @date 2019-08-02 - * @citation Liao, C., Tesfa, T., Duan, Z., & Leung, L. R. (2020). - * Watershed delineation on a hexagonal mesh grid. Environmental Modelling & Software, 104702. - * https://www.sciencedirect.com/science/article/pii/S1364815219308278 - * @github page https://github.com/changliao1025/hexwatershed - * @copyright Copyright (c) 2019 - * - */ - - #pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../compset/compset.h" - - -#include "../../rapidjson/document.h" -#include "../../rapidjson/writer.h" -#include "../../rapidjson/stringbuffer.h" -#include "../../rapidjson/istreamwrapper.h" - -#include "../json/JSONBase.h" -#include "../json/mesh.h" -#include "../json/cell.h" -#include "../json/basin.h" -#include "../json/multibasin.h" - - -using namespace std; -using namespace rapidjson; -using namespace jsonmodel; - - -namespace hexwatershed -{ - class domain { - public: - domain (); - domain (std::string sFilename_configuration_in); - ~domain (); - - std::string sWorkspace_input; - std::string sWorkspace_output; - std::string sWorkspace_output_pyflowline; - std::string sWorkspace_output_hexwatershed; - - std::string sFilename_log; - std::string sLog; - - std::string sFilename_mesh_info; - std::string sFilename_flowline_info; - //polygon vector filename - std::string sFilename_elevation_polygon; - std::string sFilename_elevation_polygon_debug; - - std::string sFilename_slope_between_polygon; - std::string sFilename_slope_between_polygon_debug; - std::string sFilename_slope_within_polygon; - std::string sFilename_slope_within_polygon_debug; - - std::string sFilename_flow_accumulation_polygon; - std::string sFilename_flow_accumulation_polygon_debug; - - std::string sFilename_watershed_polygon; - std::string sFilename_stream_confluence_polygon; - - std::string sFilename_stream_grid_polygon; - std::string sFilename_stream_grid_polygon_debug; - - std::string sFilename_subbasin_polygon; - - std::string sFilename_stream_segment_polygon; - - std::string sFilename_wetness_index_polygon; - - //polyline - std::string sFilename_stream_segment_polyline; - std::string sFilename_stream_segment_merge_polyline; - std::string sFilename_flow_direction_polyline; - std::string sFilename_flow_direction_polyline_debug; - std::string sFilename_stream_order_polyline; - - std::string sFilename_basins; - - //vtk support - std::string sFilename_vtk; - std::string sFilename_vtk_debug; - - - - //others - std::string sDate_default; - std::string sDate; - - std::string sFilename_mesh; - - std::string sExtension_json; - - std::ofstream ofs_log; // used for IO starlog file - - //std::map mParameter; //for input data and parameters - - //rapidjson object - jsonmodel::mesh cMesh; - jsonmodel::multibasin cBasin; - - rapidjson::Document pConfigDoc; - rapidjson::Document pConfigDoc_basin; - - //for global - std::vector lCellIndex_outlet; - std::vector lCellID_outlet; - - compset cCompset; //currently we only support one compset per run - //function - int domain_read (); - int domain_read_configuration_file (); - int domain_read_elevation_json(std::string sFilename_elevation_in); - int domain_read_basin_json(std::string sFilename_basin_in); - - int domain_assign_parameter (); - int domain_read_input_data(); - int domain_initialize (); - int domain_retrieve_user_input(); - int domain_run (); - int domain_save (); - int domain_cleanup (); - int domain_setup(); - - - }; -} // namespace hexwatershed diff --git a/external/hexwatershed/src/domain/domain_read.cpp b/external/hexwatershed/src/domain/domain_read.cpp deleted file mode 100755 index a576461..0000000 --- a/external/hexwatershed/src/domain/domain_read.cpp +++ /dev/null @@ -1,381 +0,0 @@ -/** - * @file domain.cpp - * @author Chang Liao (chang.liao@pnnl.gov) - * @brief the realization of the domain class - * @version 0.1 - * @date 2019-08-02 - * - * @copyright Copyright (c) 2019 - * - */ -#include "domain.h" - -namespace hexwatershed -{ - - /** - * read data from the model configuration file - * @return - */ - int domain::domain_read() - { - int error_code = 1; - domain_read_configuration_file(); - domain_retrieve_user_input(); - domain_read_input_data(); - - cCompset.sFilename_mesh_info = this->sFilename_mesh_info; - cCompset.compset_read_model(); - - std::cout << "Finished reading data!" << std::endl; - std::flush(std::cout); - return error_code; - } - - /** - * read the user provided configuration file - * @return - */ - int domain::domain_read_configuration_file() - { - int error_code = 1; - std::size_t iVector_size; - std::string sLine; // used to store each sLine - std::string sKey; // used to store the sKey - std::string sValue; // used to store the sValue - - std::vector vTokens; - - std::string sFilename_configuration = cCompset.cParameter.sFilename_configuration; - // 50================================================== - // the existence of the configuration file is checked already - // 50================================================== - - std::ifstream ifs(sFilename_configuration.c_str()); - if (!ifs.is_open()) - { - std::cerr << "Could not open file for reading!\n"; - return error_code; - } - - IStreamWrapper isw(ifs); - pConfigDoc.ParseStream(isw); - - return error_code; - } - - /** - * extract the dictionary from user provided configuration file - * @return - */ - int domain::domain_retrieve_user_input() - { - int error_code = 1; - int iMesh_type; - std::string sMesh_type; - std::string sKey = "sMesh_type"; - std::string sWorkspace_output_hexwatershed; - if (pConfigDoc.HasMember(sKey.c_str())) - { - sMesh_type = pConfigDoc[sKey.c_str()].GetString(); - } - if (sMesh_type == "hexagon") - { - iMesh_type = 1; - } - else - { - if (sMesh_type == "square") - { - iMesh_type = 2; - } - else - { - if (sMesh_type == "latlon") - { - iMesh_type = 3; - } - else - { - if (sMesh_type == "mpas") - { - iMesh_type = 4; - } - else - { - if (sMesh_type == "tin") - { - iMesh_type = 5; - } - else - { - std::cout << "Unsupported mesh type" << std::endl; - } - } - } - } - } - - cCompset.cParameter.sMesh_type = sMesh_type; - cCompset.cParameter.iMesh_type = iMesh_type; - - sKey = "iFlag_resample_method"; - - if (pConfigDoc.HasMember(sKey.c_str())) - { - cCompset.cParameter.iFlag_resample_method = pConfigDoc[sKey.c_str()].GetInt(); - } - - sKey = "iFlag_global"; - if (pConfigDoc.HasMember(sKey.c_str())) - { - cCompset.cParameter.iFlag_global = pConfigDoc[sKey.c_str()].GetInt(); - } - - sKey = "iFlag_elevation_profile"; - if (pConfigDoc.HasMember(sKey.c_str())) - { - cCompset.cParameter.iFlag_elevation_profile = pConfigDoc[sKey.c_str()].GetInt(); - } - - sKey = "iFlag_multiple_outlet"; - if (pConfigDoc.HasMember(sKey.c_str())) - { - cCompset.cParameter.iFlag_multiple_outlet = pConfigDoc[sKey.c_str()].GetInt(); - } - - sKey = "iFlag_flowline"; - if (pConfigDoc.HasMember(sKey.c_str())) - { - cCompset.cParameter.iFlag_flowline = pConfigDoc[sKey.c_str()].GetInt(); - } - - sKey = "iFlag_stream_grid_option"; - if (pConfigDoc.HasMember(sKey.c_str())) - { - cCompset.cParameter.iFlag_stream_grid_option = pConfigDoc[sKey.c_str()].GetInt(); - } - - if (cCompset.cParameter.iFlag_flowline == 1) - { - sKey = "nOutlet"; - if (pConfigDoc.HasMember(sKey.c_str())) - { - cCompset.cParameter.nOutlet = pConfigDoc[sKey.c_str()].GetInt(); - } - - sKey = "iFlag_stream_burning_topology"; - if (pConfigDoc.HasMember(sKey.c_str())) - { - cCompset.cParameter.iFlag_stream_burning_topology = pConfigDoc[sKey.c_str()].GetInt(); - } - - sKey = "dBreach_threshold"; - if (pConfigDoc.HasMember(sKey.c_str())) - { - cCompset.cParameter.dBreach_threshold = pConfigDoc[sKey.c_str()].GetFloat(); - } - - sKey = "sFilename_basins"; - - if (pConfigDoc.HasMember(sKey.c_str())) - { - sFilename_basins = pConfigDoc[sKey.c_str()].GetString(); - // read basin info - domain_read_basin_json(sFilename_basins); - - for (std::list::iterator it = cBasin.aBasin.begin(); it != cBasin.aBasin.end(); ++it) - { - cCompset.aBasin.push_back((*it)); - } - } - } - - sKey = "dAccumulation_threshold"; - if (pConfigDoc.HasMember(sKey.c_str())) - { - cCompset.cParameter.dAccumulation_threshold = pConfigDoc[sKey.c_str()].GetFloat(); - } - - sKey = "dMissing_value_dem"; - if (pConfigDoc.HasMember(sKey.c_str())) - { - cCompset.cParameter.dMissing_value_dem = pConfigDoc[sKey.c_str()].GetFloat(); - } - - sKey = "iCase_index"; - if (pConfigDoc.HasMember(sKey.c_str())) - { - cCompset.cParameter.iCase_index = pConfigDoc[sKey.c_str()].GetInt(); - } - - cCompset.cParameter.sMissing_value_default = trim(convert_float_to_string(dMissing_value_default)); - - sKey = "sDate"; - if (pConfigDoc.HasMember(sKey.c_str())) - { - sDate = pConfigDoc[sKey.c_str()].GetString(); - } - else - { - sDate = sDate_default; - } - - sKey = "sWorkspace_input"; - if (pConfigDoc.HasMember(sKey.c_str())) - { - sWorkspace_input = pConfigDoc[sKey.c_str()].GetString(); - } - - sKey = "sWorkspace_output"; - - if (pConfigDoc.HasMember(sKey.c_str())) - { - sWorkspace_output = pConfigDoc[sKey.c_str()].GetString(); - } - - sKey = "sWorkspace_output_hexwatershed"; - - if (pConfigDoc.HasMember(sKey.c_str())) - { - sWorkspace_output_hexwatershed = pConfigDoc[sKey.c_str()].GetString(); - } - - // output================================= - - if (sWorkspace_output.length() > 3) - { - // this will be the output workspace - if (path_test(sWorkspace_output) == 0) - { - make_directory(sWorkspace_output); - } - sWorkspace_output_pyflowline = sWorkspace_output + slash + "pyflowline"; - } - else - { - if (path_test(sWorkspace_output_hexwatershed) == 0) - { - make_directory(sWorkspace_output_hexwatershed); - } - sWorkspace_output_pyflowline = sWorkspace_output + slash + "pyflowline"; - } - - sFilename_mesh_info = sWorkspace_output_pyflowline + slash + sMesh_type + "_mesh_info.json"; - - cCompset.sWorkspace_output_hexwatershed = sWorkspace_output_hexwatershed; - - // vtk - cCompset.sFilename_vtk = sWorkspace_output_hexwatershed + slash + "hexwatershed.vtk"; - - // json - - cCompset.sFilename_json = sWorkspace_output_hexwatershed + slash + "hexwatershed.json"; - // others - cCompset.sFilename_domain_json= sWorkspace_output_hexwatershed + slash + "domain.json"; - - cCompset.sFilename_animation_json = sWorkspace_output_hexwatershed + slash + "animation.json"; - - sFilename_log = sWorkspace_output_hexwatershed + slash + "starlog" + sExtension_text; - ofs_log.open(sFilename_log.c_str(), ios::out); - - sLog = "=Level 1: Simulation log will be save to log file: " + - sFilename_log; - ofs_log << sLog << std::endl; - - // copy the configuration file to the output workspace - std::ifstream src(cCompset.cParameter.sFilename_configuration.c_str(), std::ios::binary); - std::string sFilename_dummy = sWorkspace_output_hexwatershed + slash + "configuration.in"; - std::ofstream dst(sFilename_dummy.c_str(), std::ios::binary); - dst << src.rdbuf(); - - return error_code; - } - - /** - * @brief read input data - * - * @return int - */ - int domain::domain_read_input_data() - { - int error_code = 1; - int iMesh_type = cCompset.cParameter.iMesh_type; - int iFlag_flowline = cCompset.cParameter.iFlag_flowline; - int iFlag_stream_burning_topology = cCompset.cParameter.iFlag_stream_burning_topology; - std::vector::iterator iIterator; - switch (iMesh_type) - { - case 1: // hexagon - { - domain_read_elevation_json(sFilename_mesh_info); - for (std::list::iterator it = cMesh.aCell.begin(); it != cMesh.aCell.end(); ++it) - { - cCompset.aCell.push_back((*it)); - } - } - break; - case 2: - { - domain_read_elevation_json(sFilename_mesh_info); - for (std::list::iterator it = cMesh.aCell.begin(); it != cMesh.aCell.end(); ++it) - { - cCompset.aCell.push_back((*it)); - } - } - break; - case 3: - { - domain_read_elevation_json(sFilename_mesh_info); - for (std::list::iterator it = cMesh.aCell.begin(); it != cMesh.aCell.end(); ++it) - { - cCompset.aCell.push_back((*it)); - } - } - break; - case 4: // mpas - { - domain_read_elevation_json(sFilename_mesh_info); - for (std::list::iterator it = cMesh.aCell.begin(); it != cMesh.aCell.end(); ++it) - { - cCompset.aCell.push_back((*it)); - } - } - break; - case 5: - { - domain_read_elevation_json(sFilename_mesh_info); - for (std::list::iterator it = cMesh.aCell.begin(); it != cMesh.aCell.end(); ++it) - { - cCompset.aCell.push_back((*it)); - } - } - break; - default: - { - domain_read_elevation_json(sFilename_mesh_info); - for (std::list::iterator it = cMesh.aCell.begin(); it != cMesh.aCell.end(); ++it) - { - cCompset.aCell.push_back((*it)); - } - } - break; - } - - return error_code; - } - - int domain::domain_read_elevation_json(std::string sFilename_elevation_in) - { - int error_code = 1; - cMesh.DeserializeFromFile(sFilename_elevation_in.c_str()); - return error_code; - } - int domain::domain_read_basin_json(std::string sFilename_basin_in) - { - int error_code = 1; - cBasin.DeserializeFromFile(sFilename_basin_in.c_str()); - return error_code; - } - -} diff --git a/external/hexwatershed/src/edge.cpp b/external/hexwatershed/src/edge.cpp deleted file mode 100755 index a4aa9c8..0000000 --- a/external/hexwatershed/src/edge.cpp +++ /dev/null @@ -1,148 +0,0 @@ - -/** - * @file edge.cpp - * @author Chang Liao (chang.liao@pnnl.gov) - * @brief - * @version 0.1 - * @date 2019-06-11 Created by Chang Liao on 4/26/18. - * - * @copyright Copyright (c) 2019 - * - */ - -#include "edge.h" - -namespace hexwatershed -{ - - edge::edge() - { - } - - edge::~edge() - { - } - - - /** - * @brief calculate the arc length of an edge on a sphere - * - * @return int - */ - int edge::calculate_length() - { - int error_code = 1; - dLength = cVertex_end.calculate_distance(cVertex_start); - if (dLength < 0.001) - { - //something is wrong - } - return error_code; - } - - /** - * @brief check whether a vertex is one the edge or not - * - * @param pVertex_in - * @return int - */ - - int edge::check_point_overlap(vertex pVertex_in) - { - int overlap = 0; - float diff; - float dDistance1, dDistance2; - dDistance1 = pVertex_in.calculate_distance(this->cVertex_start); - dDistance2 = pVertex_in.calculate_distance(this->cVertex_end); - diff = this->dLength - (dDistance1 + dDistance2); - if (abs(diff) < 0.01) - { - overlap = 1; - } - return overlap; - } - - /** - * @brief check whether an edge overlap with another edge, this algorithm has error - * - * @param pVertex_start - * @param pVertex_end - * @return int - */ - int edge::check_overlap(vertex pVertex_start, vertex pVertex_end) - { - int error_code = 1; - int overlap = 0; - float diff; - float dDistance1, dDistance2, dDistance3, dDistance4; - dDistance4 = pVertex_start.calculate_distance(pVertex_end); - dDistance1 = cVertex_start.calculate_distance(pVertex_start); - dDistance2 = cVertex_start.calculate_distance(pVertex_end); - - if (dDistance1 < dDistance2) - { - dDistance2 = cVertex_end.calculate_distance(pVertex_end); - //now we have all distance - diff = dLength - (dDistance1 + dDistance2 + dDistance4); - if (abs(diff) < 0.001) - { - //they are overlap - overlap = 1; - } - else - { - overlap = 0; - } - } - else - { - dDistance1 = cVertex_start.calculate_distance(pVertex_end); - dDistance2 = cVertex_end.calculate_distance(pVertex_start); - - //now we have all distance - diff = dLength - (dDistance1 + dDistance2 + dDistance4); - if (abs(diff) < 1) - { - //they are overlap - overlap = 1; - } - else - { - overlap = 0; - } - } - - return overlap; - } - - /** - * @brief check whether two edge are the same ignoring the direction - * - * @param pEdge_in - * @return int - */ - int edge::check_shared(edge pEdge_in) - { - int iFlag_shared = 0; - - if (this->cVertex_start == pEdge_in.cVertex_start && this->cVertex_end == pEdge_in.cVertex_end) - { - iFlag_shared = 1; - return iFlag_shared; - } - else - { - if (this->cVertex_start == pEdge_in.cVertex_end && this->cVertex_end == pEdge_in.cVertex_start) - { - iFlag_shared = 1; - return iFlag_shared; - } - else - { - iFlag_shared = 0; - } - } - - return iFlag_shared; - } -} // namespace hexwatershed \ No newline at end of file diff --git a/external/hexwatershed/src/edge.h b/external/hexwatershed/src/edge.h deleted file mode 100755 index 596bb52..0000000 --- a/external/hexwatershed/src/edge.h +++ /dev/null @@ -1,43 +0,0 @@ -/** - * @file edge.h - * @author Chang Liao (chang.liao@pnnl.gov) - * @brief Header file of the flowline class - * @version 0.1 - * @date 2019-08-02 - * @citation Liao, C., Tesfa, T., Duan, Z., & Leung, L. R. (2020). - * Watershed delineation on a hexagonal mesh grid. Environmental Modelling & Software, 104702. - * https://www.sciencedirect.com/science/article/pii/S1364815219308278 - * @github page https://github.com/changliao1025/hexwatershed - * @copyright Copyright (c) 2019 - * - */ -#pragma once - -#include -#include -#include "json/vertex.h" - -using namespace std; -using namespace jsonmodel; -namespace hexwatershed -{ - class edge { - public: - edge (); - - ~edge (); - - float dLength; - - vertex cVertex_start; - vertex cVertex_end; - - int calculate_length (); - - int check_point_overlap (vertex pt); - - int check_overlap (vertex pt_start, vertex pt_end); - - int check_shared (edge ed); - }; -} // namespace hexwatershed diff --git a/external/hexwatershed/src/flowline.cpp b/external/hexwatershed/src/flowline.cpp deleted file mode 100755 index 8b26413..0000000 --- a/external/hexwatershed/src/flowline.cpp +++ /dev/null @@ -1,93 +0,0 @@ - -/** - * @file flowline.cpp - * @author Chang Liao (chang.liao@pnnl.gov) - * @brief - * @version 0.1 - * @date 2019-06-11 Created by Chang Liao on 4/26/18. - * - * @copyright Copyright (c) 2019 - * - */ - -#include "flowline.h" - -namespace hexwatershed -{ - - flowline::flowline() - { - lCellID = -1; - iFlag_merged = 0; - iFlag_active = 1; - iFlag_new = 0; - iStream_segment = -1; - iStream_order = -1; - } - - flowline::~flowline() - { - } - - - /** - * @brief check whether two flowlines share a starting or ending vertex - * - * @param pFlowline_in - * @return int - */ - int flowline::share_vertex(flowline pFlowline_in) - { - int iFlag_share = 0; - vertex pVertex1, pVertex2; - - pVertex1 = pFlowline_in.cVertex_start; - pVertex2 = pFlowline_in.cVertex_end; - - if (pVertex1 == cVertex_start || pVertex1 == cVertex_end || pVertex2 == cVertex_start || pVertex2 == cVertex_end) - { - iFlag_share = 1; - } - - return iFlag_share; - } - - /** - * @brief check two flowlines share the specified vertex - * - * @param pFlowline_in - * @param pVertex_shared - * @return int - */ - int flowline::share_vertex(flowline pFlowline_in, vertex pVertex_shared) - { - int iFlag_share = 0; - std::vector aOut; - vertex pVertex1, pVertex2, pVertex3, pVertex4; - - pVertex1 = pFlowline_in.cVertex_start; - pVertex2 = pFlowline_in.cVertex_end; - pVertex3 = cVertex_start; - pVertex4 = cVertex_end; - - if (pVertex3 == pVertex_shared || pVertex4 == pVertex_shared) - { - if (pVertex1 == pVertex_shared ) - { - iFlag_share = 1; - - } - else - { - if (pVertex2 == pVertex_shared) - { - iFlag_share = 1; - } - - } - - } - - return iFlag_share; - } -} // namespace hexwatershed \ No newline at end of file diff --git a/external/hexwatershed/src/flowline.h b/external/hexwatershed/src/flowline.h deleted file mode 100755 index 08bd0d0..0000000 --- a/external/hexwatershed/src/flowline.h +++ /dev/null @@ -1,49 +0,0 @@ -/** - * @file flowline.h - * @author Chang Liao (chang.liao@pnnl.gov) - * @brief Header file of the flowline class - * @version 0.1 - * @date 2019-08-02 - * @citation Liao, C., Tesfa, T., Duan, Z., & Leung, L. R. (2020). - * Watershed delineation on a hexagonal mesh grid. Environmental Modelling & Software, 104702. - * https://www.sciencedirect.com/science/article/pii/S1364815219308278 - * @github page https://github.com/changliao1025/hexwatershed - * @copyright Copyright (c) 2019 - * - */ -#pragma once -#include -#include -#include "json/vertex.h" - -using namespace std; -using namespace jsonmodel; -namespace hexwatershed -{ - class flowline - { - public: - flowline(); - - ~flowline(); - - long lCellID; - int iFlag_merged; - int iFlag_active; - int iFlag_new; //this is a new flowline - - int iStream_segment; - int iStream_order; - float dLength; - //int iFlag_multiLine; - std::vector vVertex; //store all the vertex of this line - - vertex cVertex_start; - vertex cVertex_end; - - - int share_vertex(flowline pFlowline_in); - int share_vertex(flowline pFlowline_in, vertex pVertex_in); - - }; -} // namespace hexwatershed diff --git a/external/hexwatershed/src/geology.cpp b/external/hexwatershed/src/geology.cpp deleted file mode 100755 index 14279ae..0000000 --- a/external/hexwatershed/src/geology.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "geology.h" - -/** - * @brief calculate arc distance - * - * @param dLongitude_degree0 - * @param dLatitude_degree0 - * @param dLongitude_degree1 - * @param dLatitude_degree1 - * @return float - */ -float calculate_distance_based_on_lon_lat_degree(float dLongitude_degree0, -float dLatitude_degree0, -float dLongitude_degree1, -float dLatitude_degree1) -{ - float dDistance = 0.0; - float dLongitude_radian0, dLongitude_radian1, dLatitude_radian0, dLatitude_radian1; - float dDelta_longitude_radian, dDelta_latitude_radian; - float a, c, r; - - //convert decimal degrees to radians - - dLongitude_radian0 = convert_degree_to_radian(dLongitude_degree0); - dLatitude_radian0 = convert_degree_to_radian(dLatitude_degree0); - - dLongitude_radian1 = convert_degree_to_radian(dLongitude_degree1); - dLatitude_radian1 = convert_degree_to_radian(dLatitude_degree1); - - //haversine formula - dDelta_longitude_radian = dLongitude_radian1 - dLongitude_radian0; - dDelta_latitude_radian = dLatitude_radian1 - dLatitude_radian0; - - a = sin(dDelta_latitude_radian/2)* sin(dDelta_latitude_radian/2) + cos(dLatitude_radian0) * cos(dLatitude_radian1) * sin(dDelta_longitude_radian/2)* sin(dDelta_longitude_radian/2); - c = 2 * asin(sqrt(a)); - - - r = dRadius_earth; - - dDistance = c * r; - return dDistance; -} - -/** - * @brief calculate xyz location using lat/lon and elevation - * - * @param dLongitude_radian - * @param dLatitude_radian - * @param dElevation - * @return std::array - */ -std::array calculate_location_based_on_lon_lat_radian(float dLongitude_radian, float dLatitude_radian, float dElevation) -{ - std::array aLocation; - // see: http://www.mathworks.de/help/toolbox/aeroblks/llatoecefposition.html - float f = 1.0/298.257223563 ; //# Flattening factor WGS84 Model - float cosLat = cos(dLatitude_radian); - float sinLat = sin(dLatitude_radian); - float FF = (1.0-f)*(1.0-f); - float C = 1/sqrt(cosLat*cosLat + FF * sinLat*sinLat); - float S = C * FF; - - float x = (dRadius_earth * C + dElevation)*cosLat * cos(dLongitude_radian); - float y = (dRadius_earth * C + dElevation)*cosLat * sin(dLongitude_radian); - float z = (dRadius_earth * S + dElevation)*sinLat; - - aLocation[0] = x; - aLocation[1] = y; - aLocation[2] = z; - return aLocation; -} \ No newline at end of file diff --git a/external/hexwatershed/src/geology.h b/external/hexwatershed/src/geology.h deleted file mode 100755 index 6f6f541..0000000 --- a/external/hexwatershed/src/geology.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once -#include -#include -#include "global.h" -#include "conversion.h" - - -using namespace std; - -float calculate_distance_based_on_lon_lat_degree(float dLongitude_degree0, -float dLatitude_degree0, -float dLongitude_degree1, -float dLatitude_degree1); - -std::array calculate_location_based_on_lon_lat_radian(float dLatitude_radian, -float dLongitude_radian, -float dElevation); \ No newline at end of file diff --git a/external/hexwatershed/src/global.cpp b/external/hexwatershed/src/global.cpp deleted file mode 100755 index 470f359..0000000 --- a/external/hexwatershed/src/global.cpp +++ /dev/null @@ -1,126 +0,0 @@ - - - /** - * @file global.cpp - * @author Chang Liao (chang.liao@pnnl.gov) - * @brief The source file of the global file. - * @version 0.1 - * @date 2019-08-02 - * - * @copyright Copyright (c) 2019 - * - */ -#include "global.h" - -//50================================================== -//the global constant file for all the modules -//some constants or variables are written cross-platfrom -//50================================================== -const float dRadius_earth = 6378137.0; -const float small_value = 1.0E-4; //lai, denominator, etc, -const float tiny_value = 1.0E-8; //intermediate -const float near_zero = 1.0E-12; //for result - -const float pi = 3.141592654; -//const float missing_value = -9999.0; -// time -const float day_2_second = 3600 * 24; -const float day_2_minute = 60 * 24; -const float minute_2_second = 60; -const float hour_2_second = 3600; -const float dTimestep_eco3d = day_2_second; // unit: second -const float dTimestep_eco3d_minute = day_2_minute; //minutes -const float dTimestep_eco3d_hour = 24.0; //hour -const float dTimestep_eco3d_day = 1.0; //day - -const float dTimestep_eco3d_stream_minute = 1; //1.0 minute for stream routing -// length -const float meter_2_millimeter = 1.0E3; -const float meter_2_foot = 3.28084; // conversion -const float millimeter_2_meter = 1.0E-3; -const float inch_2_meter = 2.54 / 1.0E2; -const float inch_2_centimeter = 2.54; - -// area -const float square_meter_2_square_centimeter = 1.0E4; -const float hpa_2_pa = 1.0E2; - -// mass -const float gram_2_kilogram = 1.0E-3; -const float milligram_2_kilogram = 1.0E-6; -// temperature -const float kelvin_2_celsius = -273.15; -const float celsius_2_kelvin = 273.15; -// conversion -const float cubic_meter_2_cubic_centimeter = 1.0E6; -const float cubic_meter_2_cubic_liter = 1.0E3; -const float cubic_centimeter_2_cubic_meter = 1.0E-6; - -const float kilogram_per_kilogram_2_milligram_per_gram = 1.0E3; -const float milligram_per_gram_2_kilogram_per_kilogram = 1.0E-3; - -const float kilogram_per_cubic_meter_2_gram_per_cubic_centimeter = - 1.0E3 / 1.0E6; -const float kilogram_per_cubic_meter_2_gram_per_liter = 1.0; -const float kilogram_per_cubic_meter_2_milligram_per_liter = 1.0E3; -const float milligram_per_liter_2_kilogram_per_cubic_meter = 1.0E-3; - -const float kilogram_per_square_meter_2_gram_per_square_meter = 1.0E3; -const float gram_per_square_meter_2_kilogram_per_square_meter = 1.0E-3; - - -const float joule_2_calorie = 1.0 / 4.1858; - -const float joule_2_megajoule = 1.0E-6; -const float joule_2_langley = 1.0 / 41840.0; // convert from joule to langley - -const float calorie_2_joule = 4.1858; // convert from calorie to langley - - -const float langley_2_joule = 41840.0; - -// physical -const float dStefan_boltzmann = 5.670373E-8; // unit: w/m-2 K-4 -//const float dManning_roughness = 0.02; -const float radian = 0.0172; -const float dEccentricity = 0.0167; - -const float dMissing_value_default = -9999.0; -// solar constant units: watt per square meter, look at wiki: -// https://en.wikipedia.org/wiki/Solar_ ant -const float dSolar_constant = 1368.0; -const float dFrozen_temperature = 273.15; // unit: K -const float dDensity_water = 1.0E3; // density of water, unit: -const float dLatent_heat_water = - 333.55 * - 1.0E3; // heat of fusion (latent heat) of water. units: joule per kilogram -const float dSpecific_heat_water = - 4.179 * 1.0E3; // the specific heat of water, units: j / (kg * kelvin ) -const float dSpecific_heat_ice = - 2.03 * 1.0E3; // the specific heat of ice, units: j / (kg * kelvin ) -const float tkwat = 1.0; // thermal conductivity of water (w/m/kelvin) -const float tkice = 1.0; // thermal conductivity of ice (w/m/kelvin) -const float cwat = 1.0; // specific heat capacity of water (j/m**3/kelvin) -const float cice = 1.0; // specific heat capacity of ice (j/m**3/kelvin) -// gis -//const float dResolution = 500.0; // unit: meter -//const float dArea = 500.0 * 500.0; -// modules -const float dTemperature_all_rain = 273.15; // unit: kelvin -const float dTemperature_all_snow = 273.15; // unit: kelvin -const float dFraction_sublimation = 0.5; // snow, this one should be in snow class -// system -const char slash = '/'; - -std::string sError_file_missing = "The following file does not exist: "; -std::string sError_open_failed = "Failed to open file: "; -std::string sError_data_missing = "Failed to read some data from: "; -std::string sLog_data_quality = "Data quality is low. "; -std::string sLog_open_success = "Succeed to open file: "; - - std::string sExtension_header = ".hdr"; - std::string sExtension_envi = ".dat"; - std::string sExtension_text = ".txt"; - - - diff --git a/external/hexwatershed/src/global.h b/external/hexwatershed/src/global.h deleted file mode 100755 index 52dc1e4..0000000 --- a/external/hexwatershed/src/global.h +++ /dev/null @@ -1,140 +0,0 @@ - -/** - * @file global.h - * @author Chang Liao (chang.liao@pnnl.gov) - * @brief provide some constant across the program - * @version 0.1 - * @date 2019-08-02 - * @citation Liao, C., Tesfa, T., Duan, Z., & Leung, L. R. (2020). - * Watershed delineation on a hexagonal mesh grid. Environmental Modelling & Software, 104702. - * https://www.sciencedirect.com/science/article/pii/S1364815219308278 - * @github page https://github.com/changliao1025/hexwatershed - * @copyright Copyright (c) 2019 - * - */ -#pragma once -#include -using namespace std; - -//50================================================== -// the global constant file for all the modules -// some constants or variables are written cross-platfrom -//50================================================== -// math -//to reduce float point error, we used different level of thresholds to -//remove some values - -extern const float small_value; //small, from Latex -extern const float tiny_value; //extreme small, from Latex -extern const float near_zero; //the smallest - -extern const float dRadius_earth; -// -extern const float pi; -//extern const float missing_value; -// time -extern const float minute_2_second; -extern const float day_2_second; -extern const float day_2_minute; -extern const float hour_2_second; -extern const float dTimestep_eco3d; // unit: second -extern const float dTimestep_eco3d_minute; // unit: minutes -extern const float dTimestep_eco3d_hour; // unit: second -extern const float dTimestep_eco3d_day; // unit: minutes - -extern const float dTimestep_eco3d_stream_minute; // unit: minutes - -// length - -extern const float meter_2_millimeter; -extern const float meter_2_foot; // conversion -extern const float millimeter_2_meter; -extern const float inch_2_meter; -extern const float inch_2_centimeter; -// area -extern const float square_meter_2_square_centimeter; -extern const float hpa_2_pa; - -// mass -extern const float gram_2_kilogram; -extern const float milligram_2_kilogram; -// temperature -extern const float kelvin_2_celsius; -extern const float celsius_2_kelvin; -// conversion -extern const float cubic_meter_2_cubic_centimeter; -extern const float cubic_meter_2_cubic_liter; -extern const float cubic_centimeter_2_cubic_meter; - -extern const float kilogram_per_kilogram_2_milligram_per_gram; -extern const float milligram_per_gram_2_kilogram_per_kilogram; - -extern const float kilogram_per_cubic_meter_2_gram_per_cubic_centimeter; -extern const float kilogram_per_cubic_meter_2_gram_per_liter; -extern const float kilogram_per_cubic_meter_2_milligram_per_liter; -extern const float milligram_per_liter_2_kilogram_per_cubic_meter; - -extern const float kilogram_per_square_meter_2_gram_per_square_meter; - -extern const float gram_per_square_meter_2_kilogram_per_square_meter; - -extern const float joule_2_calorie; -extern const float joule_2_megajoule; -extern const float joule_2_langley; // convert from joulies to langley - -extern const float calorie_2_joule; // convert from calorie to langley - -extern const float langley_2_joule; - -extern const float dMissing_value_default; - -///50================================================== -// physical -extern const float dStefan_boltzmann; -//extern const float dManning_roughness; -extern const float radian; -extern const float dEccentricity; -// revolution speed of the Earth, radians per day , this is very close to -// pi/180, but it is different. -extern const float dSolar_constant; // units: watt per square meter, look at -// wiki: https://en.wikipedia.org/wiki/Solar_constant -extern const float dFrozen_temperature; // unit: K -extern const float dDensity_water; // density of water, unit: - -extern const float dLatent_heat_water; // heat of fusion (latent heat) of - // water. units: joule per kilogram -extern const float dSpecific_heat_water; // the specific heat of water, units: - // j / (kg * kelvin ) -extern const float dSpecific_heat_ice; // units: j / (kg * kelvin ) -extern const float tkwat; // thermal conductivity of water (w/m/kelvin) -extern const float tkice; // thermal conductivity of ice (w/m/kelvin) -extern const float cwat; // specific heat capacity of water (j/m**3/kelvin) -extern const float cice; // specific heat capacity of ice (j/m**3/kelvin) - - //50================================================== -// gis -//extern const float dResolution; // unit: meter -//extern const float dArea; -// modules -extern const float dTemperature_all_rain; // unit: kelvin -extern const float dTemperature_all_snow; // unit: kelvin -extern const float dFraction_sublimation; // -// system -extern const char slash; - -extern std::string sError_file_missing ; -extern std::string sError_open_failed ; -extern std::string sError_data_missing ; - -//log report -extern std::string sLog_data_quality ; -extern std::string sLog_open_success ; - -extern std::string sModule_cascade; -extern std::string sModule_snow ; - -extern std::string sExtension_header ; -extern std::string sExtension_envi ; -extern std::string sExtension_text ; - - diff --git a/external/hexwatershed/src/hexagon.cpp b/external/hexwatershed/src/hexagon.cpp deleted file mode 100755 index 3f08250..0000000 --- a/external/hexwatershed/src/hexagon.cpp +++ /dev/null @@ -1,138 +0,0 @@ - -/** - * @file hexagon.cpp - * @author Chang Liao (chang.liao@pnnl.gov) - * @brief - * @version 0.1 - * @date 2019-06-11Created by Chang Liao on 4/26/18. - * - * @copyright Copyright (c) 2019 - * - */ - -#include "hexagon.h" - -namespace hexwatershed -{ - - hexagon::hexagon() - { - iFlag_confluence = 0; - iFlag_active = 0; - iFlag_watershed = 0; //in any pre-defined watershed - iFlag_first_reach = 0; - iFlag_last_reach = 0; - iFlag_headwater = 0; - iFlag_stream = -1; - iFlag_stream_burned = 0; - - iFlag_stream_burning_treated = 0; - iFlag_depression_filling_treated = 0; - - iFlag_confluence_burned = 0; - iFlag_headwater_burned =0; - iStream_segment_burned = -1; - lCellID_downstream_burned = -1;//only assign it if we found on - iStream_order_burned = -1; - iFlag_outlet = -1; - lCellID_downslope_dominant = -1; - - lCellIndex=-1; - lCellIndex_watershed=-1; - lCellIndex_subbasin=-1; - - dAccumulation = 0.0; - iSubbasin = -1; - iSegment = -1; - iWatershed=-1; //the watershed it belongs to - iSegment_order = -1; - iSegment_downstream = -1; - nUpslope = 0; - nUpstream = 0; - - nVertex = -1; - dArea = -9999.0; - dElevation_mean = 0.0; - dElevation_downstream = -9999.0; - - - dSlope = 0.0; - dSlope_within= 0.0; - dSlope_max_downslope= 0.0; - dSlope_min_downslope= 0.0; - dSlope_mean_downslope= 0.0; - dSlope_max_upslope= 0.0; - dSlope_min_upslope= 0.0; - dSlope_mean_upslope= 0.0; - //dSlope_mean_between= 0.0; - - dz = -9999.0; - - dTwi = 0.0; - dLength_stream_conceptual = 0.0; - dLength_stream_burned=0.0; - - dDistance_to_downslope= 0.0; - dDistance_to_subbasin_outlet= 0.0; - dDistance_to_watershed_outlet= 0.0; - dLength_edge_mean=0.0; - } - - hexagon::~hexagon() - { - } - - - - /** - * @brief calculate the mean edge length - * - * @return int - */ - int hexagon::calculate_average_edge_length() - { - int error_code = 1; - float dLength = 0.0; - std::vector::iterator iIterator; - for (iIterator = vEdge.begin(); iIterator != vEdge.end(); iIterator++) - { - dLength = dLength + (*iIterator).dLength; - } - dLength_edge_mean = dLength / (nEdge); - return error_code; - } - - /** - * @brief calculate the effective resolution using area - * - * @return int - */ - int hexagon::calculate_effective_resolution() - { - int error_code = 1; - float dLength = 0.0; - dLength = sqrt( dArea ); - dResolution_effective = dLength ; - dLength_stream_conceptual = dResolution_effective; - return error_code; - } - - - /** - * @brief update the x y z location - * - * @return int - */ - int hexagon::update_location() - { - int error_code =1; - - std::array aLocation = calculate_location_based_on_lon_lat_radian(dLongitude_center_radian, dLatitude_center_radian, dElevation_mean); - dx = aLocation[0]; - dy = aLocation[1]; - dz = aLocation[2]; - - return error_code; - } - -} // namespace hexwatershed \ No newline at end of file diff --git a/external/hexwatershed/src/hexagon.h b/external/hexwatershed/src/hexagon.h deleted file mode 100755 index 4d9dccd..0000000 --- a/external/hexwatershed/src/hexagon.h +++ /dev/null @@ -1,149 +0,0 @@ -/** - * @file hexagon.h - * @author Chang Liao (chang.liao@pnnl.gov) - * @brief The header file the hexagon class. - * @version 0.1 - * @date 2019-08-02 - * @citation Liao, C., Tesfa, T., Duan, Z., & Leung, L. R. (2020). - * Watershed delineation on a hexagonal mesh grid. Environmental Modelling & Software, 104702. - * https://www.sciencedirect.com/science/article/pii/S1364815219308278 - * @github page https://github.com/changliao1025/hexwatershed - * @copyright Copyright (c) 2019 - * - */ -#pragma once - -#include -#include -#include -#include "global.h" -#include "json/vertex.h" -#include "edge.h" -#include "flowline.h" -using namespace std; -using namespace jsonmodel; -namespace hexwatershed -{ - class hexagon - { - public: - hexagon(); - - ~hexagon(); - - - long lCellIndex; //it includes cell outside of watershed - long lCellIndex_watershed; //only in the designed watershed - long lCellIndex_subbasin; - - /*! \brief Brief description. - * this is the mesh id from the json, it might be the same with Global ID, - * Detailed description starts here. - */ - long lCellID; - // this depends upon how mesh id was generated, it can be different from global id - int iFlag_checked; //used for loop - int iFlag_active; //if it has elevation assigned - int iFlag_watershed; //whether it is inside a watershed - int iFlag_stream; //whether it is a stream grid - int iFlag_stream_burned; /*flag for burned stream gridd*/ - - //be careful, a stream grid maybe visited multiple if breaching is enabled - - int iFlag_stream_burning_treated; - int iFlag_depression_filling_treated;//flag to indicate whether a cell is treated for elevation - - int iStream_segment_burned; - int iStream_order_burned; - int nFlowline_burned; - int iFlag_confluence_burned; - int iFlag_headwater_burned; - - int iFlag_first_reach; //whether it is the first reach of a stream - int iFlag_last_reach; //whether it is the last reach of a stream - int iFlag_headwater; //whether the stream segment is headwater, but we should set it to segment level? - int iFlag_neighbor; //this flag is used to check whether a hexagon is neighbor to another hexagon - int iFlag_outlet; //whether this hexagon is an outlet or not - int iFlag_confluence; //whether this hexagon is a stream confluence or not, confluence is where stream meets. - - int iSegment; //the stream segment index - int iSegment_order; //the stream order of segment, there are different type of definition - int iSubbasin; //the subbasin index, should be the same with the segment - int iWatershed; - - int nNeighbor; //number of neighbors, should be equal or less than nedge - int nNeighbor_land; - int nNeighbor_ocean; - int nUpslope; //all upslope including stream - int nDownslope; - int nUpstream; //only consider stream upslope - int iSegment_downstream; //if a hexagon is a stream, this is the downstream index, -1 for outlet - - int nVertex; //the vertex number from polygon, should always be constant for uniform resolution, for MPAS, this can be 5, 6, 7 - int nEdge; //total number of edge - long lCellID_downslope_dominant; //the downslope hexagon local ID - - long lCellID_downstream_burned;//the downstream mesh ID - - float dAccumulation; //the flow accumulation value. it does not consider area of hexagon in this version - float dAspect; //maybe used for radiation - float dSlope; - - float dSlope_within; //slope based on fine DEM - - float dSlope_max_downslope; //the maximum slope among all neighbors (unitless, it is a ratio) - float dSlope_min_downslope; - float dSlope_mean_downslope; - - float dSlope_max_upslope; //the maximum slope among all neighbors (unitless, it is a ratio) - float dSlope_min_upslope; - float dSlope_mean_upslope; - - //float dSlope_mean_between; - float dSlope_elevation_profile0; - - float dLength_edge_mean; //the edge/face length of hexagon (unit:m) - float dResolution_effective; - float dx; //map projection, (unit:m) - float dy; //map projection, (unit:m) - float dz; //map projection, (unit:m) - float dLongitude_center_degree; //GCS, (unit:degree) - float dLatitude_center_degree; //GCS, (unit:degree) - float dLongitude_center_radian; //GCS, (unit:degree) - float dLatitude_center_radian; //GCS, (unit:degree) - - float dElevation_mean; //from DEM, (unit:m) - float dElevation_profile0; //from DEM, (unit:m) - float dElevation_raw; //from DEM, (unit:m) - float dElevation_downstream; //down stream elevation for breach algorithm - float dArea; //the area of hexagon, (unit:m2) - float dTwi; //terrain wetness index - float dLength_stream_conceptual;//conceptual length based on mesh - float dLength_stream_burned; //the provided flowline length - - float dDistance_to_downslope; - float dDistance_to_subbasin_outlet; - float dDistance_to_watershed_outlet; - - - std::vector vNeighbor; //list of neighbor local id - std::vector vNeighbor_distance; //list of neighbor local id - - std::vector vNeighbor_land; //list of neighbor local id - std::vector vUpslope; //list of upslope local id - std::vector vDownslope; //list of downslope local id, new feature to support multiple downslope - - std::vector vUpstream; //list of upslope local id - - std::vector vVertex_index; // - std::vector vVertex; //list of vertex - std::vector vEdge; //list of vertex - std::vector vFlowline; //list of vertex - - - int calculate_average_edge_length(); - int calculate_effective_resolution(); - int update_location(); - }; - -} // namespace hexwatershed diff --git a/external/hexwatershed/src/json/JSONBase.cpp b/external/hexwatershed/src/json/JSONBase.cpp deleted file mode 100755 index 93b9574..0000000 --- a/external/hexwatershed/src/json/JSONBase.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include "JSONBase.h" - -namespace jsonmodel -{ - JSONBase::JSONBase() - { - - } - JSONBase::~JSONBase() - { - - } - - std::string JSONBase::Serialize() const - { - rapidjson::StringBuffer ss; - rapidjson::PrettyWriter writer(ss); // Can also use Writer for condensed formatting - if (Serialize(&writer)) - return ss.GetString(); - return ""; - } - - bool JSONBase::Deserialize(const std::string& s) - { - rapidjson::Document doc; - if (!InitDocument(s, doc)) - return false; - - Deserialize(doc); - - return true; - } - - bool JSONBase::DeserializeFromFile(const std::string& filePath) - { - std::ifstream f(filePath); - std::stringstream buffer; - buffer << f.rdbuf(); - f.close(); - - return Deserialize(buffer.str()); - } - - bool JSONBase::SerializeToFile(const std::string& filePath) - { - std::ofstream f(filePath); - std::string s = Serialize(); - f << s; - f.flush(); - f.close(); - - return true; - } - - bool JSONBase::InitDocument(const std::string& s, rapidjson::Document& doc) - { - if (s.empty()) - return false; - - std::string validJson(s); - - return !doc.Parse(validJson.c_str()).HasParseError() ? true : false; - } -} diff --git a/external/hexwatershed/src/json/JSONBase.h b/external/hexwatershed/src/json/JSONBase.h deleted file mode 100755 index af61a8e..0000000 --- a/external/hexwatershed/src/json/JSONBase.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once -#include "../../rapidjson/rapidjson.h" -#include "../../rapidjson/prettywriter.h"// for stringify JSON -#include "../../rapidjson/document.h"// rapidjson's DOM-style API -#include "../../rapidjson/writer.h" -#include "../../rapidjson/stringbuffer.h" // wrapper of C stream for prettywriter as output -#include "../../rapidjson/istreamwrapper.h" -#include -#include -#include -using namespace std; -namespace jsonmodel -{ - class JSONBase - { - public: - JSONBase(); - virtual ~JSONBase(); - bool DeserializeFromFile(const std::string& filePath); - bool SerializeToFile(const std::string& filePath); - - virtual std::string Serialize() const; - virtual bool Deserialize(const std::string& s); - virtual bool Deserialize(const rapidjson::Value& obj) = 0; - virtual bool Serialize(rapidjson::PrettyWriter* writer) const = 0; - protected: - bool InitDocument(const std::string & s, rapidjson::Document &doc); - }; -} diff --git a/external/hexwatershed/src/json/basin.cpp b/external/hexwatershed/src/json/basin.cpp deleted file mode 100755 index 15e3c37..0000000 --- a/external/hexwatershed/src/json/basin.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include -#include "basin.h" - -namespace jsonmodel -{ - basin::basin() - { - dLongitude_outlet_degree=-9999; - dLatitude_outlet_degree=-9999; - lCellID_outlet =-1; - } - - basin::~basin() - { - - } - - - bool basin::Deserialize(const rapidjson::Value & obj) - { - std::string sKey; - - sKey = "dLongitude_outlet_degree"; - if (obj.HasMember(sKey.c_str())) - { - this->dLongitude_outlet_degree= obj[sKey.c_str()].GetFloat(); - } - sKey = "dLatitude_outlet_degree"; - if (obj.HasMember(sKey.c_str())) - { - this->dLatitude_outlet_degree= obj[sKey.c_str()].GetFloat(); - } - - sKey = "lBasinID"; - if (obj.HasMember(sKey.c_str())) - { - this->lBasinID= obj[sKey.c_str()].GetInt64(); - } - - sKey = "lCellID_outlet"; - if (obj.HasMember(sKey.c_str())) - { - this->lCellID_outlet= obj[sKey.c_str()].GetInt64(); - } - - - return true; - } - - bool basin::Serialize(rapidjson::PrettyWriter * writer) const - { - //writer->SetIndent('\n',2); - writer->StartObject(); - - writer->String("lBasinID"); - writer->Int64(lBasinID); - - writer->String("dLongitude_outlet_degree"); - writer->Double(dLongitude_outlet_degree); - - writer->String("dLatitude_outlet_degree"); - writer->Double(dLatitude_outlet_degree); - - writer->String("lCellID_outlet"); - writer->Int64(lCellID_outlet); - - writer->EndObject(); - - return true; - } -} \ No newline at end of file diff --git a/external/hexwatershed/src/json/basin.h b/external/hexwatershed/src/json/basin.h deleted file mode 100755 index 22eaf1f..0000000 --- a/external/hexwatershed/src/json/basin.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include "JSONBase.h" -#include -#include -namespace jsonmodel -{ - class basin : public JSONBase - { - public: - basin(); - virtual ~basin(); - - virtual bool Deserialize(const rapidjson::Value& obj); - virtual bool Serialize(rapidjson::PrettyWriter* writer) const; - - int iFlag_dam; - - - float dLongitude_outlet_degree; - float dLatitude_outlet_degree; - - long lCellID_outlet; - long lBasinID; - - - private: - - }; -} \ No newline at end of file diff --git a/external/hexwatershed/src/json/cell.cpp b/external/hexwatershed/src/json/cell.cpp deleted file mode 100755 index aae3007..0000000 --- a/external/hexwatershed/src/json/cell.cpp +++ /dev/null @@ -1,230 +0,0 @@ -#include -#include "cell.h" - -namespace jsonmodel -{ - cell::cell() - { - iStream_segment_burned = -1; - iStream_order_burned = -1; - - dAccumulation = 0.0; - lCellID = -1; - lCellID_downslope = -1; - lCellID_downstream_burned = -1; - dElevation_mean = -9999.0; - dElevation_profile0 = -9999.0; - dElevation_raw = -9999.0; - dLatitude_center_degree = -9999.0; - dLongitude_center_degree = -9999.0; - dArea = -9999.0; - dDistance_to_downslope = -9999.0; - dDistance_to_subbasin_outlet = -9999.0; - dDistance_to_watershed_outlet = -9999.0; - nEdge = 0; - nVertex = 0; - nNeighbor = 0; - nNeighbor_land = 0; - nNeighbor_ocean = 0; - - dSlope_between = -9999.0; - dSlope_within = -9999.0; - } - - cell::~cell() - { - } - - bool cell::Deserialize(const rapidjson::Value &obj) - { - std::string sKey; - sKey = "dElevation_mean"; - if (obj.HasMember(sKey.c_str())) - { - this->dElevation_mean = obj[sKey.c_str()].GetFloat(); - this->dElevation_raw = this->dElevation_mean; - } - sKey = "dElevation_profile0"; - if (obj.HasMember(sKey.c_str())) - { - this->dElevation_profile0 = obj[sKey.c_str()].GetFloat(); - } - sKey = "dLatitude_center_degree"; - if (obj.HasMember(sKey.c_str())) - { - this->dLatitude_center_degree = obj[sKey.c_str()].GetFloat(); - } - - sKey = "dLongitude_center_degree"; - if (obj.HasMember(sKey.c_str())) - { - this->dLongitude_center_degree = obj[sKey.c_str()].GetFloat(); - } - - sKey = "dLength"; - if (obj.HasMember(sKey.c_str())) - { - this->dLength = obj[sKey.c_str()].GetFloat(); - } - - sKey = "dLength_flowline"; - if (obj.HasMember(sKey.c_str())) - { - this->dLength_flowline = obj[sKey.c_str()].GetFloat(); - } - - sKey = "dArea"; - if (obj.HasMember(sKey.c_str())) - { - this->dArea = obj[sKey.c_str()].GetFloat(); - } - - sKey = "lCellID"; - if (obj.HasMember(sKey.c_str())) - { - this->lCellID = obj[sKey.c_str()].GetInt64(); - } - sKey = "lCellID_downstream_burned"; - if (obj.HasMember(sKey.c_str())) - { - this->lCellID_downstream_burned = obj[sKey.c_str()].GetInt64(); - } - sKey = "iStream_segment_burned"; - if (obj.HasMember(sKey.c_str())) - { - this->iStream_segment_burned = obj[sKey.c_str()].GetInt(); - } - sKey = "iStream_order_burned"; - if (obj.HasMember(sKey.c_str())) - { - this->iStream_order_burned = obj[sKey.c_str()].GetInt(); - } - sKey = "nEdge"; - if (obj.HasMember(sKey.c_str())) - { - this->nEdge = obj[sKey.c_str()].GetInt(); - } - sKey = "nNeighbor"; - if (obj.HasMember(sKey.c_str())) - { - this->nNeighbor = obj[sKey.c_str()].GetInt(); - } - sKey = "nNeighbor_land"; - if (obj.HasMember(sKey.c_str())) - { - this->nNeighbor_land = obj[sKey.c_str()].GetInt(); - } - sKey = "nNeighbor_ocean"; - if (obj.HasMember(sKey.c_str())) - { - this->nNeighbor_ocean = obj[sKey.c_str()].GetInt(); - } - sKey = "nVertex"; - if (obj.HasMember(sKey.c_str())) - { - this->nVertex = obj[sKey.c_str()].GetInt(); - } - // for (int i = 0; i < this->nEdge; i++) - //{ - // this->aEdge.push_back(obj["aEdge"][i].GetInt64()); - // } - for (int i = 0; i < this->nNeighbor; i++) - { - this->aNeighbor.push_back(obj["aNeighbor"][i].GetInt64()); - this->aNeighbor_distance.push_back(obj["aNeighbor_distance"][i].GetFloat()); - } - for (int i = 0; i < this->nNeighbor_land; i++) - { - this->aNeighbor_land.push_back(obj["aNeighbor_land"][i].GetInt64()); - } - const rapidjson::Value &rVertex = obj["aVertex"]; - assert(rVertex.IsArray()); - - for (int i = 0; i < this->nVertex; i++) - { - vertex pVertex; - pVertex.dLongitude_degree = rVertex[i]["dLongitude_degree"].GetFloat(); - pVertex.dLatitude_degree = rVertex[i]["dLatitude_degree"].GetFloat(); - pVertex.dLongitude_radian = convert_degree_to_radian(pVertex.dLongitude_degree); - pVertex.dLatitude_radian = convert_degree_to_radian(pVertex.dLatitude_degree); - pVertex.dElevation = this->dElevation_raw; - pVertex.update_location(); - this->vVertex.push_back(pVertex); - } - - return true; - } - - bool cell::Serialize(rapidjson::PrettyWriter *writer) const - { - std::vector::const_iterator iIterator; - // writer->SetIndent('\n',2); - writer->StartObject(); - writer->String("lCellID"); - writer->Int64(lCellID); - - writer->String("lCellID_downstream_burned"); - writer->Int64(lCellID_downstream_burned); - - writer->String("lCellID_downslope"); - writer->Int64(lCellID_downslope); - - writer->String("iSegment"); - writer->Int(iStream_segment); - - writer->String("iSubbasin"); - writer->Int(iSubbasin); - - writer->String("dLongitude_center_degree"); - writer->Double(dLongitude_center_degree); - writer->String("dLatitude_center_degree"); - writer->Double(dLatitude_center_degree); - writer->String("Area"); - writer->Double(dArea); - writer->String("Elevation_raw"); - writer->Double(dElevation_raw); - writer->String("Elevation"); - writer->Double(dElevation_mean); - writer->String("Elevation_profile"); - writer->Double(dElevation_profile0); - writer->String("dSlope_between"); - writer->Double(dSlope_between); - writer->String("dSlope_profile"); - writer->Double(dSlope_profile); - // writer->String("dSlope_within"); - // writer->Double(dSlope_within); - - writer->String("dLength_conceptual"); - writer->Double(dLength); - - writer->String("dLength_flowline"); - writer->Double(dLength_flowline); - - writer->String("DrainageArea"); - writer->Double(dAccumulation); - writer->String("dDistance_to_downslope"); - writer->Double(dDistance_to_downslope); - writer->String("dDistance_to_subbasin_outlet"); - writer->Double(dDistance_to_subbasin_outlet); - writer->String("dDistance_to_watershed_outlet"); - writer->Double(dDistance_to_watershed_outlet); - // vertex information - writer->Key("vVertex"); - writer->StartArray(); - for (iIterator = this->vVertex.begin(); iIterator != this->vVertex.end(); ++iIterator) - { - writer->StartObject(); - writer->Key("dLongitude_degree"); - writer->Double((*iIterator).dLongitude_degree); - writer->Key("dLatitude_degree"); - writer->Double((*iIterator).dLatitude_degree); - writer->EndObject(); - } - - writer->EndArray(); - - writer->EndObject(); - - return true; - } -} \ No newline at end of file diff --git a/external/hexwatershed/src/json/cell.h b/external/hexwatershed/src/json/cell.h deleted file mode 100755 index b37e094..0000000 --- a/external/hexwatershed/src/json/cell.h +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -#include "JSONBase.h" -#include "vertex.h" -#include "../conversion.h" -#include -#include -namespace jsonmodel -{ - class cell : public JSONBase - { - public: - cell(); - virtual ~cell(); - - virtual bool Deserialize(const rapidjson::Value& obj); - virtual bool Serialize(rapidjson::PrettyWriter* writer) const; - - //Getters/Setters. - //std::vector aEdge; - std::vector aNeighbor; /*! aNeighbor_land; /*! aNeighbor_ocean;/*! aNeighbor_distance; /*! vVertex; - - float dElevation_mean; /*! -#include "link.h" - -namespace jsonmodel -{ - link::link() - { - - } - - link::~link() - { - - } - - - bool link::Deserialize(const rapidjson::Value & obj) - { - std::string sKey; - - - sKey = "pCell_start"; - if (obj.HasMember(sKey.c_str())) - { - this->lCellID_start= obj[sKey.c_str()].GetInt64(); - } - sKey = "pCell_end"; - if (obj.HasMember(sKey.c_str())) - { - this->lCellID_end= obj[sKey.c_str()].GetInt(); - } - - - - - - return true; - } - - bool link::Serialize(rapidjson::Writer * writer) const - { - writer->StartObject(); - //writer->String("id"); - //writer->Int(_id); - //writer->String("name"); - //writer->String(_name.c_str()); - //writer->String("category"); - //writer->String(_category.c_str()); - //writer->String("sales"); - //writer->Double(_sales); - writer->EndObject(); - - return true; - } -} \ No newline at end of file diff --git a/external/hexwatershed/src/json/link.h b/external/hexwatershed/src/json/link.h deleted file mode 100755 index e3b968d..0000000 --- a/external/hexwatershed/src/json/link.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include "JSONBase.h" -#include -#include -namespace jsonmodel -{ - class link : public JSONBase - { - public: - link(); - virtual ~link(); - - virtual bool Deserialize(const rapidjson::Value& obj); - virtual bool Serialize(rapidjson::Writer* writer) const; - - long lCellID_start; - long lCellID_end; - private: - - }; -} \ No newline at end of file diff --git a/external/hexwatershed/src/json/links.cpp b/external/hexwatershed/src/json/links.cpp deleted file mode 100755 index 20b7664..0000000 --- a/external/hexwatershed/src/json/links.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "links.h" - -namespace jsonmodel -{ - - - bool links::Deserialize(const std::string& s) - { - rapidjson::Document doc; - if (!InitDocument(s, doc)) - return false; - - if (!doc.IsArray()) - return false; - - for (rapidjson::Value::ConstValueIterator itr = doc.Begin(); itr != doc.End(); ++itr) - { - link pLink; - pLink.Deserialize(*itr); - aLink.push_back(pLink); - } - - return true; - } - - bool links::Serialize(rapidjson::Writer* writer) const - { - writer->StartArray(); - - for (std::vector::const_iterator it = aLink.begin(); it != aLink.end(); it++) - { - (*it).Serialize(writer); - } - writer->EndArray(); - - return true; - } -} \ No newline at end of file diff --git a/external/hexwatershed/src/json/links.h b/external/hexwatershed/src/json/links.h deleted file mode 100755 index 0940b99..0000000 --- a/external/hexwatershed/src/json/links.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include "link.h" -#include -#include -namespace jsonmodel -{ - class links : public JSONBase - { - public: - virtual ~links() {}; - virtual bool Deserialize(const std::string& s); - - std::vector aLink; - public: - virtual bool Deserialize(const rapidjson::Value& obj) { return false; }; - virtual bool Serialize(rapidjson::Writer* writer) const; - private: - - }; -} \ No newline at end of file diff --git a/external/hexwatershed/src/json/mesh.cpp b/external/hexwatershed/src/json/mesh.cpp deleted file mode 100755 index 0195d37..0000000 --- a/external/hexwatershed/src/json/mesh.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "mesh.h" - -namespace jsonmodel -{ - - - bool mesh::Deserialize(const std::string& s) - { - rapidjson::Document doc; - if (!InitDocument(s, doc)) - return false; - - if (!doc.IsArray()) - return false; - - for (rapidjson::Value::ConstValueIterator itr = doc.Begin(); itr != doc.End(); ++itr) - { - cell pCell; - pCell.Deserialize(*itr); - aCell.push_back(pCell); - } - - return true; - } - - bool mesh::Serialize(rapidjson::PrettyWriter* writer) const - { - writer->StartArray(); - - for (std::list::const_iterator it = aCell.begin(); it != aCell.end(); it++) - { - (*it).Serialize(writer); - } - writer->EndArray(); - - return true; - } -} \ No newline at end of file diff --git a/external/hexwatershed/src/json/mesh.h b/external/hexwatershed/src/json/mesh.h deleted file mode 100755 index f5aaac3..0000000 --- a/external/hexwatershed/src/json/mesh.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include "cell.h" -#include -#include -namespace jsonmodel -{ - class mesh : public JSONBase - { - public: - //mesh() {}; - virtual ~mesh() {}; - virtual bool Deserialize(const std::string& s); - - std::list aCell; - public: - virtual bool Deserialize(const rapidjson::Value& obj) { return false; }; - virtual bool Serialize(rapidjson::PrettyWriter* writer) const; - private: - - }; -} \ No newline at end of file diff --git a/external/hexwatershed/src/json/multibasin.cpp b/external/hexwatershed/src/json/multibasin.cpp deleted file mode 100755 index d98f3ac..0000000 --- a/external/hexwatershed/src/json/multibasin.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "multibasin.h" - -namespace jsonmodel -{ - - - bool multibasin::Deserialize(const std::string& s) - { - rapidjson::Document doc; - if (!InitDocument(s, doc)) - return false; - - if (!doc.IsArray()) - return false; - - - - - for (rapidjson::Value::ConstValueIterator itr = doc.Begin(); itr != doc.End(); ++itr) - { - basin pBasin; - pBasin.Deserialize(*itr); - aBasin.push_back(pBasin); - } - - return true; - } - - bool multibasin::Serialize(rapidjson::PrettyWriter* writer) const - { - writer->StartArray(); - - for (std::list::const_iterator it = aBasin.begin(); it != aBasin.end(); it++) - { - (*it).Serialize(writer); - } - writer->EndArray(); - - return true; - } -} \ No newline at end of file diff --git a/external/hexwatershed/src/json/multibasin.h b/external/hexwatershed/src/json/multibasin.h deleted file mode 100755 index 7f0f4ea..0000000 --- a/external/hexwatershed/src/json/multibasin.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include "basin.h" -#include -#include -namespace jsonmodel -{ - class multibasin : public JSONBase - { - public: - //multibasin() {}; - virtual ~multibasin() {}; - virtual bool Deserialize(const std::string& s); - - std::list aBasin; - public: - virtual bool Deserialize(const rapidjson::Value& obj) { return false; }; - virtual bool Serialize(rapidjson::PrettyWriter* writer) const; - private: - - }; -} \ No newline at end of file diff --git a/external/hexwatershed/src/json/vertex.cpp b/external/hexwatershed/src/json/vertex.cpp deleted file mode 100755 index 4ffbf54..0000000 --- a/external/hexwatershed/src/json/vertex.cpp +++ /dev/null @@ -1,95 +0,0 @@ -#include "vertex.h" - -namespace jsonmodel -{ - - vertex::vertex() - { - lVertexIndex = 0; - dx = -9999; //map projection - dy = -9999; //map projection - dz = -9999; //elevation of VTK - } - - vertex::~vertex() - { - } - - /** - * @brief overload the equal function - * - * @param cVertex - * @return true - * @return false - */ - - bool vertex::operator==(const vertex &cVertex) - { - float dDistance; - dDistance = calculate_distance( cVertex ); - if ( dDistance < 0.001) //careful - { - return true; - } - else - { - return false; - } - } - - /** - * @brief calculate the slope between two vertices - * - * @param pVertex_in - * @return float - */ - - float vertex::calculate_slope(vertex pVertex_in) - { - float dSlope = 0.0; - float x1; - float y1; - float z1; - float dElevation1; - float dDistance; - x1 = pVertex_in.dx; - y1 = pVertex_in.dy; - z1 = pVertex_in.dz; - dElevation1 = pVertex_in.dElevation; - dDistance= calculate_distance(pVertex_in); - - if (this->dx != x1) - { - dSlope = abs(this->dElevation - dElevation1) / dDistance; - } - else - { - /* code */ - } - return dSlope; - } - float vertex::calculate_distance(vertex pVertex_in) - { - float dDistance = 0.0; - float dLon0 = this->dLongitude_degree; - float dLat0 = this->dLatitude_degree; - float dLon1 = pVertex_in.dLongitude_degree; - float dLat1 = pVertex_in.dLatitude_degree; - - dDistance = calculate_distance_based_on_lon_lat_degree(dLon0, dLat0, dLon1, dLat1); - - return dDistance; - } - - int vertex::update_location() - { - int error_code =1; - - std::array aLocation = calculate_location_based_on_lon_lat_radian(dLongitude_radian, dLatitude_radian, dElevation); - dx = aLocation[0]; - dy = aLocation[1]; - dz = aLocation[2]; - - return error_code; - } -} // namespace hexwatershed \ No newline at end of file diff --git a/external/hexwatershed/src/json/vertex.h b/external/hexwatershed/src/json/vertex.h deleted file mode 100755 index ed732ff..0000000 --- a/external/hexwatershed/src/json/vertex.h +++ /dev/null @@ -1,48 +0,0 @@ -/** - * @file system.h - * @author Chang Liao (chang.liao@pnnl.gov) - * @brief Provide interface to the hexagon vertex - * @version 0.1 - * @date 2019-08-02 - * @citation Liao, C., Tesfa, T., Duan, Z., & Leung, L. R. (2020). - * Watershed delineation on a hexagonal mesh grid. Environmental Modelling & Software, 104702. - * https://www.sciencedirect.com/science/article/pii/S1364815219308278 - * @github page https://github.com/changliao1025/hexwatershed - * @copyright Copyright (c) 2019 - * - */ -#pragma once - -#include -#include -#include "../global.h" -#include "../geology.h" - -using namespace std; -namespace jsonmodel - { - class vertex - { - public: - vertex(); - ~vertex(); - - long lVertexIndex; //reserved - float dx; //3d sphere (unit: m) - float dy; //3d (unit: m) - float dz; // (unit: m) - float dElevation; // (unit: m) - float dLongitude_degree; - float dLatitude_degree; - - float dLongitude_radian; - float dLatitude_radian; - - bool operator==(const vertex &cVertex); - - int update_location(); - - float calculate_slope( vertex pt ); - float calculate_distance( vertex pt ); - }; - } // namespace jsonmodel \ No newline at end of file diff --git a/external/hexwatershed/src/main.cpp b/external/hexwatershed/src/main.cpp deleted file mode 100755 index a752d75..0000000 --- a/external/hexwatershed/src/main.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/** - * @file depression.h - * @author Chang Liao (chang.liao@pnnl.gov) - * @brief the main entrance - * @version 0.1 - * @date 2019-08-02 - * @citation Liao, C., Tesfa, T., Duan, Z., & Leung, L. R. (2020). - * Watershed delineation on a hexagonal mesh grid. Environmental Modelling & Software, 104702. - * https://www.sciencedirect.com/science/article/pii/S1364815219308278 - * @github page https://github.com/changliao1025/hexwatershed - * @copyright Copyright (c) 2019 - * - */ -#include -#include -#include "domain/domain.h" - -/*! \mainpage An introduction to the HexWatershed Model - * - * \section intro_sec Introduction - * - * This is the Doxygen page of the HexWatershed model. - * - * - * \section install_sec Installation - * - * \subsection step1 Step 1: Opening the box - * - * etc... - */ - -/** - * - * @param argc - * @param argv - * @return - */ -int main(int argc, char *argv[]) -{ - int error_code = 1; - - //initial program running status as success, - //the status variable changes to 0 if any step fails to proceed. - std::cout << "Start to run HexWatershed model!" << std::endl; - int program_status = 1; - std::string sConfiguration_file = ""; - if (argc == 2) //at least 2 arguments are needed - { - std::cout << "The following arguments are provided:" << std::endl; - std::cout << argv[1] << std::endl; //print out all the arguments - sConfiguration_file = argv[1]; - } - else - { - std::cout << "No arguments are provided!" << std::endl; - std::cout << "Please input the configuration file: " << std::endl; - - } - //initialize the ecosystem model - hexwatershed::domain cDomain(sConfiguration_file); - //since the class initialization does not have a return value, we check it here directly - if (cDomain.cCompset.cParameter.iFlag_configuration_file == 0) //the configuration file is effective. - { - std::cout << "The configuration file does not exit!" << "\n"; - exit(0); - } - else - { - //initialize the class member - cDomain.domain_setup(); - error_code = cDomain.domain_read(); - if (error_code != 0) - { - error_code = cDomain.domain_initialize(); - if (error_code != 0) - { - error_code = cDomain.domain_run(); - if (error_code != 0) - { - error_code = cDomain.domain_save(); - if (error_code != 0) - { - error_code = cDomain.domain_cleanup(); - } - } - } - std::cout << "Finished!" << "\n"; - program_status = 1; - } - else - { - program_status = 0; - } - - } - return program_status; - -} - diff --git a/external/hexwatershed/src/parameter.cpp b/external/hexwatershed/src/parameter.cpp deleted file mode 100755 index 039747f..0000000 --- a/external/hexwatershed/src/parameter.cpp +++ /dev/null @@ -1,35 +0,0 @@ - -/** - * @file flowline.cpp - * @author Chang Liao (chang.liao@pnnl.gov) - * @brief - * @version 0.1 - * @date 2019-06-11Created by Chang Liao on 4/26/18. - * - * @copyright Copyright (c) 2019 - * - */ - -#include "parameter.h" - -namespace hexwatershed -{ - - parameter::parameter() - { - iFlag_global = 0; - iFlag_multiple_outlet=0; - iFlag_elevation_profile = 0; - iFlag_stream_grid_option = 3; - dAccumulation_threshold = 0.01; - dBreach_threshold = 5.0; //unit in meter - nOutlet = 1; - } - - parameter::~parameter() - { - } - - - -} // namespace hexwatershed diff --git a/external/hexwatershed/src/parameter.h b/external/hexwatershed/src/parameter.h deleted file mode 100755 index 04b0f5f..0000000 --- a/external/hexwatershed/src/parameter.h +++ /dev/null @@ -1,51 +0,0 @@ -// -// Created by liao313 on 4/8/2021. -// - - -#pragma once -#include -#include -using namespace std; - -namespace hexwatershed -{ - - class parameter { - - public: - parameter(); - - ~parameter(); - int iCase_index; - int nOutlet; - int iFlag_configuration_file; - int iFlag_debug; - int iFlag_elevation_profile; - int iMesh_type; - int iFlag_global; - int iFlag_multiple_outlet; //multiple outlet in one simulation - int iFlag_resample_method; - int iFlag_flowline; //has stream burning or not - int iFlag_stream_burning_topology;//whethet to use topology for stream burning - int iFlag_stream_grid_option; - - int iFlag_slope_provided; - - int iFlag_merge_reach; - - - - //parameters - float dAccumulation_threshold; - float dBreach_threshold; //the threshold parameter for stream burning breaching algorithm - - float dMissing_value_dem; - std::string sMesh_type; - std::string sFilename_configuration; - std::string sMissing_value_default; - - }; -} - - diff --git a/external/hexwatershed/src/segment.cpp b/external/hexwatershed/src/segment.cpp deleted file mode 100755 index 3ac2dad..0000000 --- a/external/hexwatershed/src/segment.cpp +++ /dev/null @@ -1,101 +0,0 @@ - -/** - * @file segment.cpp - * @author Chang Liao (chang.liao@pnnl.gov) - * @brief - * @version 0.1 - * @date 2019-08-02 - * - * @copyright Copyright (c) 2019 - * - */ -#include "segment.h" - -namespace hexwatershed -{ - segment::segment() - { - iFlag_headwater = 0; - iSegment = 0; - iSegmentIndex = -1; - iSegment_order = -1; - iSegment_downstream = -1; - - iFlag_has_upstream = -1; - iFlag_has_downstream = -1; - nSegment_upstream = -1; - dDistance_to_watershed_outlet = 0.0; - } - - segment::~segment() - { - } - - bool segment::operator<(const segment &cSegment) - { - return (this->iSegment < cSegment.iSegment); - } - - /** - * @brief - * - * @return int - */ - int segment::calculate_stream_segment_characteristics() - { - int error_code = 1; - calculate_stream_segment_length(); - calculate_stream_segment_slope(); - return error_code; - } - - /** - * @brief calculate stream segment length - * - * @return int - */ - int segment::calculate_stream_segment_length() - { - int error_code = 1; - float dLength_total = 0.0; - - std::vector::iterator iIterator; - for (iIterator = vReach_segment.begin(); iIterator != vReach_segment.end(); iIterator++) - { - dLength_total = dLength_total + (*iIterator).dLength_stream_conceptual; - } - - dLength = dLength_total; - - return error_code; - } - - int segment::calculate_stream_segment_slope() - { - int error_code = 1; - float dElevation_diff; - float dElevation_min, dElevation_max; - - if (nReach == 1) - { - // there is only reach - dSlope_mean = vReach_segment[0].dSlope_max_downslope; - dElevation_drop = dSlope_mean * dLength; - } - else - { - dElevation_max = vReach_segment.front().dElevation_mean; - dElevation_min = vReach_segment.back().dElevation_mean; - dElevation_diff = dElevation_max - dElevation_min; - dElevation_drop = dElevation_diff; - dSlope_mean = dElevation_diff / dLength; - } - - return error_code; - } - int segment::calculate_travel_distance() - { - int error_code = 1; - return error_code; - } -} // namespace hexwatershed diff --git a/external/hexwatershed/src/segment.h b/external/hexwatershed/src/segment.h deleted file mode 100755 index ba2ed69..0000000 --- a/external/hexwatershed/src/segment.h +++ /dev/null @@ -1,65 +0,0 @@ -/** - * @file segment.h - * @author Chang Liao (chang.liao@pnnl.gov) - * @brief Header file of the stream segment class - * @version 0.1 - * @date 2019-08-02 - * @citation Liao, C., Tesfa, T., Duan, Z., & Leung, L. R. (2020). - * Watershed delineation on a hexagonal mesh grid. Environmental Modelling & Software, 104702. - * https://www.sciencedirect.com/science/article/pii/S1364815219308278 - * @github page https://github.com/changliao1025/hexwatershed - * @copyright Copyright (c) 2019 - * - */ -#pragma once -#include - -#include "hexagon.h" -#include "./json/JSONBase.h" -#include "./json/mesh.h" -#include "./json/cell.h" -#include "./json/basin.h" -#include "./json/multibasin.h" -using namespace std; -namespace hexwatershed -{ - class segment - { - public: - segment(); - - ~segment(); - - int nReach; - int iSegment; - int iSegmentIndex; - int iWatershed; //which watershed it belongs to - - int iSegment_downstream; - int iSegment_order; - int iFlag_headwater; - int iFlag_has_upstream; - int iFlag_has_downstream; - int nSegment_upstream; - - float dLength; //the total length of the stream segment - float dSlope_mean; //the average slope - float dElevation_drop; //elevation drop between headwater to outlet - float dDistance_to_watershed_outlet; - - std::vector vSegment_upstream; - - hexagon cReach_start; - hexagon cReach_end; - std::vector vReach_segment; - - //function - //sort - bool operator<(const segment &cSegment); - - int calculate_stream_segment_characteristics(); - int calculate_stream_segment_length(); - int calculate_stream_segment_slope(); - int calculate_travel_distance(); - }; -} // namespace hexwatershed diff --git a/external/hexwatershed/src/subbasin.cpp b/external/hexwatershed/src/subbasin.cpp deleted file mode 100755 index 7d2f019..0000000 --- a/external/hexwatershed/src/subbasin.cpp +++ /dev/null @@ -1,126 +0,0 @@ -// -// Created by Liao, Chang on 2020-09-07. -// - -#include "subbasin.h" - -namespace hexwatershed -{ - - subbasin::subbasin() - { - iSubbasinIndex=-1; - } - subbasin::~subbasin() - { - } - - int subbasin::calculate_subbasin_characteristics(float dLength_stream_conceptual) - { - int error_code = 1; - calculate_subbasin_total_area(); - calculate_subbasin_slope(); - calculate_subbasin_drainage_density(dLength_stream_conceptual); - return error_code; - } - - int subbasin::calculate_subbasin_total_area() - { - int error_code = 1; - float dArea_total = 0.0; - std::vector::iterator iIterator; - nCell = vCell.size(); - - for (iIterator = vCell.begin(); iIterator != vCell.end(); iIterator++) - { - if ((*iIterator).dArea < 0.0) - { - std::cout << "Something is wrong" << std::endl; - } - dArea_total = dArea_total + (*iIterator).dArea; - } - dArea = dArea_total; - if (dArea < 0.0) - { - std::cout << "Something is wrong" << std::endl; - } - - return error_code; - } - - int subbasin::calculate_subbasin_slope() - { - int error_code = 1; - int iOption = 1; - float dSlope_total = 0.0; - std::vector::iterator iIterator; - if (iOption == 1) // by cell - { - for (iIterator = vCell.begin(); iIterator != vCell.end(); iIterator++) - { - dSlope_total = dSlope_total + (*iIterator).dSlope_max_downslope; // should mean slope? - } - } - dSlope = dSlope_total / nCell; - dSlope_mean = dSlope; - return error_code; - } - int subbasin::calculate_subbasin_drainage_density(float dLength_stream_conceptual) - { - int error_code = 1; - dArea_2_stream_ratio = dArea / dLength_stream_conceptual; - - dLength_2_area_ratio = 1.0 / dArea_2_stream_ratio; - dDrainage_density = dLength_2_area_ratio; - - return error_code; - } - int subbasin::calculate_travel_distance() - { - int error_code = 1; - long lCellID_current; - long lCellIndex; - float dDistance_to_subbasin_outlet; - std::vector::iterator iIterator; - for (iIterator = vCell.begin(); iIterator != vCell.end(); iIterator++) - { - lCellID_current = (*iIterator).lCellID; - if (lCellID_current !=lCellID_outlet) - { - dDistance_to_subbasin_outlet = (*iIterator).dDistance_to_downslope; - lCellID_current = (*iIterator).lCellID_downslope_dominant; - while (lCellID_current != lCellID_outlet) - { - lCellIndex = subbasin_find_index_by_cellid(lCellID_current); - lCellID_current = vCell.at(lCellIndex).lCellID_downslope_dominant; - dDistance_to_subbasin_outlet = dDistance_to_subbasin_outlet + vCell.at(lCellIndex).dDistance_to_downslope; - } - - (*iIterator).dDistance_to_subbasin_outlet = dDistance_to_subbasin_outlet; - } - else - { - (*iIterator).dDistance_to_subbasin_outlet = 0.0; - } - - - } - - return error_code; - } - long subbasin::subbasin_find_index_by_cellid(long lCellID_in) - { - long lCellIndex_subbasin = -1; - std::vector::iterator iIterator; - for (iIterator = vCell.begin(); iIterator != vCell.end(); iIterator++) - { - if ((*iIterator).lCellID == lCellID_in) - { - lCellIndex_subbasin = (*iIterator).lCellIndex_subbasin; - break; - } - } - - return lCellIndex_subbasin; - } -} // namespace hexwatershed \ No newline at end of file diff --git a/external/hexwatershed/src/subbasin.h b/external/hexwatershed/src/subbasin.h deleted file mode 100755 index 2b26b8d..0000000 --- a/external/hexwatershed/src/subbasin.h +++ /dev/null @@ -1,48 +0,0 @@ -// -// Created by Liao, Chang on 2020-09-07. -// - -#pragma once -#include -#include "hexagon.h" -#include "./json/JSONBase.h" -#include "./json/mesh.h" -#include "./json/cell.h" -#include "./json/basin.h" -#include "./json/multibasin.h" -using namespace std; -namespace hexwatershed - { - class subbasin - { - public: - subbasin(); - - ~subbasin(); - - int iSubbasin; //each subbasin should have the same index with its segment - int iSubbasinIndex; - long nCell; - long lCellID_outlet; //the index of the subbasin outlet - float dArea; - float dSlope; - float dSlope_mean; - float dSlope_max; - float dSlope_min; - float dArea_2_stream_ratio; //the drainage density: https://en.wikipedia.org/wiki/Drainage_density - float dLength_2_area_ratio; //the drainage density: https://en.wikipedia.org/wiki/Drainage_density - float dDistance_to_subbasin_outlet; - float dDrainage_density; - hexagon cCell_outlet; //the outlet of this subbasin, this cell is actually within the subbasin because it is shared by multiple subbasin - std::vector vCell; - - - //function - int calculate_subbasin_characteristics(float dLength_stream_conceptual); - int calculate_subbasin_total_area(); - int calculate_subbasin_slope(); - int calculate_subbasin_drainage_density(float dLength_stream_conceptual); - int calculate_travel_distance(); - long subbasin_find_index_by_cellid(long lCellID_in); - }; - } // namespace hexwatershed diff --git a/external/hexwatershed/src/system.cpp b/external/hexwatershed/src/system.cpp deleted file mode 100755 index 5f67bbc..0000000 --- a/external/hexwatershed/src/system.cpp +++ /dev/null @@ -1,476 +0,0 @@ -/** - * @file system.cpp - * @author Chang Liao (chang.liao@pnnl.gov) - * @brief file and path operation functions - * @version 0.1 - * @date 2019-08-02 - * - * @copyright Copyright (c) 2019 - * - */ -#include "system.h" - -/** - * @brief test the existence of a file. not the most efficient, but easy to understand for now - * - * @param sFilename_in - * @return int - */ -int file_test(std::string sFilename_in) -{ - -#ifdef _WIN32 - //define something for Windows (32-bit and 64-bit, this part is common) - DWORD attribs = GetFileAttributesA(sFilename_in.c_str()); - if (attribs != INVALID_FILE_ATTRIBUTES) - { - if (attribs != FILE_ATTRIBUTE_DIRECTORY) - { - return 1; - } - else - { - return 0; - } - } - else - { - return 0; - } -#ifdef _WIN64 - //define something for Windows (64-bit only) -#else - //define something for Windows (32-bit only) -#endif -#elif __APPLE__ - struct stat sStat; - if (stat(sFilename_in.c_str(), &sStat) == 0) - { - if (S_ISREG(sStat.st_mode)) - { - return 1; - } - else - { - return 0; - } - } - else - { - return 0; - } -#if TARGET_IPHONE_SIMULATOR - // iOS Simulator -#elif TARGET_OS_IPHONE - // iOS device -#elif TARGET_OS_MAC - // Other kinds of Mac OS -#else -#error "Unknown Apple platform" -#endif -#elif __linux__ - // linux - struct stat sStat; - if (stat(sFilename_in.c_str(), &sStat) == 0) - { - if (S_ISREG(sStat.st_mode)) - { - return 1; - } - else - { - return 0; - } - } - else - { - return 0; - } -#elif __unix__ // all unices not caught above - // Unix -#elif defined(_POSIX_VERSION) - // POSIX -#else -#error "Unknown compiler" -#endif -} - -/** - * @brief recursive mkdir when it does not exist - * - * @param sDirectory_in - * @return int - */ -int make_directory(std::string sDirectory_in) -{ - - //the maximum length for current setting - int dir_err; - -#ifdef _WIN32 - //define something for Windows (32-bit and 64-bit, this part is common) - char tmp[MAX_PATH]; - char *p = NULL; - size_t len; - //50================================================== - //convert char * to cstring - //50================================================== - snprintf(tmp, sizeof(tmp), "%s", sDirectory_in.c_str()); - //50================================================== - len = strlen(tmp); - //50================================================== - //remove the last slash - //50================================================== - if (tmp[len - 1] == slash) - { - tmp[len - 1] = 0; - } - //50================================================== - for (p = tmp + 1; *p; p++) - { - if (*p == slash) - { - //50================================================== - // Temporarily truncate - //50================================================== - *p = 0; - - std::string temp(tmp); - if (path_test(temp) == false) - { - - dir_err = _mkdir(tmp); - } - //50================================================== - //recover the slash - //50================================================== - *p = slash; - } - } - //50================================================== - //final step - //50================================================== - - dir_err = _mkdir(tmp); - - if (-1 == dir_err) - { - cout << "Error creating directory!" << tmp << endl; - return 0; - } - else - { - return 1; - } -#ifdef _WIN64 - //define something for Windows (64-bit only) -#else - //define something for Windows (32-bit only) -#endif -#elif __APPLE__ - - char tmp[PATH_MAX]; - char *p = NULL; - size_t len; - //50================================================== - //convert char * to cstring - //50================================================== - snprintf(tmp, sizeof(tmp), "%s", sDirectory_in.c_str()); - //50================================================== - len = strlen(tmp); - //50================================================== - //remove the last slash - //50================================================== - if (tmp[len - 1] == slash) - { - tmp[len - 1] = 0; - } - //50================================================== - for (p = tmp + 1; *p; p++) - { - if (*p == slash) - { - //50================================================== - // Temporarily truncate - //50================================================== - *p = 0; - - std::string temp(tmp); - if (path_test(temp) == false) - { - - mkdir(tmp, S_IRWXU); - } - //50================================================== - //recover the slash - //50================================================== - *p = slash; - } - } - //50================================================== - //final step - //50================================================== - - dir_err = mkdir(tmp, S_IRWXU); - - if (-1 == dir_err) - { - cout << "Error creating directory!" << tmp << endl; - return 0; - } - else - { - return 1; - } -#if TARGET_IPHONE_SIMULATOR - // iOS Simulator -#elif TARGET_OS_IPHONE - // iOS device -#elif TARGET_OS_MAC - // Other kinds of Mac OS -#else -#error "Unknown Apple platform" -#endif -#elif __linux__ - // linux - char tmp[PATH_MAX]; - char *p = NULL; - size_t len; - //50================================================== - //convert char * to cstring - //50================================================== - snprintf(tmp, sizeof(tmp), "%s", sDirectory_in.c_str()); - //50================================================== - len = strlen(tmp); - //50================================================== - //remove the last slash - //50================================================== - if (tmp[len - 1] == slash) - { - tmp[len - 1] = 0; - } - //50================================================== - for (p = tmp + 1; *p; p++) - { - if (*p == slash) - { - //50================================================== - // Temporarily truncate - //50================================================== - *p = 0; - - std::string temp(tmp); - if (path_test(temp) == false) - { - - mkdir(tmp, S_IRWXU); - } - //50================================================== - //recover the slash - //50================================================== - *p = slash; - } - } - //50================================================== - //final step - //50================================================== - - dir_err = mkdir(tmp, S_IRWXU); - - if (-1 == dir_err) - { - cout << "Error creating directory!" << tmp << endl; - return 0; - } - else - { - return 1; - } -#elif __unix__ // all unices not caught above - // Unix -#elif defined(_POSIX_VERSION) - // POSIX -#else -#error "Unknown compiler" -#endif -} - -/** - * @brief test the existence of a path, use the stat header file - * - * @param sPath_in - * @return int - */ -int path_test(std::string sPath_in) -{ -#ifdef _WIN32 - DWORD attribs = GetFileAttributesA(sPath_in.c_str()); - if (attribs == FILE_ATTRIBUTE_DIRECTORY) - { - return 1; - } - else - { - return 0; - } - //define something for Windows (32-bit and 64-bit, this part is common) -#ifdef _WIN64 - //define something for Windows (64-bit only) -#else - //define something for Windows (32-bit only) -#endif -#elif __APPLE__ - - struct stat sStat; - if (stat(sPath_in.c_str(), &sStat) == 0) - { - if (S_ISDIR(sStat.st_mode)) - { - return 1; - } - else - { - return 0; - } - } - else - { - return 0; - } -#if TARGET_IPHONE_SIMULATOR - // iOS Simulator -#elif TARGET_OS_IPHONE - // iOS device -#elif TARGET_OS_MAC - // Other kinds of Mac OS -#else -#error "Unknown Apple platform" -#endif -#elif __linux__ - // linux - struct stat sStat; - if (stat(sPath_in.c_str(), &sStat) == 0) - { - if (S_ISDIR(sStat.st_mode)) - { - return 1; - } - else - { - return 0; - } - } - else - { - return 0; - } -#elif __unix__ // all unices not caught above - // Unix -#elif defined(_POSIX_VERSION) - // POSIX -#else -#error "Unknown compiler" -#endif -} - -/** - * @brief - * - * @param sCommand_in - * @return int - */ -int run_command(std::string sCommand_in) -{ - int error_code = 1; - -#ifdef _WIN32 - //define something for Windows (32-bit and 64-bit, this part is common) -#ifdef _WIN64 - //define something for Windows (64-bit only) -#else - //define something for Windows (32-bit only) -#endif -#elif __APPLE__ - - FILE *pFile; - char buffer[512]; - if (!(pFile = popen(sCommand_in.c_str(), "r"))) - { - error_code = 0; //failed to submit job - } - else - { - //get the output - while (fgets(buffer, sizeof(buffer), pFile) != NULL) - { - //prpFilet the output - std::cout << buffer << std::endl; - } - //close the output - pclose(pFile); - } -#if TARGET_IPHONE_SIMULATOR - // iOS Simulator -#elif TARGET_OS_IPHONE - // iOS device -#elif TARGET_OS_MAC - // Other kinds of Mac OS -#else -#error "Unknown Apple platform" -#endif -#elif __linux__ - // linux - FILE *pFile; - char buffer[512]; - if (!(pFile = popen(sCommand_in.c_str(), "r"))) - { - error_code = 0; //failed to submit job - } - else - { - //get the output - while (fgets(buffer, sizeof(buffer), pFile) != NULL) - { - //prpFilet the output - std::cout << buffer << std::endl; - } - //close the output - pclose(pFile); - } -#elif __unix__ // all unices not caught above - // Unix -#elif defined(_POSIX_VERSION) - // POSIX -#else -#error "Unknown compiler" -#endif - - return error_code; -} - -/** - * @brief Get the file size object - * - * @param sFilename_in - * @return long - */ -long get_file_size(std::string sFilename_in) -{ - std::ifstream ifs; - std::streampos fsize; - long lfsize; - ifs.open(sFilename_in, std::ifstream::ate | std::ifstream::binary); - if (ifs.good()) - { - fsize = ifs.tellg(); - //convert the type to long, be careful with this operation!!! - lfsize = long(fsize); - } - else - { - lfsize = -1; - } - //close the file - ifs.close(); - return lfsize; -} diff --git a/external/hexwatershed/src/system.h b/external/hexwatershed/src/system.h deleted file mode 100755 index 9541f27..0000000 --- a/external/hexwatershed/src/system.h +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @file system.h - * @author Chang Liao (chang.liao@pnnl.gov) - * @brief This class provide some cross platform system operations - * @version 0.1 - * @date 2019-08-02 - * @citation Liao, C., Tesfa, T., Duan, Z., & Leung, L. R. (2020). - * Watershed delineation on a hexagonal mesh grid. Environmental Modelling & Software, 104702. - * https://www.sciencedirect.com/science/article/pii/S1364815219308278 - * @github page https://github.com/changliao1025/hexwatershed - * @copyright Copyright (c) 2019 - * - */ -#pragma once -//the global variables for all other modules -//c library -#include -#include -#include -//c++ library - -#include -#include - -#include -//50================================================== -//cros-platform header -#ifdef _WIN32 -//define something for Windows (32-bit and 64-bit, this part is common) -#include -#include -#ifdef _WIN64 -//define something for Windows (64-bit only) -#else -//define something for Windows (32-bit only) -#endif -#elif __APPLE__ -#include -#include -#if TARGET_IPHONE_SIMULATOR -// iOS Simulator -#elif TARGET_OS_IPHONE -// iOS device -#elif TARGET_OS_MAC -// Other kinds of Mac OS -#else -#error "Unknown Apple platform" -#endif -#elif __linux__ -// linux -#include -#include -#elif __unix__ // all unices not caught above -// Unix -#elif defined(_POSIX_VERSION) -// POSIX -#else -#error "Unknown compiler" -#endif - -//50================================================== -#include "global.h" - -//50================================================== -using namespace std; -//50================================================== -//functions -//50================================================== - -//50================================================== -//test whether a file exists or not -//50================================================== -int file_test(std::string sFilename); - -//50================================================== -//make directory () -//50================================================== -int make_directory(std::string sDirectory); - -//50================================================== -//check whether a directory exists or not -//50================================================== -int path_test(std::string sPath); - -int run_command(std::string sCommand); - -long get_file_size(std::string sFilename); diff --git a/external/hexwatershed/src/watershed.cpp b/external/hexwatershed/src/watershed.cpp deleted file mode 100755 index f072932..0000000 --- a/external/hexwatershed/src/watershed.cpp +++ /dev/null @@ -1,1259 +0,0 @@ -/** - * @file watershed.cpp - * @author Chang Liao (chang.liao@pnnl.gov) - * @brief - * @version 0.1 - * @date 2019-08-02 - * - * @copyright Copyright (c) 2019 - * - */ - -#include "watershed.h" - -namespace hexwatershed -{ - watershed::watershed() - { - iWatershed = -1; - } - - watershed::~watershed() - { - } - - int watershed::watershed_define_stream_confluence() - { - int error_code = 1; - int iCount = 0; - nSegment = 0; - nConfluence = 0; - long lCellID_downstream; - long lCellIndex_downstream; - std::vector::iterator iIterator_self; - - iCount = 0; - - for (iIterator_self = vCell.begin(); iIterator_self != vCell.end(); iIterator_self++) - { - // we only consider cells within the watershed - if ((*iIterator_self).iFlag_stream == 1 && (*iIterator_self).iWatershed == iWatershed) - { - lCellID_downstream = (*iIterator_self).lCellID_downslope_dominant; - lCellIndex_downstream = watershed_find_index_by_cell_id(lCellID_downstream); - if (lCellIndex_downstream != -1) - { - (vCell.at(lCellIndex_downstream)).vUpstream.push_back((*iIterator_self).lCellID); // use id instead of index - } - else - { - // std::cout << (*iIterator_self).lCellIndex << ", outlet is: " << lCellIndex_downstream << std::endl; - } - } - } - // sum up the size the upstream - for (iIterator_self = vCell.begin(); iIterator_self != vCell.end(); iIterator_self++) - { - (*iIterator_self).nUpstream = ((*iIterator_self).vUpstream).size(); - } - // calculate total segment - vConfluence.clear(); - for (iIterator_self = vCell.begin(); iIterator_self != vCell.end(); iIterator_self++) - { - if ((*iIterator_self).nUpstream > 1 && (*iIterator_self).iWatershed == iWatershed && (*iIterator_self).iFlag_stream == 1) - { - iCount = iCount + 1; - (*iIterator_self).iFlag_confluence = 1; - - vConfluence.push_back((*iIterator_self)); - } - } - nConfluence = iCount; - nSegment = 1; - for (iIterator_self = vConfluence.begin(); iIterator_self != vConfluence.end(); iIterator_self++) - { - nSegment = nSegment + (*iIterator_self).vUpstream.size(); - } - nSubbasin = nSegment; - // sort cannot be used directly here - - return error_code; - } - int watershed::watershed_define_stream_segment() - { - int error_code = 1; - long lCellIndex_outlet; // this is a local variable for each subbasin - int iFlag_confluence; - int iFlag_headwater; - - int iUpstream; - - long lCellIndex_current; - long lCellID_current; - long lCellID_upstream; - - lCellIndex_outlet = watershed_find_index_by_cell_id(lCellID_outlet); - iFlag_confluence = vCell.at(lCellIndex_outlet).iFlag_confluence; - lCellIndex_current = vCell.at(lCellIndex_outlet).lCellIndex_watershed; - lCellID_current = vCell.at(lCellIndex_outlet).lCellID; - vSegment.clear(); - segment cSegment; - std::vector vReach_segment; - vCell.at(lCellIndex_outlet).iFlag_last_reach = 1; - - - if (nSegment == 1) //these is only one segment in this watershed - { - iSegment_current = nSegment; - vCell.at(lCellIndex_outlet).iSegment = iSegment_current; - vReach_segment.push_back(vCell.at(lCellIndex_outlet)); - iFlag_headwater = 0; - while (iFlag_headwater != 1) - { - iUpstream = vCell.at(lCellIndex_current).nUpstream; - if (iUpstream == 1) // - { - lCellID_upstream = (vCell.at(lCellIndex_current)).vUpstream[0]; - lCellIndex_current = watershed_find_index_by_cell_id(lCellID_upstream); - vCell.at(lCellIndex_current).iSegment = iSegment_current; - vReach_segment.push_back(vCell.at(lCellIndex_current)); - } - else - { // headwater - vCell.at(lCellIndex_current).iFlag_first_reach = 1; - lCellID_current = vCell.at(lCellIndex_current).lCellID; - iFlag_headwater = 1; - } - } - - // this is the last reach of a segment - std::reverse(vReach_segment.begin(), vReach_segment.end()); - cSegment.vReach_segment = vReach_segment; - cSegment.nReach = vReach_segment.size(); - cSegment.cReach_start = vReach_segment.front(); - cSegment.cReach_end = vReach_segment.back(); - cSegment.iSegment = 1; - cSegment.iSegmentIndex = cSegment.iSegment - 1; // - cSegment.iSegment; - cSegment.nSegment_upstream = cSegment.cReach_start.nUpstream; - cSegment.iFlag_has_upstream = 0; - cSegment.iWatershed = iWatershed; - cSegment.iFlag_has_downstream = 0; //it has no downstream - cSegment.iFlag_headwater = 1; - vSegment.push_back(cSegment); - } - else - { - iSegment_current = nSegment; - vCell.at(lCellIndex_outlet).iSegment = iSegment_current; - vReach_segment.push_back(vCell.at(lCellIndex_outlet)); - if (iFlag_confluence == 1) // the outlet is actually a confluence - { - cSegment.vReach_segment = vReach_segment; - cSegment.nReach = 1; - cSegment.cReach_start = vReach_segment.front(); - cSegment.cReach_end = vReach_segment.back(); - cSegment.iSegment = nSegment; - cSegment.iSegmentIndex = cSegment.iSegment - 1; //- cSegment.iSegment; - cSegment.nSegment_upstream = cSegment.cReach_start.nUpstream; - cSegment.iFlag_has_upstream = 1; - cSegment.iFlag_has_downstream = 0; - cSegment.iWatershed = iWatershed; - vSegment.push_back(cSegment); - } - else - { - while (iFlag_confluence != 1) - { - iUpstream = vCell.at(lCellIndex_current).nUpstream; - if (iUpstream == 1) // - { - lCellID_upstream = (vCell.at(lCellIndex_current)).vUpstream[0]; - lCellIndex_current = watershed_find_index_by_cell_id(lCellID_upstream); - vCell.at(lCellIndex_current).iSegment = iSegment_current; - vReach_segment.push_back(vCell.at(lCellIndex_current)); - } - else - { // headwater - //vCell.at(lCellIndex_current).iSegment = iSegment_current; - vCell.at(lCellIndex_current).iFlag_first_reach = 1; - lCellID_current = vCell.at(lCellIndex_current).lCellID; - //vReach_segment.push_back(vCell.at(lCellIndex_current)); - iFlag_confluence = 1; - //std::cout << lCellID_current << std::endl; - } - } - - // this is the last reach of a segment - std::reverse(vReach_segment.begin(), vReach_segment.end()); - cSegment.vReach_segment = vReach_segment; - cSegment.nReach = vReach_segment.size(); - cSegment.cReach_start = vReach_segment.front(); - cSegment.cReach_end = vReach_segment.back(); - cSegment.iSegment = nSegment; - cSegment.iSegmentIndex = cSegment.iSegment - 1; // - cSegment.iSegment; - cSegment.nSegment_upstream = cSegment.cReach_start.nUpstream; - cSegment.iFlag_has_upstream = 1; - cSegment.iWatershed = iWatershed; - cSegment.iFlag_has_downstream = 0; - if (cSegment.cReach_start.iFlag_headwater == 1) - { - cSegment.iFlag_headwater = 1; - } - vSegment.push_back(cSegment); - } - iSegment_current = iSegment_current - 1; - watershed_tag_confluence_upstream(lCellID_current); - // in fact the segment is ordered by default already, just reservely - // std::sort(vSegment.begin(), vSegment.end()); - std::reverse(vSegment.begin(), vSegment.end()); - } - return error_code; - } - int watershed::watershed_tag_confluence_upstream(long lCellID_confluence) - { - int error_code = 1; - int nUpstream; - int iFlag_first_reach; - int iFlag_confluence; - int iSegment_confluence; - long lCellID_upstream; - long lCellIndex_upstream; - segment cSegment; // be careful with the scope - std::vector vUpstream; - std::vector::iterator iterator_upstream; - std::vector vReach_segment; - - long lCellIndex_confluence = watershed_find_index_by_cell_id(lCellID_confluence); - - // if may not be necessary to use these flags in this algorithm because it will only search for the segment - vUpstream = vCell.at(lCellIndex_confluence).vUpstream; - iSegment_confluence = vCell.at(lCellIndex_confluence).iSegment; - for (iterator_upstream = vUpstream.begin(); - iterator_upstream != vUpstream.end(); - iterator_upstream++) - { - lCellID_upstream = *iterator_upstream; - lCellIndex_upstream = watershed_find_index_by_cell_id(lCellID_upstream); - iFlag_first_reach = 0; - // remember that it is possible a segment only has one reach - iFlag_confluence = vCell.at(lCellIndex_upstream).iFlag_confluence; - vCell.at(lCellIndex_upstream).iFlag_last_reach = 1; - // use last reach to find next stream segment - vCell.at(lCellIndex_upstream).iSegment_downstream = vCell.at(lCellIndex_confluence).iSegment; - vReach_segment.clear(); - - // if the immediate upstream is also confluence: 1-1, we can quickly setup then move on - // to the confluence - if (iFlag_confluence == 1) - { - // continuous confluence, in this case, we need to set only one reach and move on - nUpstream = (vCell.at(lCellIndex_upstream)).nUpstream; - // we need to set 4 importnat attributes - vCell.at(lCellIndex_upstream).iSegment = iSegment_current; - (vCell.at(lCellIndex_upstream)).iFlag_first_reach = 1; - //(vCell.at(lCellIndex_upstream)).iFlag_last_reach = 1; - (vCell.at(lCellIndex_upstream)).iFlag_headwater = 0; - - vReach_segment.push_back(vCell.at(lCellIndex_upstream)); - // it has only one reach - cSegment.vReach_segment = vReach_segment; - cSegment.nReach = vReach_segment.size(); - cSegment.cReach_start = vReach_segment.front(); - cSegment.cReach_end = vReach_segment.back(); - cSegment.iSegment = iSegment_current; - cSegment.iSegmentIndex = cSegment.iSegment - 1; //- cSegment.iSegment; - cSegment.iFlag_has_downstream = 1; - cSegment.iFlag_has_upstream = 1; - cSegment.iFlag_headwater = 0; - cSegment.iWatershed = iWatershed; - cSegment.iSegment_downstream = iSegment_confluence; - // add the segment to the watershed object - vSegment.push_back(cSegment); - - // update segment index - iSegment_current = iSegment_current - 1; - watershed_tag_confluence_upstream(lCellID_upstream); - } - else - { - // if there is at least one reach that is not a confluence: 1-0-1 or 1-0-2 - while (iFlag_confluence != 1) // 1-0-1 - { - // it has only one upstream - nUpstream = (vCell.at(lCellIndex_upstream)).nUpstream; - (vCell.at(lCellIndex_upstream)).iSegment = iSegment_current; - if (nUpstream == 0) - { - // this is the headwater, 1-0-2 - iFlag_first_reach = 1; - (vCell.at(lCellIndex_upstream)).iFlag_first_reach = 1; - (vCell.at(lCellIndex_upstream)).iFlag_headwater = 1; - vReach_segment.push_back(vCell.at(lCellIndex_upstream)); - break; - } - else - { - // 1-0-0 - (vCell.at(lCellIndex_upstream)).iFlag_last_reach = 0; - (vCell.at(lCellIndex_upstream)).iFlag_first_reach = 0; - (vCell.at(lCellIndex_upstream)).iFlag_headwater = 0; - vReach_segment.push_back(vCell.at(lCellIndex_upstream)); - // we are on the stream segment and there is only one upstream - // move to upstream - lCellID_upstream = (vCell.at(lCellIndex_upstream)).vUpstream[0]; - lCellIndex_upstream = watershed_find_index_by_cell_id(lCellID_upstream); - iFlag_confluence = vCell.at(lCellIndex_upstream).iFlag_confluence; - // should not add now - } - } - // either we reach the headwater or we find the next confluence - if (iFlag_first_reach == 1) - { - // it is already been pushed back - cSegment.iFlag_has_upstream = 0; - cSegment.iFlag_headwater = 1; - } - else - { - // this is a new confluence, so we need to push it back - (vCell.at(lCellIndex_upstream)).iSegment = iSegment_current; - (vCell.at(lCellIndex_upstream)).iFlag_last_reach = 0; - (vCell.at(lCellIndex_upstream)).iFlag_first_reach = 1; - (vCell.at(lCellIndex_upstream)).iFlag_headwater = 0; - vReach_segment.push_back(vCell.at(lCellIndex_upstream)); - - cSegment.iFlag_has_upstream = 1; - cSegment.iFlag_headwater = 0; - } - - std::reverse(vReach_segment.begin(), vReach_segment.end()); - cSegment.vReach_segment = vReach_segment; - cSegment.nReach = vReach_segment.size(); - cSegment.cReach_start = vReach_segment.front(); - cSegment.cReach_end = vReach_segment.back(); - cSegment.iSegment = iSegment_current; - cSegment.iSegmentIndex = cSegment.iSegment - 1; // nSegment - cSegment.iSegment; - cSegment.iFlag_has_downstream = 1; - cSegment.iWatershed = iWatershed; - cSegment.iSegment_downstream = iSegment_confluence; - vSegment.push_back(cSegment); - iSegment_current = iSegment_current - 1; - if (iFlag_first_reach != 1) - { - watershed_tag_confluence_upstream(lCellID_upstream); - } - } - } - - return error_code; - } - - /** - * build the stream topology based on stream segment information - * @return - */ - int watershed::watershed_build_stream_topology() - { - int error_code = 1; - int iSegment; - // rebuild stream topology - std::vector::iterator iIterator_segment_self; - std::vector::iterator iIterator_segment; - - if (nSegment ==1) - { - vSegment.at(0).nSegment_upstream = 0; - vSegment.at(0).vSegment_upstream.clear(); - } - else - { - for (iIterator_segment_self = vSegment.begin(); - iIterator_segment_self != vSegment.end(); - iIterator_segment_self++) - { - iSegment = (*iIterator_segment_self).iSegment_downstream; - for (iIterator_segment = vSegment.begin(); - iIterator_segment != vSegment.end(); - iIterator_segment++) - { - if (iSegment == (*iIterator_segment).iSegment) - { - (*iIterator_segment).vSegment_upstream.push_back((*iIterator_segment_self).iSegment); - } - } - } - for (iIterator_segment = vSegment.begin(); - iIterator_segment != vSegment.end(); - iIterator_segment++) - { - (*iIterator_segment).nSegment_upstream = (*iIterator_segment).vSegment_upstream.size(); - } - } - - - return error_code; - } - - /** - * build the stream order based on stream topology - * @return - */ - int watershed::watershed_define_stream_order() - { - int error_code = 1; - int iSegment; - int iUpstream; - int iStream_order_max; - int iFlag_all_upstream_done; - - std::vector vStream_order; - - std::vector::iterator iIterator_segment; - - if (nSegment==1) - { - vSegment.at(0).iSegment_order = 1; - } - else - { - - for (iIterator_segment = vSegment.begin(); - iIterator_segment != vSegment.end(); - iIterator_segment++) - { - if ((*iIterator_segment).iFlag_headwater == 1) - { - (*iIterator_segment).iSegment_order = 1; - } - } - - while (vSegment.back().iSegment_order == -1) - { - for (iIterator_segment = vSegment.begin(); - iIterator_segment != vSegment.end(); - iIterator_segment++) - { - - if ((*iIterator_segment).iSegment_order == -1) - { - iFlag_all_upstream_done = 1; - vStream_order.clear(); - for (iUpstream = 0; - iUpstream < (*iIterator_segment).nSegment_upstream; - iUpstream++) - { - iSegment = (*iIterator_segment).vSegment_upstream.at(iUpstream); - if (vSegment.at(iSegment - 1).iSegment_order == -1) - { - iFlag_all_upstream_done = 0; - } - else - { - vStream_order.push_back(vSegment.at(iSegment - 1).iSegment_order); - } - } - - if (iFlag_all_upstream_done == 1) - { - if (vStream_order.at(0) == vStream_order.at(1)) - { - (*iIterator_segment).iSegment_order = vStream_order.at(0) + 1; - } - else - { - iStream_order_max = (*max_element(std::begin(vStream_order), std::end(vStream_order))); // c++11 - (*iIterator_segment).iSegment_order = iStream_order_max; - } - } - } - else - { - // finished - } - } - } - - } - return error_code; - } - int watershed::watershed_define_subbasin_old() - { - - int error_code = 1; - int iFound_outlet; - int iFlag_checked; - int iSubbasin; - long lCellIndex_self; - long lCellIndex_current; - long lCellID_outlet; - long lCellIndex_outlet; // local outlet - long lCellIndex_subbasin; - long lCellID_downslope; - long lCellIndex_downslope; - long lCellIndex_accumulation; - std::vector vAccumulation; - std::vector::iterator iterator_accumulation; - std::vector vConfluence_copy(vConfluence); - std::vector::iterator iIterator_self; - std::vector::iterator iIterator_upstream; - std::vector::iterator iIterator_current; - - // the whole watershed first - for (iIterator_self = vCell.begin(); iIterator_self != vCell.end(); iIterator_self++) - { - (*iIterator_self).iFlag_checked = 0; - if ((*iIterator_self).iWatershed == iWatershed) // not using flag anymore - { - (*iIterator_self).iSubbasin = nSegment; - } - } - - for (iIterator_self = vConfluence_copy.begin(); iIterator_self != vConfluence_copy.end(); iIterator_self++) - { - vAccumulation.push_back((*iIterator_self).dAccumulation); - } - - - - // now starting from the confluences loop, vConfluence_copy is only usable for one watershed - while (vConfluence_copy.size() != 0) - { - iterator_accumulation = min_element(std::begin(vAccumulation), std::end(vAccumulation)); - lCellIndex_accumulation = std::distance(vAccumulation.begin(), iterator_accumulation); - std::vector vUpstream((vConfluence_copy.at(lCellIndex_accumulation)).vUpstream); - for (iIterator_upstream = vUpstream.begin(); iIterator_upstream != vUpstream.end(); iIterator_upstream++) - { - // use the watershed method again here - lCellID_outlet = *iIterator_upstream; - lCellIndex_outlet = watershed_find_index_by_cell_id(lCellID_outlet); - iSubbasin = (vCell.at(lCellIndex_outlet)).iSegment; - (vCell.at(lCellIndex_outlet)).iSubbasin = iSubbasin; - for (iIterator_self = vCell.begin(); iIterator_self != vCell.end(); iIterator_self++) - { - iFound_outlet = 0; - lCellIndex_current = (*iIterator_self).lCellIndex_watershed; - iFlag_checked = (*iIterator_self).iFlag_checked; - if (iFlag_checked==1) - { - continue; - } - while (iFound_outlet != 1) - { - lCellID_downslope = vCell.at(lCellIndex_current).lCellID_downslope_dominant; - if (lCellID_outlet == lCellID_downslope) - { - - iFound_outlet = 1; - (*iIterator_self).iSubbasin = iSubbasin; - (*iIterator_self).iFlag_checked=1; - } - else - { - lCellIndex_current = watershed_find_index_by_cell_id(lCellID_downslope); - if (lCellIndex_current == -1) - { - // this one does not belong in this watershed - iFound_outlet = 1; - } - else - { - lCellID_downslope = vCell.at(lCellIndex_current).lCellID_downslope_dominant; - if (lCellID_downslope == -1) - { - // this is the outlet - iFound_outlet = 1; - //(*iIterator_self).iFlag_checked=1; - } - else - { - // std::cout << lCellID_downslope << std::endl; - } - } - } - } - } - } - - // remove the confluence now - vAccumulation.erase(iterator_accumulation); - vConfluence_copy.erase(vConfluence_copy.begin() + lCellIndex_accumulation); - // repeat - } - - // assign watershed subbasin cell, maybe later? - vSubbasin.clear(); - for (int iSubbasin = 1; iSubbasin <= nSubbasin; iSubbasin++) - { - subbasin cSubbasin; - cSubbasin.iSubbasin = iSubbasin; - cSubbasin.iSubbasinIndex = cSubbasin.iSubbasin - 1; - vSubbasin.push_back(cSubbasin); - } - - for (int iSubbasin = 1; iSubbasin <= nSubbasin; iSubbasin++) - { - lCellIndex_subbasin = 0; - for (iIterator_self = vCell.begin(); iIterator_self != vCell.end(); iIterator_self++) - { - int iSubbasin_dummy = (*iIterator_self).iSubbasin; - if (iSubbasin_dummy == iSubbasin) - { - (*iIterator_self).lCellIndex_subbasin = lCellIndex_subbasin; - (vSubbasin[iSubbasin - 1]).vCell.push_back(*iIterator_self); - lCellIndex_subbasin = lCellIndex_subbasin + 1; - } - else - { - if (iSubbasin_dummy == -1) - { - std::cout << "Something is wrong" << std::endl; - } - } - } - } - - return error_code; - } - //The new method for performance improvement - int watershed::watershed_define_subbasin() - { - - int error_code = 1; - int iFound_outlet; - int iFlag_checked; - int iFlag_checked_downslope; - int iSubbasin; - long lCellIndex_self; - long lCellIndex_current; - long lCellID_outlet; - long lCellIndex_outlet; // local outlet - long lCellIndex_subbasin; - long lCellID_downslope; - long lCellIndex_downslope; - long lCellIndex_accumulation; - long lIndex_confluence; - std::vector vAccumulation; - std::vector::iterator iterator_accumulation; - std::vector::iterator iIterator_self; - std::vector::iterator iIterator_path; - std::vector::iterator iIterator_current; - std::vector vSearchPath; - // assign watershed subbasin cell, maybe later? - vSubbasin.clear(); - for (int iSubbasin = 1; iSubbasin <= nSubbasin; iSubbasin++) - { - subbasin cSubbasin; - cSubbasin.iSubbasin = iSubbasin; - cSubbasin.iSubbasinIndex = cSubbasin.iSubbasin - 1; - vSubbasin.push_back(cSubbasin); - } - // the whole watershed first - - //reset flag, we set all segment cell as - for (iIterator_self = vCell.begin(); iIterator_self != vCell.end(); iIterator_self++) - { - if ((*iIterator_self).iSegment >= 1) - { - iSubbasin = (*iIterator_self).iSegment; - (*iIterator_self).iFlag_checked = 1; - (*iIterator_self).iSubbasin = iSubbasin; - (*iIterator_self).lCellIndex_subbasin = vSubbasin.at(iSubbasin-1).vCell.size(); - vSubbasin.at(iSubbasin-1).vCell.push_back((*iIterator_self)); - } - else - { - (*iIterator_self).iFlag_checked = 0; - } - } - - for (iIterator_self = vCell.begin(); iIterator_self != vCell.end(); iIterator_self++) - { - lCellIndex_current = (*iIterator_self).lCellIndex_watershed; - iFlag_checked = (*iIterator_self).iFlag_checked; - if(iFlag_checked == 0) - { - vSearchPath.clear(); - while(iFlag_checked_downslope==0) - {//not found keep adding to path - vSearchPath.push_back(lCellIndex_current); - lCellID_downslope = vCell.at(lCellIndex_current).lCellID_downslope_dominant; - lCellIndex_current = watershed_find_index_by_cell_id(lCellID_downslope); - if (lCellIndex_current != -1) - { - iFlag_checked_downslope = vCell.at(lCellIndex_current).iFlag_checked; - } - else - { - std::cout << "This shouldn't happen!" << std::endl; - } - } - iSubbasin = vCell.at(lCellIndex_current).iSubbasin; - for (iIterator_path = vSearchPath.begin(); iIterator_path != vSearchPath.end(); iIterator_path++) - { - vCell.at(*iIterator_path).iSubbasin = iSubbasin; - vCell.at(*iIterator_path).iFlag_checked = 1; - vCell.at(*iIterator_path).lCellIndex_subbasin = vSubbasin.at(iSubbasin-1).vCell.size(); - vSubbasin.at(iSubbasin-1).vCell.push_back( vCell.at(*iIterator_path) ); - - } - } - } - return error_code; - } - int watershed::watershed_update_attribute() - { - int error_code = 1; - int iFlag_found; - long lCellID; - long lCellID2; - long lCellIndex_watershed; - std::vector::iterator iIterator_self; - std::vector::iterator iIterator1; - std::vector::iterator iIterator2; - - - for (int iSubbasin = 1; iSubbasin <= nSubbasin; iSubbasin++) - { - for (iIterator2 = vSubbasin.at(iSubbasin - 1).vCell.begin(); iIterator2 != vSubbasin.at(iSubbasin - 1).vCell.end(); iIterator2++) - { - lCellIndex_watershed = (*iIterator2).lCellIndex_watershed; - vCell.at(lCellIndex_watershed).iSubbasin = (*iIterator2).iSubbasin; - vCell.at(lCellIndex_watershed).dDistance_to_subbasin_outlet = (*iIterator2).dDistance_to_subbasin_outlet; - vCell.at(lCellIndex_watershed).dDistance_to_watershed_outlet = (*iIterator2).dDistance_to_watershed_outlet; - } - } - - - return error_code; - } - - /** - * calculate the watershed characteristics - * @return - */ - int watershed::calculate_watershed_characteristics() - { - int error_code = 1; - int iSegment; - int iSegment_downstream; - int iSegmentIndex; - float dLength; - float dDistance_to_watershed_outlet; - float dLength_stream_conceptual; - - std::vector::iterator iIterator0; - std::vector::iterator iIterator2; - std::vector::iterator iIterator1; - - for (iIterator0 = vSegment.begin(); iIterator0 != vSegment.end(); iIterator0++) - { - (*iIterator0).calculate_stream_segment_characteristics(); - } - for (iIterator0 = vSegment.begin(); iIterator0 != vSegment.end(); iIterator0++) - { - if ((*iIterator0).iSegment == nSegment) - { - // this is the last segment - (*iIterator0).dDistance_to_watershed_outlet = 0.0; - } - else - { - iSegment_downstream = (*iIterator0).iSegment_downstream; - dDistance_to_watershed_outlet = 0.0; //(*iIterator0).dLength; - while (iSegment_downstream != nSegment) - { - iSegmentIndex = watershed_find_index_by_segment_id(iSegment_downstream); - dLength = vSegment.at(iSegmentIndex).dLength; - dDistance_to_watershed_outlet = dDistance_to_watershed_outlet + dLength; - iSegment_downstream = vSegment.at(iSegmentIndex).iSegment_downstream; - } - //add last segment - iSegmentIndex = watershed_find_index_by_segment_id(iSegment_downstream); - dDistance_to_watershed_outlet = dDistance_to_watershed_outlet + vSegment.at(iSegmentIndex).dLength; - - (*iIterator0).dDistance_to_watershed_outlet = dDistance_to_watershed_outlet; - } - } - - for (int iSubbasin = 1; iSubbasin <= nSubbasin; iSubbasin++) - { - iSegment = iSubbasin; - vSubbasin.at(iSubbasin - 1).cCell_outlet = vSegment.at(iSegment - 1).cReach_end; - vSubbasin.at(iSubbasin - 1).lCellID_outlet = vSegment.at(iSegment - 1).cReach_end.lCellID; - dLength_stream_conceptual = vSegment.at(iSegment - 1).dLength; - vSubbasin.at(iSubbasin - 1).calculate_subbasin_characteristics(dLength_stream_conceptual); - } - - calculate_travel_distance(); - watershed_update_attribute(); - calculate_watershed_drainage_area(); - calculate_watershed_total_stream_length(); - calculate_watershed_longest_stream_length(); - calculate_watershed_drainage_density(); - calculate_watershed_average_slope(); - calculate_topographic_wetness_index(); - - // save watershed characteristics to the file - - //std::cout << "The watershed characteristics are calculated successfully!" << std::endl; - - return error_code; - } - - /** - * calculate the watershed drainage total area - * we can either sum up hexagon or sum up subbasin - * @return - */ - int watershed::calculate_watershed_drainage_area() - { - int error_code = 1; - int iOption = 2; // sum up subbasin - - float dArea_total = 0.0; - std::vector::iterator iIterator; - std::vector::iterator iIterator1; - if (iOption == 1) - { - for (iIterator = vCell.begin(); iIterator != vCell.end(); iIterator++) - { - dArea_total = dArea_total + (*iIterator).dArea; - } - } - else - { - for (iIterator1 = vSubbasin.begin(); iIterator1 != vSubbasin.end(); iIterator1++) - { - dArea_total = dArea_total + (*iIterator1).dArea; - } - } - dArea = dArea_total; - return error_code; - } - - /** - * calculate the total stream length - * @return - */ - int watershed::calculate_watershed_total_stream_length() - { - int error_code = 1; - int iOption = 2; // sum up subbasin - - float dLength_total = 0.0; - - std::vector::iterator iIterator; - std::vector::iterator iIterator1; - if (iOption == 1) - { - for (iIterator = vCell.begin(); iIterator != vCell.end(); iIterator++) - { - - if ((*iIterator).iFlag_stream == 1) - { - // should have calculated dLength_stream_conceptual by now - dLength_total = dLength_total + (*iIterator).dLength_stream_conceptual; - } - } - } - else - { - for (iIterator1 = vSegment.begin(); iIterator1 != vSegment.end(); iIterator1++) - { - dLength_total = dLength_total + (*iIterator1).dLength; - } - } - - dLength_stream_conceptual = dLength_total; - - return error_code; - } - - /** - * calculate the longest stream length - * @return - */ - int watershed::calculate_watershed_longest_stream_length() - { - int error_code = 1; - - float dLength_longest = 0.0; - float dLength_stream_conceptual; - - // loop through head water - std::vector::iterator iIterator; - - for (iIterator = vSegment.begin(); iIterator != vSegment.end(); iIterator++) - { - dLength_stream_conceptual = (*iIterator).dLength; - if (dLength_stream_conceptual > dLength_longest) - { - dLength_longest = dLength_stream_conceptual; - } - } - - dLongest_length_stream = dLength_longest; - - return error_code; - } - - /** - * calculate the watershed area to stream length ratio - * @return - */ - int watershed::calculate_watershed_drainage_density() - { - int error_code = 1; - - float dRatio = 0.0; - - if (dLength_stream_conceptual > 0) - { - dRatio = dArea / dLength_stream_conceptual; - } - - dArea_2_stream_ratio = dRatio; - dLength_2_area_ratio = 1.0 / dRatio; - dDrainage_density = dLength_2_area_ratio; - - return error_code; - } - - /** - * calculate the mean slope of the watershed - * we can use either subbasin or each cell - * @return - */ - int watershed::calculate_watershed_average_slope() - { - int error_code = 1; - int iOption = 1; - float dSlope_total = 0.0; - std::vector::iterator iIterator; - std::vector::iterator iIterator1; - - nCell = vCell.size(); - if (iOption == 1) // by cell - { - for (iIterator = vCell.begin(); iIterator != vCell.end(); iIterator++) - { - dSlope_total = dSlope_total + (*iIterator).dSlope_max_downslope; // should mean slope? - } - } - else // by subbasin - { - for (iIterator1 = vSubbasin.begin(); iIterator1 != vSubbasin.end(); iIterator1++) - { - dSlope_total = dSlope_total + (*iIterator1).dSlope; - } - } - - dSlope = dSlope_total / nCell; - dSlope_mean = dSlope; - return error_code; - } - - /** - * calculate the TWI index using method from //https://en.wikipedia.org/wiki/Topographic_wetness_index - * // {\displaystyle \ln {a \over \tan b}} - * @return - */ - int watershed::calculate_topographic_wetness_index() - { - int error_code = 1; - float a; - float b; - float c; - float d; - float dTwi; - std::vector::iterator iIterator; - // can use openmp - for (iIterator = vCell.begin(); iIterator != vCell.end(); iIterator++) - { - // if ((*iIterator).iFlag_outlet == 1) - //{ - // (*iIterator).dTwi = -1; - // } - // else - //{ - a = float(((*iIterator).dAccumulation)); - b = (*iIterator).dSlope_max_downslope; - c = tan(b); - if (a == 0 || c == 0) - { - std::cout << a << b << c << std::endl; - } - dTwi = log2(a / c); - if (isnan(float(dTwi))) - { - std::cout << a << b << c << std::endl; - } - (*iIterator).dTwi = dTwi; - //} - } - - return error_code; - } - - int watershed::calculate_travel_distance() - { - int error_code = 1; - int iSegment; - int iSubbasin; - int iSegment_downstream; - int iSegmentIndex; - float dDistance_to_watershed_outlet; - // calculate confluence travel - std::vector::iterator iIterator; - std::vector::iterator iIterator0; - std::vector::iterator iIterator1; - - - for (iIterator1 = vSubbasin.begin(); iIterator1 != vSubbasin.end(); iIterator1++) - { - (*iIterator1).calculate_travel_distance(); - } - - for ( iSubbasin = 1; iSubbasin <= nSubbasin; iSubbasin++) - { - iSegment= iSubbasin; - if (iSubbasin == nSubbasin) - { - for (iIterator = vSubbasin.at(iSubbasin - 1).vCell.begin(); iIterator != vSubbasin.at(iSubbasin - 1).vCell.end(); iIterator++) - { - (*iIterator).dDistance_to_watershed_outlet = (*iIterator).dDistance_to_subbasin_outlet ; - } - } - else - { - //iSegment_downstream = vSegment.at(iSegment-1).iSegment_downstream; - iSegmentIndex = watershed_find_index_by_segment_id(iSegment); - //dDistance_to_watershed_outlet = vSegment.at(iSegmentIndex).dDistance_to_watershed_outlet; - dDistance_to_watershed_outlet = vSegment.at(iSegmentIndex).dDistance_to_watershed_outlet; - for (iIterator = vSubbasin.at(iSubbasin - 1).vCell.begin(); iIterator != vSubbasin.at(iSubbasin - 1).vCell.end(); iIterator++) - { - (*iIterator).dDistance_to_watershed_outlet = (*iIterator).dDistance_to_subbasin_outlet + dDistance_to_watershed_outlet; - } - } - - } - - return error_code; - } - /** - * save the watershed characteristics in the output - * @return - */ - int watershed::save_watershed_characteristics() - { - int error_code = 1; - std::string sLine; - std::ofstream ofs; - ofs.open(sFilename_watershed_characteristics.c_str(), ios::out); - if (ofs.good()) - { - sLine = "Total number of cells: " + convert_float_to_string(nCell); - ofs << sLine << std::endl; - - sLine = "Watershed drainage area: " + convert_float_to_string(dArea); - ofs << sLine << std::endl; - - sLine = "Longest stream length: " + convert_float_to_string(dLongest_length_stream); - ofs << sLine << std::endl; - - sLine = "Total stream length: " + convert_float_to_string(dLength_stream_conceptual); - ofs << sLine << std::endl; - - sLine = "Drainage density: " + convert_float_to_string(dDrainage_density); - ofs << sLine << std::endl; - - sLine = "Average slope: " + convert_float_to_string(dSlope_mean); - ofs << sLine << std::endl; - - ofs.close(); - } - - return error_code; - } - - int watershed::save_segment_characteristics() - { - int error_code = 1; - std::string sLine; - std::vector::iterator iIterator1; - std::ofstream ofs; - ofs.open(sFilename_segment_characteristics.c_str(), ios::out); - if (ofs.good()) - { - sLine = "Segment ID, downstream segment ID, stream order, total length, elevation drop, average slope"; - ofs << sLine << std::endl; - for (iIterator1 = vSegment.begin(); iIterator1 != vSegment.end(); iIterator1++) - { - - sLine = convert_integer_to_string((*iIterator1).iSegment) + "," - + convert_integer_to_string((*iIterator1).iSegment_downstream) + "," - + convert_integer_to_string((*iIterator1).iSegment_order) + "," - + convert_float_to_string((*iIterator1).dLength) + "," - + convert_float_to_string((*iIterator1).dElevation_drop) + "," - + convert_float_to_string((*iIterator1).dSlope_mean); - ofs << sLine << std::endl; - } - ofs.close(); - } - return error_code; - } - - int watershed::save_subbasin_characteristics() - { - int error_code = 1; - std::string sLine; - std::vector::iterator iIterator1; - std::ofstream ofs; - ofs.open(sFilename_subbasin_characteristics.c_str(), ios::out); - if (ofs.good()) - { - sLine = "Subbasin ID, Outlet ID, number of cell, total area, average slope, area_to_length, drainage density"; - ofs << sLine << std::endl; - for (iIterator1 = vSubbasin.begin(); iIterator1 != vSubbasin.end(); iIterator1++) - { - sLine = convert_integer_to_string((*iIterator1).iSubbasin) + "," - + convert_long_to_string((*iIterator1).lCellID_outlet) + "," - + convert_long_to_string((*iIterator1).nCell) + "," + convert_float_to_string((*iIterator1).dArea) + "," + convert_float_to_string((*iIterator1).dSlope_mean) + "," + convert_float_to_string((*iIterator1).dArea_2_stream_ratio) + "," + convert_float_to_string((*iIterator1).dDrainage_density) + ","; - ofs << sLine << std::endl; - } - ofs.close(); - } - return error_code; - } - - int watershed::watershed_save_json() - { - int error_code = 1; - std::vector::iterator iIterator; - - jsonmodel::mesh cMesh; - for (iIterator = vCell.begin(); iIterator != vCell.end(); iIterator++) - { - if ((*iIterator).iFlag_watershed == 1) - { - cell pCell; - pCell.dLongitude_center_degree = (*iIterator).dLongitude_center_degree; - pCell.dLatitude_center_degree = (*iIterator).dLatitude_center_degree; - pCell.dSlope_between = (*iIterator).dSlope_max_downslope; - pCell.dSlope_profile = (*iIterator).dSlope_elevation_profile0; - pCell.dDistance_to_downslope = (*iIterator).dDistance_to_downslope; - pCell.dDistance_to_subbasin_outlet = (*iIterator).dDistance_to_subbasin_outlet; - pCell.dDistance_to_watershed_outlet = (*iIterator).dDistance_to_watershed_outlet; - pCell.dElevation_mean = (*iIterator).dElevation_mean; - pCell.dElevation_raw = (*iIterator).dElevation_raw; - pCell.dElevation_profile0 = (*iIterator).dElevation_profile0; - pCell.dLength = (*iIterator).dLength_stream_conceptual; - pCell.dLength_flowline = (*iIterator).dLength_stream_burned; - pCell.dArea = (*iIterator).dArea; - pCell.lCellID = (*iIterator).lCellID; - pCell.iStream_segment = (*iIterator).iSegment; - pCell.iSubbasin = (*iIterator).iSubbasin; - pCell.iStream_segment_burned = (*iIterator).iStream_segment_burned; // flag for burned stream - pCell.lCellID_downslope = (*iIterator).lCellID_downslope_dominant; - pCell.dAccumulation = (*iIterator).dAccumulation; - pCell.vVertex = (*iIterator).vVertex; - pCell.nVertex = pCell.vVertex.size(); - cMesh.aCell.push_back(pCell); - } - } - - cMesh.SerializeToFile(sFilename_watershed_json.c_str()); - return error_code; - } - - int watershed::watershed_save_stream_edge_json() - { - int error_code = 1; - std::vector::iterator iIterator1; - std::vector::iterator iIterator; - - jsonmodel::mesh cMesh; - for (iIterator1 = vSegment.begin(); iIterator1 != vSegment.end(); iIterator1++) - { - for (iIterator = (*iIterator1).vReach_segment.begin(); iIterator != (*iIterator1).vReach_segment.end(); iIterator++) - { - cell pCell; - pCell.dLongitude_center_degree = (*iIterator).dLongitude_center_degree; - pCell.dLatitude_center_degree = (*iIterator).dLatitude_center_degree; - pCell.dSlope_between = (*iIterator).dSlope_max_downslope; - pCell.dSlope_profile = (*iIterator).dSlope_elevation_profile0; - pCell.dDistance_to_downslope = (*iIterator).dDistance_to_downslope; - pCell.dDistance_to_subbasin_outlet = (*iIterator).dDistance_to_subbasin_outlet; - pCell.dDistance_to_watershed_outlet = (*iIterator).dDistance_to_watershed_outlet; - pCell.dElevation_mean = (*iIterator).dElevation_mean; - pCell.dElevation_raw = (*iIterator).dElevation_raw; - pCell.dElevation_profile0 = (*iIterator).dElevation_profile0; - pCell.dLength = (*iIterator).dLength_stream_conceptual; - pCell.dLength_flowline = (*iIterator).dLength_stream_burned; - pCell.dArea = (*iIterator).dArea; - pCell.lCellID = (*iIterator).lCellID; - pCell.iStream_segment = (*iIterator).iSegment; - pCell.iSubbasin = (*iIterator).iSubbasin; - pCell.iStream_segment_burned = (*iIterator).iStream_segment_burned; // flag for burned stream - pCell.lCellID_downslope = (*iIterator).lCellID_downslope_dominant; - pCell.dAccumulation = (*iIterator).dAccumulation; - pCell.vVertex = (*iIterator).vVertex; - pCell.nVertex = pCell.vVertex.size(); - cMesh.aCell.push_back(pCell); - - } - } - cMesh.SerializeToFile(sFilename_watershed_stream_edge_json.c_str()); - return error_code; - } - - long watershed::watershed_find_index_by_cell_id(long lCellID_in) - { - long lCellIndex_watershed = -1; - std::vector::iterator iIterator; - for (iIterator = vCell.begin(); iIterator != vCell.end(); iIterator++) - { - if ((*iIterator).lCellID == lCellID_in) - { - lCellIndex_watershed = (*iIterator).lCellIndex_watershed; - break; - } - } - - return lCellIndex_watershed; - } - - int watershed::watershed_find_index_by_segment_id(int iSegment_in) - { - int iSegmentIndex = -1; - std::vector::iterator iIterator; - for (iIterator = vSegment.begin(); iIterator != vSegment.end(); iIterator++) - { - if ((*iIterator).iSegment == iSegment_in) - { - iSegmentIndex = (*iIterator).iSegmentIndex; - break; - } - } - - return iSegmentIndex; - } - - int watershed::watershed_find_index_by_subbasin_id(int iSegment_in) - { - int iSubbasinIndex = -1; - std::vector::iterator iIterator; - for (iIterator = vSubbasin.begin(); iIterator != vSubbasin.end(); iIterator++) - { - if ((*iIterator).iSubbasin == iSegment_in) - { - iSubbasinIndex = (*iIterator).iSubbasinIndex; - break; - } - } - - return iSubbasinIndex; - } - - -} // namespace hexwatershed diff --git a/external/hexwatershed/src/watershed.h b/external/hexwatershed/src/watershed.h deleted file mode 100755 index 8a6cc6c..0000000 --- a/external/hexwatershed/src/watershed.h +++ /dev/null @@ -1,116 +0,0 @@ -/** - * @file watershed.h - * @author Chang Liao (chang.liao@pnnl.gov) - * @brief This class provide interface to watershed characteristics, - * @version 0.1 - * @date 2019-08-02 - * @citation Liao, C., Tesfa, T., Duan, Z., & Leung, L. R. (2020). - * Watershed delineation on a hexagonal mesh grid. Environmental Modelling & Software, 104702. - * https://www.sciencedirect.com/science/article/pii/S1364815219308278 - * @github page https://github.com/changliao1025/hexwatershed - * @copyright Copyright (c) 2019 - * - */ -#pragma once -#include -#include -#include -#include -#include -#include "conversion.h" -#include "hexagon.h" -#include "segment.h" -#include "subbasin.h" - -#include "./json/JSONBase.h" -#include "./json/mesh.h" -#include "./json/cell.h" -#include "./json/basin.h" -#include "./json/multibasin.h" -using namespace std; - -namespace hexwatershed -{ - // some improvements are needed in next development - class watershed - { - public: - watershed(); - - ~watershed(); - - int iWatershed; // id - - - - int iSegment_current; - float dArea; - float dSlope; - float dSlope_mean; - float dSlope_max; - float dSlope_min; - long nCell; - long nSegment; - long nSubbasin; - long nConfluence; - - long lCellID_outlet; // the mesh ID of the outlet - - float dArea_2_stream_ratio; // the drainage density: https://en.wikipedia.org/wiki/Drainage_density - float dLength_2_area_ratio; // the drainage density: https://en.wikipedia.org/wiki/Drainage_density - float dDrainage_density; - float dLongest_length_stream; // the length of longest stream segment - float dLength_stream_conceptual; // total stream length - - - std::string sWorkspace_output_watershed; - std::string sFilename_watershed_characteristics; - std::string sFilename_segment_characteristics; - std::string sFilename_subbasin_characteristics; - - std::string sFilename_watershed_json; - std::string sFilename_watershed_stream_edge_json; - - - std::vector vCell; - std::vector vSegment; - std::vector vSubbasin; - std::vector vConfluence; - - // function - - int watershed_define_stream_confluence(); - int watershed_define_stream_segment(); - int watershed_tag_confluence_upstream( long lCellID_confluence); - - int watershed_build_stream_topology(); - int watershed_define_stream_order(); - int watershed_define_subbasin_old(); - int watershed_define_subbasin(); - int watershed_update_attribute(); - - // the watershed characteristics for comparison - int calculate_watershed_characteristics(); - int calculate_watershed_drainage_area(); - int calculate_watershed_total_stream_length(); - int calculate_watershed_longest_stream_length(); - int calculate_watershed_drainage_density(); - int calculate_watershed_average_slope(); - int calculate_topographic_wetness_index(); - int calculate_travel_distance(); - - int save_watershed_characteristics(); - int save_segment_characteristics(); - int save_subbasin_characteristics(); - - int watershed_save_json(); - - int watershed_save_stream_edge_json(); - - - long watershed_find_index_by_cell_id(long lCellID); - int watershed_find_index_by_segment_id(int iSegment); - int watershed_find_index_by_subbasin_id(int iSubbasin); - - }; -} diff --git a/pyhexwatershed/algorithms/auxiliary/export_json_to_geojson_polygon.py b/pyhexwatershed/algorithms/auxiliary/export_json_to_geojson_polygon.py index d95e315..c279ee2 100644 --- a/pyhexwatershed/algorithms/auxiliary/export_json_to_geojson_polygon.py +++ b/pyhexwatershed/algorithms/auxiliary/export_json_to_geojson_polygon.py @@ -26,11 +26,8 @@ def export_json_to_geojson_polygon(sFilename_json_in, pSrs.ImportFromEPSG(4326) # WGS84 lat/lon pLayer = pDataset.CreateLayer('hexwatershed', pSrs, geom_type=ogr.wkbPolygon) #Add basic attributes cellid - pLayer.CreateField(ogr.FieldDefn('cellid', ogr.OFTInteger64)) #long type for high resolution - - + pLayer.CreateField(ogr.FieldDefn('cellid', ogr.OFTInteger64)) #long type for high resolution nField_in = len(aVariable_json_in) - nField_out = len(aVariable_geojson_out) if nField_in != nField_out: print("Error: the field number of input and output are not the same") @@ -55,15 +52,13 @@ def export_json_to_geojson_polygon(sFilename_json_in, with open(sFilename_json_in) as json_file: data = json.load(json_file) ncell = len(data) - lID = 0 + #lID = 0 for i in range(ncell): pcell = data[i] lCellID = int(pcell['lCellID']) - lCellID_downslope = int(pcell['lCellID_downslope']) - x_start=float(pcell['dLongitude_center_degree']) - y_start=float(pcell['dLatitude_center_degree']) - - + #lCellID_downslope = int(pcell['lCellID_downslope']) + #x_start=float(pcell['dLongitude_center_degree']) + #y_start=float(pcell['dLatitude_center_degree']) vVertex = pcell['vVertex'] nvertex = len(vVertex) pPolygon = ogr.Geometry(ogr.wkbPolygon) diff --git a/pyhexwatershed/algorithms/auxiliary/merge_cell_to_polygon.py b/pyhexwatershed/algorithms/auxiliary/merge_cell_to_polygon.py new file mode 100644 index 0000000..447d7ec --- /dev/null +++ b/pyhexwatershed/algorithms/auxiliary/merge_cell_to_polygon.py @@ -0,0 +1,83 @@ +import os +import json +from osgeo import gdal, ogr, osr, gdalconst +from collections import defaultdict + +def merge_cell_to_polygon(sFilename_in, sFilename_out, sVariable_in): + #https://gis.stackexchange.com/questions/85028/dissolve-aggregate-polygons-with-ogr2ogr-or-gpc + #ogr2ogr output.shp input.shp -dialect sqlite -sql "SELECT ST_Union(geometry), dissolve_field FROM input GROUP BY dissolve_field" + pDataset_in = ogr.Open(sFilename_in) + layer_name = pDataset_in.GetLayerByIndex(0).GetName() + pKwargs = ' -f "Parquet" -dialect sqlite -sql "SELECT ST_Union(geometry), ' + sVariable_in + ' FROM ' + layer_name + ' GROUP BY ' + sVariable_in + '"' + gdal.VectorTranslate( sFilename_out, sFilename_in, options = pKwargs) + + return + +def merge_cell_to_polygon_slow(sFilename_in, sFilename_out, sVariable_in, iVariable_type_in): + + pDriver_geojson = ogr.GetDriverByName('GeoJSON') + pDriver_geojson = ogr.GetDriverByName('Parquet') + + if os.path.exists(sFilename_out): + pDriver_geojson.DeleteDataSource(sFilename_out) + + pDataset_out = pDriver_geojson.CreateDataSource(sFilename_out) + if pDataset_out is None: + print('Dataset not created') + return + + pDataset_in = ogr.Open(sFilename_in) + # Get the first layer in the file + pLayer_in = pDataset_in.GetLayer(0) + pLayerDefn_in = pLayer_in.GetLayerDefn() + # Count the number of features (polygons) + nFeature = pLayer_in.GetFeatureCount() + # Get the spatial reference of the layer + pSpatial_reference = pLayer_in.GetSpatialRef() + wkt2 = pSpatial_reference.ExportToWkt() + pLayer_out = pDataset_out.CreateLayer('layer', pSpatial_reference, geom_type=ogr.wkbPolygon) + pGeometry_merge = ogr.Geometry(ogr.wkbPolygon) + #copy layer definition + pLayerDefn = pLayer_out.GetLayerDefn() + if iVariable_type_in == 1: #integer + pField = ogr.FieldDefn(sVariable_in, ogr.OFTInteger) + pField.SetWidth(10) + else: #float + pField = ogr.FieldDefn(sVariable_in, ogr.OFTReal) + pField.SetWidth(20) + pField.SetPrecision(8) + pass + pLayer_out.CreateField(pField) + + pLayerDefn = pLayer_out.GetLayerDefn() + pFeature_out = ogr.Feature(pLayerDefn) + + features_by_attribute = defaultdict(list) + for i in range(nFeature): + pFeature_in = pLayer_in.GetFeature(i) + pGeometry = pFeature_in.GetGeometryRef() + # Get the attribute value + attribute_value = pFeature_in.GetField(sVariable_in) + # Add the feature to the list of features for this attribute value + features_by_attribute[attribute_value].append(pGeometry) + + # For each attribute value, merge the features and create a new feature in the output layer + for attribute_value, features in features_by_attribute.items(): + pGeometry_merge = ogr.Geometry(ogr.wkbPolygon) + for pGeometry in features: + # Union the geometry of each feature with the merged polygon + pGeometry_merge = pGeometry_merge.Union(pGeometry) + + # Create a new feature in the output layer + pFeature_out = ogr.Feature(pLayer_out.GetLayerDefn()) + pFeature_out.SetGeometry(pGeometry_merge) + pFeature_out.SetField(sVariable_in, attribute_value) + pLayer_out.CreateFeature(pFeature_out) + + pDataset_out.Destroy() + pDataset_in.Destroy() + + return + + + diff --git a/pyhexwatershed/classes/_visual.py b/pyhexwatershed/classes/_visual.py index 59280a5..bd1ab8c 100644 --- a/pyhexwatershed/classes/_visual.py +++ b/pyhexwatershed/classes/_visual.py @@ -6,6 +6,8 @@ from pyearth.visual.map.vector.map_vector_polyline_data import map_vector_polyline_data from pyearth.visual.map.vector.map_multiple_vector_data import map_multiple_vector_data +from pyearth.visual.animate.animate_vector_polygon_data import animate_vector_polygon_data + def plot(self, iFlag_type_in = None, iFlag_title_in = None, @@ -17,14 +19,14 @@ def plot(self, iFigheight_in=None, iFont_size_in=None, iFlag_scientific_notation_colorbar_in=None, - dData_min_in = None, - dData_max_in = None, + dData_min_in = None, + dData_max_in = None, aExtent_in = None, pProjection_map_in = None): - aPolyline = ['flow_direction', 'stream_segment', 'stream_order' ] - aPolygon = ['area','elevation', 'drainage_area', 'slope', 'travel_distance'] - aMixed = ['flow_direction_with_mesh', 'flow_direction_with_observation'] + aPolyline = ['flow_direction', 'stream_segment', 'stream_order','flowline_filter' ] + aPolygon = ['area','elevation', 'drainage_area', 'slope', 'travel_distance', 'hillslope'] + aMixed = ['flow_direction_with_mesh', 'flow_direction_with_observation','hillslope_with_flow_direction'] if iFlag_title_in is None: @@ -49,7 +51,11 @@ def plot(self, if self.iMesh_type == 4: sResolution = 'Resolution: 3 ~ 10 km' else: - sResolution = 'Resolution: ' + "{:0d}".format( int(self.dResolution_meter/1000) ) + ' km' + if self.dResolution_meter > 1000: + sResolution = 'Resolution: ' + "{:0d}".format( int(self.dResolution_meter/1000) ) + ' km' + else: + sResolution = 'Resolution: ' + "{:0d}".format( int(self.dResolution_meter) ) + ' m' + aLegend.append(sResolution) if self.iFlag_stream_burning_topology ==1: sText = 'Stream topology: on' @@ -89,8 +95,7 @@ def plot(self, self._plot_mesh(sFilename_output_in=sFilename_output_in, aExtent_in = aExtent_in, pProjection_map_in = pProjection_map_in) - else: - + else: if self.iFlag_multiple_outlet == 1: sFilename_mesh = self.sFilename_mesh self._plot_mesh_with_variable( sVariable_in, @@ -104,8 +109,6 @@ def plot(self, else: #for each basin #polygon based, only mesh - - for pBasin in self.aBasin: sFilename_mesh = pBasin.sFilename_variable_polygon pBasin.basin_plot( iFlag_type_in, @@ -143,7 +146,7 @@ def plot(self, sFilename_mesh_in = sFilename_mesh, iFont_size_in = iFont_size_in, iFlag_title_in = iFlag_title_in, - iFlag_openstreetmap_in= iFlag_openstreetmap_in, + iFlag_openstreetmap_in= iFlag_openstreetmap_in, sVariable_in = sVariable_in, sFilename_output_in=sFilename_output_in, aExtent_in = aExtent_in, @@ -224,10 +227,24 @@ def _plot_mesh_with_flow_direction(self, def _animate(self, sFilename_in, iFlag_type_in = None, iFigwidth_in=None, iFigheight_in=None, + iFont_size_in=None, aExtent_in = None, pProjection_map_in = None): #this function is under update + sFilename_mesh = self.sFilename_mesh + sFilename_animation_json = self.sFilename_animation_json + sFilename_animation_out = sFilename_in + animate_vector_polygon_data( + sFilename_mesh, + sFilename_animation_json, + sFilename_animation_out, + iFlag_type_in=None, + iFigwidth_in=None, + iFigheight_in=None, + aExtent_in=None, + sTitle_in= 'Hybrid stream burning and depression filling', + pProjection_map_in=None) return diff --git a/pyhexwatershed/classes/pycase.py b/pyhexwatershed/classes/pycase.py index af70da6..80494a6 100644 --- a/pyhexwatershed/classes/pycase.py +++ b/pyhexwatershed/classes/pycase.py @@ -18,11 +18,14 @@ from pyflowline.classes.vertex import pyvertex from pyhexwatershed.algorithms.auxiliary.export_json_to_geojson_polyline import export_json_to_geojson_polyline from pyhexwatershed.algorithms.auxiliary.export_json_to_geojson_polygon import export_json_to_geojson_polygon +from pyhexwatershed.algorithms.auxiliary.merge_cell_to_polygon import merge_cell_to_polygon from pyhexwatershed.algorithms.auxiliary.merge_stream_edge_to_stream_segment import merge_stream_edge_to_stream_segment from pyearth.gis.spatialref.reproject_coodinates import reproject_coordinates, reproject_coordinates_batch from pyearth.gis.gdal.read.raster.gdal_read_geotiff_file import gdal_read_geotiff_file from pyearth.toolbox.data.geoparquet.convert_geojson_to_geoparquet import convert_geojson_to_geoparquet +from pyearth.toolbox.reader.text_reader_string import text_reader_string + pDate = datetime.datetime.today() sDate_default = "{:04d}".format(pDate.year) + "{:02d}".format(pDate.month) + "{:02d}".format(pDate.day) @@ -83,6 +86,7 @@ class hexwatershedcase(object): sFilename_distance_to_outlet= '' sFilename_variable_polyline='' sFilename_variable_polygon='' + sFilename_animation_json='' sRegion='' sModel='' @@ -356,6 +360,8 @@ def __init__(self, aConfig_in): self.sFilename_variable_polyline = os.path.join(str(Path(self.sWorkspace_output_hexwatershed) ) , sMesh_type + "_variable_polyline.geojson" ) self.sFilename_variable_polygon = os.path.join(str(Path(self.sWorkspace_output_hexwatershed) ) , sMesh_type + "_variable_polygon.geojson" ) + + self.sFilename_animation_json = os.path.join(str(Path(self.sWorkspace_output_hexwatershed) ) , "animation.json" ) return def tojson(self): @@ -744,6 +750,10 @@ def search_upstream(lCellID_in): if lCellID in aCell_remove: aCell_elevation.remove(pCell) + #we may print the removed info for debug purpose + for lCellID in aCell_remove: + print('Cell removed:', lCellID) + ptimer.stop() self.pPyFlowline.aCell = aCell_elevation @@ -823,8 +833,8 @@ def pyhexwatershed_export(self): else: #if the pyflowline does not turn on flowline, #then we need to include at least one watershed - self.pyhexwatershed_export_flow_direction() - self.pyhexwatershed_export_stream_segment() + #self.pyhexwatershed_export_flow_direction() + #self.pyhexwatershed_export_stream_segment() #polygon #self.pyhexwatershed_export_elevation() @@ -930,6 +940,39 @@ def pyhexwatershed_export_stream_segment(self): merge_stream_edge_to_stream_segment(sFilename_stream_edge_geojson, sFilename_stream_segment_geojson, pVertex_outlet) + else: #even there is no flowline, it could be elevation-based simulation + iWatershed = 1 + pBasin = self.aBasin[iWatershed-1] + sFilename_stream_edge = pBasin.sFilename_stream_edge_json + sFilename_stream_edge_geojson = pBasin.sFilename_stream_edge + sFilename_stream_segment_geojson = pBasin.sFilename_stream_segment + aVariable_json_in = ['lStream_segment'] + aVariable_geojson_out = ['stream_segment'] + aVariable_type_out= [1] + export_json_to_geojson_polyline(sFilename_stream_edge, + sFilename_stream_edge_geojson, + aVariable_json_in, + aVariable_geojson_out, + aVariable_type_out) + #how about segment? maybe a lightly different function is needed. + #we can extract the outlet from the watershed txt file + sFilename_watershed_characteristics = pBasin.sFilename_watershed_characteristics_txt + #read the txt and get the outlet location + dummy_data = text_reader_string(sFilename_watershed_characteristics, iSkipline_in= 1, cDelimiter_in= ':') + #find which line has the longitude and latitude + lIndex_longtitude = np.where(dummy_data[:,0] == 'Outlet longitude degree')[0] + lIndex_latitude = np.where(dummy_data[:,0] == 'Outlet latitude degree')[0] + dLongitude_outlet_longitude = float(dummy_data[lIndex_longtitude, 1]) + dLatitude_outlet_latitude = float(dummy_data[lIndex_latitude, 1]) + point = dict() + point['dLongitude_degree'] = dLongitude_outlet_longitude + point['dLatitude_degree'] = dLatitude_outlet_latitude + pVertex_outlet=pyvertex(point) + merge_stream_edge_to_stream_segment(sFilename_stream_edge_geojson, + sFilename_stream_segment_geojson, + pVertex_outlet) + + pass @@ -1062,13 +1105,21 @@ def pyhexwatershed_export_all_polygon_variables(self): aVariable_geojson = ['subbasin','hillslope','area','elevation', 'slope', 'drainage_area','travel_distance'] aVariable_type= [1,1,2,2,2,2,2] - export_json_to_geojson_polygon(sFilename_json, - sFilename_geojson, - aVariable_json, - aVariable_geojson, - aVariable_type) - + #export_json_to_geojson_polygon(sFilename_json, + # sFilename_geojson, + # aVariable_json, + # aVariable_geojson, + # aVariable_type) #convert to geoparquet for visualization - convert_geojson_to_geoparquet(sFilename_geojson, sFilename_geojson.replace('.geojson','.parquet')) + sFilename_parquet = sFilename_geojson.replace('.geojson','.parquet') + #convert_geojson_to_geoparquet(sFilename_geojson, sFilename_parquet) + #because each geojson file has many small polygons, we can merge them into large polygons + #get the folder of the geojson + sFolder = os.path.dirname(sFilename_geojson) + sFilename_subbasin = os.path.join( sFolder, 'subbasin.parquet' ) #sFilename_geojson.replace('.geojson','_subbasin.parquet') + merge_cell_to_polygon(sFilename_parquet, sFilename_subbasin,'subbasin') + sFilename_hillslope = os.path.join( sFolder, 'hillslope.parquet' ) #sFilename_geojson.replace('.geojson','_hillslope.parquet') + merge_cell_to_polygon(sFilename_parquet, sFilename_hillslope,'hillslope') + return From 1415ca9a69edbbafb37e5071f5036c8d3e5b89a9 Mon Sep 17 00:00:00 2001 From: changliao1025 Date: Mon, 15 Apr 2024 10:56:06 -0700 Subject: [PATCH 3/4] remove json library --- external/rapidjson/allocators.h | 692 ----- external/rapidjson/cursorstreamwrapper.h | 78 - external/rapidjson/document.h | 3027 ---------------------- external/rapidjson/encodedstream.h | 299 --- external/rapidjson/encodings.h | 716 ----- external/rapidjson/error/en.h | 122 - external/rapidjson/error/error.h | 216 -- external/rapidjson/filereadstream.h | 99 - external/rapidjson/filewritestream.h | 104 - external/rapidjson/fwd.h | 151 -- external/rapidjson/internal/biginteger.h | 290 --- external/rapidjson/internal/clzll.h | 71 - external/rapidjson/internal/diyfp.h | 257 -- external/rapidjson/internal/dtoa.h | 245 -- external/rapidjson/internal/ieee754.h | 78 - external/rapidjson/internal/itoa.h | 308 --- external/rapidjson/internal/meta.h | 186 -- external/rapidjson/internal/pow10.h | 55 - external/rapidjson/internal/regex.h | 739 ------ external/rapidjson/internal/stack.h | 232 -- external/rapidjson/internal/strfunc.h | 83 - external/rapidjson/internal/strtod.h | 290 --- external/rapidjson/internal/swap.h | 46 - external/rapidjson/istreamwrapper.h | 128 - external/rapidjson/memorybuffer.h | 70 - external/rapidjson/memorystream.h | 71 - external/rapidjson/msinttypes/inttypes.h | 316 --- external/rapidjson/msinttypes/stdint.h | 300 --- external/rapidjson/ostreamwrapper.h | 81 - external/rapidjson/pointer.h | 1482 ----------- external/rapidjson/prettywriter.h | 277 -- external/rapidjson/rapidjson.h | 741 ------ external/rapidjson/reader.h | 2244 ---------------- external/rapidjson/schema.h | 2795 -------------------- external/rapidjson/stream.h | 223 -- external/rapidjson/stringbuffer.h | 121 - external/rapidjson/uri.h | 466 ---- external/rapidjson/writer.h | 710 ----- external/readme.md | 0 39 files changed, 18409 deletions(-) delete mode 100755 external/rapidjson/allocators.h delete mode 100755 external/rapidjson/cursorstreamwrapper.h delete mode 100755 external/rapidjson/document.h delete mode 100755 external/rapidjson/encodedstream.h delete mode 100755 external/rapidjson/encodings.h delete mode 100755 external/rapidjson/error/en.h delete mode 100755 external/rapidjson/error/error.h delete mode 100755 external/rapidjson/filereadstream.h delete mode 100755 external/rapidjson/filewritestream.h delete mode 100755 external/rapidjson/fwd.h delete mode 100755 external/rapidjson/internal/biginteger.h delete mode 100755 external/rapidjson/internal/clzll.h delete mode 100755 external/rapidjson/internal/diyfp.h delete mode 100755 external/rapidjson/internal/dtoa.h delete mode 100755 external/rapidjson/internal/ieee754.h delete mode 100755 external/rapidjson/internal/itoa.h delete mode 100755 external/rapidjson/internal/meta.h delete mode 100755 external/rapidjson/internal/pow10.h delete mode 100755 external/rapidjson/internal/regex.h delete mode 100755 external/rapidjson/internal/stack.h delete mode 100755 external/rapidjson/internal/strfunc.h delete mode 100755 external/rapidjson/internal/strtod.h delete mode 100755 external/rapidjson/internal/swap.h delete mode 100755 external/rapidjson/istreamwrapper.h delete mode 100755 external/rapidjson/memorybuffer.h delete mode 100755 external/rapidjson/memorystream.h delete mode 100755 external/rapidjson/msinttypes/inttypes.h delete mode 100755 external/rapidjson/msinttypes/stdint.h delete mode 100755 external/rapidjson/ostreamwrapper.h delete mode 100755 external/rapidjson/pointer.h delete mode 100755 external/rapidjson/prettywriter.h delete mode 100755 external/rapidjson/rapidjson.h delete mode 100755 external/rapidjson/reader.h delete mode 100755 external/rapidjson/schema.h delete mode 100755 external/rapidjson/stream.h delete mode 100755 external/rapidjson/stringbuffer.h delete mode 100755 external/rapidjson/uri.h delete mode 100755 external/rapidjson/writer.h create mode 100644 external/readme.md diff --git a/external/rapidjson/allocators.h b/external/rapidjson/allocators.h deleted file mode 100755 index 12bc5ba..0000000 --- a/external/rapidjson/allocators.h +++ /dev/null @@ -1,692 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_ALLOCATORS_H_ -#define RAPIDJSON_ALLOCATORS_H_ - -#include "rapidjson.h" -#include "internal/meta.h" - -#include - -#if RAPIDJSON_HAS_CXX11 -#include -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -/////////////////////////////////////////////////////////////////////////////// -// Allocator - -/*! \class rapidjson::Allocator - \brief Concept for allocating, resizing and freeing memory block. - - Note that Malloc() and Realloc() are non-static but Free() is static. - - So if an allocator need to support Free(), it needs to put its pointer in - the header of memory block. - -\code -concept Allocator { - static const bool kNeedFree; //!< Whether this allocator needs to call Free(). - - // Allocate a memory block. - // \param size of the memory block in bytes. - // \returns pointer to the memory block. - void* Malloc(size_t size); - - // Resize a memory block. - // \param originalPtr The pointer to current memory block. Null pointer is permitted. - // \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.) - // \param newSize the new size in bytes. - void* Realloc(void* originalPtr, size_t originalSize, size_t newSize); - - // Free a memory block. - // \param pointer to the memory block. Null pointer is permitted. - static void Free(void *ptr); -}; -\endcode -*/ - - -/*! \def RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY - \ingroup RAPIDJSON_CONFIG - \brief User-defined kDefaultChunkCapacity definition. - - User can define this as any \c size that is a power of 2. -*/ - -#ifndef RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY -#define RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY (64 * 1024) -#endif - - -/////////////////////////////////////////////////////////////////////////////// -// CrtAllocator - -//! C-runtime library allocator. -/*! This class is just wrapper for standard C library memory routines. - \note implements Allocator concept -*/ -class CrtAllocator { -public: - static const bool kNeedFree = true; - void* Malloc(size_t size) { - if (size) // behavior of malloc(0) is implementation defined. - return RAPIDJSON_MALLOC(size); - else - return NULL; // standardize to returning NULL. - } - void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { - (void)originalSize; - if (newSize == 0) { - RAPIDJSON_FREE(originalPtr); - return NULL; - } - return RAPIDJSON_REALLOC(originalPtr, newSize); - } - static void Free(void *ptr) RAPIDJSON_NOEXCEPT { RAPIDJSON_FREE(ptr); } - - bool operator==(const CrtAllocator&) const RAPIDJSON_NOEXCEPT { - return true; - } - bool operator!=(const CrtAllocator&) const RAPIDJSON_NOEXCEPT { - return false; - } -}; - -/////////////////////////////////////////////////////////////////////////////// -// MemoryPoolAllocator - -//! Default memory allocator used by the parser and DOM. -/*! This allocator allocate memory blocks from pre-allocated memory chunks. - - It does not free memory blocks. And Realloc() only allocate new memory. - - The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default. - - User may also supply a buffer as the first chunk. - - If the user-buffer is full then additional chunks are allocated by BaseAllocator. - - The user-buffer is not deallocated by this allocator. - - \tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator. - \note implements Allocator concept -*/ -template -class MemoryPoolAllocator { - //! Chunk header for perpending to each chunk. - /*! Chunks are stored as a singly linked list. - */ - struct ChunkHeader { - size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself). - size_t size; //!< Current size of allocated memory in bytes. - ChunkHeader *next; //!< Next chunk in the linked list. - }; - - struct SharedData { - ChunkHeader *chunkHead; //!< Head of the chunk linked-list. Only the head chunk serves allocation. - BaseAllocator* ownBaseAllocator; //!< base allocator created by this object. - size_t refcount; - bool ownBuffer; - }; - - static const size_t SIZEOF_SHARED_DATA = RAPIDJSON_ALIGN(sizeof(SharedData)); - static const size_t SIZEOF_CHUNK_HEADER = RAPIDJSON_ALIGN(sizeof(ChunkHeader)); - - static inline ChunkHeader *GetChunkHead(SharedData *shared) - { - return reinterpret_cast(reinterpret_cast(shared) + SIZEOF_SHARED_DATA); - } - static inline uint8_t *GetChunkBuffer(SharedData *shared) - { - return reinterpret_cast(shared->chunkHead) + SIZEOF_CHUNK_HEADER; - } - - static const size_t kDefaultChunkCapacity = RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY; //!< Default chunk capacity. - -public: - static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator) - static const bool kRefCounted = true; //!< Tell users that this allocator is reference counted on copy - - //! Constructor with chunkSize. - /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. - \param baseAllocator The allocator for allocating memory chunks. - */ - explicit - MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : - chunk_capacity_(chunkSize), - baseAllocator_(baseAllocator ? baseAllocator : RAPIDJSON_NEW(BaseAllocator)()), - shared_(static_cast(baseAllocator_ ? baseAllocator_->Malloc(SIZEOF_SHARED_DATA + SIZEOF_CHUNK_HEADER) : 0)) - { - RAPIDJSON_ASSERT(baseAllocator_ != 0); - RAPIDJSON_ASSERT(shared_ != 0); - if (baseAllocator) { - shared_->ownBaseAllocator = 0; - } - else { - shared_->ownBaseAllocator = baseAllocator_; - } - shared_->chunkHead = GetChunkHead(shared_); - shared_->chunkHead->capacity = 0; - shared_->chunkHead->size = 0; - shared_->chunkHead->next = 0; - shared_->ownBuffer = true; - shared_->refcount = 1; - } - - //! Constructor with user-supplied buffer. - /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size. - - The user buffer will not be deallocated when this allocator is destructed. - - \param buffer User supplied buffer. - \param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader). - \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. - \param baseAllocator The allocator for allocating memory chunks. - */ - MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : - chunk_capacity_(chunkSize), - baseAllocator_(baseAllocator), - shared_(static_cast(AlignBuffer(buffer, size))) - { - RAPIDJSON_ASSERT(size >= SIZEOF_SHARED_DATA + SIZEOF_CHUNK_HEADER); - shared_->chunkHead = GetChunkHead(shared_); - shared_->chunkHead->capacity = size - SIZEOF_SHARED_DATA - SIZEOF_CHUNK_HEADER; - shared_->chunkHead->size = 0; - shared_->chunkHead->next = 0; - shared_->ownBaseAllocator = 0; - shared_->ownBuffer = false; - shared_->refcount = 1; - } - - MemoryPoolAllocator(const MemoryPoolAllocator& rhs) RAPIDJSON_NOEXCEPT : - chunk_capacity_(rhs.chunk_capacity_), - baseAllocator_(rhs.baseAllocator_), - shared_(rhs.shared_) - { - RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); - ++shared_->refcount; - } - MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) RAPIDJSON_NOEXCEPT - { - RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0); - ++rhs.shared_->refcount; - this->~MemoryPoolAllocator(); - baseAllocator_ = rhs.baseAllocator_; - chunk_capacity_ = rhs.chunk_capacity_; - shared_ = rhs.shared_; - return *this; - } - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - MemoryPoolAllocator(MemoryPoolAllocator&& rhs) RAPIDJSON_NOEXCEPT : - chunk_capacity_(rhs.chunk_capacity_), - baseAllocator_(rhs.baseAllocator_), - shared_(rhs.shared_) - { - RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0); - rhs.shared_ = 0; - } - MemoryPoolAllocator& operator=(MemoryPoolAllocator&& rhs) RAPIDJSON_NOEXCEPT - { - RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0); - this->~MemoryPoolAllocator(); - baseAllocator_ = rhs.baseAllocator_; - chunk_capacity_ = rhs.chunk_capacity_; - shared_ = rhs.shared_; - rhs.shared_ = 0; - return *this; - } -#endif - - //! Destructor. - /*! This deallocates all memory chunks, excluding the user-supplied buffer. - */ - ~MemoryPoolAllocator() RAPIDJSON_NOEXCEPT { - if (!shared_) { - // do nothing if moved - return; - } - if (shared_->refcount > 1) { - --shared_->refcount; - return; - } - Clear(); - BaseAllocator *a = shared_->ownBaseAllocator; - if (shared_->ownBuffer) { - baseAllocator_->Free(shared_); - } - RAPIDJSON_DELETE(a); - } - - //! Deallocates all memory chunks, excluding the first/user one. - void Clear() RAPIDJSON_NOEXCEPT { - RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); - for (;;) { - ChunkHeader* c = shared_->chunkHead; - if (!c->next) { - break; - } - shared_->chunkHead = c->next; - baseAllocator_->Free(c); - } - shared_->chunkHead->size = 0; - } - - //! Computes the total capacity of allocated memory chunks. - /*! \return total capacity in bytes. - */ - size_t Capacity() const RAPIDJSON_NOEXCEPT { - RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); - size_t capacity = 0; - for (ChunkHeader* c = shared_->chunkHead; c != 0; c = c->next) - capacity += c->capacity; - return capacity; - } - - //! Computes the memory blocks allocated. - /*! \return total used bytes. - */ - size_t Size() const RAPIDJSON_NOEXCEPT { - RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); - size_t size = 0; - for (ChunkHeader* c = shared_->chunkHead; c != 0; c = c->next) - size += c->size; - return size; - } - - //! Whether the allocator is shared. - /*! \return true or false. - */ - bool Shared() const RAPIDJSON_NOEXCEPT { - RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); - return shared_->refcount > 1; - } - - //! Allocates a memory block. (concept Allocator) - void* Malloc(size_t size) { - RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); - if (!size) - return NULL; - - size = RAPIDJSON_ALIGN(size); - if (RAPIDJSON_UNLIKELY(shared_->chunkHead->size + size > shared_->chunkHead->capacity)) - if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size)) - return NULL; - - void *buffer = GetChunkBuffer(shared_) + shared_->chunkHead->size; - shared_->chunkHead->size += size; - return buffer; - } - - //! Resizes a memory block (concept Allocator) - void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { - if (originalPtr == 0) - return Malloc(newSize); - - RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); - if (newSize == 0) - return NULL; - - originalSize = RAPIDJSON_ALIGN(originalSize); - newSize = RAPIDJSON_ALIGN(newSize); - - // Do not shrink if new size is smaller than original - if (originalSize >= newSize) - return originalPtr; - - // Simply expand it if it is the last allocation and there is sufficient space - if (originalPtr == GetChunkBuffer(shared_) + shared_->chunkHead->size - originalSize) { - size_t increment = static_cast(newSize - originalSize); - if (shared_->chunkHead->size + increment <= shared_->chunkHead->capacity) { - shared_->chunkHead->size += increment; - return originalPtr; - } - } - - // Realloc process: allocate and copy memory, do not free original buffer. - if (void* newBuffer = Malloc(newSize)) { - if (originalSize) - std::memcpy(newBuffer, originalPtr, originalSize); - return newBuffer; - } - else - return NULL; - } - - //! Frees a memory block (concept Allocator) - static void Free(void *ptr) RAPIDJSON_NOEXCEPT { (void)ptr; } // Do nothing - - //! Compare (equality) with another MemoryPoolAllocator - bool operator==(const MemoryPoolAllocator& rhs) const RAPIDJSON_NOEXCEPT { - RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); - RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0); - return shared_ == rhs.shared_; - } - //! Compare (inequality) with another MemoryPoolAllocator - bool operator!=(const MemoryPoolAllocator& rhs) const RAPIDJSON_NOEXCEPT { - return !operator==(rhs); - } - -private: - //! Creates a new chunk. - /*! \param capacity Capacity of the chunk in bytes. - \return true if success. - */ - bool AddChunk(size_t capacity) { - if (!baseAllocator_) - shared_->ownBaseAllocator = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator)(); - if (ChunkHeader* chunk = static_cast(baseAllocator_->Malloc(SIZEOF_CHUNK_HEADER + capacity))) { - chunk->capacity = capacity; - chunk->size = 0; - chunk->next = shared_->chunkHead; - shared_->chunkHead = chunk; - return true; - } - else - return false; - } - - static inline void* AlignBuffer(void* buf, size_t &size) - { - RAPIDJSON_NOEXCEPT_ASSERT(buf != 0); - const uintptr_t mask = sizeof(void*) - 1; - const uintptr_t ubuf = reinterpret_cast(buf); - if (RAPIDJSON_UNLIKELY(ubuf & mask)) { - const uintptr_t abuf = (ubuf + mask) & ~mask; - RAPIDJSON_ASSERT(size >= abuf - ubuf); - buf = reinterpret_cast(abuf); - size -= abuf - ubuf; - } - return buf; - } - - size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated. - BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks. - SharedData *shared_; //!< The shared data of the allocator -}; - -namespace internal { - template - struct IsRefCounted : - public FalseType - { }; - template - struct IsRefCounted::Type> : - public TrueType - { }; -} - -template -inline T* Realloc(A& a, T* old_p, size_t old_n, size_t new_n) -{ - RAPIDJSON_NOEXCEPT_ASSERT(old_n <= SIZE_MAX / sizeof(T) && new_n <= SIZE_MAX / sizeof(T)); - return static_cast(a.Realloc(old_p, old_n * sizeof(T), new_n * sizeof(T))); -} - -template -inline T *Malloc(A& a, size_t n = 1) -{ - return Realloc(a, NULL, 0, n); -} - -template -inline void Free(A& a, T *p, size_t n = 1) -{ - static_cast(Realloc(a, p, n, 0)); -} - -#ifdef __GNUC__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(effc++) // std::allocator can safely be inherited -#endif - -template -class StdAllocator : - public std::allocator -{ - typedef std::allocator allocator_type; -#if RAPIDJSON_HAS_CXX11 - typedef std::allocator_traits traits_type; -#else - typedef allocator_type traits_type; -#endif - -public: - typedef BaseAllocator BaseAllocatorType; - - StdAllocator() RAPIDJSON_NOEXCEPT : - allocator_type(), - baseAllocator_() - { } - - StdAllocator(const StdAllocator& rhs) RAPIDJSON_NOEXCEPT : - allocator_type(rhs), - baseAllocator_(rhs.baseAllocator_) - { } - - template - StdAllocator(const StdAllocator& rhs) RAPIDJSON_NOEXCEPT : - allocator_type(rhs), - baseAllocator_(rhs.baseAllocator_) - { } - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - StdAllocator(StdAllocator&& rhs) RAPIDJSON_NOEXCEPT : - allocator_type(std::move(rhs)), - baseAllocator_(std::move(rhs.baseAllocator_)) - { } -#endif -#if RAPIDJSON_HAS_CXX11 - using propagate_on_container_move_assignment = std::true_type; - using propagate_on_container_swap = std::true_type; -#endif - - /* implicit */ - StdAllocator(const BaseAllocator& allocator) RAPIDJSON_NOEXCEPT : - allocator_type(), - baseAllocator_(allocator) - { } - - ~StdAllocator() RAPIDJSON_NOEXCEPT - { } - - template - struct rebind { - typedef StdAllocator other; - }; - - typedef typename traits_type::size_type size_type; - typedef typename traits_type::difference_type difference_type; - - typedef typename traits_type::value_type value_type; - typedef typename traits_type::pointer pointer; - typedef typename traits_type::const_pointer const_pointer; - -#if RAPIDJSON_HAS_CXX11 - - typedef typename std::add_lvalue_reference::type &reference; - typedef typename std::add_lvalue_reference::type>::type &const_reference; - - pointer address(reference r) const RAPIDJSON_NOEXCEPT - { - return std::addressof(r); - } - const_pointer address(const_reference r) const RAPIDJSON_NOEXCEPT - { - return std::addressof(r); - } - - size_type max_size() const RAPIDJSON_NOEXCEPT - { - return traits_type::max_size(*this); - } - - template - void construct(pointer p, Args&&... args) - { - traits_type::construct(*this, p, std::forward(args)...); - } - void destroy(pointer p) - { - traits_type::destroy(*this, p); - } - -#else // !RAPIDJSON_HAS_CXX11 - - typedef typename allocator_type::reference reference; - typedef typename allocator_type::const_reference const_reference; - - pointer address(reference r) const RAPIDJSON_NOEXCEPT - { - return allocator_type::address(r); - } - const_pointer address(const_reference r) const RAPIDJSON_NOEXCEPT - { - return allocator_type::address(r); - } - - size_type max_size() const RAPIDJSON_NOEXCEPT - { - return allocator_type::max_size(); - } - - void construct(pointer p, const_reference r) - { - allocator_type::construct(p, r); - } - void destroy(pointer p) - { - allocator_type::destroy(p); - } - -#endif // !RAPIDJSON_HAS_CXX11 - - template - U* allocate(size_type n = 1, const void* = 0) - { - return RAPIDJSON_NAMESPACE::Malloc(baseAllocator_, n); - } - template - void deallocate(U* p, size_type n = 1) - { - RAPIDJSON_NAMESPACE::Free(baseAllocator_, p, n); - } - - pointer allocate(size_type n = 1, const void* = 0) - { - return allocate(n); - } - void deallocate(pointer p, size_type n = 1) - { - deallocate(p, n); - } - -#if RAPIDJSON_HAS_CXX11 - using is_always_equal = std::is_empty; -#endif - - template - bool operator==(const StdAllocator& rhs) const RAPIDJSON_NOEXCEPT - { - return baseAllocator_ == rhs.baseAllocator_; - } - template - bool operator!=(const StdAllocator& rhs) const RAPIDJSON_NOEXCEPT - { - return !operator==(rhs); - } - - //! rapidjson Allocator concept - static const bool kNeedFree = BaseAllocator::kNeedFree; - static const bool kRefCounted = internal::IsRefCounted::Value; - void* Malloc(size_t size) - { - return baseAllocator_.Malloc(size); - } - void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) - { - return baseAllocator_.Realloc(originalPtr, originalSize, newSize); - } - static void Free(void *ptr) RAPIDJSON_NOEXCEPT - { - BaseAllocator::Free(ptr); - } - -private: - template - friend class StdAllocator; // access to StdAllocator.* - - BaseAllocator baseAllocator_; -}; - -#if !RAPIDJSON_HAS_CXX17 // std::allocator deprecated in C++17 -template -class StdAllocator : - public std::allocator -{ - typedef std::allocator allocator_type; - -public: - typedef BaseAllocator BaseAllocatorType; - - StdAllocator() RAPIDJSON_NOEXCEPT : - allocator_type(), - baseAllocator_() - { } - - StdAllocator(const StdAllocator& rhs) RAPIDJSON_NOEXCEPT : - allocator_type(rhs), - baseAllocator_(rhs.baseAllocator_) - { } - - template - StdAllocator(const StdAllocator& rhs) RAPIDJSON_NOEXCEPT : - allocator_type(rhs), - baseAllocator_(rhs.baseAllocator_) - { } - - /* implicit */ - StdAllocator(const BaseAllocator& baseAllocator) RAPIDJSON_NOEXCEPT : - allocator_type(), - baseAllocator_(baseAllocator) - { } - - ~StdAllocator() RAPIDJSON_NOEXCEPT - { } - - template - struct rebind { - typedef StdAllocator other; - }; - - typedef typename allocator_type::value_type value_type; - -private: - template - friend class StdAllocator; // access to StdAllocator.* - - BaseAllocator baseAllocator_; -}; -#endif - -#ifdef __GNUC__ -RAPIDJSON_DIAG_POP -#endif - -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_ENCODINGS_H_ diff --git a/external/rapidjson/cursorstreamwrapper.h b/external/rapidjson/cursorstreamwrapper.h deleted file mode 100755 index fd6513d..0000000 --- a/external/rapidjson/cursorstreamwrapper.h +++ /dev/null @@ -1,78 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_CURSORSTREAMWRAPPER_H_ -#define RAPIDJSON_CURSORSTREAMWRAPPER_H_ - -#include "stream.h" - -#if defined(__GNUC__) -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(effc++) -#endif - -#if defined(_MSC_VER) && _MSC_VER <= 1800 -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(4702) // unreachable code -RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated -#endif - -RAPIDJSON_NAMESPACE_BEGIN - - -//! Cursor stream wrapper for counting line and column number if error exists. -/*! - \tparam InputStream Any stream that implements Stream Concept -*/ -template > -class CursorStreamWrapper : public GenericStreamWrapper { -public: - typedef typename Encoding::Ch Ch; - - CursorStreamWrapper(InputStream& is): - GenericStreamWrapper(is), line_(1), col_(0) {} - - // counting line and column number - Ch Take() { - Ch ch = this->is_.Take(); - if(ch == '\n') { - line_ ++; - col_ = 0; - } else { - col_ ++; - } - return ch; - } - - //! Get the error line number, if error exists. - size_t GetLine() const { return line_; } - //! Get the error column number, if error exists. - size_t GetColumn() const { return col_; } - -private: - size_t line_; //!< Current Line - size_t col_; //!< Current Column -}; - -#if defined(_MSC_VER) && _MSC_VER <= 1800 -RAPIDJSON_DIAG_POP -#endif - -#if defined(__GNUC__) -RAPIDJSON_DIAG_POP -#endif - -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_CURSORSTREAMWRAPPER_H_ diff --git a/external/rapidjson/document.h b/external/rapidjson/document.h deleted file mode 100755 index e2cc600..0000000 --- a/external/rapidjson/document.h +++ /dev/null @@ -1,3027 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_DOCUMENT_H_ -#define RAPIDJSON_DOCUMENT_H_ - -/*! \file document.h */ - -#include "reader.h" -#include "internal/meta.h" -#include "internal/strfunc.h" -#include "memorystream.h" -#include "encodedstream.h" -#include // placement new -#include -#ifdef __cpp_lib_three_way_comparison -#include -#endif - -RAPIDJSON_DIAG_PUSH -#ifdef __clang__ -RAPIDJSON_DIAG_OFF(padded) -RAPIDJSON_DIAG_OFF(switch-enum) -RAPIDJSON_DIAG_OFF(c++98-compat) -#elif defined(_MSC_VER) -RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant -RAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible loss of data -#endif - -#ifdef __GNUC__ -RAPIDJSON_DIAG_OFF(effc++) -#endif // __GNUC__ - -#ifdef GetObject -// see https://github.com/Tencent/rapidjson/issues/1448 -// a former included windows.h might have defined a macro called GetObject, which affects -// GetObject defined here. This ensures the macro does not get applied -#pragma push_macro("GetObject") -#define RAPIDJSON_WINDOWS_GETOBJECT_WORKAROUND_APPLIED -#undef GetObject -#endif - -#ifndef RAPIDJSON_NOMEMBERITERATORCLASS -#include // std::random_access_iterator_tag -#endif - -#if RAPIDJSON_USE_MEMBERSMAP -#include // std::multimap -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -// Forward declaration. -template -class GenericValue; - -template -class GenericDocument; - -/*! \def RAPIDJSON_DEFAULT_ALLOCATOR - \ingroup RAPIDJSON_CONFIG - \brief Allows to choose default allocator. - - User can define this to use CrtAllocator or MemoryPoolAllocator. -*/ -#ifndef RAPIDJSON_DEFAULT_ALLOCATOR -#define RAPIDJSON_DEFAULT_ALLOCATOR MemoryPoolAllocator -#endif - -/*! \def RAPIDJSON_DEFAULT_STACK_ALLOCATOR - \ingroup RAPIDJSON_CONFIG - \brief Allows to choose default stack allocator for Document. - - User can define this to use CrtAllocator or MemoryPoolAllocator. -*/ -#ifndef RAPIDJSON_DEFAULT_STACK_ALLOCATOR -#define RAPIDJSON_DEFAULT_STACK_ALLOCATOR CrtAllocator -#endif - -/*! \def RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY - \ingroup RAPIDJSON_CONFIG - \brief User defined kDefaultObjectCapacity value. - - User can define this as any natural number. -*/ -#ifndef RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY -// number of objects that rapidjson::Value allocates memory for by default -#define RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY 16 -#endif - -/*! \def RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY - \ingroup RAPIDJSON_CONFIG - \brief User defined kDefaultArrayCapacity value. - - User can define this as any natural number. -*/ -#ifndef RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY -// number of array elements that rapidjson::Value allocates memory for by default -#define RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY 16 -#endif - -//! Name-value pair in a JSON object value. -/*! - This class was internal to GenericValue. It used to be a inner struct. - But a compiler (IBM XL C/C++ for AIX) have reported to have problem with that so it moved as a namespace scope struct. - https://code.google.com/p/rapidjson/issues/detail?id=64 -*/ -template -class GenericMember { -public: - GenericValue name; //!< name of member (must be a string) - GenericValue value; //!< value of member. - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - //! Move constructor in C++11 - GenericMember(GenericMember&& rhs) RAPIDJSON_NOEXCEPT - : name(std::move(rhs.name)), - value(std::move(rhs.value)) - { - } - - //! Move assignment in C++11 - GenericMember& operator=(GenericMember&& rhs) RAPIDJSON_NOEXCEPT { - return *this = static_cast(rhs); - } -#endif - - //! Assignment with move semantics. - /*! \param rhs Source of the assignment. Its name and value will become a null value after assignment. - */ - GenericMember& operator=(GenericMember& rhs) RAPIDJSON_NOEXCEPT { - if (RAPIDJSON_LIKELY(this != &rhs)) { - name = rhs.name; - value = rhs.value; - } - return *this; - } - - // swap() for std::sort() and other potential use in STL. - friend inline void swap(GenericMember& a, GenericMember& b) RAPIDJSON_NOEXCEPT { - a.name.Swap(b.name); - a.value.Swap(b.value); - } - -private: - //! Copy constructor is not permitted. - GenericMember(const GenericMember& rhs); -}; - -/////////////////////////////////////////////////////////////////////////////// -// GenericMemberIterator - -#ifndef RAPIDJSON_NOMEMBERITERATORCLASS - -//! (Constant) member iterator for a JSON object value -/*! - \tparam Const Is this a constant iterator? - \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document) - \tparam Allocator Allocator type for allocating memory of object, array and string. - - This class implements a Random Access Iterator for GenericMember elements - of a GenericValue, see ISO/IEC 14882:2003(E) C++ standard, 24.1 [lib.iterator.requirements]. - - \note This iterator implementation is mainly intended to avoid implicit - conversions from iterator values to \c NULL, - e.g. from GenericValue::FindMember. - - \note Define \c RAPIDJSON_NOMEMBERITERATORCLASS to fall back to a - pointer-based implementation, if your platform doesn't provide - the C++ header. - - \see GenericMember, GenericValue::MemberIterator, GenericValue::ConstMemberIterator - */ -template -class GenericMemberIterator { - - friend class GenericValue; - template friend class GenericMemberIterator; - - typedef GenericMember PlainType; - typedef typename internal::MaybeAddConst::Type ValueType; - -public: - //! Iterator type itself - typedef GenericMemberIterator Iterator; - //! Constant iterator type - typedef GenericMemberIterator ConstIterator; - //! Non-constant iterator type - typedef GenericMemberIterator NonConstIterator; - - /** \name std::iterator_traits support */ - //@{ - typedef ValueType value_type; - typedef ValueType * pointer; - typedef ValueType & reference; - typedef std::ptrdiff_t difference_type; - typedef std::random_access_iterator_tag iterator_category; - //@} - - //! Pointer to (const) GenericMember - typedef pointer Pointer; - //! Reference to (const) GenericMember - typedef reference Reference; - //! Signed integer type (e.g. \c ptrdiff_t) - typedef difference_type DifferenceType; - - //! Default constructor (singular value) - /*! Creates an iterator pointing to no element. - \note All operations, except for comparisons, are undefined on such values. - */ - GenericMemberIterator() : ptr_() {} - - //! Iterator conversions to more const - /*! - \param it (Non-const) iterator to copy from - - Allows the creation of an iterator from another GenericMemberIterator - that is "less const". Especially, creating a non-constant iterator - from a constant iterator are disabled: - \li const -> non-const (not ok) - \li const -> const (ok) - \li non-const -> const (ok) - \li non-const -> non-const (ok) - - \note If the \c Const template parameter is already \c false, this - constructor effectively defines a regular copy-constructor. - Otherwise, the copy constructor is implicitly defined. - */ - GenericMemberIterator(const NonConstIterator & it) : ptr_(it.ptr_) {} - Iterator& operator=(const NonConstIterator & it) { ptr_ = it.ptr_; return *this; } - - //! @name stepping - //@{ - Iterator& operator++(){ ++ptr_; return *this; } - Iterator& operator--(){ --ptr_; return *this; } - Iterator operator++(int){ Iterator old(*this); ++ptr_; return old; } - Iterator operator--(int){ Iterator old(*this); --ptr_; return old; } - //@} - - //! @name increment/decrement - //@{ - Iterator operator+(DifferenceType n) const { return Iterator(ptr_+n); } - Iterator operator-(DifferenceType n) const { return Iterator(ptr_-n); } - - Iterator& operator+=(DifferenceType n) { ptr_+=n; return *this; } - Iterator& operator-=(DifferenceType n) { ptr_-=n; return *this; } - //@} - - //! @name relations - //@{ - template bool operator==(const GenericMemberIterator& that) const { return ptr_ == that.ptr_; } - template bool operator!=(const GenericMemberIterator& that) const { return ptr_ != that.ptr_; } - template bool operator<=(const GenericMemberIterator& that) const { return ptr_ <= that.ptr_; } - template bool operator>=(const GenericMemberIterator& that) const { return ptr_ >= that.ptr_; } - template bool operator< (const GenericMemberIterator& that) const { return ptr_ < that.ptr_; } - template bool operator> (const GenericMemberIterator& that) const { return ptr_ > that.ptr_; } - -#ifdef __cpp_lib_three_way_comparison - template std::strong_ordering operator<=>(const GenericMemberIterator& that) const { return ptr_ <=> that.ptr_; } -#endif - //@} - - //! @name dereference - //@{ - Reference operator*() const { return *ptr_; } - Pointer operator->() const { return ptr_; } - Reference operator[](DifferenceType n) const { return ptr_[n]; } - //@} - - //! Distance - DifferenceType operator-(ConstIterator that) const { return ptr_-that.ptr_; } - -private: - //! Internal constructor from plain pointer - explicit GenericMemberIterator(Pointer p) : ptr_(p) {} - - Pointer ptr_; //!< raw pointer -}; - -#else // RAPIDJSON_NOMEMBERITERATORCLASS - -// class-based member iterator implementation disabled, use plain pointers - -template -class GenericMemberIterator; - -//! non-const GenericMemberIterator -template -class GenericMemberIterator { -public: - //! use plain pointer as iterator type - typedef GenericMember* Iterator; -}; -//! const GenericMemberIterator -template -class GenericMemberIterator { -public: - //! use plain const pointer as iterator type - typedef const GenericMember* Iterator; -}; - -#endif // RAPIDJSON_NOMEMBERITERATORCLASS - -/////////////////////////////////////////////////////////////////////////////// -// GenericStringRef - -//! Reference to a constant string (not taking a copy) -/*! - \tparam CharType character type of the string - - This helper class is used to automatically infer constant string - references for string literals, especially from \c const \b (!) - character arrays. - - The main use is for creating JSON string values without copying the - source string via an \ref Allocator. This requires that the referenced - string pointers have a sufficient lifetime, which exceeds the lifetime - of the associated GenericValue. - - \b Example - \code - Value v("foo"); // ok, no need to copy & calculate length - const char foo[] = "foo"; - v.SetString(foo); // ok - - const char* bar = foo; - // Value x(bar); // not ok, can't rely on bar's lifetime - Value x(StringRef(bar)); // lifetime explicitly guaranteed by user - Value y(StringRef(bar, 3)); // ok, explicitly pass length - \endcode - - \see StringRef, GenericValue::SetString -*/ -template -struct GenericStringRef { - typedef CharType Ch; //!< character type of the string - - //! Create string reference from \c const character array -#ifndef __clang__ // -Wdocumentation - /*! - This constructor implicitly creates a constant string reference from - a \c const character array. It has better performance than - \ref StringRef(const CharType*) by inferring the string \ref length - from the array length, and also supports strings containing null - characters. - - \tparam N length of the string, automatically inferred - - \param str Constant character array, lifetime assumed to be longer - than the use of the string in e.g. a GenericValue - - \post \ref s == str - - \note Constant complexity. - \note There is a hidden, private overload to disallow references to - non-const character arrays to be created via this constructor. - By this, e.g. function-scope arrays used to be filled via - \c snprintf are excluded from consideration. - In such cases, the referenced string should be \b copied to the - GenericValue instead. - */ -#endif - template - GenericStringRef(const CharType (&str)[N]) RAPIDJSON_NOEXCEPT - : s(str), length(N-1) {} - - //! Explicitly create string reference from \c const character pointer -#ifndef __clang__ // -Wdocumentation - /*! - This constructor can be used to \b explicitly create a reference to - a constant string pointer. - - \see StringRef(const CharType*) - - \param str Constant character pointer, lifetime assumed to be longer - than the use of the string in e.g. a GenericValue - - \post \ref s == str - - \note There is a hidden, private overload to disallow references to - non-const character arrays to be created via this constructor. - By this, e.g. function-scope arrays used to be filled via - \c snprintf are excluded from consideration. - In such cases, the referenced string should be \b copied to the - GenericValue instead. - */ -#endif - explicit GenericStringRef(const CharType* str) - : s(str), length(NotNullStrLen(str)) {} - - //! Create constant string reference from pointer and length -#ifndef __clang__ // -Wdocumentation - /*! \param str constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue - \param len length of the string, excluding the trailing NULL terminator - - \post \ref s == str && \ref length == len - \note Constant complexity. - */ -#endif - GenericStringRef(const CharType* str, SizeType len) - : s(RAPIDJSON_LIKELY(str) ? str : emptyString), length(len) { RAPIDJSON_ASSERT(str != 0 || len == 0u); } - - GenericStringRef(const GenericStringRef& rhs) : s(rhs.s), length(rhs.length) {} - - //! implicit conversion to plain CharType pointer - operator const Ch *() const { return s; } - - const Ch* const s; //!< plain CharType pointer - const SizeType length; //!< length of the string (excluding the trailing NULL terminator) - -private: - SizeType NotNullStrLen(const CharType* str) { - RAPIDJSON_ASSERT(str != 0); - return internal::StrLen(str); - } - - /// Empty string - used when passing in a NULL pointer - static const Ch emptyString[]; - - //! Disallow construction from non-const array - template - GenericStringRef(CharType (&str)[N]) /* = delete */; - //! Copy assignment operator not permitted - immutable type - GenericStringRef& operator=(const GenericStringRef& rhs) /* = delete */; -}; - -template -const CharType GenericStringRef::emptyString[] = { CharType() }; - -//! Mark a character pointer as constant string -/*! Mark a plain character pointer as a "string literal". This function - can be used to avoid copying a character string to be referenced as a - value in a JSON GenericValue object, if the string's lifetime is known - to be valid long enough. - \tparam CharType Character type of the string - \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue - \return GenericStringRef string reference object - \relatesalso GenericStringRef - - \see GenericValue::GenericValue(StringRefType), GenericValue::operator=(StringRefType), GenericValue::SetString(StringRefType), GenericValue::PushBack(StringRefType, Allocator&), GenericValue::AddMember -*/ -template -inline GenericStringRef StringRef(const CharType* str) { - return GenericStringRef(str); -} - -//! Mark a character pointer as constant string -/*! Mark a plain character pointer as a "string literal". This function - can be used to avoid copying a character string to be referenced as a - value in a JSON GenericValue object, if the string's lifetime is known - to be valid long enough. - - This version has better performance with supplied length, and also - supports string containing null characters. - - \tparam CharType character type of the string - \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue - \param length The length of source string. - \return GenericStringRef string reference object - \relatesalso GenericStringRef -*/ -template -inline GenericStringRef StringRef(const CharType* str, size_t length) { - return GenericStringRef(str, SizeType(length)); -} - -#if RAPIDJSON_HAS_STDSTRING -//! Mark a string object as constant string -/*! Mark a string object (e.g. \c std::string) as a "string literal". - This function can be used to avoid copying a string to be referenced as a - value in a JSON GenericValue object, if the string's lifetime is known - to be valid long enough. - - \tparam CharType character type of the string - \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue - \return GenericStringRef string reference object - \relatesalso GenericStringRef - \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. -*/ -template -inline GenericStringRef StringRef(const std::basic_string& str) { - return GenericStringRef(str.data(), SizeType(str.size())); -} -#endif - -/////////////////////////////////////////////////////////////////////////////// -// GenericValue type traits -namespace internal { - -template -struct IsGenericValueImpl : FalseType {}; - -// select candidates according to nested encoding and allocator types -template struct IsGenericValueImpl::Type, typename Void::Type> - : IsBaseOf, T>::Type {}; - -// helper to match arbitrary GenericValue instantiations, including derived classes -template struct IsGenericValue : IsGenericValueImpl::Type {}; - -} // namespace internal - -/////////////////////////////////////////////////////////////////////////////// -// TypeHelper - -namespace internal { - -template -struct TypeHelper {}; - -template -struct TypeHelper { - static bool Is(const ValueType& v) { return v.IsBool(); } - static bool Get(const ValueType& v) { return v.GetBool(); } - static ValueType& Set(ValueType& v, bool data) { return v.SetBool(data); } - static ValueType& Set(ValueType& v, bool data, typename ValueType::AllocatorType&) { return v.SetBool(data); } -}; - -template -struct TypeHelper { - static bool Is(const ValueType& v) { return v.IsInt(); } - static int Get(const ValueType& v) { return v.GetInt(); } - static ValueType& Set(ValueType& v, int data) { return v.SetInt(data); } - static ValueType& Set(ValueType& v, int data, typename ValueType::AllocatorType&) { return v.SetInt(data); } -}; - -template -struct TypeHelper { - static bool Is(const ValueType& v) { return v.IsUint(); } - static unsigned Get(const ValueType& v) { return v.GetUint(); } - static ValueType& Set(ValueType& v, unsigned data) { return v.SetUint(data); } - static ValueType& Set(ValueType& v, unsigned data, typename ValueType::AllocatorType&) { return v.SetUint(data); } -}; - -#ifdef _MSC_VER -RAPIDJSON_STATIC_ASSERT(sizeof(long) == sizeof(int)); -template -struct TypeHelper { - static bool Is(const ValueType& v) { return v.IsInt(); } - static long Get(const ValueType& v) { return v.GetInt(); } - static ValueType& Set(ValueType& v, long data) { return v.SetInt(data); } - static ValueType& Set(ValueType& v, long data, typename ValueType::AllocatorType&) { return v.SetInt(data); } -}; - -RAPIDJSON_STATIC_ASSERT(sizeof(unsigned long) == sizeof(unsigned)); -template -struct TypeHelper { - static bool Is(const ValueType& v) { return v.IsUint(); } - static unsigned long Get(const ValueType& v) { return v.GetUint(); } - static ValueType& Set(ValueType& v, unsigned long data) { return v.SetUint(data); } - static ValueType& Set(ValueType& v, unsigned long data, typename ValueType::AllocatorType&) { return v.SetUint(data); } -}; -#endif - -template -struct TypeHelper { - static bool Is(const ValueType& v) { return v.IsInt64(); } - static int64_t Get(const ValueType& v) { return v.GetInt64(); } - static ValueType& Set(ValueType& v, int64_t data) { return v.SetInt64(data); } - static ValueType& Set(ValueType& v, int64_t data, typename ValueType::AllocatorType&) { return v.SetInt64(data); } -}; - -template -struct TypeHelper { - static bool Is(const ValueType& v) { return v.IsUint64(); } - static uint64_t Get(const ValueType& v) { return v.GetUint64(); } - static ValueType& Set(ValueType& v, uint64_t data) { return v.SetUint64(data); } - static ValueType& Set(ValueType& v, uint64_t data, typename ValueType::AllocatorType&) { return v.SetUint64(data); } -}; - -template -struct TypeHelper { - static bool Is(const ValueType& v) { return v.IsDouble(); } - static double Get(const ValueType& v) { return v.GetDouble(); } - static ValueType& Set(ValueType& v, double data) { return v.SetDouble(data); } - static ValueType& Set(ValueType& v, double data, typename ValueType::AllocatorType&) { return v.SetDouble(data); } -}; - -template -struct TypeHelper { - static bool Is(const ValueType& v) { return v.IsFloat(); } - static float Get(const ValueType& v) { return v.GetFloat(); } - static ValueType& Set(ValueType& v, float data) { return v.SetFloat(data); } - static ValueType& Set(ValueType& v, float data, typename ValueType::AllocatorType&) { return v.SetFloat(data); } -}; - -template -struct TypeHelper { - typedef const typename ValueType::Ch* StringType; - static bool Is(const ValueType& v) { return v.IsString(); } - static StringType Get(const ValueType& v) { return v.GetString(); } - static ValueType& Set(ValueType& v, const StringType data) { return v.SetString(typename ValueType::StringRefType(data)); } - static ValueType& Set(ValueType& v, const StringType data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); } -}; - -#if RAPIDJSON_HAS_STDSTRING -template -struct TypeHelper > { - typedef std::basic_string StringType; - static bool Is(const ValueType& v) { return v.IsString(); } - static StringType Get(const ValueType& v) { return StringType(v.GetString(), v.GetStringLength()); } - static ValueType& Set(ValueType& v, const StringType& data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); } -}; -#endif - -template -struct TypeHelper { - typedef typename ValueType::Array ArrayType; - static bool Is(const ValueType& v) { return v.IsArray(); } - static ArrayType Get(ValueType& v) { return v.GetArray(); } - static ValueType& Set(ValueType& v, ArrayType data) { return v = data; } - static ValueType& Set(ValueType& v, ArrayType data, typename ValueType::AllocatorType&) { return v = data; } -}; - -template -struct TypeHelper { - typedef typename ValueType::ConstArray ArrayType; - static bool Is(const ValueType& v) { return v.IsArray(); } - static ArrayType Get(const ValueType& v) { return v.GetArray(); } -}; - -template -struct TypeHelper { - typedef typename ValueType::Object ObjectType; - static bool Is(const ValueType& v) { return v.IsObject(); } - static ObjectType Get(ValueType& v) { return v.GetObject(); } - static ValueType& Set(ValueType& v, ObjectType data) { return v = data; } - static ValueType& Set(ValueType& v, ObjectType data, typename ValueType::AllocatorType&) { return v = data; } -}; - -template -struct TypeHelper { - typedef typename ValueType::ConstObject ObjectType; - static bool Is(const ValueType& v) { return v.IsObject(); } - static ObjectType Get(const ValueType& v) { return v.GetObject(); } -}; - -} // namespace internal - -// Forward declarations -template class GenericArray; -template class GenericObject; - -/////////////////////////////////////////////////////////////////////////////// -// GenericValue - -//! Represents a JSON value. Use Value for UTF8 encoding and default allocator. -/*! - A JSON value can be one of 7 types. This class is a variant type supporting - these types. - - Use the Value if UTF8 and default allocator - - \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document) - \tparam Allocator Allocator type for allocating memory of object, array and string. -*/ -template -class GenericValue { -public: - //! Name-value pair in an object. - typedef GenericMember Member; - typedef Encoding EncodingType; //!< Encoding type from template parameter. - typedef Allocator AllocatorType; //!< Allocator type from template parameter. - typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. - typedef GenericStringRef StringRefType; //!< Reference to a constant string - typedef typename GenericMemberIterator::Iterator MemberIterator; //!< Member iterator for iterating in object. - typedef typename GenericMemberIterator::Iterator ConstMemberIterator; //!< Constant member iterator for iterating in object. - typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array. - typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array. - typedef GenericValue ValueType; //!< Value type of itself. - typedef GenericArray Array; - typedef GenericArray ConstArray; - typedef GenericObject Object; - typedef GenericObject ConstObject; - - //!@name Constructors and destructor. - //@{ - - //! Default constructor creates a null value. - GenericValue() RAPIDJSON_NOEXCEPT : data_() { data_.f.flags = kNullFlag; } - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - //! Move constructor in C++11 - GenericValue(GenericValue&& rhs) RAPIDJSON_NOEXCEPT : data_(rhs.data_) { - rhs.data_.f.flags = kNullFlag; // give up contents - } -#endif - -private: - //! Copy constructor is not permitted. - GenericValue(const GenericValue& rhs); - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - //! Moving from a GenericDocument is not permitted. - template - GenericValue(GenericDocument&& rhs); - - //! Move assignment from a GenericDocument is not permitted. - template - GenericValue& operator=(GenericDocument&& rhs); -#endif - -public: - - //! Constructor with JSON value type. - /*! This creates a Value of specified type with default content. - \param type Type of the value. - \note Default content for number is zero. - */ - explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_() { - static const uint16_t defaultFlags[] = { - kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag, - kNumberAnyFlag - }; - RAPIDJSON_NOEXCEPT_ASSERT(type >= kNullType && type <= kNumberType); - data_.f.flags = defaultFlags[type]; - - // Use ShortString to store empty string. - if (type == kStringType) - data_.ss.SetLength(0); - } - - //! Explicit copy constructor (with allocator) - /*! Creates a copy of a Value by using the given Allocator - \tparam SourceAllocator allocator of \c rhs - \param rhs Value to copy from (read-only) - \param allocator Allocator for allocating copied elements and buffers. Commonly use GenericDocument::GetAllocator(). - \param copyConstStrings Force copying of constant strings (e.g. referencing an in-situ buffer) - \see CopyFrom() - */ - template - GenericValue(const GenericValue& rhs, Allocator& allocator, bool copyConstStrings = false) { - switch (rhs.GetType()) { - case kObjectType: - DoCopyMembers(rhs, allocator, copyConstStrings); - break; - case kArrayType: { - SizeType count = rhs.data_.a.size; - GenericValue* le = reinterpret_cast(allocator.Malloc(count * sizeof(GenericValue))); - const GenericValue* re = rhs.GetElementsPointer(); - for (SizeType i = 0; i < count; i++) - new (&le[i]) GenericValue(re[i], allocator, copyConstStrings); - data_.f.flags = kArrayFlag; - data_.a.size = data_.a.capacity = count; - SetElementsPointer(le); - } - break; - case kStringType: - if (rhs.data_.f.flags == kConstStringFlag && !copyConstStrings) { - data_.f.flags = rhs.data_.f.flags; - data_ = *reinterpret_cast(&rhs.data_); - } - else - SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator); - break; - default: - data_.f.flags = rhs.data_.f.flags; - data_ = *reinterpret_cast(&rhs.data_); - break; - } - } - - //! Constructor for boolean value. - /*! \param b Boolean value - \note This constructor is limited to \em real boolean values and rejects - implicitly converted types like arbitrary pointers. Use an explicit cast - to \c bool, if you want to construct a boolean JSON value in such cases. - */ -#ifndef RAPIDJSON_DOXYGEN_RUNNING // hide SFINAE from Doxygen - template - explicit GenericValue(T b, RAPIDJSON_ENABLEIF((internal::IsSame))) RAPIDJSON_NOEXCEPT // See #472 -#else - explicit GenericValue(bool b) RAPIDJSON_NOEXCEPT -#endif - : data_() { - // safe-guard against failing SFINAE - RAPIDJSON_STATIC_ASSERT((internal::IsSame::Value)); - data_.f.flags = b ? kTrueFlag : kFalseFlag; - } - - //! Constructor for int value. - explicit GenericValue(int i) RAPIDJSON_NOEXCEPT : data_() { - data_.n.i64 = i; - data_.f.flags = (i >= 0) ? (kNumberIntFlag | kUintFlag | kUint64Flag) : kNumberIntFlag; - } - - //! Constructor for unsigned value. - explicit GenericValue(unsigned u) RAPIDJSON_NOEXCEPT : data_() { - data_.n.u64 = u; - data_.f.flags = (u & 0x80000000) ? kNumberUintFlag : (kNumberUintFlag | kIntFlag | kInt64Flag); - } - - //! Constructor for int64_t value. - explicit GenericValue(int64_t i64) RAPIDJSON_NOEXCEPT : data_() { - data_.n.i64 = i64; - data_.f.flags = kNumberInt64Flag; - if (i64 >= 0) { - data_.f.flags |= kNumberUint64Flag; - if (!(static_cast(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) - data_.f.flags |= kUintFlag; - if (!(static_cast(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) - data_.f.flags |= kIntFlag; - } - else if (i64 >= static_cast(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) - data_.f.flags |= kIntFlag; - } - - //! Constructor for uint64_t value. - explicit GenericValue(uint64_t u64) RAPIDJSON_NOEXCEPT : data_() { - data_.n.u64 = u64; - data_.f.flags = kNumberUint64Flag; - if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000))) - data_.f.flags |= kInt64Flag; - if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) - data_.f.flags |= kUintFlag; - if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) - data_.f.flags |= kIntFlag; - } - - //! Constructor for double value. - explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = d; data_.f.flags = kNumberDoubleFlag; } - - //! Constructor for float value. - explicit GenericValue(float f) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = static_cast(f); data_.f.flags = kNumberDoubleFlag; } - - //! Constructor for constant string (i.e. do not make a copy of string) - GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(StringRef(s, length)); } - - //! Constructor for constant string (i.e. do not make a copy of string) - explicit GenericValue(StringRefType s) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(s); } - - //! Constructor for copy-string (i.e. do make a copy of string) - GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_() { SetStringRaw(StringRef(s, length), allocator); } - - //! Constructor for copy-string (i.e. do make a copy of string) - GenericValue(const Ch*s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); } - -#if RAPIDJSON_HAS_STDSTRING - //! Constructor for copy-string from a string object (i.e. do make a copy of string) - /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. - */ - GenericValue(const std::basic_string& s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); } -#endif - - //! Constructor for Array. - /*! - \param a An array obtained by \c GetArray(). - \note \c Array is always pass-by-value. - \note the source array is moved into this value and the sourec array becomes empty. - */ - GenericValue(Array a) RAPIDJSON_NOEXCEPT : data_(a.value_.data_) { - a.value_.data_ = Data(); - a.value_.data_.f.flags = kArrayFlag; - } - - //! Constructor for Object. - /*! - \param o An object obtained by \c GetObject(). - \note \c Object is always pass-by-value. - \note the source object is moved into this value and the sourec object becomes empty. - */ - GenericValue(Object o) RAPIDJSON_NOEXCEPT : data_(o.value_.data_) { - o.value_.data_ = Data(); - o.value_.data_.f.flags = kObjectFlag; - } - - //! Destructor. - /*! Need to destruct elements of array, members of object, or copy-string. - */ - ~GenericValue() { - // With RAPIDJSON_USE_MEMBERSMAP, the maps need to be destroyed to release - // their Allocator if it's refcounted (e.g. MemoryPoolAllocator). - if (Allocator::kNeedFree || (RAPIDJSON_USE_MEMBERSMAP+0 && - internal::IsRefCounted::Value)) { - switch(data_.f.flags) { - case kArrayFlag: - { - GenericValue* e = GetElementsPointer(); - for (GenericValue* v = e; v != e + data_.a.size; ++v) - v->~GenericValue(); - if (Allocator::kNeedFree) { // Shortcut by Allocator's trait - Allocator::Free(e); - } - } - break; - - case kObjectFlag: - DoFreeMembers(); - break; - - case kCopyStringFlag: - if (Allocator::kNeedFree) { // Shortcut by Allocator's trait - Allocator::Free(const_cast(GetStringPointer())); - } - break; - - default: - break; // Do nothing for other types. - } - } - } - - //@} - - //!@name Assignment operators - //@{ - - //! Assignment with move semantics. - /*! \param rhs Source of the assignment. It will become a null value after assignment. - */ - GenericValue& operator=(GenericValue& rhs) RAPIDJSON_NOEXCEPT { - if (RAPIDJSON_LIKELY(this != &rhs)) { - // Can't destroy "this" before assigning "rhs", otherwise "rhs" - // could be used after free if it's an sub-Value of "this", - // hence the temporary danse. - GenericValue temp; - temp.RawAssign(rhs); - this->~GenericValue(); - RawAssign(temp); - } - return *this; - } - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - //! Move assignment in C++11 - GenericValue& operator=(GenericValue&& rhs) RAPIDJSON_NOEXCEPT { - return *this = rhs.Move(); - } -#endif - - //! Assignment of constant string reference (no copy) - /*! \param str Constant string reference to be assigned - \note This overload is needed to avoid clashes with the generic primitive type assignment overload below. - \see GenericStringRef, operator=(T) - */ - GenericValue& operator=(StringRefType str) RAPIDJSON_NOEXCEPT { - GenericValue s(str); - return *this = s; - } - - //! Assignment with primitive types. - /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t - \param value The value to be assigned. - - \note The source type \c T explicitly disallows all pointer types, - especially (\c const) \ref Ch*. This helps avoiding implicitly - referencing character strings with insufficient lifetime, use - \ref SetString(const Ch*, Allocator&) (for copying) or - \ref StringRef() (to explicitly mark the pointer as constant) instead. - All other pointer types would implicitly convert to \c bool, - use \ref SetBool() instead. - */ - template - RAPIDJSON_DISABLEIF_RETURN((internal::IsPointer), (GenericValue&)) - operator=(T value) { - GenericValue v(value); - return *this = v; - } - - //! Deep-copy assignment from Value - /*! Assigns a \b copy of the Value to the current Value object - \tparam SourceAllocator Allocator type of \c rhs - \param rhs Value to copy from (read-only) - \param allocator Allocator to use for copying - \param copyConstStrings Force copying of constant strings (e.g. referencing an in-situ buffer) - */ - template - GenericValue& CopyFrom(const GenericValue& rhs, Allocator& allocator, bool copyConstStrings = false) { - RAPIDJSON_ASSERT(static_cast(this) != static_cast(&rhs)); - this->~GenericValue(); - new (this) GenericValue(rhs, allocator, copyConstStrings); - return *this; - } - - //! Exchange the contents of this value with those of other. - /*! - \param other Another value. - \note Constant complexity. - */ - GenericValue& Swap(GenericValue& other) RAPIDJSON_NOEXCEPT { - GenericValue temp; - temp.RawAssign(*this); - RawAssign(other); - other.RawAssign(temp); - return *this; - } - - //! free-standing swap function helper - /*! - Helper function to enable support for common swap implementation pattern based on \c std::swap: - \code - void swap(MyClass& a, MyClass& b) { - using std::swap; - swap(a.value, b.value); - // ... - } - \endcode - \see Swap() - */ - friend inline void swap(GenericValue& a, GenericValue& b) RAPIDJSON_NOEXCEPT { a.Swap(b); } - - //! Prepare Value for move semantics - /*! \return *this */ - GenericValue& Move() RAPIDJSON_NOEXCEPT { return *this; } - //@} - - //!@name Equal-to and not-equal-to operators - //@{ - //! Equal-to operator - /*! - \note If an object contains duplicated named member, comparing equality with any object is always \c false. - \note Complexity is quadratic in Object's member number and linear for the rest (number of all values in the subtree and total lengths of all strings). - */ - template - bool operator==(const GenericValue& rhs) const { - typedef GenericValue RhsType; - if (GetType() != rhs.GetType()) - return false; - - switch (GetType()) { - case kObjectType: // Warning: O(n^2) inner-loop - if (data_.o.size != rhs.data_.o.size) - return false; - for (ConstMemberIterator lhsMemberItr = MemberBegin(); lhsMemberItr != MemberEnd(); ++lhsMemberItr) { - typename RhsType::ConstMemberIterator rhsMemberItr = rhs.FindMember(lhsMemberItr->name); - if (rhsMemberItr == rhs.MemberEnd() || lhsMemberItr->value != rhsMemberItr->value) - return false; - } - return true; - - case kArrayType: - if (data_.a.size != rhs.data_.a.size) - return false; - for (SizeType i = 0; i < data_.a.size; i++) - if ((*this)[i] != rhs[i]) - return false; - return true; - - case kStringType: - return StringEqual(rhs); - - case kNumberType: - if (IsDouble() || rhs.IsDouble()) { - double a = GetDouble(); // May convert from integer to double. - double b = rhs.GetDouble(); // Ditto - return a >= b && a <= b; // Prevent -Wfloat-equal - } - else - return data_.n.u64 == rhs.data_.n.u64; - - default: - return true; - } - } - - //! Equal-to operator with const C-string pointer - bool operator==(const Ch* rhs) const { return *this == GenericValue(StringRef(rhs)); } - -#if RAPIDJSON_HAS_STDSTRING - //! Equal-to operator with string object - /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. - */ - bool operator==(const std::basic_string& rhs) const { return *this == GenericValue(StringRef(rhs)); } -#endif - - //! Equal-to operator with primitive types - /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c true, \c false - */ - template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr,internal::IsGenericValue >), (bool)) operator==(const T& rhs) const { return *this == GenericValue(rhs); } - - //! Not-equal-to operator - /*! \return !(*this == rhs) - */ - template - bool operator!=(const GenericValue& rhs) const { return !(*this == rhs); } - - //! Not-equal-to operator with const C-string pointer - bool operator!=(const Ch* rhs) const { return !(*this == rhs); } - - //! Not-equal-to operator with arbitrary types - /*! \return !(*this == rhs) - */ - template RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator!=(const T& rhs) const { return !(*this == rhs); } - -#ifndef __cpp_lib_three_way_comparison - //! Equal-to operator with arbitrary types (symmetric version) - /*! \return (rhs == lhs) - */ - template friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator==(const T& lhs, const GenericValue& rhs) { return rhs == lhs; } - - //! Not-Equal-to operator with arbitrary types (symmetric version) - /*! \return !(rhs == lhs) - */ - template friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); } - //@} -#endif - - //!@name Type - //@{ - - Type GetType() const { return static_cast(data_.f.flags & kTypeMask); } - bool IsNull() const { return data_.f.flags == kNullFlag; } - bool IsFalse() const { return data_.f.flags == kFalseFlag; } - bool IsTrue() const { return data_.f.flags == kTrueFlag; } - bool IsBool() const { return (data_.f.flags & kBoolFlag) != 0; } - bool IsObject() const { return data_.f.flags == kObjectFlag; } - bool IsArray() const { return data_.f.flags == kArrayFlag; } - bool IsNumber() const { return (data_.f.flags & kNumberFlag) != 0; } - bool IsInt() const { return (data_.f.flags & kIntFlag) != 0; } - bool IsUint() const { return (data_.f.flags & kUintFlag) != 0; } - bool IsInt64() const { return (data_.f.flags & kInt64Flag) != 0; } - bool IsUint64() const { return (data_.f.flags & kUint64Flag) != 0; } - bool IsDouble() const { return (data_.f.flags & kDoubleFlag) != 0; } - bool IsString() const { return (data_.f.flags & kStringFlag) != 0; } - - // Checks whether a number can be losslessly converted to a double. - bool IsLosslessDouble() const { - if (!IsNumber()) return false; - if (IsUint64()) { - uint64_t u = GetUint64(); - volatile double d = static_cast(u); - return (d >= 0.0) - && (d < static_cast((std::numeric_limits::max)())) - && (u == static_cast(d)); - } - if (IsInt64()) { - int64_t i = GetInt64(); - volatile double d = static_cast(i); - return (d >= static_cast((std::numeric_limits::min)())) - && (d < static_cast((std::numeric_limits::max)())) - && (i == static_cast(d)); - } - return true; // double, int, uint are always lossless - } - - // Checks whether a number is a float (possible lossy). - bool IsFloat() const { - if ((data_.f.flags & kDoubleFlag) == 0) - return false; - double d = GetDouble(); - return d >= -3.4028234e38 && d <= 3.4028234e38; - } - // Checks whether a number can be losslessly converted to a float. - bool IsLosslessFloat() const { - if (!IsNumber()) return false; - double a = GetDouble(); - if (a < static_cast(-(std::numeric_limits::max)()) - || a > static_cast((std::numeric_limits::max)())) - return false; - double b = static_cast(static_cast(a)); - return a >= b && a <= b; // Prevent -Wfloat-equal - } - - //@} - - //!@name Null - //@{ - - GenericValue& SetNull() { this->~GenericValue(); new (this) GenericValue(); return *this; } - - //@} - - //!@name Bool - //@{ - - bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return data_.f.flags == kTrueFlag; } - //!< Set boolean value - /*! \post IsBool() == true */ - GenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; } - - //@} - - //!@name Object - //@{ - - //! Set this value as an empty object. - /*! \post IsObject() == true */ - GenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; } - - //! Get the number of members in the object. - SizeType MemberCount() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size; } - - //! Get the capacity of object. - SizeType MemberCapacity() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.capacity; } - - //! Check whether the object is empty. - bool ObjectEmpty() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size == 0; } - - //! Get a value from an object associated with the name. - /*! \pre IsObject() == true - \tparam T Either \c Ch or \c const \c Ch (template used for disambiguation with \ref operator[](SizeType)) - \note In version 0.1x, if the member is not found, this function returns a null value. This makes issue 7. - Since 0.2, if the name is not correct, it will assert. - If user is unsure whether a member exists, user should use HasMember() first. - A better approach is to use FindMember(). - \note Linear time complexity. - */ - template - RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >),(GenericValue&)) operator[](T* name) { - GenericValue n(StringRef(name)); - return (*this)[n]; - } - template - RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >),(const GenericValue&)) operator[](T* name) const { return const_cast(*this)[name]; } - - //! Get a value from an object associated with the name. - /*! \pre IsObject() == true - \tparam SourceAllocator Allocator of the \c name value - - \note Compared to \ref operator[](T*), this version is faster because it does not need a StrLen(). - And it can also handle strings with embedded null characters. - - \note Linear time complexity. - */ - template - GenericValue& operator[](const GenericValue& name) { - MemberIterator member = FindMember(name); - if (member != MemberEnd()) - return member->value; - else { - RAPIDJSON_ASSERT(false); // see above note - - // This will generate -Wexit-time-destructors in clang - // static GenericValue NullValue; - // return NullValue; - - // Use static buffer and placement-new to prevent destruction - static char buffer[sizeof(GenericValue)]; - return *new (buffer) GenericValue(); - } - } - template - const GenericValue& operator[](const GenericValue& name) const { return const_cast(*this)[name]; } - -#if RAPIDJSON_HAS_STDSTRING - //! Get a value from an object associated with name (string object). - GenericValue& operator[](const std::basic_string& name) { return (*this)[GenericValue(StringRef(name))]; } - const GenericValue& operator[](const std::basic_string& name) const { return (*this)[GenericValue(StringRef(name))]; } -#endif - - //! Const member iterator - /*! \pre IsObject() == true */ - ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer()); } - //! Const \em past-the-end member iterator - /*! \pre IsObject() == true */ - ConstMemberIterator MemberEnd() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer() + data_.o.size); } - //! Member iterator - /*! \pre IsObject() == true */ - MemberIterator MemberBegin() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer()); } - //! \em Past-the-end member iterator - /*! \pre IsObject() == true */ - MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer() + data_.o.size); } - - //! Request the object to have enough capacity to store members. - /*! \param newCapacity The capacity that the object at least need to have. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \note Linear time complexity. - */ - GenericValue& MemberReserve(SizeType newCapacity, Allocator &allocator) { - RAPIDJSON_ASSERT(IsObject()); - DoReserveMembers(newCapacity, allocator); - return *this; - } - - //! Check whether a member exists in the object. - /*! - \param name Member name to be searched. - \pre IsObject() == true - \return Whether a member with that name exists. - \note It is better to use FindMember() directly if you need the obtain the value as well. - \note Linear time complexity. - */ - bool HasMember(const Ch* name) const { return FindMember(name) != MemberEnd(); } - -#if RAPIDJSON_HAS_STDSTRING - //! Check whether a member exists in the object with string object. - /*! - \param name Member name to be searched. - \pre IsObject() == true - \return Whether a member with that name exists. - \note It is better to use FindMember() directly if you need the obtain the value as well. - \note Linear time complexity. - */ - bool HasMember(const std::basic_string& name) const { return FindMember(name) != MemberEnd(); } -#endif - - //! Check whether a member exists in the object with GenericValue name. - /*! - This version is faster because it does not need a StrLen(). It can also handle string with null character. - \param name Member name to be searched. - \pre IsObject() == true - \return Whether a member with that name exists. - \note It is better to use FindMember() directly if you need the obtain the value as well. - \note Linear time complexity. - */ - template - bool HasMember(const GenericValue& name) const { return FindMember(name) != MemberEnd(); } - - //! Find member by name. - /*! - \param name Member name to be searched. - \pre IsObject() == true - \return Iterator to member, if it exists. - Otherwise returns \ref MemberEnd(). - - \note Earlier versions of Rapidjson returned a \c NULL pointer, in case - the requested member doesn't exist. For consistency with e.g. - \c std::map, this has been changed to MemberEnd() now. - \note Linear time complexity. - */ - MemberIterator FindMember(const Ch* name) { - GenericValue n(StringRef(name)); - return FindMember(n); - } - - ConstMemberIterator FindMember(const Ch* name) const { return const_cast(*this).FindMember(name); } - - //! Find member by name. - /*! - This version is faster because it does not need a StrLen(). It can also handle string with null character. - \param name Member name to be searched. - \pre IsObject() == true - \return Iterator to member, if it exists. - Otherwise returns \ref MemberEnd(). - - \note Earlier versions of Rapidjson returned a \c NULL pointer, in case - the requested member doesn't exist. For consistency with e.g. - \c std::map, this has been changed to MemberEnd() now. - \note Linear time complexity. - */ - template - MemberIterator FindMember(const GenericValue& name) { - RAPIDJSON_ASSERT(IsObject()); - RAPIDJSON_ASSERT(name.IsString()); - return DoFindMember(name); - } - template ConstMemberIterator FindMember(const GenericValue& name) const { return const_cast(*this).FindMember(name); } - -#if RAPIDJSON_HAS_STDSTRING - //! Find member by string object name. - /*! - \param name Member name to be searched. - \pre IsObject() == true - \return Iterator to member, if it exists. - Otherwise returns \ref MemberEnd(). - */ - MemberIterator FindMember(const std::basic_string& name) { return FindMember(GenericValue(StringRef(name))); } - ConstMemberIterator FindMember(const std::basic_string& name) const { return FindMember(GenericValue(StringRef(name))); } -#endif - - //! Add a member (name-value pair) to the object. - /*! \param name A string value as name of member. - \param value Value of any type. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \note The ownership of \c name and \c value will be transferred to this object on success. - \pre IsObject() && name.IsString() - \post name.IsNull() && value.IsNull() - \note Amortized Constant time complexity. - */ - GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) { - RAPIDJSON_ASSERT(IsObject()); - RAPIDJSON_ASSERT(name.IsString()); - DoAddMember(name, value, allocator); - return *this; - } - - //! Add a constant string value as member (name-value pair) to the object. - /*! \param name A string value as name of member. - \param value constant string reference as value of member. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \pre IsObject() - \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below. - \note Amortized Constant time complexity. - */ - GenericValue& AddMember(GenericValue& name, StringRefType value, Allocator& allocator) { - GenericValue v(value); - return AddMember(name, v, allocator); - } - -#if RAPIDJSON_HAS_STDSTRING - //! Add a string object as member (name-value pair) to the object. - /*! \param name A string value as name of member. - \param value constant string reference as value of member. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \pre IsObject() - \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below. - \note Amortized Constant time complexity. - */ - GenericValue& AddMember(GenericValue& name, std::basic_string& value, Allocator& allocator) { - GenericValue v(value, allocator); - return AddMember(name, v, allocator); - } -#endif - - //! Add any primitive value as member (name-value pair) to the object. - /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t - \param name A string value as name of member. - \param value Value of primitive type \c T as value of member - \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \pre IsObject() - - \note The source type \c T explicitly disallows all pointer types, - especially (\c const) \ref Ch*. This helps avoiding implicitly - referencing character strings with insufficient lifetime, use - \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref - AddMember(StringRefType, StringRefType, Allocator&). - All other pointer types would implicitly convert to \c bool, - use an explicit cast instead, if needed. - \note Amortized Constant time complexity. - */ - template - RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&)) - AddMember(GenericValue& name, T value, Allocator& allocator) { - GenericValue v(value); - return AddMember(name, v, allocator); - } - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - GenericValue& AddMember(GenericValue&& name, GenericValue&& value, Allocator& allocator) { - return AddMember(name, value, allocator); - } - GenericValue& AddMember(GenericValue&& name, GenericValue& value, Allocator& allocator) { - return AddMember(name, value, allocator); - } - GenericValue& AddMember(GenericValue& name, GenericValue&& value, Allocator& allocator) { - return AddMember(name, value, allocator); - } - GenericValue& AddMember(StringRefType name, GenericValue&& value, Allocator& allocator) { - GenericValue n(name); - return AddMember(n, value, allocator); - } -#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS - - - //! Add a member (name-value pair) to the object. - /*! \param name A constant string reference as name of member. - \param value Value of any type. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \note The ownership of \c value will be transferred to this object on success. - \pre IsObject() - \post value.IsNull() - \note Amortized Constant time complexity. - */ - GenericValue& AddMember(StringRefType name, GenericValue& value, Allocator& allocator) { - GenericValue n(name); - return AddMember(n, value, allocator); - } - - //! Add a constant string value as member (name-value pair) to the object. - /*! \param name A constant string reference as name of member. - \param value constant string reference as value of member. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \pre IsObject() - \note This overload is needed to avoid clashes with the generic primitive type AddMember(StringRefType,T,Allocator&) overload below. - \note Amortized Constant time complexity. - */ - GenericValue& AddMember(StringRefType name, StringRefType value, Allocator& allocator) { - GenericValue v(value); - return AddMember(name, v, allocator); - } - - //! Add any primitive value as member (name-value pair) to the object. - /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t - \param name A constant string reference as name of member. - \param value Value of primitive type \c T as value of member - \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \pre IsObject() - - \note The source type \c T explicitly disallows all pointer types, - especially (\c const) \ref Ch*. This helps avoiding implicitly - referencing character strings with insufficient lifetime, use - \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref - AddMember(StringRefType, StringRefType, Allocator&). - All other pointer types would implicitly convert to \c bool, - use an explicit cast instead, if needed. - \note Amortized Constant time complexity. - */ - template - RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&)) - AddMember(StringRefType name, T value, Allocator& allocator) { - GenericValue n(name); - return AddMember(n, value, allocator); - } - - //! Remove all members in the object. - /*! This function do not deallocate memory in the object, i.e. the capacity is unchanged. - \note Linear time complexity. - */ - void RemoveAllMembers() { - RAPIDJSON_ASSERT(IsObject()); - DoClearMembers(); - } - - //! Remove a member in object by its name. - /*! \param name Name of member to be removed. - \return Whether the member existed. - \note This function may reorder the object members. Use \ref - EraseMember(ConstMemberIterator) if you need to preserve the - relative order of the remaining members. - \note Linear time complexity. - */ - bool RemoveMember(const Ch* name) { - GenericValue n(StringRef(name)); - return RemoveMember(n); - } - -#if RAPIDJSON_HAS_STDSTRING - bool RemoveMember(const std::basic_string& name) { return RemoveMember(GenericValue(StringRef(name))); } -#endif - - template - bool RemoveMember(const GenericValue& name) { - MemberIterator m = FindMember(name); - if (m != MemberEnd()) { - RemoveMember(m); - return true; - } - else - return false; - } - - //! Remove a member in object by iterator. - /*! \param m member iterator (obtained by FindMember() or MemberBegin()). - \return the new iterator after removal. - \note This function may reorder the object members. Use \ref - EraseMember(ConstMemberIterator) if you need to preserve the - relative order of the remaining members. - \note Constant time complexity. - */ - MemberIterator RemoveMember(MemberIterator m) { - RAPIDJSON_ASSERT(IsObject()); - RAPIDJSON_ASSERT(data_.o.size > 0); - RAPIDJSON_ASSERT(GetMembersPointer() != 0); - RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd()); - return DoRemoveMember(m); - } - - //! Remove a member from an object by iterator. - /*! \param pos iterator to the member to remove - \pre IsObject() == true && \ref MemberBegin() <= \c pos < \ref MemberEnd() - \return Iterator following the removed element. - If the iterator \c pos refers to the last element, the \ref MemberEnd() iterator is returned. - \note This function preserves the relative order of the remaining object - members. If you do not need this, use the more efficient \ref RemoveMember(MemberIterator). - \note Linear time complexity. - */ - MemberIterator EraseMember(ConstMemberIterator pos) { - return EraseMember(pos, pos +1); - } - - //! Remove members in the range [first, last) from an object. - /*! \param first iterator to the first member to remove - \param last iterator following the last member to remove - \pre IsObject() == true && \ref MemberBegin() <= \c first <= \c last <= \ref MemberEnd() - \return Iterator following the last removed element. - \note This function preserves the relative order of the remaining object - members. - \note Linear time complexity. - */ - MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) { - RAPIDJSON_ASSERT(IsObject()); - RAPIDJSON_ASSERT(data_.o.size > 0); - RAPIDJSON_ASSERT(GetMembersPointer() != 0); - RAPIDJSON_ASSERT(first >= MemberBegin()); - RAPIDJSON_ASSERT(first <= last); - RAPIDJSON_ASSERT(last <= MemberEnd()); - return DoEraseMembers(first, last); - } - - //! Erase a member in object by its name. - /*! \param name Name of member to be removed. - \return Whether the member existed. - \note Linear time complexity. - */ - bool EraseMember(const Ch* name) { - GenericValue n(StringRef(name)); - return EraseMember(n); - } - -#if RAPIDJSON_HAS_STDSTRING - bool EraseMember(const std::basic_string& name) { return EraseMember(GenericValue(StringRef(name))); } -#endif - - template - bool EraseMember(const GenericValue& name) { - MemberIterator m = FindMember(name); - if (m != MemberEnd()) { - EraseMember(m); - return true; - } - else - return false; - } - - Object GetObject() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); } - Object GetObj() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); } - ConstObject GetObject() const { RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); } - ConstObject GetObj() const { RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); } - - //@} - - //!@name Array - //@{ - - //! Set this value as an empty array. - /*! \post IsArray == true */ - GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; } - - //! Get the number of elements in array. - SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; } - - //! Get the capacity of array. - SizeType Capacity() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.capacity; } - - //! Check whether the array is empty. - bool Empty() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size == 0; } - - //! Remove all elements in the array. - /*! This function do not deallocate memory in the array, i.e. the capacity is unchanged. - \note Linear time complexity. - */ - void Clear() { - RAPIDJSON_ASSERT(IsArray()); - GenericValue* e = GetElementsPointer(); - for (GenericValue* v = e; v != e + data_.a.size; ++v) - v->~GenericValue(); - data_.a.size = 0; - } - - //! Get an element from array by index. - /*! \pre IsArray() == true - \param index Zero-based index of element. - \see operator[](T*) - */ - GenericValue& operator[](SizeType index) { - RAPIDJSON_ASSERT(IsArray()); - RAPIDJSON_ASSERT(index < data_.a.size); - return GetElementsPointer()[index]; - } - const GenericValue& operator[](SizeType index) const { return const_cast(*this)[index]; } - - //! Element iterator - /*! \pre IsArray() == true */ - ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer(); } - //! \em Past-the-end element iterator - /*! \pre IsArray() == true */ - ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer() + data_.a.size; } - //! Constant element iterator - /*! \pre IsArray() == true */ - ConstValueIterator Begin() const { return const_cast(*this).Begin(); } - //! Constant \em past-the-end element iterator - /*! \pre IsArray() == true */ - ConstValueIterator End() const { return const_cast(*this).End(); } - - //! Request the array to have enough capacity to store elements. - /*! \param newCapacity The capacity that the array at least need to have. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \note Linear time complexity. - */ - GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) { - RAPIDJSON_ASSERT(IsArray()); - if (newCapacity > data_.a.capacity) { - SetElementsPointer(reinterpret_cast(allocator.Realloc(GetElementsPointer(), data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue)))); - data_.a.capacity = newCapacity; - } - return *this; - } - - //! Append a GenericValue at the end of the array. - /*! \param value Value to be appended. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \pre IsArray() == true - \post value.IsNull() == true - \return The value itself for fluent API. - \note The ownership of \c value will be transferred to this array on success. - \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. - \note Amortized constant time complexity. - */ - GenericValue& PushBack(GenericValue& value, Allocator& allocator) { - RAPIDJSON_ASSERT(IsArray()); - if (data_.a.size >= data_.a.capacity) - Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : (data_.a.capacity + (data_.a.capacity + 1) / 2), allocator); - GetElementsPointer()[data_.a.size++].RawAssign(value); - return *this; - } - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - GenericValue& PushBack(GenericValue&& value, Allocator& allocator) { - return PushBack(value, allocator); - } -#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS - - //! Append a constant string reference at the end of the array. - /*! \param value Constant string reference to be appended. - \param allocator Allocator for reallocating memory. It must be the same one used previously. Commonly use GenericDocument::GetAllocator(). - \pre IsArray() == true - \return The value itself for fluent API. - \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. - \note Amortized constant time complexity. - \see GenericStringRef - */ - GenericValue& PushBack(StringRefType value, Allocator& allocator) { - return (*this).template PushBack(value, allocator); - } - - //! Append a primitive value at the end of the array. - /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t - \param value Value of primitive type T to be appended. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \pre IsArray() == true - \return The value itself for fluent API. - \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. - - \note The source type \c T explicitly disallows all pointer types, - especially (\c const) \ref Ch*. This helps avoiding implicitly - referencing character strings with insufficient lifetime, use - \ref PushBack(GenericValue&, Allocator&) or \ref - PushBack(StringRefType, Allocator&). - All other pointer types would implicitly convert to \c bool, - use an explicit cast instead, if needed. - \note Amortized constant time complexity. - */ - template - RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&)) - PushBack(T value, Allocator& allocator) { - GenericValue v(value); - return PushBack(v, allocator); - } - - //! Remove the last element in the array. - /*! - \note Constant time complexity. - */ - GenericValue& PopBack() { - RAPIDJSON_ASSERT(IsArray()); - RAPIDJSON_ASSERT(!Empty()); - GetElementsPointer()[--data_.a.size].~GenericValue(); - return *this; - } - - //! Remove an element of array by iterator. - /*! - \param pos iterator to the element to remove - \pre IsArray() == true && \ref Begin() <= \c pos < \ref End() - \return Iterator following the removed element. If the iterator pos refers to the last element, the End() iterator is returned. - \note Linear time complexity. - */ - ValueIterator Erase(ConstValueIterator pos) { - return Erase(pos, pos + 1); - } - - //! Remove elements in the range [first, last) of the array. - /*! - \param first iterator to the first element to remove - \param last iterator following the last element to remove - \pre IsArray() == true && \ref Begin() <= \c first <= \c last <= \ref End() - \return Iterator following the last removed element. - \note Linear time complexity. - */ - ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) { - RAPIDJSON_ASSERT(IsArray()); - RAPIDJSON_ASSERT(data_.a.size > 0); - RAPIDJSON_ASSERT(GetElementsPointer() != 0); - RAPIDJSON_ASSERT(first >= Begin()); - RAPIDJSON_ASSERT(first <= last); - RAPIDJSON_ASSERT(last <= End()); - ValueIterator pos = Begin() + (first - Begin()); - for (ValueIterator itr = pos; itr != last; ++itr) - itr->~GenericValue(); - std::memmove(static_cast(pos), last, static_cast(End() - last) * sizeof(GenericValue)); - data_.a.size -= static_cast(last - first); - return pos; - } - - Array GetArray() { RAPIDJSON_ASSERT(IsArray()); return Array(*this); } - ConstArray GetArray() const { RAPIDJSON_ASSERT(IsArray()); return ConstArray(*this); } - - //@} - - //!@name Number - //@{ - - int GetInt() const { RAPIDJSON_ASSERT(data_.f.flags & kIntFlag); return data_.n.i.i; } - unsigned GetUint() const { RAPIDJSON_ASSERT(data_.f.flags & kUintFlag); return data_.n.u.u; } - int64_t GetInt64() const { RAPIDJSON_ASSERT(data_.f.flags & kInt64Flag); return data_.n.i64; } - uint64_t GetUint64() const { RAPIDJSON_ASSERT(data_.f.flags & kUint64Flag); return data_.n.u64; } - - //! Get the value as double type. - /*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessDouble() to check whether the converison is lossless. - */ - double GetDouble() const { - RAPIDJSON_ASSERT(IsNumber()); - if ((data_.f.flags & kDoubleFlag) != 0) return data_.n.d; // exact type, no conversion. - if ((data_.f.flags & kIntFlag) != 0) return data_.n.i.i; // int -> double - if ((data_.f.flags & kUintFlag) != 0) return data_.n.u.u; // unsigned -> double - if ((data_.f.flags & kInt64Flag) != 0) return static_cast(data_.n.i64); // int64_t -> double (may lose precision) - RAPIDJSON_ASSERT((data_.f.flags & kUint64Flag) != 0); return static_cast(data_.n.u64); // uint64_t -> double (may lose precision) - } - - //! Get the value as float type. - /*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessFloat() to check whether the converison is lossless. - */ - float GetFloat() const { - return static_cast(GetDouble()); - } - - GenericValue& SetInt(int i) { this->~GenericValue(); new (this) GenericValue(i); return *this; } - GenericValue& SetUint(unsigned u) { this->~GenericValue(); new (this) GenericValue(u); return *this; } - GenericValue& SetInt64(int64_t i64) { this->~GenericValue(); new (this) GenericValue(i64); return *this; } - GenericValue& SetUint64(uint64_t u64) { this->~GenericValue(); new (this) GenericValue(u64); return *this; } - GenericValue& SetDouble(double d) { this->~GenericValue(); new (this) GenericValue(d); return *this; } - GenericValue& SetFloat(float f) { this->~GenericValue(); new (this) GenericValue(static_cast(f)); return *this; } - - //@} - - //!@name String - //@{ - - const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return DataString(data_); } - - //! Get the length of string. - /*! Since rapidjson permits "\\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength(). - */ - SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return DataStringLength(data_); } - - //! Set this value as a string without copying source string. - /*! This version has better performance with supplied length, and also support string containing null character. - \param s source string pointer. - \param length The length of source string, excluding the trailing null terminator. - \return The value itself for fluent API. - \post IsString() == true && GetString() == s && GetStringLength() == length - \see SetString(StringRefType) - */ - GenericValue& SetString(const Ch* s, SizeType length) { return SetString(StringRef(s, length)); } - - //! Set this value as a string without copying source string. - /*! \param s source string reference - \return The value itself for fluent API. - \post IsString() == true && GetString() == s && GetStringLength() == s.length - */ - GenericValue& SetString(StringRefType s) { this->~GenericValue(); SetStringRaw(s); return *this; } - - //! Set this value as a string by copying from source string. - /*! This version has better performance with supplied length, and also support string containing null character. - \param s source string. - \param length The length of source string, excluding the trailing null terminator. - \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length - */ - GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { return SetString(StringRef(s, length), allocator); } - - //! Set this value as a string by copying from source string. - /*! \param s source string. - \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length - */ - GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(StringRef(s), allocator); } - - //! Set this value as a string by copying from source string. - /*! \param s source string reference - \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \post IsString() == true && GetString() != s.s && strcmp(GetString(),s) == 0 && GetStringLength() == length - */ - GenericValue& SetString(StringRefType s, Allocator& allocator) { this->~GenericValue(); SetStringRaw(s, allocator); return *this; } - -#if RAPIDJSON_HAS_STDSTRING - //! Set this value as a string by copying from source string. - /*! \param s source string. - \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \post IsString() == true && GetString() != s.data() && strcmp(GetString(),s.data() == 0 && GetStringLength() == s.size() - \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. - */ - GenericValue& SetString(const std::basic_string& s, Allocator& allocator) { return SetString(StringRef(s), allocator); } -#endif - - //@} - - //!@name Array - //@{ - - //! Templated version for checking whether this value is type T. - /*! - \tparam T Either \c bool, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c float, \c const \c char*, \c std::basic_string - */ - template - bool Is() const { return internal::TypeHelper::Is(*this); } - - template - T Get() const { return internal::TypeHelper::Get(*this); } - - template - T Get() { return internal::TypeHelper::Get(*this); } - - template - ValueType& Set(const T& data) { return internal::TypeHelper::Set(*this, data); } - - template - ValueType& Set(const T& data, AllocatorType& allocator) { return internal::TypeHelper::Set(*this, data, allocator); } - - //@} - - //! Generate events of this value to a Handler. - /*! This function adopts the GoF visitor pattern. - Typical usage is to output this JSON value as JSON text via Writer, which is a Handler. - It can also be used to deep clone this value via GenericDocument, which is also a Handler. - \tparam Handler type of handler. - \param handler An object implementing concept Handler. - */ - template - bool Accept(Handler& handler) const { - switch(GetType()) { - case kNullType: return handler.Null(); - case kFalseType: return handler.Bool(false); - case kTrueType: return handler.Bool(true); - - case kObjectType: - if (RAPIDJSON_UNLIKELY(!handler.StartObject())) - return false; - for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) { - RAPIDJSON_ASSERT(m->name.IsString()); // User may change the type of name by MemberIterator. - if (RAPIDJSON_UNLIKELY(!handler.Key(m->name.GetString(), m->name.GetStringLength(), (m->name.data_.f.flags & kCopyFlag) != 0))) - return false; - if (RAPIDJSON_UNLIKELY(!m->value.Accept(handler))) - return false; - } - return handler.EndObject(data_.o.size); - - case kArrayType: - if (RAPIDJSON_UNLIKELY(!handler.StartArray())) - return false; - for (ConstValueIterator v = Begin(); v != End(); ++v) - if (RAPIDJSON_UNLIKELY(!v->Accept(handler))) - return false; - return handler.EndArray(data_.a.size); - - case kStringType: - return handler.String(GetString(), GetStringLength(), (data_.f.flags & kCopyFlag) != 0); - - default: - RAPIDJSON_ASSERT(GetType() == kNumberType); - if (IsDouble()) return handler.Double(data_.n.d); - else if (IsInt()) return handler.Int(data_.n.i.i); - else if (IsUint()) return handler.Uint(data_.n.u.u); - else if (IsInt64()) return handler.Int64(data_.n.i64); - else return handler.Uint64(data_.n.u64); - } - } - -private: - template friend class GenericValue; - template friend class GenericDocument; - - enum { - kBoolFlag = 0x0008, - kNumberFlag = 0x0010, - kIntFlag = 0x0020, - kUintFlag = 0x0040, - kInt64Flag = 0x0080, - kUint64Flag = 0x0100, - kDoubleFlag = 0x0200, - kStringFlag = 0x0400, - kCopyFlag = 0x0800, - kInlineStrFlag = 0x1000, - - // Initial flags of different types. - kNullFlag = kNullType, - // These casts are added to suppress the warning on MSVC about bitwise operations between enums of different types. - kTrueFlag = static_cast(kTrueType) | static_cast(kBoolFlag), - kFalseFlag = static_cast(kFalseType) | static_cast(kBoolFlag), - kNumberIntFlag = static_cast(kNumberType) | static_cast(kNumberFlag | kIntFlag | kInt64Flag), - kNumberUintFlag = static_cast(kNumberType) | static_cast(kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag), - kNumberInt64Flag = static_cast(kNumberType) | static_cast(kNumberFlag | kInt64Flag), - kNumberUint64Flag = static_cast(kNumberType) | static_cast(kNumberFlag | kUint64Flag), - kNumberDoubleFlag = static_cast(kNumberType) | static_cast(kNumberFlag | kDoubleFlag), - kNumberAnyFlag = static_cast(kNumberType) | static_cast(kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag), - kConstStringFlag = static_cast(kStringType) | static_cast(kStringFlag), - kCopyStringFlag = static_cast(kStringType) | static_cast(kStringFlag | kCopyFlag), - kShortStringFlag = static_cast(kStringType) | static_cast(kStringFlag | kCopyFlag | kInlineStrFlag), - kObjectFlag = kObjectType, - kArrayFlag = kArrayType, - - kTypeMask = 0x07 - }; - - static const SizeType kDefaultArrayCapacity = RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY; - static const SizeType kDefaultObjectCapacity = RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY; - - struct Flag { -#if RAPIDJSON_48BITPOINTER_OPTIMIZATION - char payload[sizeof(SizeType) * 2 + 6]; // 2 x SizeType + lower 48-bit pointer -#elif RAPIDJSON_64BIT - char payload[sizeof(SizeType) * 2 + sizeof(void*) + 6]; // 6 padding bytes -#else - char payload[sizeof(SizeType) * 2 + sizeof(void*) + 2]; // 2 padding bytes -#endif - uint16_t flags; - }; - - struct String { - SizeType length; - SizeType hashcode; //!< reserved - const Ch* str; - }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode - - // implementation detail: ShortString can represent zero-terminated strings up to MaxSize chars - // (excluding the terminating zero) and store a value to determine the length of the contained - // string in the last character str[LenPos] by storing "MaxSize - length" there. If the string - // to store has the maximal length of MaxSize then str[LenPos] will be 0 and therefore act as - // the string terminator as well. For getting the string length back from that value just use - // "MaxSize - str[LenPos]". - // This allows to store 13-chars strings in 32-bit mode, 21-chars strings in 64-bit mode, - // 13-chars strings for RAPIDJSON_48BITPOINTER_OPTIMIZATION=1 inline (for `UTF8`-encoded strings). - struct ShortString { - enum { MaxChars = sizeof(static_cast(0)->payload) / sizeof(Ch), MaxSize = MaxChars - 1, LenPos = MaxSize }; - Ch str[MaxChars]; - - inline static bool Usable(SizeType len) { return (MaxSize >= len); } - inline void SetLength(SizeType len) { str[LenPos] = static_cast(MaxSize - len); } - inline SizeType GetLength() const { return static_cast(MaxSize - str[LenPos]); } - }; // at most as many bytes as "String" above => 12 bytes in 32-bit mode, 16 bytes in 64-bit mode - - // By using proper binary layout, retrieval of different integer types do not need conversions. - union Number { -#if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN - struct I { - int i; - char padding[4]; - }i; - struct U { - unsigned u; - char padding2[4]; - }u; -#else - struct I { - char padding[4]; - int i; - }i; - struct U { - char padding2[4]; - unsigned u; - }u; -#endif - int64_t i64; - uint64_t u64; - double d; - }; // 8 bytes - - struct ObjectData { - SizeType size; - SizeType capacity; - Member* members; - }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode - - struct ArrayData { - SizeType size; - SizeType capacity; - GenericValue* elements; - }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode - - union Data { - String s; - ShortString ss; - Number n; - ObjectData o; - ArrayData a; - Flag f; - }; // 16 bytes in 32-bit mode, 24 bytes in 64-bit mode, 16 bytes in 64-bit with RAPIDJSON_48BITPOINTER_OPTIMIZATION - - static RAPIDJSON_FORCEINLINE const Ch* DataString(const Data& data) { - return (data.f.flags & kInlineStrFlag) ? data.ss.str : RAPIDJSON_GETPOINTER(Ch, data.s.str); - } - static RAPIDJSON_FORCEINLINE SizeType DataStringLength(const Data& data) { - return (data.f.flags & kInlineStrFlag) ? data.ss.GetLength() : data.s.length; - } - - RAPIDJSON_FORCEINLINE const Ch* GetStringPointer() const { return RAPIDJSON_GETPOINTER(Ch, data_.s.str); } - RAPIDJSON_FORCEINLINE const Ch* SetStringPointer(const Ch* str) { return RAPIDJSON_SETPOINTER(Ch, data_.s.str, str); } - RAPIDJSON_FORCEINLINE GenericValue* GetElementsPointer() const { return RAPIDJSON_GETPOINTER(GenericValue, data_.a.elements); } - RAPIDJSON_FORCEINLINE GenericValue* SetElementsPointer(GenericValue* elements) { return RAPIDJSON_SETPOINTER(GenericValue, data_.a.elements, elements); } - RAPIDJSON_FORCEINLINE Member* GetMembersPointer() const { return RAPIDJSON_GETPOINTER(Member, data_.o.members); } - RAPIDJSON_FORCEINLINE Member* SetMembersPointer(Member* members) { return RAPIDJSON_SETPOINTER(Member, data_.o.members, members); } - -#if RAPIDJSON_USE_MEMBERSMAP - - struct MapTraits { - struct Less { - bool operator()(const Data& s1, const Data& s2) const { - SizeType n1 = DataStringLength(s1), n2 = DataStringLength(s2); - int cmp = std::memcmp(DataString(s1), DataString(s2), sizeof(Ch) * (n1 < n2 ? n1 : n2)); - return cmp < 0 || (cmp == 0 && n1 < n2); - } - }; - typedef std::pair Pair; - typedef std::multimap > Map; - typedef typename Map::iterator Iterator; - }; - typedef typename MapTraits::Map Map; - typedef typename MapTraits::Less MapLess; - typedef typename MapTraits::Pair MapPair; - typedef typename MapTraits::Iterator MapIterator; - - // - // Layout of the members' map/array, re(al)located according to the needed capacity: - // - // {Map*}<>{capacity}<>{Member[capacity]}<>{MapIterator[capacity]} - // - // (where <> stands for the RAPIDJSON_ALIGN-ment, if needed) - // - - static RAPIDJSON_FORCEINLINE size_t GetMapLayoutSize(SizeType capacity) { - return RAPIDJSON_ALIGN(sizeof(Map*)) + - RAPIDJSON_ALIGN(sizeof(SizeType)) + - RAPIDJSON_ALIGN(capacity * sizeof(Member)) + - capacity * sizeof(MapIterator); - } - - static RAPIDJSON_FORCEINLINE SizeType &GetMapCapacity(Map* &map) { - return *reinterpret_cast(reinterpret_cast(&map) + - RAPIDJSON_ALIGN(sizeof(Map*))); - } - - static RAPIDJSON_FORCEINLINE Member* GetMapMembers(Map* &map) { - return reinterpret_cast(reinterpret_cast(&map) + - RAPIDJSON_ALIGN(sizeof(Map*)) + - RAPIDJSON_ALIGN(sizeof(SizeType))); - } - - static RAPIDJSON_FORCEINLINE MapIterator* GetMapIterators(Map* &map) { - return reinterpret_cast(reinterpret_cast(&map) + - RAPIDJSON_ALIGN(sizeof(Map*)) + - RAPIDJSON_ALIGN(sizeof(SizeType)) + - RAPIDJSON_ALIGN(GetMapCapacity(map) * sizeof(Member))); - } - - static RAPIDJSON_FORCEINLINE Map* &GetMap(Member* members) { - RAPIDJSON_ASSERT(members != 0); - return *reinterpret_cast(reinterpret_cast(members) - - RAPIDJSON_ALIGN(sizeof(SizeType)) - - RAPIDJSON_ALIGN(sizeof(Map*))); - } - - // Some compilers' debug mechanisms want all iterators to be destroyed, for their accounting.. - RAPIDJSON_FORCEINLINE MapIterator DropMapIterator(MapIterator& rhs) { -#if RAPIDJSON_HAS_CXX11 - MapIterator ret = std::move(rhs); -#else - MapIterator ret = rhs; -#endif - rhs.~MapIterator(); - return ret; - } - - Map* &DoReallocMap(Map** oldMap, SizeType newCapacity, Allocator& allocator) { - Map **newMap = static_cast(allocator.Malloc(GetMapLayoutSize(newCapacity))); - GetMapCapacity(*newMap) = newCapacity; - if (!oldMap) { - *newMap = new (allocator.Malloc(sizeof(Map))) Map(MapLess(), allocator); - } - else { - *newMap = *oldMap; - size_t count = (*oldMap)->size(); - std::memcpy(static_cast(GetMapMembers(*newMap)), - static_cast(GetMapMembers(*oldMap)), - count * sizeof(Member)); - MapIterator *oldIt = GetMapIterators(*oldMap), - *newIt = GetMapIterators(*newMap); - while (count--) { - new (&newIt[count]) MapIterator(DropMapIterator(oldIt[count])); - } - Allocator::Free(oldMap); - } - return *newMap; - } - - RAPIDJSON_FORCEINLINE Member* DoAllocMembers(SizeType capacity, Allocator& allocator) { - return GetMapMembers(DoReallocMap(0, capacity, allocator)); - } - - void DoReserveMembers(SizeType newCapacity, Allocator& allocator) { - ObjectData& o = data_.o; - if (newCapacity > o.capacity) { - Member* oldMembers = GetMembersPointer(); - Map **oldMap = oldMembers ? &GetMap(oldMembers) : 0, - *&newMap = DoReallocMap(oldMap, newCapacity, allocator); - RAPIDJSON_SETPOINTER(Member, o.members, GetMapMembers(newMap)); - o.capacity = newCapacity; - } - } - - template - MemberIterator DoFindMember(const GenericValue& name) { - if (Member* members = GetMembersPointer()) { - Map* &map = GetMap(members); - MapIterator mit = map->find(reinterpret_cast(name.data_)); - if (mit != map->end()) { - return MemberIterator(&members[mit->second]); - } - } - return MemberEnd(); - } - - void DoClearMembers() { - if (Member* members = GetMembersPointer()) { - Map* &map = GetMap(members); - MapIterator* mit = GetMapIterators(map); - for (SizeType i = 0; i < data_.o.size; i++) { - map->erase(DropMapIterator(mit[i])); - members[i].~Member(); - } - data_.o.size = 0; - } - } - - void DoFreeMembers() { - if (Member* members = GetMembersPointer()) { - GetMap(members)->~Map(); - for (SizeType i = 0; i < data_.o.size; i++) { - members[i].~Member(); - } - if (Allocator::kNeedFree) { // Shortcut by Allocator's trait - Map** map = &GetMap(members); - Allocator::Free(*map); - Allocator::Free(map); - } - } - } - -#else // !RAPIDJSON_USE_MEMBERSMAP - - RAPIDJSON_FORCEINLINE Member* DoAllocMembers(SizeType capacity, Allocator& allocator) { - return Malloc(allocator, capacity); - } - - void DoReserveMembers(SizeType newCapacity, Allocator& allocator) { - ObjectData& o = data_.o; - if (newCapacity > o.capacity) { - Member* newMembers = Realloc(allocator, GetMembersPointer(), o.capacity, newCapacity); - RAPIDJSON_SETPOINTER(Member, o.members, newMembers); - o.capacity = newCapacity; - } - } - - template - MemberIterator DoFindMember(const GenericValue& name) { - MemberIterator member = MemberBegin(); - for ( ; member != MemberEnd(); ++member) - if (name.StringEqual(member->name)) - break; - return member; - } - - void DoClearMembers() { - for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) - m->~Member(); - data_.o.size = 0; - } - - void DoFreeMembers() { - for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) - m->~Member(); - Allocator::Free(GetMembersPointer()); - } - -#endif // !RAPIDJSON_USE_MEMBERSMAP - - void DoAddMember(GenericValue& name, GenericValue& value, Allocator& allocator) { - ObjectData& o = data_.o; - if (o.size >= o.capacity) - DoReserveMembers(o.capacity ? (o.capacity + (o.capacity + 1) / 2) : kDefaultObjectCapacity, allocator); - Member* members = GetMembersPointer(); - Member* m = members + o.size; - m->name.RawAssign(name); - m->value.RawAssign(value); -#if RAPIDJSON_USE_MEMBERSMAP - Map* &map = GetMap(members); - MapIterator* mit = GetMapIterators(map); - new (&mit[o.size]) MapIterator(map->insert(MapPair(m->name.data_, o.size))); -#endif - ++o.size; - } - - MemberIterator DoRemoveMember(MemberIterator m) { - ObjectData& o = data_.o; - Member* members = GetMembersPointer(); -#if RAPIDJSON_USE_MEMBERSMAP - Map* &map = GetMap(members); - MapIterator* mit = GetMapIterators(map); - SizeType mpos = static_cast(&*m - members); - map->erase(DropMapIterator(mit[mpos])); -#endif - MemberIterator last(members + (o.size - 1)); - if (o.size > 1 && m != last) { -#if RAPIDJSON_USE_MEMBERSMAP - new (&mit[mpos]) MapIterator(DropMapIterator(mit[&*last - members])); - mit[mpos]->second = mpos; -#endif - *m = *last; // Move the last one to this place - } - else { - m->~Member(); // Only one left, just destroy - } - --o.size; - return m; - } - - MemberIterator DoEraseMembers(ConstMemberIterator first, ConstMemberIterator last) { - ObjectData& o = data_.o; - MemberIterator beg = MemberBegin(), - pos = beg + (first - beg), - end = MemberEnd(); -#if RAPIDJSON_USE_MEMBERSMAP - Map* &map = GetMap(GetMembersPointer()); - MapIterator* mit = GetMapIterators(map); -#endif - for (MemberIterator itr = pos; itr != last; ++itr) { -#if RAPIDJSON_USE_MEMBERSMAP - map->erase(DropMapIterator(mit[itr - beg])); -#endif - itr->~Member(); - } -#if RAPIDJSON_USE_MEMBERSMAP - if (first != last) { - // Move remaining members/iterators - MemberIterator next = pos + (last - first); - for (MemberIterator itr = pos; next != end; ++itr, ++next) { - std::memcpy(static_cast(&*itr), &*next, sizeof(Member)); - SizeType mpos = static_cast(itr - beg); - new (&mit[mpos]) MapIterator(DropMapIterator(mit[next - beg])); - mit[mpos]->second = mpos; - } - } -#else - std::memmove(static_cast(&*pos), &*last, - static_cast(end - last) * sizeof(Member)); -#endif - o.size -= static_cast(last - first); - return pos; - } - - template - void DoCopyMembers(const GenericValue& rhs, Allocator& allocator, bool copyConstStrings) { - RAPIDJSON_ASSERT(rhs.GetType() == kObjectType); - - data_.f.flags = kObjectFlag; - SizeType count = rhs.data_.o.size; - Member* lm = DoAllocMembers(count, allocator); - const typename GenericValue::Member* rm = rhs.GetMembersPointer(); -#if RAPIDJSON_USE_MEMBERSMAP - Map* &map = GetMap(lm); - MapIterator* mit = GetMapIterators(map); -#endif - for (SizeType i = 0; i < count; i++) { - new (&lm[i].name) GenericValue(rm[i].name, allocator, copyConstStrings); - new (&lm[i].value) GenericValue(rm[i].value, allocator, copyConstStrings); -#if RAPIDJSON_USE_MEMBERSMAP - new (&mit[i]) MapIterator(map->insert(MapPair(lm[i].name.data_, i))); -#endif - } - data_.o.size = data_.o.capacity = count; - SetMembersPointer(lm); - } - - // Initialize this value as array with initial data, without calling destructor. - void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) { - data_.f.flags = kArrayFlag; - if (count) { - GenericValue* e = static_cast(allocator.Malloc(count * sizeof(GenericValue))); - SetElementsPointer(e); - std::memcpy(static_cast(e), values, count * sizeof(GenericValue)); - } - else - SetElementsPointer(0); - data_.a.size = data_.a.capacity = count; - } - - //! Initialize this value as object with initial data, without calling destructor. - void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) { - data_.f.flags = kObjectFlag; - if (count) { - Member* m = DoAllocMembers(count, allocator); - SetMembersPointer(m); - std::memcpy(static_cast(m), members, count * sizeof(Member)); -#if RAPIDJSON_USE_MEMBERSMAP - Map* &map = GetMap(m); - MapIterator* mit = GetMapIterators(map); - for (SizeType i = 0; i < count; i++) { - new (&mit[i]) MapIterator(map->insert(MapPair(m[i].name.data_, i))); - } -#endif - } - else - SetMembersPointer(0); - data_.o.size = data_.o.capacity = count; - } - - //! Initialize this value as constant string, without calling destructor. - void SetStringRaw(StringRefType s) RAPIDJSON_NOEXCEPT { - data_.f.flags = kConstStringFlag; - SetStringPointer(s); - data_.s.length = s.length; - } - - //! Initialize this value as copy string with initial data, without calling destructor. - void SetStringRaw(StringRefType s, Allocator& allocator) { - Ch* str = 0; - if (ShortString::Usable(s.length)) { - data_.f.flags = kShortStringFlag; - data_.ss.SetLength(s.length); - str = data_.ss.str; - } else { - data_.f.flags = kCopyStringFlag; - data_.s.length = s.length; - str = static_cast(allocator.Malloc((s.length + 1) * sizeof(Ch))); - SetStringPointer(str); - } - std::memcpy(str, s, s.length * sizeof(Ch)); - str[s.length] = '\0'; - } - - //! Assignment without calling destructor - void RawAssign(GenericValue& rhs) RAPIDJSON_NOEXCEPT { - data_ = rhs.data_; - // data_.f.flags = rhs.data_.f.flags; - rhs.data_.f.flags = kNullFlag; - } - - template - bool StringEqual(const GenericValue& rhs) const { - RAPIDJSON_ASSERT(IsString()); - RAPIDJSON_ASSERT(rhs.IsString()); - - const SizeType len1 = GetStringLength(); - const SizeType len2 = rhs.GetStringLength(); - if(len1 != len2) { return false; } - - const Ch* const str1 = GetString(); - const Ch* const str2 = rhs.GetString(); - if(str1 == str2) { return true; } // fast path for constant string - - return (std::memcmp(str1, str2, sizeof(Ch) * len1) == 0); - } - - Data data_; -}; - -//! GenericValue with UTF8 encoding -typedef GenericValue > Value; - -/////////////////////////////////////////////////////////////////////////////// -// GenericDocument - -//! A document for parsing JSON text as DOM. -/*! - \note implements Handler concept - \tparam Encoding Encoding for both parsing and string storage. - \tparam Allocator Allocator for allocating memory for the DOM - \tparam StackAllocator Allocator for allocating memory for stack during parsing. - \warning Although GenericDocument inherits from GenericValue, the API does \b not provide any virtual functions, especially no virtual destructor. To avoid memory leaks, do not \c delete a GenericDocument object via a pointer to a GenericValue. -*/ -template -class GenericDocument : public GenericValue { -public: - typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. - typedef GenericValue ValueType; //!< Value type of the document. - typedef Allocator AllocatorType; //!< Allocator type from template parameter. - - //! Constructor - /*! Creates an empty document of specified type. - \param type Mandatory type of object to create. - \param allocator Optional allocator for allocating memory. - \param stackCapacity Optional initial capacity of stack in bytes. - \param stackAllocator Optional allocator for allocating memory for stack. - */ - explicit GenericDocument(Type type, Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) : - GenericValue(type), allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_() - { - if (!allocator_) - ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); - } - - //! Constructor - /*! Creates an empty document which type is Null. - \param allocator Optional allocator for allocating memory. - \param stackCapacity Optional initial capacity of stack in bytes. - \param stackAllocator Optional allocator for allocating memory for stack. - */ - GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) : - allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_() - { - if (!allocator_) - ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); - } - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - //! Move constructor in C++11 - GenericDocument(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT - : ValueType(std::forward(rhs)), // explicit cast to avoid prohibited move from Document - allocator_(rhs.allocator_), - ownAllocator_(rhs.ownAllocator_), - stack_(std::move(rhs.stack_)), - parseResult_(rhs.parseResult_) - { - rhs.allocator_ = 0; - rhs.ownAllocator_ = 0; - rhs.parseResult_ = ParseResult(); - } -#endif - - ~GenericDocument() { - // Clear the ::ValueType before ownAllocator is destroyed, ~ValueType() - // runs last and may access its elements or members which would be freed - // with an allocator like MemoryPoolAllocator (CrtAllocator does not - // free its data when destroyed, but MemoryPoolAllocator does). - if (ownAllocator_) { - ValueType::SetNull(); - } - Destroy(); - } - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - //! Move assignment in C++11 - GenericDocument& operator=(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT - { - // The cast to ValueType is necessary here, because otherwise it would - // attempt to call GenericValue's templated assignment operator. - ValueType::operator=(std::forward(rhs)); - - // Calling the destructor here would prematurely call stack_'s destructor - Destroy(); - - allocator_ = rhs.allocator_; - ownAllocator_ = rhs.ownAllocator_; - stack_ = std::move(rhs.stack_); - parseResult_ = rhs.parseResult_; - - rhs.allocator_ = 0; - rhs.ownAllocator_ = 0; - rhs.parseResult_ = ParseResult(); - - return *this; - } -#endif - - //! Exchange the contents of this document with those of another. - /*! - \param rhs Another document. - \note Constant complexity. - \see GenericValue::Swap - */ - GenericDocument& Swap(GenericDocument& rhs) RAPIDJSON_NOEXCEPT { - ValueType::Swap(rhs); - stack_.Swap(rhs.stack_); - internal::Swap(allocator_, rhs.allocator_); - internal::Swap(ownAllocator_, rhs.ownAllocator_); - internal::Swap(parseResult_, rhs.parseResult_); - return *this; - } - - // Allow Swap with ValueType. - // Refer to Effective C++ 3rd Edition/Item 33: Avoid hiding inherited names. - using ValueType::Swap; - - //! free-standing swap function helper - /*! - Helper function to enable support for common swap implementation pattern based on \c std::swap: - \code - void swap(MyClass& a, MyClass& b) { - using std::swap; - swap(a.doc, b.doc); - // ... - } - \endcode - \see Swap() - */ - friend inline void swap(GenericDocument& a, GenericDocument& b) RAPIDJSON_NOEXCEPT { a.Swap(b); } - - //! Populate this document by a generator which produces SAX events. - /*! \tparam Generator A functor with bool f(Handler) prototype. - \param g Generator functor which sends SAX events to the parameter. - \return The document itself for fluent API. - */ - template - GenericDocument& Populate(Generator& g) { - ClearStackOnExit scope(*this); - if (g(*this)) { - RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object - ValueType::operator=(*stack_.template Pop(1));// Move value from stack to document - } - return *this; - } - - //!@name Parse from stream - //!@{ - - //! Parse JSON text from an input stream (with Encoding conversion) - /*! \tparam parseFlags Combination of \ref ParseFlag. - \tparam SourceEncoding Encoding of input stream - \tparam InputStream Type of input stream, implementing Stream concept - \param is Input stream to be parsed. - \return The document itself for fluent API. - */ - template - GenericDocument& ParseStream(InputStream& is) { - GenericReader reader( - stack_.HasAllocator() ? &stack_.GetAllocator() : 0); - ClearStackOnExit scope(*this); - parseResult_ = reader.template Parse(is, *this); - if (parseResult_) { - RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object - ValueType::operator=(*stack_.template Pop(1));// Move value from stack to document - } - return *this; - } - - //! Parse JSON text from an input stream - /*! \tparam parseFlags Combination of \ref ParseFlag. - \tparam InputStream Type of input stream, implementing Stream concept - \param is Input stream to be parsed. - \return The document itself for fluent API. - */ - template - GenericDocument& ParseStream(InputStream& is) { - return ParseStream(is); - } - - //! Parse JSON text from an input stream (with \ref kParseDefaultFlags) - /*! \tparam InputStream Type of input stream, implementing Stream concept - \param is Input stream to be parsed. - \return The document itself for fluent API. - */ - template - GenericDocument& ParseStream(InputStream& is) { - return ParseStream(is); - } - //!@} - - //!@name Parse in-place from mutable string - //!@{ - - //! Parse JSON text from a mutable string - /*! \tparam parseFlags Combination of \ref ParseFlag. - \param str Mutable zero-terminated string to be parsed. - \return The document itself for fluent API. - */ - template - GenericDocument& ParseInsitu(Ch* str) { - GenericInsituStringStream s(str); - return ParseStream(s); - } - - //! Parse JSON text from a mutable string (with \ref kParseDefaultFlags) - /*! \param str Mutable zero-terminated string to be parsed. - \return The document itself for fluent API. - */ - GenericDocument& ParseInsitu(Ch* str) { - return ParseInsitu(str); - } - //!@} - - //!@name Parse from read-only string - //!@{ - - //! Parse JSON text from a read-only string (with Encoding conversion) - /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag). - \tparam SourceEncoding Transcoding from input Encoding - \param str Read-only zero-terminated string to be parsed. - */ - template - GenericDocument& Parse(const typename SourceEncoding::Ch* str) { - RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); - GenericStringStream s(str); - return ParseStream(s); - } - - //! Parse JSON text from a read-only string - /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag). - \param str Read-only zero-terminated string to be parsed. - */ - template - GenericDocument& Parse(const Ch* str) { - return Parse(str); - } - - //! Parse JSON text from a read-only string (with \ref kParseDefaultFlags) - /*! \param str Read-only zero-terminated string to be parsed. - */ - GenericDocument& Parse(const Ch* str) { - return Parse(str); - } - - template - GenericDocument& Parse(const typename SourceEncoding::Ch* str, size_t length) { - RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); - MemoryStream ms(reinterpret_cast(str), length * sizeof(typename SourceEncoding::Ch)); - EncodedInputStream is(ms); - ParseStream(is); - return *this; - } - - template - GenericDocument& Parse(const Ch* str, size_t length) { - return Parse(str, length); - } - - GenericDocument& Parse(const Ch* str, size_t length) { - return Parse(str, length); - } - -#if RAPIDJSON_HAS_STDSTRING - template - GenericDocument& Parse(const std::basic_string& str) { - // c_str() is constant complexity according to standard. Should be faster than Parse(const char*, size_t) - return Parse(str.c_str()); - } - - template - GenericDocument& Parse(const std::basic_string& str) { - return Parse(str.c_str()); - } - - GenericDocument& Parse(const std::basic_string& str) { - return Parse(str); - } -#endif // RAPIDJSON_HAS_STDSTRING - - //!@} - - //!@name Handling parse errors - //!@{ - - //! Whether a parse error has occurred in the last parsing. - bool HasParseError() const { return parseResult_.IsError(); } - - //! Get the \ref ParseErrorCode of last parsing. - ParseErrorCode GetParseError() const { return parseResult_.Code(); } - - //! Get the position of last parsing error in input, 0 otherwise. - size_t GetErrorOffset() const { return parseResult_.Offset(); } - - //! Implicit conversion to get the last parse result -#ifndef __clang // -Wdocumentation - /*! \return \ref ParseResult of the last parse operation - - \code - Document doc; - ParseResult ok = doc.Parse(json); - if (!ok) - printf( "JSON parse error: %s (%u)\n", GetParseError_En(ok.Code()), ok.Offset()); - \endcode - */ -#endif - operator ParseResult() const { return parseResult_; } - //!@} - - //! Get the allocator of this document. - Allocator& GetAllocator() { - RAPIDJSON_ASSERT(allocator_); - return *allocator_; - } - - //! Get the capacity of stack in bytes. - size_t GetStackCapacity() const { return stack_.GetCapacity(); } - -private: - // clear stack on any exit from ParseStream, e.g. due to exception - struct ClearStackOnExit { - explicit ClearStackOnExit(GenericDocument& d) : d_(d) {} - ~ClearStackOnExit() { d_.ClearStack(); } - private: - ClearStackOnExit(const ClearStackOnExit&); - ClearStackOnExit& operator=(const ClearStackOnExit&); - GenericDocument& d_; - }; - - // callers of the following private Handler functions - // template friend class GenericReader; // for parsing - template friend class GenericValue; // for deep copying - -public: - // Implementation of Handler - bool Null() { new (stack_.template Push()) ValueType(); return true; } - bool Bool(bool b) { new (stack_.template Push()) ValueType(b); return true; } - bool Int(int i) { new (stack_.template Push()) ValueType(i); return true; } - bool Uint(unsigned i) { new (stack_.template Push()) ValueType(i); return true; } - bool Int64(int64_t i) { new (stack_.template Push()) ValueType(i); return true; } - bool Uint64(uint64_t i) { new (stack_.template Push()) ValueType(i); return true; } - bool Double(double d) { new (stack_.template Push()) ValueType(d); return true; } - - bool RawNumber(const Ch* str, SizeType length, bool copy) { - if (copy) - new (stack_.template Push()) ValueType(str, length, GetAllocator()); - else - new (stack_.template Push()) ValueType(str, length); - return true; - } - - bool String(const Ch* str, SizeType length, bool copy) { - if (copy) - new (stack_.template Push()) ValueType(str, length, GetAllocator()); - else - new (stack_.template Push()) ValueType(str, length); - return true; - } - - bool StartObject() { new (stack_.template Push()) ValueType(kObjectType); return true; } - - bool Key(const Ch* str, SizeType length, bool copy) { return String(str, length, copy); } - - bool EndObject(SizeType memberCount) { - typename ValueType::Member* members = stack_.template Pop(memberCount); - stack_.template Top()->SetObjectRaw(members, memberCount, GetAllocator()); - return true; - } - - bool StartArray() { new (stack_.template Push()) ValueType(kArrayType); return true; } - - bool EndArray(SizeType elementCount) { - ValueType* elements = stack_.template Pop(elementCount); - stack_.template Top()->SetArrayRaw(elements, elementCount, GetAllocator()); - return true; - } - -private: - //! Prohibit copying - GenericDocument(const GenericDocument&); - //! Prohibit assignment - GenericDocument& operator=(const GenericDocument&); - - void ClearStack() { - if (Allocator::kNeedFree) - while (stack_.GetSize() > 0) // Here assumes all elements in stack array are GenericValue (Member is actually 2 GenericValue objects) - (stack_.template Pop(1))->~ValueType(); - else - stack_.Clear(); - stack_.ShrinkToFit(); - } - - void Destroy() { - RAPIDJSON_DELETE(ownAllocator_); - } - - static const size_t kDefaultStackCapacity = 1024; - Allocator* allocator_; - Allocator* ownAllocator_; - internal::Stack stack_; - ParseResult parseResult_; -}; - -//! GenericDocument with UTF8 encoding -typedef GenericDocument > Document; - - -//! Helper class for accessing Value of array type. -/*! - Instance of this helper class is obtained by \c GenericValue::GetArray(). - In addition to all APIs for array type, it provides range-based for loop if \c RAPIDJSON_HAS_CXX11_RANGE_FOR=1. -*/ -template -class GenericArray { -public: - typedef GenericArray ConstArray; - typedef GenericArray Array; - typedef ValueT PlainType; - typedef typename internal::MaybeAddConst::Type ValueType; - typedef ValueType* ValueIterator; // This may be const or non-const iterator - typedef const ValueT* ConstValueIterator; - typedef typename ValueType::AllocatorType AllocatorType; - typedef typename ValueType::StringRefType StringRefType; - - template - friend class GenericValue; - - GenericArray(const GenericArray& rhs) : value_(rhs.value_) {} - GenericArray& operator=(const GenericArray& rhs) { value_ = rhs.value_; return *this; } - ~GenericArray() {} - - operator ValueType&() const { return value_; } - SizeType Size() const { return value_.Size(); } - SizeType Capacity() const { return value_.Capacity(); } - bool Empty() const { return value_.Empty(); } - void Clear() const { value_.Clear(); } - ValueType& operator[](SizeType index) const { return value_[index]; } - ValueIterator Begin() const { return value_.Begin(); } - ValueIterator End() const { return value_.End(); } - GenericArray Reserve(SizeType newCapacity, AllocatorType &allocator) const { value_.Reserve(newCapacity, allocator); return *this; } - GenericArray PushBack(ValueType& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - GenericArray PushBack(ValueType&& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } -#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS - GenericArray PushBack(StringRefType value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } - template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (const GenericArray&)) PushBack(T value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } - GenericArray PopBack() const { value_.PopBack(); return *this; } - ValueIterator Erase(ConstValueIterator pos) const { return value_.Erase(pos); } - ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) const { return value_.Erase(first, last); } - -#if RAPIDJSON_HAS_CXX11_RANGE_FOR - ValueIterator begin() const { return value_.Begin(); } - ValueIterator end() const { return value_.End(); } -#endif - -private: - GenericArray(); - GenericArray(ValueType& value) : value_(value) {} - ValueType& value_; -}; - -//! Helper class for accessing Value of object type. -/*! - Instance of this helper class is obtained by \c GenericValue::GetObject(). - In addition to all APIs for array type, it provides range-based for loop if \c RAPIDJSON_HAS_CXX11_RANGE_FOR=1. -*/ -template -class GenericObject { -public: - typedef GenericObject ConstObject; - typedef GenericObject Object; - typedef ValueT PlainType; - typedef typename internal::MaybeAddConst::Type ValueType; - typedef GenericMemberIterator MemberIterator; // This may be const or non-const iterator - typedef GenericMemberIterator ConstMemberIterator; - typedef typename ValueType::AllocatorType AllocatorType; - typedef typename ValueType::StringRefType StringRefType; - typedef typename ValueType::EncodingType EncodingType; - typedef typename ValueType::Ch Ch; - - template - friend class GenericValue; - - GenericObject(const GenericObject& rhs) : value_(rhs.value_) {} - GenericObject& operator=(const GenericObject& rhs) { value_ = rhs.value_; return *this; } - ~GenericObject() {} - - operator ValueType&() const { return value_; } - SizeType MemberCount() const { return value_.MemberCount(); } - SizeType MemberCapacity() const { return value_.MemberCapacity(); } - bool ObjectEmpty() const { return value_.ObjectEmpty(); } - template ValueType& operator[](T* name) const { return value_[name]; } - template ValueType& operator[](const GenericValue& name) const { return value_[name]; } -#if RAPIDJSON_HAS_STDSTRING - ValueType& operator[](const std::basic_string& name) const { return value_[name]; } -#endif - MemberIterator MemberBegin() const { return value_.MemberBegin(); } - MemberIterator MemberEnd() const { return value_.MemberEnd(); } - GenericObject MemberReserve(SizeType newCapacity, AllocatorType &allocator) const { value_.MemberReserve(newCapacity, allocator); return *this; } - bool HasMember(const Ch* name) const { return value_.HasMember(name); } -#if RAPIDJSON_HAS_STDSTRING - bool HasMember(const std::basic_string& name) const { return value_.HasMember(name); } -#endif - template bool HasMember(const GenericValue& name) const { return value_.HasMember(name); } - MemberIterator FindMember(const Ch* name) const { return value_.FindMember(name); } - template MemberIterator FindMember(const GenericValue& name) const { return value_.FindMember(name); } -#if RAPIDJSON_HAS_STDSTRING - MemberIterator FindMember(const std::basic_string& name) const { return value_.FindMember(name); } -#endif - GenericObject AddMember(ValueType& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } - GenericObject AddMember(ValueType& name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } -#if RAPIDJSON_HAS_STDSTRING - GenericObject AddMember(ValueType& name, std::basic_string& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } -#endif - template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) AddMember(ValueType& name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - GenericObject AddMember(ValueType&& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } - GenericObject AddMember(ValueType&& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } - GenericObject AddMember(ValueType& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } - GenericObject AddMember(StringRefType name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } -#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS - GenericObject AddMember(StringRefType name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } - GenericObject AddMember(StringRefType name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } - template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericObject)) AddMember(StringRefType name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } - void RemoveAllMembers() { value_.RemoveAllMembers(); } - bool RemoveMember(const Ch* name) const { return value_.RemoveMember(name); } -#if RAPIDJSON_HAS_STDSTRING - bool RemoveMember(const std::basic_string& name) const { return value_.RemoveMember(name); } -#endif - template bool RemoveMember(const GenericValue& name) const { return value_.RemoveMember(name); } - MemberIterator RemoveMember(MemberIterator m) const { return value_.RemoveMember(m); } - MemberIterator EraseMember(ConstMemberIterator pos) const { return value_.EraseMember(pos); } - MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) const { return value_.EraseMember(first, last); } - bool EraseMember(const Ch* name) const { return value_.EraseMember(name); } -#if RAPIDJSON_HAS_STDSTRING - bool EraseMember(const std::basic_string& name) const { return EraseMember(ValueType(StringRef(name))); } -#endif - template bool EraseMember(const GenericValue& name) const { return value_.EraseMember(name); } - -#if RAPIDJSON_HAS_CXX11_RANGE_FOR - MemberIterator begin() const { return value_.MemberBegin(); } - MemberIterator end() const { return value_.MemberEnd(); } -#endif - -private: - GenericObject(); - GenericObject(ValueType& value) : value_(value) {} - ValueType& value_; -}; - -RAPIDJSON_NAMESPACE_END -RAPIDJSON_DIAG_POP - -#ifdef RAPIDJSON_WINDOWS_GETOBJECT_WORKAROUND_APPLIED -#pragma pop_macro("GetObject") -#undef RAPIDJSON_WINDOWS_GETOBJECT_WORKAROUND_APPLIED -#endif - -#endif // RAPIDJSON_DOCUMENT_H_ diff --git a/external/rapidjson/encodedstream.h b/external/rapidjson/encodedstream.h deleted file mode 100755 index cf046b8..0000000 --- a/external/rapidjson/encodedstream.h +++ /dev/null @@ -1,299 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_ENCODEDSTREAM_H_ -#define RAPIDJSON_ENCODEDSTREAM_H_ - -#include "stream.h" -#include "memorystream.h" - -#ifdef __GNUC__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(effc++) -#endif - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(padded) -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -//! Input byte stream wrapper with a statically bound encoding. -/*! - \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE. - \tparam InputByteStream Type of input byte stream. For example, FileReadStream. -*/ -template -class EncodedInputStream { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); -public: - typedef typename Encoding::Ch Ch; - - EncodedInputStream(InputByteStream& is) : is_(is) { - current_ = Encoding::TakeBOM(is_); - } - - Ch Peek() const { return current_; } - Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; } - size_t Tell() const { return is_.Tell(); } - - // Not implemented - void Put(Ch) { RAPIDJSON_ASSERT(false); } - void Flush() { RAPIDJSON_ASSERT(false); } - Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } - -private: - EncodedInputStream(const EncodedInputStream&); - EncodedInputStream& operator=(const EncodedInputStream&); - - InputByteStream& is_; - Ch current_; -}; - -//! Specialized for UTF8 MemoryStream. -template <> -class EncodedInputStream, MemoryStream> { -public: - typedef UTF8<>::Ch Ch; - - EncodedInputStream(MemoryStream& is) : is_(is) { - if (static_cast(is_.Peek()) == 0xEFu) is_.Take(); - if (static_cast(is_.Peek()) == 0xBBu) is_.Take(); - if (static_cast(is_.Peek()) == 0xBFu) is_.Take(); - } - Ch Peek() const { return is_.Peek(); } - Ch Take() { return is_.Take(); } - size_t Tell() const { return is_.Tell(); } - - // Not implemented - void Put(Ch) {} - void Flush() {} - Ch* PutBegin() { return 0; } - size_t PutEnd(Ch*) { return 0; } - - MemoryStream& is_; - -private: - EncodedInputStream(const EncodedInputStream&); - EncodedInputStream& operator=(const EncodedInputStream&); -}; - -//! Output byte stream wrapper with statically bound encoding. -/*! - \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE. - \tparam OutputByteStream Type of input byte stream. For example, FileWriteStream. -*/ -template -class EncodedOutputStream { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); -public: - typedef typename Encoding::Ch Ch; - - EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) { - if (putBOM) - Encoding::PutBOM(os_); - } - - void Put(Ch c) { Encoding::Put(os_, c); } - void Flush() { os_.Flush(); } - - // Not implemented - Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;} - Ch Take() { RAPIDJSON_ASSERT(false); return 0;} - size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } - Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } - -private: - EncodedOutputStream(const EncodedOutputStream&); - EncodedOutputStream& operator=(const EncodedOutputStream&); - - OutputByteStream& os_; -}; - -#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8::x, UTF16LE::x, UTF16BE::x, UTF32LE::x, UTF32BE::x - -//! Input stream wrapper with dynamically bound encoding and automatic encoding detection. -/*! - \tparam CharType Type of character for reading. - \tparam InputByteStream type of input byte stream to be wrapped. -*/ -template -class AutoUTFInputStream { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); -public: - typedef CharType Ch; - - //! Constructor. - /*! - \param is input stream to be wrapped. - \param type UTF encoding type if it is not detected from the stream. - */ - AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) { - RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE); - DetectType(); - static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) }; - takeFunc_ = f[type_]; - current_ = takeFunc_(*is_); - } - - UTFType GetType() const { return type_; } - bool HasBOM() const { return hasBOM_; } - - Ch Peek() const { return current_; } - Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; } - size_t Tell() const { return is_->Tell(); } - - // Not implemented - void Put(Ch) { RAPIDJSON_ASSERT(false); } - void Flush() { RAPIDJSON_ASSERT(false); } - Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } - -private: - AutoUTFInputStream(const AutoUTFInputStream&); - AutoUTFInputStream& operator=(const AutoUTFInputStream&); - - // Detect encoding type with BOM or RFC 4627 - void DetectType() { - // BOM (Byte Order Mark): - // 00 00 FE FF UTF-32BE - // FF FE 00 00 UTF-32LE - // FE FF UTF-16BE - // FF FE UTF-16LE - // EF BB BF UTF-8 - - const unsigned char* c = reinterpret_cast(is_->Peek4()); - if (!c) - return; - - unsigned bom = static_cast(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24)); - hasBOM_ = false; - if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } - else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } - else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take(); } - else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take(); } - else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); } - - // RFC 4627: Section 3 - // "Since the first two characters of a JSON text will always be ASCII - // characters [RFC0020], it is possible to determine whether an octet - // stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking - // at the pattern of nulls in the first four octets." - // 00 00 00 xx UTF-32BE - // 00 xx 00 xx UTF-16BE - // xx 00 00 00 UTF-32LE - // xx 00 xx 00 UTF-16LE - // xx xx xx xx UTF-8 - - if (!hasBOM_) { - int pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0); - switch (pattern) { - case 0x08: type_ = kUTF32BE; break; - case 0x0A: type_ = kUTF16BE; break; - case 0x01: type_ = kUTF32LE; break; - case 0x05: type_ = kUTF16LE; break; - case 0x0F: type_ = kUTF8; break; - default: break; // Use type defined by user. - } - } - - // Runtime check whether the size of character type is sufficient. It only perform checks with assertion. - if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2); - if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4); - } - - typedef Ch (*TakeFunc)(InputByteStream& is); - InputByteStream* is_; - UTFType type_; - Ch current_; - TakeFunc takeFunc_; - bool hasBOM_; -}; - -//! Output stream wrapper with dynamically bound encoding and automatic encoding detection. -/*! - \tparam CharType Type of character for writing. - \tparam OutputByteStream type of output byte stream to be wrapped. -*/ -template -class AutoUTFOutputStream { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); -public: - typedef CharType Ch; - - //! Constructor. - /*! - \param os output stream to be wrapped. - \param type UTF encoding type. - \param putBOM Whether to write BOM at the beginning of the stream. - */ - AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) { - RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE); - - // Runtime check whether the size of character type is sufficient. It only perform checks with assertion. - if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2); - if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4); - - static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) }; - putFunc_ = f[type_]; - - if (putBOM) - PutBOM(); - } - - UTFType GetType() const { return type_; } - - void Put(Ch c) { putFunc_(*os_, c); } - void Flush() { os_->Flush(); } - - // Not implemented - Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;} - Ch Take() { RAPIDJSON_ASSERT(false); return 0;} - size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } - Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } - -private: - AutoUTFOutputStream(const AutoUTFOutputStream&); - AutoUTFOutputStream& operator=(const AutoUTFOutputStream&); - - void PutBOM() { - typedef void (*PutBOMFunc)(OutputByteStream&); - static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) }; - f[type_](*os_); - } - - typedef void (*PutFunc)(OutputByteStream&, Ch); - - OutputByteStream* os_; - UTFType type_; - PutFunc putFunc_; -}; - -#undef RAPIDJSON_ENCODINGS_FUNC - -RAPIDJSON_NAMESPACE_END - -#ifdef __clang__ -RAPIDJSON_DIAG_POP -#endif - -#ifdef __GNUC__ -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_FILESTREAM_H_ diff --git a/external/rapidjson/encodings.h b/external/rapidjson/encodings.h deleted file mode 100755 index 50ad18b..0000000 --- a/external/rapidjson/encodings.h +++ /dev/null @@ -1,716 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_ENCODINGS_H_ -#define RAPIDJSON_ENCODINGS_H_ - -#include "rapidjson.h" - -#if defined(_MSC_VER) && !defined(__clang__) -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data -RAPIDJSON_DIAG_OFF(4702) // unreachable code -#elif defined(__GNUC__) -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(effc++) -RAPIDJSON_DIAG_OFF(overflow) -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -/////////////////////////////////////////////////////////////////////////////// -// Encoding - -/*! \class rapidjson::Encoding - \brief Concept for encoding of Unicode characters. - -\code -concept Encoding { - typename Ch; //! Type of character. A "character" is actually a code unit in unicode's definition. - - enum { supportUnicode = 1 }; // or 0 if not supporting unicode - - //! \brief Encode a Unicode codepoint to an output stream. - //! \param os Output stream. - //! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively. - template - static void Encode(OutputStream& os, unsigned codepoint); - - //! \brief Decode a Unicode codepoint from an input stream. - //! \param is Input stream. - //! \param codepoint Output of the unicode codepoint. - //! \return true if a valid codepoint can be decoded from the stream. - template - static bool Decode(InputStream& is, unsigned* codepoint); - - //! \brief Validate one Unicode codepoint from an encoded stream. - //! \param is Input stream to obtain codepoint. - //! \param os Output for copying one codepoint. - //! \return true if it is valid. - //! \note This function just validating and copying the codepoint without actually decode it. - template - static bool Validate(InputStream& is, OutputStream& os); - - // The following functions are deal with byte streams. - - //! Take a character from input byte stream, skip BOM if exist. - template - static CharType TakeBOM(InputByteStream& is); - - //! Take a character from input byte stream. - template - static Ch Take(InputByteStream& is); - - //! Put BOM to output byte stream. - template - static void PutBOM(OutputByteStream& os); - - //! Put a character to output byte stream. - template - static void Put(OutputByteStream& os, Ch c); -}; -\endcode -*/ - -/////////////////////////////////////////////////////////////////////////////// -// UTF8 - -//! UTF-8 encoding. -/*! http://en.wikipedia.org/wiki/UTF-8 - http://tools.ietf.org/html/rfc3629 - \tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char. - \note implements Encoding concept -*/ -template -struct UTF8 { - typedef CharType Ch; - - enum { supportUnicode = 1 }; - - template - static void Encode(OutputStream& os, unsigned codepoint) { - if (codepoint <= 0x7F) - os.Put(static_cast(codepoint & 0xFF)); - else if (codepoint <= 0x7FF) { - os.Put(static_cast(0xC0 | ((codepoint >> 6) & 0xFF))); - os.Put(static_cast(0x80 | ((codepoint & 0x3F)))); - } - else if (codepoint <= 0xFFFF) { - os.Put(static_cast(0xE0 | ((codepoint >> 12) & 0xFF))); - os.Put(static_cast(0x80 | ((codepoint >> 6) & 0x3F))); - os.Put(static_cast(0x80 | (codepoint & 0x3F))); - } - else { - RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); - os.Put(static_cast(0xF0 | ((codepoint >> 18) & 0xFF))); - os.Put(static_cast(0x80 | ((codepoint >> 12) & 0x3F))); - os.Put(static_cast(0x80 | ((codepoint >> 6) & 0x3F))); - os.Put(static_cast(0x80 | (codepoint & 0x3F))); - } - } - - template - static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { - if (codepoint <= 0x7F) - PutUnsafe(os, static_cast(codepoint & 0xFF)); - else if (codepoint <= 0x7FF) { - PutUnsafe(os, static_cast(0xC0 | ((codepoint >> 6) & 0xFF))); - PutUnsafe(os, static_cast(0x80 | ((codepoint & 0x3F)))); - } - else if (codepoint <= 0xFFFF) { - PutUnsafe(os, static_cast(0xE0 | ((codepoint >> 12) & 0xFF))); - PutUnsafe(os, static_cast(0x80 | ((codepoint >> 6) & 0x3F))); - PutUnsafe(os, static_cast(0x80 | (codepoint & 0x3F))); - } - else { - RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); - PutUnsafe(os, static_cast(0xF0 | ((codepoint >> 18) & 0xFF))); - PutUnsafe(os, static_cast(0x80 | ((codepoint >> 12) & 0x3F))); - PutUnsafe(os, static_cast(0x80 | ((codepoint >> 6) & 0x3F))); - PutUnsafe(os, static_cast(0x80 | (codepoint & 0x3F))); - } - } - - template - static bool Decode(InputStream& is, unsigned* codepoint) { -#define RAPIDJSON_COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast(c) & 0x3Fu) -#define RAPIDJSON_TRANS(mask) result &= ((GetRange(static_cast(c)) & mask) != 0) -#define RAPIDJSON_TAIL() RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x70) - typename InputStream::Ch c = is.Take(); - if (!(c & 0x80)) { - *codepoint = static_cast(c); - return true; - } - - unsigned char type = GetRange(static_cast(c)); - if (type >= 32) { - *codepoint = 0; - } else { - *codepoint = (0xFFu >> type) & static_cast(c); - } - bool result = true; - switch (type) { - case 2: RAPIDJSON_TAIL(); return result; - case 3: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; - case 4: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x50); RAPIDJSON_TAIL(); return result; - case 5: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x10); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; - case 6: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; - case 10: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x20); RAPIDJSON_TAIL(); return result; - case 11: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x60); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; - default: return false; - } -#undef RAPIDJSON_COPY -#undef RAPIDJSON_TRANS -#undef RAPIDJSON_TAIL - } - - template - static bool Validate(InputStream& is, OutputStream& os) { -#define RAPIDJSON_COPY() os.Put(c = is.Take()) -#define RAPIDJSON_TRANS(mask) result &= ((GetRange(static_cast(c)) & mask) != 0) -#define RAPIDJSON_TAIL() RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x70) - Ch c; - RAPIDJSON_COPY(); - if (!(c & 0x80)) - return true; - - bool result = true; - switch (GetRange(static_cast(c))) { - case 2: RAPIDJSON_TAIL(); return result; - case 3: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; - case 4: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x50); RAPIDJSON_TAIL(); return result; - case 5: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x10); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; - case 6: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; - case 10: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x20); RAPIDJSON_TAIL(); return result; - case 11: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x60); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; - default: return false; - } -#undef RAPIDJSON_COPY -#undef RAPIDJSON_TRANS -#undef RAPIDJSON_TAIL - } - - static unsigned char GetRange(unsigned char c) { - // Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ - // With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types. - static const unsigned char type[] = { - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, - 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, - 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, - 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, - 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8, - }; - return type[c]; - } - - template - static CharType TakeBOM(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - typename InputByteStream::Ch c = Take(is); - if (static_cast(c) != 0xEFu) return c; - c = is.Take(); - if (static_cast(c) != 0xBBu) return c; - c = is.Take(); - if (static_cast(c) != 0xBFu) return c; - c = is.Take(); - return c; - } - - template - static Ch Take(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - return static_cast(is.Take()); - } - - template - static void PutBOM(OutputByteStream& os) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(static_cast(0xEFu)); - os.Put(static_cast(0xBBu)); - os.Put(static_cast(0xBFu)); - } - - template - static void Put(OutputByteStream& os, Ch c) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(static_cast(c)); - } -}; - -/////////////////////////////////////////////////////////////////////////////// -// UTF16 - -//! UTF-16 encoding. -/*! http://en.wikipedia.org/wiki/UTF-16 - http://tools.ietf.org/html/rfc2781 - \tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead. - \note implements Encoding concept - - \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness. - For streaming, use UTF16LE and UTF16BE, which handle endianness. -*/ -template -struct UTF16 { - typedef CharType Ch; - RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2); - - enum { supportUnicode = 1 }; - - template - static void Encode(OutputStream& os, unsigned codepoint) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); - if (codepoint <= 0xFFFF) { - RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair - os.Put(static_cast(codepoint)); - } - else { - RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); - unsigned v = codepoint - 0x10000; - os.Put(static_cast((v >> 10) | 0xD800)); - os.Put(static_cast((v & 0x3FF) | 0xDC00)); - } - } - - - template - static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); - if (codepoint <= 0xFFFF) { - RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair - PutUnsafe(os, static_cast(codepoint)); - } - else { - RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); - unsigned v = codepoint - 0x10000; - PutUnsafe(os, static_cast((v >> 10) | 0xD800)); - PutUnsafe(os, static_cast((v & 0x3FF) | 0xDC00)); - } - } - - template - static bool Decode(InputStream& is, unsigned* codepoint) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); - typename InputStream::Ch c = is.Take(); - if (c < 0xD800 || c > 0xDFFF) { - *codepoint = static_cast(c); - return true; - } - else if (c <= 0xDBFF) { - *codepoint = (static_cast(c) & 0x3FF) << 10; - c = is.Take(); - *codepoint |= (static_cast(c) & 0x3FF); - *codepoint += 0x10000; - return c >= 0xDC00 && c <= 0xDFFF; - } - return false; - } - - template - static bool Validate(InputStream& is, OutputStream& os) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); - typename InputStream::Ch c; - os.Put(static_cast(c = is.Take())); - if (c < 0xD800 || c > 0xDFFF) - return true; - else if (c <= 0xDBFF) { - os.Put(c = is.Take()); - return c >= 0xDC00 && c <= 0xDFFF; - } - return false; - } -}; - -//! UTF-16 little endian encoding. -template -struct UTF16LE : UTF16 { - template - static CharType TakeBOM(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - CharType c = Take(is); - return static_cast(c) == 0xFEFFu ? Take(is) : c; - } - - template - static CharType Take(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - unsigned c = static_cast(is.Take()); - c |= static_cast(static_cast(is.Take())) << 8; - return static_cast(c); - } - - template - static void PutBOM(OutputByteStream& os) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(static_cast(0xFFu)); - os.Put(static_cast(0xFEu)); - } - - template - static void Put(OutputByteStream& os, CharType c) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(static_cast(static_cast(c) & 0xFFu)); - os.Put(static_cast((static_cast(c) >> 8) & 0xFFu)); - } -}; - -//! UTF-16 big endian encoding. -template -struct UTF16BE : UTF16 { - template - static CharType TakeBOM(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - CharType c = Take(is); - return static_cast(c) == 0xFEFFu ? Take(is) : c; - } - - template - static CharType Take(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - unsigned c = static_cast(static_cast(is.Take())) << 8; - c |= static_cast(static_cast(is.Take())); - return static_cast(c); - } - - template - static void PutBOM(OutputByteStream& os) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(static_cast(0xFEu)); - os.Put(static_cast(0xFFu)); - } - - template - static void Put(OutputByteStream& os, CharType c) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(static_cast((static_cast(c) >> 8) & 0xFFu)); - os.Put(static_cast(static_cast(c) & 0xFFu)); - } -}; - -/////////////////////////////////////////////////////////////////////////////// -// UTF32 - -//! UTF-32 encoding. -/*! http://en.wikipedia.org/wiki/UTF-32 - \tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead. - \note implements Encoding concept - - \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness. - For streaming, use UTF32LE and UTF32BE, which handle endianness. -*/ -template -struct UTF32 { - typedef CharType Ch; - RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4); - - enum { supportUnicode = 1 }; - - template - static void Encode(OutputStream& os, unsigned codepoint) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4); - RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); - os.Put(codepoint); - } - - template - static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4); - RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); - PutUnsafe(os, codepoint); - } - - template - static bool Decode(InputStream& is, unsigned* codepoint) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4); - Ch c = is.Take(); - *codepoint = c; - return c <= 0x10FFFF; - } - - template - static bool Validate(InputStream& is, OutputStream& os) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4); - Ch c; - os.Put(c = is.Take()); - return c <= 0x10FFFF; - } -}; - -//! UTF-32 little endian enocoding. -template -struct UTF32LE : UTF32 { - template - static CharType TakeBOM(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - CharType c = Take(is); - return static_cast(c) == 0x0000FEFFu ? Take(is) : c; - } - - template - static CharType Take(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - unsigned c = static_cast(is.Take()); - c |= static_cast(static_cast(is.Take())) << 8; - c |= static_cast(static_cast(is.Take())) << 16; - c |= static_cast(static_cast(is.Take())) << 24; - return static_cast(c); - } - - template - static void PutBOM(OutputByteStream& os) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(static_cast(0xFFu)); - os.Put(static_cast(0xFEu)); - os.Put(static_cast(0x00u)); - os.Put(static_cast(0x00u)); - } - - template - static void Put(OutputByteStream& os, CharType c) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(static_cast(c & 0xFFu)); - os.Put(static_cast((c >> 8) & 0xFFu)); - os.Put(static_cast((c >> 16) & 0xFFu)); - os.Put(static_cast((c >> 24) & 0xFFu)); - } -}; - -//! UTF-32 big endian encoding. -template -struct UTF32BE : UTF32 { - template - static CharType TakeBOM(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - CharType c = Take(is); - return static_cast(c) == 0x0000FEFFu ? Take(is) : c; - } - - template - static CharType Take(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - unsigned c = static_cast(static_cast(is.Take())) << 24; - c |= static_cast(static_cast(is.Take())) << 16; - c |= static_cast(static_cast(is.Take())) << 8; - c |= static_cast(static_cast(is.Take())); - return static_cast(c); - } - - template - static void PutBOM(OutputByteStream& os) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(static_cast(0x00u)); - os.Put(static_cast(0x00u)); - os.Put(static_cast(0xFEu)); - os.Put(static_cast(0xFFu)); - } - - template - static void Put(OutputByteStream& os, CharType c) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(static_cast((c >> 24) & 0xFFu)); - os.Put(static_cast((c >> 16) & 0xFFu)); - os.Put(static_cast((c >> 8) & 0xFFu)); - os.Put(static_cast(c & 0xFFu)); - } -}; - -/////////////////////////////////////////////////////////////////////////////// -// ASCII - -//! ASCII encoding. -/*! http://en.wikipedia.org/wiki/ASCII - \tparam CharType Code unit for storing 7-bit ASCII data. Default is char. - \note implements Encoding concept -*/ -template -struct ASCII { - typedef CharType Ch; - - enum { supportUnicode = 0 }; - - template - static void Encode(OutputStream& os, unsigned codepoint) { - RAPIDJSON_ASSERT(codepoint <= 0x7F); - os.Put(static_cast(codepoint & 0xFF)); - } - - template - static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { - RAPIDJSON_ASSERT(codepoint <= 0x7F); - PutUnsafe(os, static_cast(codepoint & 0xFF)); - } - - template - static bool Decode(InputStream& is, unsigned* codepoint) { - uint8_t c = static_cast(is.Take()); - *codepoint = c; - return c <= 0X7F; - } - - template - static bool Validate(InputStream& is, OutputStream& os) { - uint8_t c = static_cast(is.Take()); - os.Put(static_cast(c)); - return c <= 0x7F; - } - - template - static CharType TakeBOM(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - uint8_t c = static_cast(Take(is)); - return static_cast(c); - } - - template - static Ch Take(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - return static_cast(is.Take()); - } - - template - static void PutBOM(OutputByteStream& os) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - (void)os; - } - - template - static void Put(OutputByteStream& os, Ch c) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(static_cast(c)); - } -}; - -/////////////////////////////////////////////////////////////////////////////// -// AutoUTF - -//! Runtime-specified UTF encoding type of a stream. -enum UTFType { - kUTF8 = 0, //!< UTF-8. - kUTF16LE = 1, //!< UTF-16 little endian. - kUTF16BE = 2, //!< UTF-16 big endian. - kUTF32LE = 3, //!< UTF-32 little endian. - kUTF32BE = 4 //!< UTF-32 big endian. -}; - -//! Dynamically select encoding according to stream's runtime-specified UTF encoding type. -/*! \note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType(). -*/ -template -struct AutoUTF { - typedef CharType Ch; - - enum { supportUnicode = 1 }; - -#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8::x, UTF16LE::x, UTF16BE::x, UTF32LE::x, UTF32BE::x - - template - static RAPIDJSON_FORCEINLINE void Encode(OutputStream& os, unsigned codepoint) { - typedef void (*EncodeFunc)(OutputStream&, unsigned); - static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) }; - (*f[os.GetType()])(os, codepoint); - } - - template - static RAPIDJSON_FORCEINLINE void EncodeUnsafe(OutputStream& os, unsigned codepoint) { - typedef void (*EncodeFunc)(OutputStream&, unsigned); - static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(EncodeUnsafe) }; - (*f[os.GetType()])(os, codepoint); - } - - template - static RAPIDJSON_FORCEINLINE bool Decode(InputStream& is, unsigned* codepoint) { - typedef bool (*DecodeFunc)(InputStream&, unsigned*); - static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) }; - return (*f[is.GetType()])(is, codepoint); - } - - template - static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) { - typedef bool (*ValidateFunc)(InputStream&, OutputStream&); - static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) }; - return (*f[is.GetType()])(is, os); - } - -#undef RAPIDJSON_ENCODINGS_FUNC -}; - -/////////////////////////////////////////////////////////////////////////////// -// Transcoder - -//! Encoding conversion. -template -struct Transcoder { - //! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream. - template - static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) { - unsigned codepoint; - if (!SourceEncoding::Decode(is, &codepoint)) - return false; - TargetEncoding::Encode(os, codepoint); - return true; - } - - template - static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) { - unsigned codepoint; - if (!SourceEncoding::Decode(is, &codepoint)) - return false; - TargetEncoding::EncodeUnsafe(os, codepoint); - return true; - } - - //! Validate one Unicode codepoint from an encoded stream. - template - static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) { - return Transcode(is, os); // Since source/target encoding is different, must transcode. - } -}; - -// Forward declaration. -template -inline void PutUnsafe(Stream& stream, typename Stream::Ch c); - -//! Specialization of Transcoder with same source and target encoding. -template -struct Transcoder { - template - static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) { - os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class. - return true; - } - - template - static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) { - PutUnsafe(os, is.Take()); // Just copy one code unit. This semantic is different from primary template class. - return true; - } - - template - static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) { - return Encoding::Validate(is, os); // source/target encoding are the same - } -}; - -RAPIDJSON_NAMESPACE_END - -#if defined(__GNUC__) || (defined(_MSC_VER) && !defined(__clang__)) -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_ENCODINGS_H_ diff --git a/external/rapidjson/error/en.h b/external/rapidjson/error/en.h deleted file mode 100755 index 5d2e57b..0000000 --- a/external/rapidjson/error/en.h +++ /dev/null @@ -1,122 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_ERROR_EN_H_ -#define RAPIDJSON_ERROR_EN_H_ - -#include "error.h" - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(switch-enum) -RAPIDJSON_DIAG_OFF(covered-switch-default) -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -//! Maps error code of parsing into error message. -/*! - \ingroup RAPIDJSON_ERRORS - \param parseErrorCode Error code obtained in parsing. - \return the error message. - \note User can make a copy of this function for localization. - Using switch-case is safer for future modification of error codes. -*/ -inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) { - switch (parseErrorCode) { - case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error."); - - case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty."); - case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values."); - - case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value."); - - case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member."); - case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member."); - case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member."); - - case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element."); - - case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string."); - case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid."); - case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string."); - case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string."); - case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string."); - - case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double."); - case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number."); - case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number."); - - case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error."); - case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error."); - - default: return RAPIDJSON_ERROR_STRING("Unknown error."); - } -} - -//! Maps error code of validation into error message. -/*! - \ingroup RAPIDJSON_ERRORS - \param validateErrorCode Error code obtained from validator. - \return the error message. - \note User can make a copy of this function for localization. - Using switch-case is safer for future modification of error codes. -*/ -inline const RAPIDJSON_ERROR_CHARTYPE* GetValidateError_En(ValidateErrorCode validateErrorCode) { - switch (validateErrorCode) { - case kValidateErrors: return RAPIDJSON_ERROR_STRING("One or more validation errors have occurred"); - case kValidateErrorNone: return RAPIDJSON_ERROR_STRING("No error."); - - case kValidateErrorMultipleOf: return RAPIDJSON_ERROR_STRING("Number '%actual' is not a multiple of the 'multipleOf' value '%expected'."); - case kValidateErrorMaximum: return RAPIDJSON_ERROR_STRING("Number '%actual' is greater than the 'maximum' value '%expected'."); - case kValidateErrorExclusiveMaximum: return RAPIDJSON_ERROR_STRING("Number '%actual' is greater than or equal to the 'exclusiveMaximum' value '%expected'."); - case kValidateErrorMinimum: return RAPIDJSON_ERROR_STRING("Number '%actual' is less than the 'minimum' value '%expected'."); - case kValidateErrorExclusiveMinimum: return RAPIDJSON_ERROR_STRING("Number '%actual' is less than or equal to the 'exclusiveMinimum' value '%expected'."); - - case kValidateErrorMaxLength: return RAPIDJSON_ERROR_STRING("String '%actual' is longer than the 'maxLength' value '%expected'."); - case kValidateErrorMinLength: return RAPIDJSON_ERROR_STRING("String '%actual' is shorter than the 'minLength' value '%expected'."); - case kValidateErrorPattern: return RAPIDJSON_ERROR_STRING("String '%actual' does not match the 'pattern' regular expression."); - - case kValidateErrorMaxItems: return RAPIDJSON_ERROR_STRING("Array of length '%actual' is longer than the 'maxItems' value '%expected'."); - case kValidateErrorMinItems: return RAPIDJSON_ERROR_STRING("Array of length '%actual' is shorter than the 'minItems' value '%expected'."); - case kValidateErrorUniqueItems: return RAPIDJSON_ERROR_STRING("Array has duplicate items at indices '%duplicates' but 'uniqueItems' is true."); - case kValidateErrorAdditionalItems: return RAPIDJSON_ERROR_STRING("Array has an additional item at index '%disallowed' that is not allowed by the schema."); - - case kValidateErrorMaxProperties: return RAPIDJSON_ERROR_STRING("Object has '%actual' members which is more than 'maxProperties' value '%expected'."); - case kValidateErrorMinProperties: return RAPIDJSON_ERROR_STRING("Object has '%actual' members which is less than 'minProperties' value '%expected'."); - case kValidateErrorRequired: return RAPIDJSON_ERROR_STRING("Object is missing the following members required by the schema: '%missing'."); - case kValidateErrorAdditionalProperties: return RAPIDJSON_ERROR_STRING("Object has an additional member '%disallowed' that is not allowed by the schema."); - case kValidateErrorPatternProperties: return RAPIDJSON_ERROR_STRING("Object has 'patternProperties' that are not allowed by the schema."); - case kValidateErrorDependencies: return RAPIDJSON_ERROR_STRING("Object has missing property or schema dependencies, refer to following errors."); - - case kValidateErrorEnum: return RAPIDJSON_ERROR_STRING("Property has a value that is not one of its allowed enumerated values."); - case kValidateErrorType: return RAPIDJSON_ERROR_STRING("Property has a type '%actual' that is not in the following list: '%expected'."); - - case kValidateErrorOneOf: return RAPIDJSON_ERROR_STRING("Property did not match any of the sub-schemas specified by 'oneOf', refer to following errors."); - case kValidateErrorOneOfMatch: return RAPIDJSON_ERROR_STRING("Property matched more than one of the sub-schemas specified by 'oneOf'."); - case kValidateErrorAllOf: return RAPIDJSON_ERROR_STRING("Property did not match all of the sub-schemas specified by 'allOf', refer to following errors."); - case kValidateErrorAnyOf: return RAPIDJSON_ERROR_STRING("Property did not match any of the sub-schemas specified by 'anyOf', refer to following errors."); - case kValidateErrorNot: return RAPIDJSON_ERROR_STRING("Property matched the sub-schema specified by 'not'."); - - default: return RAPIDJSON_ERROR_STRING("Unknown error."); - } -} - -RAPIDJSON_NAMESPACE_END - -#ifdef __clang__ -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_ERROR_EN_H_ diff --git a/external/rapidjson/error/error.h b/external/rapidjson/error/error.h deleted file mode 100755 index 6270da1..0000000 --- a/external/rapidjson/error/error.h +++ /dev/null @@ -1,216 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_ERROR_ERROR_H_ -#define RAPIDJSON_ERROR_ERROR_H_ - -#include "../rapidjson.h" - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(padded) -#endif - -/*! \file error.h */ - -/*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */ - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_ERROR_CHARTYPE - -//! Character type of error messages. -/*! \ingroup RAPIDJSON_ERRORS - The default character type is \c char. - On Windows, user can define this macro as \c TCHAR for supporting both - unicode/non-unicode settings. -*/ -#ifndef RAPIDJSON_ERROR_CHARTYPE -#define RAPIDJSON_ERROR_CHARTYPE char -#endif - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_ERROR_STRING - -//! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[]. -/*! \ingroup RAPIDJSON_ERRORS - By default this conversion macro does nothing. - On Windows, user can define this macro as \c _T(x) for supporting both - unicode/non-unicode settings. -*/ -#ifndef RAPIDJSON_ERROR_STRING -#define RAPIDJSON_ERROR_STRING(x) x -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -/////////////////////////////////////////////////////////////////////////////// -// ParseErrorCode - -//! Error code of parsing. -/*! \ingroup RAPIDJSON_ERRORS - \see GenericReader::Parse, GenericReader::GetParseErrorCode -*/ -enum ParseErrorCode { - kParseErrorNone = 0, //!< No error. - - kParseErrorDocumentEmpty, //!< The document is empty. - kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values. - - kParseErrorValueInvalid, //!< Invalid value. - - kParseErrorObjectMissName, //!< Missing a name for object member. - kParseErrorObjectMissColon, //!< Missing a colon after a name of object member. - kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member. - - kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element. - - kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string. - kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid. - kParseErrorStringEscapeInvalid, //!< Invalid escape character in string. - kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string. - kParseErrorStringInvalidEncoding, //!< Invalid encoding in string. - - kParseErrorNumberTooBig, //!< Number too big to be stored in double. - kParseErrorNumberMissFraction, //!< Miss fraction part in number. - kParseErrorNumberMissExponent, //!< Miss exponent in number. - - kParseErrorTermination, //!< Parsing was terminated. - kParseErrorUnspecificSyntaxError //!< Unspecific syntax error. -}; - -//! Result of parsing (wraps ParseErrorCode) -/*! - \ingroup RAPIDJSON_ERRORS - \code - Document doc; - ParseResult ok = doc.Parse("[42]"); - if (!ok) { - fprintf(stderr, "JSON parse error: %s (%u)", - GetParseError_En(ok.Code()), ok.Offset()); - exit(EXIT_FAILURE); - } - \endcode - \see GenericReader::Parse, GenericDocument::Parse -*/ -struct ParseResult { - //!! Unspecified boolean type - typedef bool (ParseResult::*BooleanType)() const; -public: - //! Default constructor, no error. - ParseResult() : code_(kParseErrorNone), offset_(0) {} - //! Constructor to set an error. - ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {} - - //! Get the error code. - ParseErrorCode Code() const { return code_; } - //! Get the error offset, if \ref IsError(), 0 otherwise. - size_t Offset() const { return offset_; } - - //! Explicit conversion to \c bool, returns \c true, iff !\ref IsError(). - operator BooleanType() const { return !IsError() ? &ParseResult::IsError : NULL; } - //! Whether the result is an error. - bool IsError() const { return code_ != kParseErrorNone; } - - bool operator==(const ParseResult& that) const { return code_ == that.code_; } - bool operator==(ParseErrorCode code) const { return code_ == code; } - friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; } - - bool operator!=(const ParseResult& that) const { return !(*this == that); } - bool operator!=(ParseErrorCode code) const { return !(*this == code); } - friend bool operator!=(ParseErrorCode code, const ParseResult & err) { return err != code; } - - //! Reset error code. - void Clear() { Set(kParseErrorNone); } - //! Update error code and offset. - void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; } - -private: - ParseErrorCode code_; - size_t offset_; -}; - -//! Function pointer type of GetParseError(). -/*! \ingroup RAPIDJSON_ERRORS - - This is the prototype for \c GetParseError_X(), where \c X is a locale. - User can dynamically change locale in runtime, e.g.: -\code - GetParseErrorFunc GetParseError = GetParseError_En; // or whatever - const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode()); -\endcode -*/ -typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode); - -/////////////////////////////////////////////////////////////////////////////// -// ValidateErrorCode - -//! Error codes when validating. -/*! \ingroup RAPIDJSON_ERRORS - \see GenericSchemaValidator -*/ -enum ValidateErrorCode { - kValidateErrors = -1, //!< Top level error code when kValidateContinueOnErrorsFlag set. - kValidateErrorNone = 0, //!< No error. - - kValidateErrorMultipleOf, //!< Number is not a multiple of the 'multipleOf' value. - kValidateErrorMaximum, //!< Number is greater than the 'maximum' value. - kValidateErrorExclusiveMaximum, //!< Number is greater than or equal to the 'maximum' value. - kValidateErrorMinimum, //!< Number is less than the 'minimum' value. - kValidateErrorExclusiveMinimum, //!< Number is less than or equal to the 'minimum' value. - - kValidateErrorMaxLength, //!< String is longer than the 'maxLength' value. - kValidateErrorMinLength, //!< String is longer than the 'maxLength' value. - kValidateErrorPattern, //!< String does not match the 'pattern' regular expression. - - kValidateErrorMaxItems, //!< Array is longer than the 'maxItems' value. - kValidateErrorMinItems, //!< Array is shorter than the 'minItems' value. - kValidateErrorUniqueItems, //!< Array has duplicate items but 'uniqueItems' is true. - kValidateErrorAdditionalItems, //!< Array has additional items that are not allowed by the schema. - - kValidateErrorMaxProperties, //!< Object has more members than 'maxProperties' value. - kValidateErrorMinProperties, //!< Object has less members than 'minProperties' value. - kValidateErrorRequired, //!< Object is missing one or more members required by the schema. - kValidateErrorAdditionalProperties, //!< Object has additional members that are not allowed by the schema. - kValidateErrorPatternProperties, //!< See other errors. - kValidateErrorDependencies, //!< Object has missing property or schema dependencies. - - kValidateErrorEnum, //!< Property has a value that is not one of its allowed enumerated values - kValidateErrorType, //!< Property has a type that is not allowed by the schema.. - - kValidateErrorOneOf, //!< Property did not match any of the sub-schemas specified by 'oneOf'. - kValidateErrorOneOfMatch, //!< Property matched more than one of the sub-schemas specified by 'oneOf'. - kValidateErrorAllOf, //!< Property did not match all of the sub-schemas specified by 'allOf'. - kValidateErrorAnyOf, //!< Property did not match any of the sub-schemas specified by 'anyOf'. - kValidateErrorNot //!< Property matched the sub-schema specified by 'not'. -}; - -//! Function pointer type of GetValidateError(). -/*! \ingroup RAPIDJSON_ERRORS - - This is the prototype for \c GetValidateError_X(), where \c X is a locale. - User can dynamically change locale in runtime, e.g.: -\code - GetValidateErrorFunc GetValidateError = GetValidateError_En; // or whatever - const RAPIDJSON_ERROR_CHARTYPE* s = GetValidateError(validator.GetInvalidSchemaCode()); -\endcode -*/ -typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetValidateErrorFunc)(ValidateErrorCode); - -RAPIDJSON_NAMESPACE_END - -#ifdef __clang__ -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_ERROR_ERROR_H_ diff --git a/external/rapidjson/filereadstream.h b/external/rapidjson/filereadstream.h deleted file mode 100755 index f8bb43c..0000000 --- a/external/rapidjson/filereadstream.h +++ /dev/null @@ -1,99 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_FILEREADSTREAM_H_ -#define RAPIDJSON_FILEREADSTREAM_H_ - -#include "stream.h" -#include - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(padded) -RAPIDJSON_DIAG_OFF(unreachable-code) -RAPIDJSON_DIAG_OFF(missing-noreturn) -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -//! File byte stream for input using fread(). -/*! - \note implements Stream concept -*/ -class FileReadStream { -public: - typedef char Ch; //!< Character type (byte). - - //! Constructor. - /*! - \param fp File pointer opened for read. - \param buffer user-supplied buffer. - \param bufferSize size of buffer in bytes. Must >=4 bytes. - */ - FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { - RAPIDJSON_ASSERT(fp_ != 0); - RAPIDJSON_ASSERT(bufferSize >= 4); - Read(); - } - - Ch Peek() const { return *current_; } - Ch Take() { Ch c = *current_; Read(); return c; } - size_t Tell() const { return count_ + static_cast(current_ - buffer_); } - - // Not implemented - void Put(Ch) { RAPIDJSON_ASSERT(false); } - void Flush() { RAPIDJSON_ASSERT(false); } - Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } - - // For encoding detection only. - const Ch* Peek4() const { - return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0; - } - -private: - void Read() { - if (current_ < bufferLast_) - ++current_; - else if (!eof_) { - count_ += readCount_; - readCount_ = std::fread(buffer_, 1, bufferSize_, fp_); - bufferLast_ = buffer_ + readCount_ - 1; - current_ = buffer_; - - if (readCount_ < bufferSize_) { - buffer_[readCount_] = '\0'; - ++bufferLast_; - eof_ = true; - } - } - } - - std::FILE* fp_; - Ch *buffer_; - size_t bufferSize_; - Ch *bufferLast_; - Ch *current_; - size_t readCount_; - size_t count_; //!< Number of characters read - bool eof_; -}; - -RAPIDJSON_NAMESPACE_END - -#ifdef __clang__ -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_FILESTREAM_H_ diff --git a/external/rapidjson/filewritestream.h b/external/rapidjson/filewritestream.h deleted file mode 100755 index 5d89588..0000000 --- a/external/rapidjson/filewritestream.h +++ /dev/null @@ -1,104 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_FILEWRITESTREAM_H_ -#define RAPIDJSON_FILEWRITESTREAM_H_ - -#include "stream.h" -#include - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(unreachable-code) -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -//! Wrapper of C file stream for output using fwrite(). -/*! - \note implements Stream concept -*/ -class FileWriteStream { -public: - typedef char Ch; //!< Character type. Only support char. - - FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) { - RAPIDJSON_ASSERT(fp_ != 0); - } - - void Put(char c) { - if (current_ >= bufferEnd_) - Flush(); - - *current_++ = c; - } - - void PutN(char c, size_t n) { - size_t avail = static_cast(bufferEnd_ - current_); - while (n > avail) { - std::memset(current_, c, avail); - current_ += avail; - Flush(); - n -= avail; - avail = static_cast(bufferEnd_ - current_); - } - - if (n > 0) { - std::memset(current_, c, n); - current_ += n; - } - } - - void Flush() { - if (current_ != buffer_) { - size_t result = std::fwrite(buffer_, 1, static_cast(current_ - buffer_), fp_); - if (result < static_cast(current_ - buffer_)) { - // failure deliberately ignored at this time - // added to avoid warn_unused_result build errors - } - current_ = buffer_; - } - } - - // Not implemented - char Peek() const { RAPIDJSON_ASSERT(false); return 0; } - char Take() { RAPIDJSON_ASSERT(false); return 0; } - size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } - char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } - -private: - // Prohibit copy constructor & assignment operator. - FileWriteStream(const FileWriteStream&); - FileWriteStream& operator=(const FileWriteStream&); - - std::FILE* fp_; - char *buffer_; - char *bufferEnd_; - char *current_; -}; - -//! Implement specialized version of PutN() with memset() for better performance. -template<> -inline void PutN(FileWriteStream& stream, char c, size_t n) { - stream.PutN(c, n); -} - -RAPIDJSON_NAMESPACE_END - -#ifdef __clang__ -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_FILESTREAM_H_ diff --git a/external/rapidjson/fwd.h b/external/rapidjson/fwd.h deleted file mode 100755 index d62f77f..0000000 --- a/external/rapidjson/fwd.h +++ /dev/null @@ -1,151 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_FWD_H_ -#define RAPIDJSON_FWD_H_ - -#include "rapidjson.h" - -RAPIDJSON_NAMESPACE_BEGIN - -// encodings.h - -template struct UTF8; -template struct UTF16; -template struct UTF16BE; -template struct UTF16LE; -template struct UTF32; -template struct UTF32BE; -template struct UTF32LE; -template struct ASCII; -template struct AutoUTF; - -template -struct Transcoder; - -// allocators.h - -class CrtAllocator; - -template -class MemoryPoolAllocator; - -// stream.h - -template -struct GenericStringStream; - -typedef GenericStringStream > StringStream; - -template -struct GenericInsituStringStream; - -typedef GenericInsituStringStream > InsituStringStream; - -// stringbuffer.h - -template -class GenericStringBuffer; - -typedef GenericStringBuffer, CrtAllocator> StringBuffer; - -// filereadstream.h - -class FileReadStream; - -// filewritestream.h - -class FileWriteStream; - -// memorybuffer.h - -template -struct GenericMemoryBuffer; - -typedef GenericMemoryBuffer MemoryBuffer; - -// memorystream.h - -struct MemoryStream; - -// reader.h - -template -struct BaseReaderHandler; - -template -class GenericReader; - -typedef GenericReader, UTF8, CrtAllocator> Reader; - -// writer.h - -template -class Writer; - -// prettywriter.h - -template -class PrettyWriter; - -// document.h - -template -class GenericMember; - -template -class GenericMemberIterator; - -template -struct GenericStringRef; - -template -class GenericValue; - -typedef GenericValue, MemoryPoolAllocator > Value; - -template -class GenericDocument; - -typedef GenericDocument, MemoryPoolAllocator, CrtAllocator> Document; - -// pointer.h - -template -class GenericPointer; - -typedef GenericPointer Pointer; - -// schema.h - -template -class IGenericRemoteSchemaDocumentProvider; - -template -class GenericSchemaDocument; - -typedef GenericSchemaDocument SchemaDocument; -typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProvider; - -template < - typename SchemaDocumentType, - typename OutputHandler, - typename StateAllocator> -class GenericSchemaValidator; - -typedef GenericSchemaValidator, void>, CrtAllocator> SchemaValidator; - -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_RAPIDJSONFWD_H_ diff --git a/external/rapidjson/internal/biginteger.h b/external/rapidjson/internal/biginteger.h deleted file mode 100755 index 1245578..0000000 --- a/external/rapidjson/internal/biginteger.h +++ /dev/null @@ -1,290 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_BIGINTEGER_H_ -#define RAPIDJSON_BIGINTEGER_H_ - -#include "../rapidjson.h" - -#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && defined(_M_AMD64) -#include // for _umul128 -#pragma intrinsic(_umul128) -#endif - -RAPIDJSON_NAMESPACE_BEGIN -namespace internal { - -class BigInteger { -public: - typedef uint64_t Type; - - BigInteger(const BigInteger& rhs) : count_(rhs.count_) { - std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type)); - } - - explicit BigInteger(uint64_t u) : count_(1) { - digits_[0] = u; - } - - BigInteger(const char* decimals, size_t length) : count_(1) { - RAPIDJSON_ASSERT(length > 0); - digits_[0] = 0; - size_t i = 0; - const size_t kMaxDigitPerIteration = 19; // 2^64 = 18446744073709551616 > 10^19 - while (length >= kMaxDigitPerIteration) { - AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration); - length -= kMaxDigitPerIteration; - i += kMaxDigitPerIteration; - } - - if (length > 0) - AppendDecimal64(decimals + i, decimals + i + length); - } - - BigInteger& operator=(const BigInteger &rhs) - { - if (this != &rhs) { - count_ = rhs.count_; - std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type)); - } - return *this; - } - - BigInteger& operator=(uint64_t u) { - digits_[0] = u; - count_ = 1; - return *this; - } - - BigInteger& operator+=(uint64_t u) { - Type backup = digits_[0]; - digits_[0] += u; - for (size_t i = 0; i < count_ - 1; i++) { - if (digits_[i] >= backup) - return *this; // no carry - backup = digits_[i + 1]; - digits_[i + 1] += 1; - } - - // Last carry - if (digits_[count_ - 1] < backup) - PushBack(1); - - return *this; - } - - BigInteger& operator*=(uint64_t u) { - if (u == 0) return *this = 0; - if (u == 1) return *this; - if (*this == 1) return *this = u; - - uint64_t k = 0; - for (size_t i = 0; i < count_; i++) { - uint64_t hi; - digits_[i] = MulAdd64(digits_[i], u, k, &hi); - k = hi; - } - - if (k > 0) - PushBack(k); - - return *this; - } - - BigInteger& operator*=(uint32_t u) { - if (u == 0) return *this = 0; - if (u == 1) return *this; - if (*this == 1) return *this = u; - - uint64_t k = 0; - for (size_t i = 0; i < count_; i++) { - const uint64_t c = digits_[i] >> 32; - const uint64_t d = digits_[i] & 0xFFFFFFFF; - const uint64_t uc = u * c; - const uint64_t ud = u * d; - const uint64_t p0 = ud + k; - const uint64_t p1 = uc + (p0 >> 32); - digits_[i] = (p0 & 0xFFFFFFFF) | (p1 << 32); - k = p1 >> 32; - } - - if (k > 0) - PushBack(k); - - return *this; - } - - BigInteger& operator<<=(size_t shift) { - if (IsZero() || shift == 0) return *this; - - size_t offset = shift / kTypeBit; - size_t interShift = shift % kTypeBit; - RAPIDJSON_ASSERT(count_ + offset <= kCapacity); - - if (interShift == 0) { - std::memmove(digits_ + offset, digits_, count_ * sizeof(Type)); - count_ += offset; - } - else { - digits_[count_] = 0; - for (size_t i = count_; i > 0; i--) - digits_[i + offset] = (digits_[i] << interShift) | (digits_[i - 1] >> (kTypeBit - interShift)); - digits_[offset] = digits_[0] << interShift; - count_ += offset; - if (digits_[count_]) - count_++; - } - - std::memset(digits_, 0, offset * sizeof(Type)); - - return *this; - } - - bool operator==(const BigInteger& rhs) const { - return count_ == rhs.count_ && std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0; - } - - bool operator==(const Type rhs) const { - return count_ == 1 && digits_[0] == rhs; - } - - BigInteger& MultiplyPow5(unsigned exp) { - static const uint32_t kPow5[12] = { - 5, - 5 * 5, - 5 * 5 * 5, - 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 - }; - if (exp == 0) return *this; - for (; exp >= 27; exp -= 27) *this *= RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27 - for (; exp >= 13; exp -= 13) *this *= static_cast(1220703125u); // 5^13 - if (exp > 0) *this *= kPow5[exp - 1]; - return *this; - } - - // Compute absolute difference of this and rhs. - // Assume this != rhs - bool Difference(const BigInteger& rhs, BigInteger* out) const { - int cmp = Compare(rhs); - RAPIDJSON_ASSERT(cmp != 0); - const BigInteger *a, *b; // Makes a > b - bool ret; - if (cmp < 0) { a = &rhs; b = this; ret = true; } - else { a = this; b = &rhs; ret = false; } - - Type borrow = 0; - for (size_t i = 0; i < a->count_; i++) { - Type d = a->digits_[i] - borrow; - if (i < b->count_) - d -= b->digits_[i]; - borrow = (d > a->digits_[i]) ? 1 : 0; - out->digits_[i] = d; - if (d != 0) - out->count_ = i + 1; - } - - return ret; - } - - int Compare(const BigInteger& rhs) const { - if (count_ != rhs.count_) - return count_ < rhs.count_ ? -1 : 1; - - for (size_t i = count_; i-- > 0;) - if (digits_[i] != rhs.digits_[i]) - return digits_[i] < rhs.digits_[i] ? -1 : 1; - - return 0; - } - - size_t GetCount() const { return count_; } - Type GetDigit(size_t index) const { RAPIDJSON_ASSERT(index < count_); return digits_[index]; } - bool IsZero() const { return count_ == 1 && digits_[0] == 0; } - -private: - void AppendDecimal64(const char* begin, const char* end) { - uint64_t u = ParseUint64(begin, end); - if (IsZero()) - *this = u; - else { - unsigned exp = static_cast(end - begin); - (MultiplyPow5(exp) <<= exp) += u; // *this = *this * 10^exp + u - } - } - - void PushBack(Type digit) { - RAPIDJSON_ASSERT(count_ < kCapacity); - digits_[count_++] = digit; - } - - static uint64_t ParseUint64(const char* begin, const char* end) { - uint64_t r = 0; - for (const char* p = begin; p != end; ++p) { - RAPIDJSON_ASSERT(*p >= '0' && *p <= '9'); - r = r * 10u + static_cast(*p - '0'); - } - return r; - } - - // Assume a * b + k < 2^128 - static uint64_t MulAdd64(uint64_t a, uint64_t b, uint64_t k, uint64_t* outHigh) { -#if defined(_MSC_VER) && defined(_M_AMD64) - uint64_t low = _umul128(a, b, outHigh) + k; - if (low < k) - (*outHigh)++; - return low; -#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__) - __extension__ typedef unsigned __int128 uint128; - uint128 p = static_cast(a) * static_cast(b); - p += k; - *outHigh = static_cast(p >> 64); - return static_cast(p); -#else - const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32; - uint64_t x0 = a0 * b0, x1 = a0 * b1, x2 = a1 * b0, x3 = a1 * b1; - x1 += (x0 >> 32); // can't give carry - x1 += x2; - if (x1 < x2) - x3 += (static_cast(1) << 32); - uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF); - uint64_t hi = x3 + (x1 >> 32); - - lo += k; - if (lo < k) - hi++; - *outHigh = hi; - return lo; -#endif - } - - static const size_t kBitCount = 3328; // 64bit * 54 > 10^1000 - static const size_t kCapacity = kBitCount / sizeof(Type); - static const size_t kTypeBit = sizeof(Type) * 8; - - Type digits_[kCapacity]; - size_t count_; -}; - -} // namespace internal -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_BIGINTEGER_H_ diff --git a/external/rapidjson/internal/clzll.h b/external/rapidjson/internal/clzll.h deleted file mode 100755 index 8fc5118..0000000 --- a/external/rapidjson/internal/clzll.h +++ /dev/null @@ -1,71 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_CLZLL_H_ -#define RAPIDJSON_CLZLL_H_ - -#include "../rapidjson.h" - -#if defined(_MSC_VER) && !defined(UNDER_CE) -#include -#if defined(_WIN64) -#pragma intrinsic(_BitScanReverse64) -#else -#pragma intrinsic(_BitScanReverse) -#endif -#endif - -RAPIDJSON_NAMESPACE_BEGIN -namespace internal { - -inline uint32_t clzll(uint64_t x) { - // Passing 0 to __builtin_clzll is UB in GCC and results in an - // infinite loop in the software implementation. - RAPIDJSON_ASSERT(x != 0); - -#if defined(_MSC_VER) && !defined(UNDER_CE) - unsigned long r = 0; -#if defined(_WIN64) - _BitScanReverse64(&r, x); -#else - // Scan the high 32 bits. - if (_BitScanReverse(&r, static_cast(x >> 32))) - return 63 - (r + 32); - - // Scan the low 32 bits. - _BitScanReverse(&r, static_cast(x & 0xFFFFFFFF)); -#endif // _WIN64 - - return 63 - r; -#elif (defined(__GNUC__) && __GNUC__ >= 4) || RAPIDJSON_HAS_BUILTIN(__builtin_clzll) - // __builtin_clzll wrapper - return static_cast(__builtin_clzll(x)); -#else - // naive version - uint32_t r = 0; - while (!(x & (static_cast(1) << 63))) { - x <<= 1; - ++r; - } - - return r; -#endif // _MSC_VER -} - -#define RAPIDJSON_CLZLL RAPIDJSON_NAMESPACE::internal::clzll - -} // namespace internal -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_CLZLL_H_ diff --git a/external/rapidjson/internal/diyfp.h b/external/rapidjson/internal/diyfp.h deleted file mode 100755 index a40797e..0000000 --- a/external/rapidjson/internal/diyfp.h +++ /dev/null @@ -1,257 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -// This is a C++ header-only implementation of Grisu2 algorithm from the publication: -// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with -// integers." ACM Sigplan Notices 45.6 (2010): 233-243. - -#ifndef RAPIDJSON_DIYFP_H_ -#define RAPIDJSON_DIYFP_H_ - -#include "../rapidjson.h" -#include "clzll.h" -#include - -#if defined(_MSC_VER) && defined(_M_AMD64) && !defined(__INTEL_COMPILER) -#include -#pragma intrinsic(_umul128) -#endif - -RAPIDJSON_NAMESPACE_BEGIN -namespace internal { - -#ifdef __GNUC__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(effc++) -#endif - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(padded) -#endif - -struct DiyFp { - DiyFp() : f(), e() {} - - DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {} - - explicit DiyFp(double d) { - union { - double d; - uint64_t u64; - } u = { d }; - - int biased_e = static_cast((u.u64 & kDpExponentMask) >> kDpSignificandSize); - uint64_t significand = (u.u64 & kDpSignificandMask); - if (biased_e != 0) { - f = significand + kDpHiddenBit; - e = biased_e - kDpExponentBias; - } - else { - f = significand; - e = kDpMinExponent + 1; - } - } - - DiyFp operator-(const DiyFp& rhs) const { - return DiyFp(f - rhs.f, e); - } - - DiyFp operator*(const DiyFp& rhs) const { -#if defined(_MSC_VER) && defined(_M_AMD64) - uint64_t h; - uint64_t l = _umul128(f, rhs.f, &h); - if (l & (uint64_t(1) << 63)) // rounding - h++; - return DiyFp(h, e + rhs.e + 64); -#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__) - __extension__ typedef unsigned __int128 uint128; - uint128 p = static_cast(f) * static_cast(rhs.f); - uint64_t h = static_cast(p >> 64); - uint64_t l = static_cast(p); - if (l & (uint64_t(1) << 63)) // rounding - h++; - return DiyFp(h, e + rhs.e + 64); -#else - const uint64_t M32 = 0xFFFFFFFF; - const uint64_t a = f >> 32; - const uint64_t b = f & M32; - const uint64_t c = rhs.f >> 32; - const uint64_t d = rhs.f & M32; - const uint64_t ac = a * c; - const uint64_t bc = b * c; - const uint64_t ad = a * d; - const uint64_t bd = b * d; - uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32); - tmp += 1U << 31; /// mult_round - return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64); -#endif - } - - DiyFp Normalize() const { - int s = static_cast(clzll(f)); - return DiyFp(f << s, e - s); - } - - DiyFp NormalizeBoundary() const { - DiyFp res = *this; - while (!(res.f & (kDpHiddenBit << 1))) { - res.f <<= 1; - res.e--; - } - res.f <<= (kDiySignificandSize - kDpSignificandSize - 2); - res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2); - return res; - } - - void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const { - DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary(); - DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1); - mi.f <<= mi.e - pl.e; - mi.e = pl.e; - *plus = pl; - *minus = mi; - } - - double ToDouble() const { - union { - double d; - uint64_t u64; - }u; - RAPIDJSON_ASSERT(f <= kDpHiddenBit + kDpSignificandMask); - if (e < kDpDenormalExponent) { - // Underflow. - return 0.0; - } - if (e >= kDpMaxExponent) { - // Overflow. - return std::numeric_limits::infinity(); - } - const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 : - static_cast(e + kDpExponentBias); - u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize); - return u.d; - } - - static const int kDiySignificandSize = 64; - static const int kDpSignificandSize = 52; - static const int kDpExponentBias = 0x3FF + kDpSignificandSize; - static const int kDpMaxExponent = 0x7FF - kDpExponentBias; - static const int kDpMinExponent = -kDpExponentBias; - static const int kDpDenormalExponent = -kDpExponentBias + 1; - static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); - static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); - static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); - - uint64_t f; - int e; -}; - -inline DiyFp GetCachedPowerByIndex(size_t index) { - // 10^-348, 10^-340, ..., 10^340 - static const uint64_t kCachedPowers_F[] = { - RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76), - RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea), - RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df), - RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f), - RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c), - RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5), - RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d), - RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637), - RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7), - RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5), - RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b), - RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996), - RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6), - RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8), - RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053), - RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd), - RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94), - RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b), - RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac), - RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3), - RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb), - RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c), - RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000), - RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984), - RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70), - RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245), - RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8), - RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a), - RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea), - RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85), - RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2), - RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3), - RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25), - RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece), - RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5), - RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a), - RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c), - RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a), - RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129), - RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429), - RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d), - RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841), - RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9), - RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b) - }; - static const int16_t kCachedPowers_E[] = { - -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, - -954, -927, -901, -874, -847, -821, -794, -768, -741, -715, - -688, -661, -635, -608, -582, -555, -529, -502, -475, -449, - -422, -396, -369, -343, -316, -289, -263, -236, -210, -183, - -157, -130, -103, -77, -50, -24, 3, 30, 56, 83, - 109, 136, 162, 189, 216, 242, 269, 295, 322, 348, - 375, 402, 428, 455, 481, 508, 534, 561, 588, 614, - 641, 667, 694, 720, 747, 774, 800, 827, 853, 880, - 907, 933, 960, 986, 1013, 1039, 1066 - }; - RAPIDJSON_ASSERT(index < 87); - return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]); -} - -inline DiyFp GetCachedPower(int e, int* K) { - - //int k = static_cast(ceil((-61 - e) * 0.30102999566398114)) + 374; - double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive - int k = static_cast(dk); - if (dk - k > 0.0) - k++; - - unsigned index = static_cast((k >> 3) + 1); - *K = -(-348 + static_cast(index << 3)); // decimal exponent no need lookup table - - return GetCachedPowerByIndex(index); -} - -inline DiyFp GetCachedPower10(int exp, int *outExp) { - RAPIDJSON_ASSERT(exp >= -348); - unsigned index = static_cast(exp + 348) / 8u; - *outExp = -348 + static_cast(index) * 8; - return GetCachedPowerByIndex(index); -} - -#ifdef __GNUC__ -RAPIDJSON_DIAG_POP -#endif - -#ifdef __clang__ -RAPIDJSON_DIAG_POP -RAPIDJSON_DIAG_OFF(padded) -#endif - -} // namespace internal -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_DIYFP_H_ diff --git a/external/rapidjson/internal/dtoa.h b/external/rapidjson/internal/dtoa.h deleted file mode 100755 index 621402f..0000000 --- a/external/rapidjson/internal/dtoa.h +++ /dev/null @@ -1,245 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -// This is a C++ header-only implementation of Grisu2 algorithm from the publication: -// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with -// integers." ACM Sigplan Notices 45.6 (2010): 233-243. - -#ifndef RAPIDJSON_DTOA_ -#define RAPIDJSON_DTOA_ - -#include "itoa.h" // GetDigitsLut() -#include "diyfp.h" -#include "ieee754.h" - -RAPIDJSON_NAMESPACE_BEGIN -namespace internal { - -#ifdef __GNUC__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(effc++) -RAPIDJSON_DIAG_OFF(array-bounds) // some gcc versions generate wrong warnings https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124 -#endif - -inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) { - while (rest < wp_w && delta - rest >= ten_kappa && - (rest + ten_kappa < wp_w || /// closer - wp_w - rest > rest + ten_kappa - wp_w)) { - buffer[len - 1]--; - rest += ten_kappa; - } -} - -inline int CountDecimalDigit32(uint32_t n) { - // Simple pure C++ implementation was faster than __builtin_clz version in this situation. - if (n < 10) return 1; - if (n < 100) return 2; - if (n < 1000) return 3; - if (n < 10000) return 4; - if (n < 100000) return 5; - if (n < 1000000) return 6; - if (n < 10000000) return 7; - if (n < 100000000) return 8; - // Will not reach 10 digits in DigitGen() - //if (n < 1000000000) return 9; - //return 10; - return 9; -} - -inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) { - static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; - const DiyFp one(uint64_t(1) << -Mp.e, Mp.e); - const DiyFp wp_w = Mp - W; - uint32_t p1 = static_cast(Mp.f >> -one.e); - uint64_t p2 = Mp.f & (one.f - 1); - int kappa = CountDecimalDigit32(p1); // kappa in [0, 9] - *len = 0; - - while (kappa > 0) { - uint32_t d = 0; - switch (kappa) { - case 9: d = p1 / 100000000; p1 %= 100000000; break; - case 8: d = p1 / 10000000; p1 %= 10000000; break; - case 7: d = p1 / 1000000; p1 %= 1000000; break; - case 6: d = p1 / 100000; p1 %= 100000; break; - case 5: d = p1 / 10000; p1 %= 10000; break; - case 4: d = p1 / 1000; p1 %= 1000; break; - case 3: d = p1 / 100; p1 %= 100; break; - case 2: d = p1 / 10; p1 %= 10; break; - case 1: d = p1; p1 = 0; break; - default:; - } - if (d || *len) - buffer[(*len)++] = static_cast('0' + static_cast(d)); - kappa--; - uint64_t tmp = (static_cast(p1) << -one.e) + p2; - if (tmp <= delta) { - *K += kappa; - GrisuRound(buffer, *len, delta, tmp, static_cast(kPow10[kappa]) << -one.e, wp_w.f); - return; - } - } - - // kappa = 0 - for (;;) { - p2 *= 10; - delta *= 10; - char d = static_cast(p2 >> -one.e); - if (d || *len) - buffer[(*len)++] = static_cast('0' + d); - p2 &= one.f - 1; - kappa--; - if (p2 < delta) { - *K += kappa; - int index = -kappa; - GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[index] : 0)); - return; - } - } -} - -inline void Grisu2(double value, char* buffer, int* length, int* K) { - const DiyFp v(value); - DiyFp w_m, w_p; - v.NormalizedBoundaries(&w_m, &w_p); - - const DiyFp c_mk = GetCachedPower(w_p.e, K); - const DiyFp W = v.Normalize() * c_mk; - DiyFp Wp = w_p * c_mk; - DiyFp Wm = w_m * c_mk; - Wm.f++; - Wp.f--; - DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K); -} - -inline char* WriteExponent(int K, char* buffer) { - if (K < 0) { - *buffer++ = '-'; - K = -K; - } - - if (K >= 100) { - *buffer++ = static_cast('0' + static_cast(K / 100)); - K %= 100; - const char* d = GetDigitsLut() + K * 2; - *buffer++ = d[0]; - *buffer++ = d[1]; - } - else if (K >= 10) { - const char* d = GetDigitsLut() + K * 2; - *buffer++ = d[0]; - *buffer++ = d[1]; - } - else - *buffer++ = static_cast('0' + static_cast(K)); - - return buffer; -} - -inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) { - const int kk = length + k; // 10^(kk-1) <= v < 10^kk - - if (0 <= k && kk <= 21) { - // 1234e7 -> 12340000000 - for (int i = length; i < kk; i++) - buffer[i] = '0'; - buffer[kk] = '.'; - buffer[kk + 1] = '0'; - return &buffer[kk + 2]; - } - else if (0 < kk && kk <= 21) { - // 1234e-2 -> 12.34 - std::memmove(&buffer[kk + 1], &buffer[kk], static_cast(length - kk)); - buffer[kk] = '.'; - if (0 > k + maxDecimalPlaces) { - // When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1 - // Remove extra trailing zeros (at least one) after truncation. - for (int i = kk + maxDecimalPlaces; i > kk + 1; i--) - if (buffer[i] != '0') - return &buffer[i + 1]; - return &buffer[kk + 2]; // Reserve one zero - } - else - return &buffer[length + 1]; - } - else if (-6 < kk && kk <= 0) { - // 1234e-6 -> 0.001234 - const int offset = 2 - kk; - std::memmove(&buffer[offset], &buffer[0], static_cast(length)); - buffer[0] = '0'; - buffer[1] = '.'; - for (int i = 2; i < offset; i++) - buffer[i] = '0'; - if (length - kk > maxDecimalPlaces) { - // When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1 - // Remove extra trailing zeros (at least one) after truncation. - for (int i = maxDecimalPlaces + 1; i > 2; i--) - if (buffer[i] != '0') - return &buffer[i + 1]; - return &buffer[3]; // Reserve one zero - } - else - return &buffer[length + offset]; - } - else if (kk < -maxDecimalPlaces) { - // Truncate to zero - buffer[0] = '0'; - buffer[1] = '.'; - buffer[2] = '0'; - return &buffer[3]; - } - else if (length == 1) { - // 1e30 - buffer[1] = 'e'; - return WriteExponent(kk - 1, &buffer[2]); - } - else { - // 1234e30 -> 1.234e33 - std::memmove(&buffer[2], &buffer[1], static_cast(length - 1)); - buffer[1] = '.'; - buffer[length + 1] = 'e'; - return WriteExponent(kk - 1, &buffer[0 + length + 2]); - } -} - -inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324) { - RAPIDJSON_ASSERT(maxDecimalPlaces >= 1); - Double d(value); - if (d.IsZero()) { - if (d.Sign()) - *buffer++ = '-'; // -0.0, Issue #289 - buffer[0] = '0'; - buffer[1] = '.'; - buffer[2] = '0'; - return &buffer[3]; - } - else { - if (value < 0) { - *buffer++ = '-'; - value = -value; - } - int length, K; - Grisu2(value, buffer, &length, &K); - return Prettify(buffer, length, K, maxDecimalPlaces); - } -} - -#ifdef __GNUC__ -RAPIDJSON_DIAG_POP -#endif - -} // namespace internal -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_DTOA_ diff --git a/external/rapidjson/internal/ieee754.h b/external/rapidjson/internal/ieee754.h deleted file mode 100755 index 68c9e96..0000000 --- a/external/rapidjson/internal/ieee754.h +++ /dev/null @@ -1,78 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_IEEE754_ -#define RAPIDJSON_IEEE754_ - -#include "../rapidjson.h" - -RAPIDJSON_NAMESPACE_BEGIN -namespace internal { - -class Double { -public: - Double() {} - Double(double d) : d_(d) {} - Double(uint64_t u) : u_(u) {} - - double Value() const { return d_; } - uint64_t Uint64Value() const { return u_; } - - double NextPositiveDouble() const { - RAPIDJSON_ASSERT(!Sign()); - return Double(u_ + 1).Value(); - } - - bool Sign() const { return (u_ & kSignMask) != 0; } - uint64_t Significand() const { return u_ & kSignificandMask; } - int Exponent() const { return static_cast(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); } - - bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; } - bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; } - bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; } - bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; } - bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; } - - uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); } - int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; } - uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; } - - static int EffectiveSignificandSize(int order) { - if (order >= -1021) - return 53; - else if (order <= -1074) - return 0; - else - return order + 1074; - } - -private: - static const int kSignificandSize = 52; - static const int kExponentBias = 0x3FF; - static const int kDenormalExponent = 1 - kExponentBias; - static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000); - static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); - static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); - static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); - - union { - double d_; - uint64_t u_; - }; -}; - -} // namespace internal -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_IEEE754_ diff --git a/external/rapidjson/internal/itoa.h b/external/rapidjson/internal/itoa.h deleted file mode 100755 index 9fe8c93..0000000 --- a/external/rapidjson/internal/itoa.h +++ /dev/null @@ -1,308 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_ITOA_ -#define RAPIDJSON_ITOA_ - -#include "../rapidjson.h" - -RAPIDJSON_NAMESPACE_BEGIN -namespace internal { - -inline const char* GetDigitsLut() { - static const char cDigitsLut[200] = { - '0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9', - '1','0','1','1','1','2','1','3','1','4','1','5','1','6','1','7','1','8','1','9', - '2','0','2','1','2','2','2','3','2','4','2','5','2','6','2','7','2','8','2','9', - '3','0','3','1','3','2','3','3','3','4','3','5','3','6','3','7','3','8','3','9', - '4','0','4','1','4','2','4','3','4','4','4','5','4','6','4','7','4','8','4','9', - '5','0','5','1','5','2','5','3','5','4','5','5','5','6','5','7','5','8','5','9', - '6','0','6','1','6','2','6','3','6','4','6','5','6','6','6','7','6','8','6','9', - '7','0','7','1','7','2','7','3','7','4','7','5','7','6','7','7','7','8','7','9', - '8','0','8','1','8','2','8','3','8','4','8','5','8','6','8','7','8','8','8','9', - '9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9' - }; - return cDigitsLut; -} - -inline char* u32toa(uint32_t value, char* buffer) { - RAPIDJSON_ASSERT(buffer != 0); - - const char* cDigitsLut = GetDigitsLut(); - - if (value < 10000) { - const uint32_t d1 = (value / 100) << 1; - const uint32_t d2 = (value % 100) << 1; - - if (value >= 1000) - *buffer++ = cDigitsLut[d1]; - if (value >= 100) - *buffer++ = cDigitsLut[d1 + 1]; - if (value >= 10) - *buffer++ = cDigitsLut[d2]; - *buffer++ = cDigitsLut[d2 + 1]; - } - else if (value < 100000000) { - // value = bbbbcccc - const uint32_t b = value / 10000; - const uint32_t c = value % 10000; - - const uint32_t d1 = (b / 100) << 1; - const uint32_t d2 = (b % 100) << 1; - - const uint32_t d3 = (c / 100) << 1; - const uint32_t d4 = (c % 100) << 1; - - if (value >= 10000000) - *buffer++ = cDigitsLut[d1]; - if (value >= 1000000) - *buffer++ = cDigitsLut[d1 + 1]; - if (value >= 100000) - *buffer++ = cDigitsLut[d2]; - *buffer++ = cDigitsLut[d2 + 1]; - - *buffer++ = cDigitsLut[d3]; - *buffer++ = cDigitsLut[d3 + 1]; - *buffer++ = cDigitsLut[d4]; - *buffer++ = cDigitsLut[d4 + 1]; - } - else { - // value = aabbbbcccc in decimal - - const uint32_t a = value / 100000000; // 1 to 42 - value %= 100000000; - - if (a >= 10) { - const unsigned i = a << 1; - *buffer++ = cDigitsLut[i]; - *buffer++ = cDigitsLut[i + 1]; - } - else - *buffer++ = static_cast('0' + static_cast(a)); - - const uint32_t b = value / 10000; // 0 to 9999 - const uint32_t c = value % 10000; // 0 to 9999 - - const uint32_t d1 = (b / 100) << 1; - const uint32_t d2 = (b % 100) << 1; - - const uint32_t d3 = (c / 100) << 1; - const uint32_t d4 = (c % 100) << 1; - - *buffer++ = cDigitsLut[d1]; - *buffer++ = cDigitsLut[d1 + 1]; - *buffer++ = cDigitsLut[d2]; - *buffer++ = cDigitsLut[d2 + 1]; - *buffer++ = cDigitsLut[d3]; - *buffer++ = cDigitsLut[d3 + 1]; - *buffer++ = cDigitsLut[d4]; - *buffer++ = cDigitsLut[d4 + 1]; - } - return buffer; -} - -inline char* i32toa(int32_t value, char* buffer) { - RAPIDJSON_ASSERT(buffer != 0); - uint32_t u = static_cast(value); - if (value < 0) { - *buffer++ = '-'; - u = ~u + 1; - } - - return u32toa(u, buffer); -} - -inline char* u64toa(uint64_t value, char* buffer) { - RAPIDJSON_ASSERT(buffer != 0); - const char* cDigitsLut = GetDigitsLut(); - const uint64_t kTen8 = 100000000; - const uint64_t kTen9 = kTen8 * 10; - const uint64_t kTen10 = kTen8 * 100; - const uint64_t kTen11 = kTen8 * 1000; - const uint64_t kTen12 = kTen8 * 10000; - const uint64_t kTen13 = kTen8 * 100000; - const uint64_t kTen14 = kTen8 * 1000000; - const uint64_t kTen15 = kTen8 * 10000000; - const uint64_t kTen16 = kTen8 * kTen8; - - if (value < kTen8) { - uint32_t v = static_cast(value); - if (v < 10000) { - const uint32_t d1 = (v / 100) << 1; - const uint32_t d2 = (v % 100) << 1; - - if (v >= 1000) - *buffer++ = cDigitsLut[d1]; - if (v >= 100) - *buffer++ = cDigitsLut[d1 + 1]; - if (v >= 10) - *buffer++ = cDigitsLut[d2]; - *buffer++ = cDigitsLut[d2 + 1]; - } - else { - // value = bbbbcccc - const uint32_t b = v / 10000; - const uint32_t c = v % 10000; - - const uint32_t d1 = (b / 100) << 1; - const uint32_t d2 = (b % 100) << 1; - - const uint32_t d3 = (c / 100) << 1; - const uint32_t d4 = (c % 100) << 1; - - if (value >= 10000000) - *buffer++ = cDigitsLut[d1]; - if (value >= 1000000) - *buffer++ = cDigitsLut[d1 + 1]; - if (value >= 100000) - *buffer++ = cDigitsLut[d2]; - *buffer++ = cDigitsLut[d2 + 1]; - - *buffer++ = cDigitsLut[d3]; - *buffer++ = cDigitsLut[d3 + 1]; - *buffer++ = cDigitsLut[d4]; - *buffer++ = cDigitsLut[d4 + 1]; - } - } - else if (value < kTen16) { - const uint32_t v0 = static_cast(value / kTen8); - const uint32_t v1 = static_cast(value % kTen8); - - const uint32_t b0 = v0 / 10000; - const uint32_t c0 = v0 % 10000; - - const uint32_t d1 = (b0 / 100) << 1; - const uint32_t d2 = (b0 % 100) << 1; - - const uint32_t d3 = (c0 / 100) << 1; - const uint32_t d4 = (c0 % 100) << 1; - - const uint32_t b1 = v1 / 10000; - const uint32_t c1 = v1 % 10000; - - const uint32_t d5 = (b1 / 100) << 1; - const uint32_t d6 = (b1 % 100) << 1; - - const uint32_t d7 = (c1 / 100) << 1; - const uint32_t d8 = (c1 % 100) << 1; - - if (value >= kTen15) - *buffer++ = cDigitsLut[d1]; - if (value >= kTen14) - *buffer++ = cDigitsLut[d1 + 1]; - if (value >= kTen13) - *buffer++ = cDigitsLut[d2]; - if (value >= kTen12) - *buffer++ = cDigitsLut[d2 + 1]; - if (value >= kTen11) - *buffer++ = cDigitsLut[d3]; - if (value >= kTen10) - *buffer++ = cDigitsLut[d3 + 1]; - if (value >= kTen9) - *buffer++ = cDigitsLut[d4]; - - *buffer++ = cDigitsLut[d4 + 1]; - *buffer++ = cDigitsLut[d5]; - *buffer++ = cDigitsLut[d5 + 1]; - *buffer++ = cDigitsLut[d6]; - *buffer++ = cDigitsLut[d6 + 1]; - *buffer++ = cDigitsLut[d7]; - *buffer++ = cDigitsLut[d7 + 1]; - *buffer++ = cDigitsLut[d8]; - *buffer++ = cDigitsLut[d8 + 1]; - } - else { - const uint32_t a = static_cast(value / kTen16); // 1 to 1844 - value %= kTen16; - - if (a < 10) - *buffer++ = static_cast('0' + static_cast(a)); - else if (a < 100) { - const uint32_t i = a << 1; - *buffer++ = cDigitsLut[i]; - *buffer++ = cDigitsLut[i + 1]; - } - else if (a < 1000) { - *buffer++ = static_cast('0' + static_cast(a / 100)); - - const uint32_t i = (a % 100) << 1; - *buffer++ = cDigitsLut[i]; - *buffer++ = cDigitsLut[i + 1]; - } - else { - const uint32_t i = (a / 100) << 1; - const uint32_t j = (a % 100) << 1; - *buffer++ = cDigitsLut[i]; - *buffer++ = cDigitsLut[i + 1]; - *buffer++ = cDigitsLut[j]; - *buffer++ = cDigitsLut[j + 1]; - } - - const uint32_t v0 = static_cast(value / kTen8); - const uint32_t v1 = static_cast(value % kTen8); - - const uint32_t b0 = v0 / 10000; - const uint32_t c0 = v0 % 10000; - - const uint32_t d1 = (b0 / 100) << 1; - const uint32_t d2 = (b0 % 100) << 1; - - const uint32_t d3 = (c0 / 100) << 1; - const uint32_t d4 = (c0 % 100) << 1; - - const uint32_t b1 = v1 / 10000; - const uint32_t c1 = v1 % 10000; - - const uint32_t d5 = (b1 / 100) << 1; - const uint32_t d6 = (b1 % 100) << 1; - - const uint32_t d7 = (c1 / 100) << 1; - const uint32_t d8 = (c1 % 100) << 1; - - *buffer++ = cDigitsLut[d1]; - *buffer++ = cDigitsLut[d1 + 1]; - *buffer++ = cDigitsLut[d2]; - *buffer++ = cDigitsLut[d2 + 1]; - *buffer++ = cDigitsLut[d3]; - *buffer++ = cDigitsLut[d3 + 1]; - *buffer++ = cDigitsLut[d4]; - *buffer++ = cDigitsLut[d4 + 1]; - *buffer++ = cDigitsLut[d5]; - *buffer++ = cDigitsLut[d5 + 1]; - *buffer++ = cDigitsLut[d6]; - *buffer++ = cDigitsLut[d6 + 1]; - *buffer++ = cDigitsLut[d7]; - *buffer++ = cDigitsLut[d7 + 1]; - *buffer++ = cDigitsLut[d8]; - *buffer++ = cDigitsLut[d8 + 1]; - } - - return buffer; -} - -inline char* i64toa(int64_t value, char* buffer) { - RAPIDJSON_ASSERT(buffer != 0); - uint64_t u = static_cast(value); - if (value < 0) { - *buffer++ = '-'; - u = ~u + 1; - } - - return u64toa(u, buffer); -} - -} // namespace internal -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_ITOA_ diff --git a/external/rapidjson/internal/meta.h b/external/rapidjson/internal/meta.h deleted file mode 100755 index 27092dc..0000000 --- a/external/rapidjson/internal/meta.h +++ /dev/null @@ -1,186 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_INTERNAL_META_H_ -#define RAPIDJSON_INTERNAL_META_H_ - -#include "../rapidjson.h" - -#ifdef __GNUC__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(effc++) -#endif - -#if defined(_MSC_VER) && !defined(__clang__) -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(6334) -#endif - -#if RAPIDJSON_HAS_CXX11_TYPETRAITS -#include -#endif - -//@cond RAPIDJSON_INTERNAL -RAPIDJSON_NAMESPACE_BEGIN -namespace internal { - -// Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching -template struct Void { typedef void Type; }; - -/////////////////////////////////////////////////////////////////////////////// -// BoolType, TrueType, FalseType -// -template struct BoolType { - static const bool Value = Cond; - typedef BoolType Type; -}; -typedef BoolType TrueType; -typedef BoolType FalseType; - - -/////////////////////////////////////////////////////////////////////////////// -// SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr -// - -template struct SelectIfImpl { template struct Apply { typedef T1 Type; }; }; -template <> struct SelectIfImpl { template struct Apply { typedef T2 Type; }; }; -template struct SelectIfCond : SelectIfImpl::template Apply {}; -template struct SelectIf : SelectIfCond {}; - -template struct AndExprCond : FalseType {}; -template <> struct AndExprCond : TrueType {}; -template struct OrExprCond : TrueType {}; -template <> struct OrExprCond : FalseType {}; - -template struct BoolExpr : SelectIf::Type {}; -template struct NotExpr : SelectIf::Type {}; -template struct AndExpr : AndExprCond::Type {}; -template struct OrExpr : OrExprCond::Type {}; - - -/////////////////////////////////////////////////////////////////////////////// -// AddConst, MaybeAddConst, RemoveConst -template struct AddConst { typedef const T Type; }; -template struct MaybeAddConst : SelectIfCond {}; -template struct RemoveConst { typedef T Type; }; -template struct RemoveConst { typedef T Type; }; - - -/////////////////////////////////////////////////////////////////////////////// -// IsSame, IsConst, IsMoreConst, IsPointer -// -template struct IsSame : FalseType {}; -template struct IsSame : TrueType {}; - -template struct IsConst : FalseType {}; -template struct IsConst : TrueType {}; - -template -struct IsMoreConst - : AndExpr::Type, typename RemoveConst::Type>, - BoolType::Value >= IsConst::Value> >::Type {}; - -template struct IsPointer : FalseType {}; -template struct IsPointer : TrueType {}; - -/////////////////////////////////////////////////////////////////////////////// -// IsBaseOf -// -#if RAPIDJSON_HAS_CXX11_TYPETRAITS - -template struct IsBaseOf - : BoolType< ::std::is_base_of::value> {}; - -#else // simplified version adopted from Boost - -template struct IsBaseOfImpl { - RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0); - RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0); - - typedef char (&Yes)[1]; - typedef char (&No) [2]; - - template - static Yes Check(const D*, T); - static No Check(const B*, int); - - struct Host { - operator const B*() const; - operator const D*(); - }; - - enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) }; -}; - -template struct IsBaseOf - : OrExpr, BoolExpr > >::Type {}; - -#endif // RAPIDJSON_HAS_CXX11_TYPETRAITS - - -////////////////////////////////////////////////////////////////////////// -// EnableIf / DisableIf -// -template struct EnableIfCond { typedef T Type; }; -template struct EnableIfCond { /* empty */ }; - -template struct DisableIfCond { typedef T Type; }; -template struct DisableIfCond { /* empty */ }; - -template -struct EnableIf : EnableIfCond {}; - -template -struct DisableIf : DisableIfCond {}; - -// SFINAE helpers -struct SfinaeTag {}; -template struct RemoveSfinaeTag; -template struct RemoveSfinaeTag { typedef T Type; }; - -#define RAPIDJSON_REMOVEFPTR_(type) \ - typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \ - < ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type - -#define RAPIDJSON_ENABLEIF(cond) \ - typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ - ::Type * = NULL - -#define RAPIDJSON_DISABLEIF(cond) \ - typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ - ::Type * = NULL - -#define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \ - typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ - ::Type - -#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \ - typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ - ::Type - -} // namespace internal -RAPIDJSON_NAMESPACE_END -//@endcond - -#if defined(_MSC_VER) && !defined(__clang__) -RAPIDJSON_DIAG_POP -#endif - -#ifdef __GNUC__ -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_INTERNAL_META_H_ diff --git a/external/rapidjson/internal/pow10.h b/external/rapidjson/internal/pow10.h deleted file mode 100755 index eae1a43..0000000 --- a/external/rapidjson/internal/pow10.h +++ /dev/null @@ -1,55 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_POW10_ -#define RAPIDJSON_POW10_ - -#include "../rapidjson.h" - -RAPIDJSON_NAMESPACE_BEGIN -namespace internal { - -//! Computes integer powers of 10 in double (10.0^n). -/*! This function uses lookup table for fast and accurate results. - \param n non-negative exponent. Must <= 308. - \return 10.0^n -*/ -inline double Pow10(int n) { - static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes - 1e+0, - 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20, - 1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40, - 1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60, - 1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80, - 1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100, - 1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120, - 1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140, - 1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160, - 1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180, - 1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200, - 1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220, - 1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240, - 1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260, - 1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280, - 1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300, - 1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308 - }; - RAPIDJSON_ASSERT(n >= 0 && n <= 308); - return e[n]; -} - -} // namespace internal -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_POW10_ diff --git a/external/rapidjson/internal/regex.h b/external/rapidjson/internal/regex.h deleted file mode 100755 index 6446c40..0000000 --- a/external/rapidjson/internal/regex.h +++ /dev/null @@ -1,739 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_INTERNAL_REGEX_H_ -#define RAPIDJSON_INTERNAL_REGEX_H_ - -#include "../allocators.h" -#include "../stream.h" -#include "stack.h" - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(padded) -RAPIDJSON_DIAG_OFF(switch-enum) -#elif defined(_MSC_VER) -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated -#endif - -#ifdef __GNUC__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(effc++) -#endif - -#ifndef RAPIDJSON_REGEX_VERBOSE -#define RAPIDJSON_REGEX_VERBOSE 0 -#endif - -RAPIDJSON_NAMESPACE_BEGIN -namespace internal { - -/////////////////////////////////////////////////////////////////////////////// -// DecodedStream - -template -class DecodedStream { -public: - DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); } - unsigned Peek() { return codepoint_; } - unsigned Take() { - unsigned c = codepoint_; - if (c) // No further decoding when '\0' - Decode(); - return c; - } - -private: - void Decode() { - if (!Encoding::Decode(ss_, &codepoint_)) - codepoint_ = 0; - } - - SourceStream& ss_; - unsigned codepoint_; -}; - -/////////////////////////////////////////////////////////////////////////////// -// GenericRegex - -static const SizeType kRegexInvalidState = ~SizeType(0); //!< Represents an invalid index in GenericRegex::State::out, out1 -static const SizeType kRegexInvalidRange = ~SizeType(0); - -template -class GenericRegexSearch; - -//! Regular expression engine with subset of ECMAscript grammar. -/*! - Supported regular expression syntax: - - \c ab Concatenation - - \c a|b Alternation - - \c a? Zero or one - - \c a* Zero or more - - \c a+ One or more - - \c a{3} Exactly 3 times - - \c a{3,} At least 3 times - - \c a{3,5} 3 to 5 times - - \c (ab) Grouping - - \c ^a At the beginning - - \c a$ At the end - - \c . Any character - - \c [abc] Character classes - - \c [a-c] Character class range - - \c [a-z0-9_] Character class combination - - \c [^abc] Negated character classes - - \c [^a-c] Negated character class range - - \c [\b] Backspace (U+0008) - - \c \\| \\\\ ... Escape characters - - \c \\f Form feed (U+000C) - - \c \\n Line feed (U+000A) - - \c \\r Carriage return (U+000D) - - \c \\t Tab (U+0009) - - \c \\v Vertical tab (U+000B) - - \note This is a Thompson NFA engine, implemented with reference to - Cox, Russ. "Regular Expression Matching Can Be Simple And Fast (but is slow in Java, Perl, PHP, Python, Ruby,...).", - https://swtch.com/~rsc/regexp/regexp1.html -*/ -template -class GenericRegex { -public: - typedef Encoding EncodingType; - typedef typename Encoding::Ch Ch; - template friend class GenericRegexSearch; - - GenericRegex(const Ch* source, Allocator* allocator = 0) : - ownAllocator_(allocator ? 0 : RAPIDJSON_NEW(Allocator)()), allocator_(allocator ? allocator : ownAllocator_), - states_(allocator_, 256), ranges_(allocator_, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(), - anchorBegin_(), anchorEnd_() - { - GenericStringStream ss(source); - DecodedStream, Encoding> ds(ss); - Parse(ds); - } - - ~GenericRegex() - { - RAPIDJSON_DELETE(ownAllocator_); - } - - bool IsValid() const { - return root_ != kRegexInvalidState; - } - -private: - enum Operator { - kZeroOrOne, - kZeroOrMore, - kOneOrMore, - kConcatenation, - kAlternation, - kLeftParenthesis - }; - - static const unsigned kAnyCharacterClass = 0xFFFFFFFF; //!< For '.' - static const unsigned kRangeCharacterClass = 0xFFFFFFFE; - static const unsigned kRangeNegationFlag = 0x80000000; - - struct Range { - unsigned start; // - unsigned end; - SizeType next; - }; - - struct State { - SizeType out; //!< Equals to kInvalid for matching state - SizeType out1; //!< Equals to non-kInvalid for split - SizeType rangeStart; - unsigned codepoint; - }; - - struct Frag { - Frag(SizeType s, SizeType o, SizeType m) : start(s), out(o), minIndex(m) {} - SizeType start; - SizeType out; //!< link-list of all output states - SizeType minIndex; - }; - - State& GetState(SizeType index) { - RAPIDJSON_ASSERT(index < stateCount_); - return states_.template Bottom()[index]; - } - - const State& GetState(SizeType index) const { - RAPIDJSON_ASSERT(index < stateCount_); - return states_.template Bottom()[index]; - } - - Range& GetRange(SizeType index) { - RAPIDJSON_ASSERT(index < rangeCount_); - return ranges_.template Bottom()[index]; - } - - const Range& GetRange(SizeType index) const { - RAPIDJSON_ASSERT(index < rangeCount_); - return ranges_.template Bottom()[index]; - } - - template - void Parse(DecodedStream& ds) { - Stack operandStack(allocator_, 256); // Frag - Stack operatorStack(allocator_, 256); // Operator - Stack atomCountStack(allocator_, 256); // unsigned (Atom per parenthesis) - - *atomCountStack.template Push() = 0; - - unsigned codepoint; - while (ds.Peek() != 0) { - switch (codepoint = ds.Take()) { - case '^': - anchorBegin_ = true; - break; - - case '$': - anchorEnd_ = true; - break; - - case '|': - while (!operatorStack.Empty() && *operatorStack.template Top() < kAlternation) - if (!Eval(operandStack, *operatorStack.template Pop(1))) - return; - *operatorStack.template Push() = kAlternation; - *atomCountStack.template Top() = 0; - break; - - case '(': - *operatorStack.template Push() = kLeftParenthesis; - *atomCountStack.template Push() = 0; - break; - - case ')': - while (!operatorStack.Empty() && *operatorStack.template Top() != kLeftParenthesis) - if (!Eval(operandStack, *operatorStack.template Pop(1))) - return; - if (operatorStack.Empty()) - return; - operatorStack.template Pop(1); - atomCountStack.template Pop(1); - ImplicitConcatenation(atomCountStack, operatorStack); - break; - - case '?': - if (!Eval(operandStack, kZeroOrOne)) - return; - break; - - case '*': - if (!Eval(operandStack, kZeroOrMore)) - return; - break; - - case '+': - if (!Eval(operandStack, kOneOrMore)) - return; - break; - - case '{': - { - unsigned n, m; - if (!ParseUnsigned(ds, &n)) - return; - - if (ds.Peek() == ',') { - ds.Take(); - if (ds.Peek() == '}') - m = kInfinityQuantifier; - else if (!ParseUnsigned(ds, &m) || m < n) - return; - } - else - m = n; - - if (!EvalQuantifier(operandStack, n, m) || ds.Peek() != '}') - return; - ds.Take(); - } - break; - - case '.': - PushOperand(operandStack, kAnyCharacterClass); - ImplicitConcatenation(atomCountStack, operatorStack); - break; - - case '[': - { - SizeType range; - if (!ParseRange(ds, &range)) - return; - SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, kRangeCharacterClass); - GetState(s).rangeStart = range; - *operandStack.template Push() = Frag(s, s, s); - } - ImplicitConcatenation(atomCountStack, operatorStack); - break; - - case '\\': // Escape character - if (!CharacterEscape(ds, &codepoint)) - return; // Unsupported escape character - // fall through to default - RAPIDJSON_DELIBERATE_FALLTHROUGH; - - default: // Pattern character - PushOperand(operandStack, codepoint); - ImplicitConcatenation(atomCountStack, operatorStack); - } - } - - while (!operatorStack.Empty()) - if (!Eval(operandStack, *operatorStack.template Pop(1))) - return; - - // Link the operand to matching state. - if (operandStack.GetSize() == sizeof(Frag)) { - Frag* e = operandStack.template Pop(1); - Patch(e->out, NewState(kRegexInvalidState, kRegexInvalidState, 0)); - root_ = e->start; - -#if RAPIDJSON_REGEX_VERBOSE - printf("root: %d\n", root_); - for (SizeType i = 0; i < stateCount_ ; i++) { - State& s = GetState(i); - printf("[%2d] out: %2d out1: %2d c: '%c'\n", i, s.out, s.out1, (char)s.codepoint); - } - printf("\n"); -#endif - } - } - - SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) { - State* s = states_.template Push(); - s->out = out; - s->out1 = out1; - s->codepoint = codepoint; - s->rangeStart = kRegexInvalidRange; - return stateCount_++; - } - - void PushOperand(Stack& operandStack, unsigned codepoint) { - SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, codepoint); - *operandStack.template Push() = Frag(s, s, s); - } - - void ImplicitConcatenation(Stack& atomCountStack, Stack& operatorStack) { - if (*atomCountStack.template Top()) - *operatorStack.template Push() = kConcatenation; - (*atomCountStack.template Top())++; - } - - SizeType Append(SizeType l1, SizeType l2) { - SizeType old = l1; - while (GetState(l1).out != kRegexInvalidState) - l1 = GetState(l1).out; - GetState(l1).out = l2; - return old; - } - - void Patch(SizeType l, SizeType s) { - for (SizeType next; l != kRegexInvalidState; l = next) { - next = GetState(l).out; - GetState(l).out = s; - } - } - - bool Eval(Stack& operandStack, Operator op) { - switch (op) { - case kConcatenation: - RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag) * 2); - { - Frag e2 = *operandStack.template Pop(1); - Frag e1 = *operandStack.template Pop(1); - Patch(e1.out, e2.start); - *operandStack.template Push() = Frag(e1.start, e2.out, Min(e1.minIndex, e2.minIndex)); - } - return true; - - case kAlternation: - if (operandStack.GetSize() >= sizeof(Frag) * 2) { - Frag e2 = *operandStack.template Pop(1); - Frag e1 = *operandStack.template Pop(1); - SizeType s = NewState(e1.start, e2.start, 0); - *operandStack.template Push() = Frag(s, Append(e1.out, e2.out), Min(e1.minIndex, e2.minIndex)); - return true; - } - return false; - - case kZeroOrOne: - if (operandStack.GetSize() >= sizeof(Frag)) { - Frag e = *operandStack.template Pop(1); - SizeType s = NewState(kRegexInvalidState, e.start, 0); - *operandStack.template Push() = Frag(s, Append(e.out, s), e.minIndex); - return true; - } - return false; - - case kZeroOrMore: - if (operandStack.GetSize() >= sizeof(Frag)) { - Frag e = *operandStack.template Pop(1); - SizeType s = NewState(kRegexInvalidState, e.start, 0); - Patch(e.out, s); - *operandStack.template Push() = Frag(s, s, e.minIndex); - return true; - } - return false; - - case kOneOrMore: - if (operandStack.GetSize() >= sizeof(Frag)) { - Frag e = *operandStack.template Pop(1); - SizeType s = NewState(kRegexInvalidState, e.start, 0); - Patch(e.out, s); - *operandStack.template Push() = Frag(e.start, s, e.minIndex); - return true; - } - return false; - - default: - // syntax error (e.g. unclosed kLeftParenthesis) - return false; - } - } - - bool EvalQuantifier(Stack& operandStack, unsigned n, unsigned m) { - RAPIDJSON_ASSERT(n <= m); - RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag)); - - if (n == 0) { - if (m == 0) // a{0} not support - return false; - else if (m == kInfinityQuantifier) - Eval(operandStack, kZeroOrMore); // a{0,} -> a* - else { - Eval(operandStack, kZeroOrOne); // a{0,5} -> a? - for (unsigned i = 0; i < m - 1; i++) - CloneTopOperand(operandStack); // a{0,5} -> a? a? a? a? a? - for (unsigned i = 0; i < m - 1; i++) - Eval(operandStack, kConcatenation); // a{0,5} -> a?a?a?a?a? - } - return true; - } - - for (unsigned i = 0; i < n - 1; i++) // a{3} -> a a a - CloneTopOperand(operandStack); - - if (m == kInfinityQuantifier) - Eval(operandStack, kOneOrMore); // a{3,} -> a a a+ - else if (m > n) { - CloneTopOperand(operandStack); // a{3,5} -> a a a a - Eval(operandStack, kZeroOrOne); // a{3,5} -> a a a a? - for (unsigned i = n; i < m - 1; i++) - CloneTopOperand(operandStack); // a{3,5} -> a a a a? a? - for (unsigned i = n; i < m; i++) - Eval(operandStack, kConcatenation); // a{3,5} -> a a aa?a? - } - - for (unsigned i = 0; i < n - 1; i++) - Eval(operandStack, kConcatenation); // a{3} -> aaa, a{3,} -> aaa+, a{3.5} -> aaaa?a? - - return true; - } - - static SizeType Min(SizeType a, SizeType b) { return a < b ? a : b; } - - void CloneTopOperand(Stack& operandStack) { - const Frag src = *operandStack.template Top(); // Copy constructor to prevent invalidation - SizeType count = stateCount_ - src.minIndex; // Assumes top operand contains states in [src->minIndex, stateCount_) - State* s = states_.template Push(count); - memcpy(s, &GetState(src.minIndex), count * sizeof(State)); - for (SizeType j = 0; j < count; j++) { - if (s[j].out != kRegexInvalidState) - s[j].out += count; - if (s[j].out1 != kRegexInvalidState) - s[j].out1 += count; - } - *operandStack.template Push() = Frag(src.start + count, src.out + count, src.minIndex + count); - stateCount_ += count; - } - - template - bool ParseUnsigned(DecodedStream& ds, unsigned* u) { - unsigned r = 0; - if (ds.Peek() < '0' || ds.Peek() > '9') - return false; - while (ds.Peek() >= '0' && ds.Peek() <= '9') { - if (r >= 429496729 && ds.Peek() > '5') // 2^32 - 1 = 4294967295 - return false; // overflow - r = r * 10 + (ds.Take() - '0'); - } - *u = r; - return true; - } - - template - bool ParseRange(DecodedStream& ds, SizeType* range) { - bool isBegin = true; - bool negate = false; - int step = 0; - SizeType start = kRegexInvalidRange; - SizeType current = kRegexInvalidRange; - unsigned codepoint; - while ((codepoint = ds.Take()) != 0) { - if (isBegin) { - isBegin = false; - if (codepoint == '^') { - negate = true; - continue; - } - } - - switch (codepoint) { - case ']': - if (start == kRegexInvalidRange) - return false; // Error: nothing inside [] - if (step == 2) { // Add trailing '-' - SizeType r = NewRange('-'); - RAPIDJSON_ASSERT(current != kRegexInvalidRange); - GetRange(current).next = r; - } - if (negate) - GetRange(start).start |= kRangeNegationFlag; - *range = start; - return true; - - case '\\': - if (ds.Peek() == 'b') { - ds.Take(); - codepoint = 0x0008; // Escape backspace character - } - else if (!CharacterEscape(ds, &codepoint)) - return false; - // fall through to default - RAPIDJSON_DELIBERATE_FALLTHROUGH; - - default: - switch (step) { - case 1: - if (codepoint == '-') { - step++; - break; - } - // fall through to step 0 for other characters - RAPIDJSON_DELIBERATE_FALLTHROUGH; - - case 0: - { - SizeType r = NewRange(codepoint); - if (current != kRegexInvalidRange) - GetRange(current).next = r; - if (start == kRegexInvalidRange) - start = r; - current = r; - } - step = 1; - break; - - default: - RAPIDJSON_ASSERT(step == 2); - GetRange(current).end = codepoint; - step = 0; - } - } - } - return false; - } - - SizeType NewRange(unsigned codepoint) { - Range* r = ranges_.template Push(); - r->start = r->end = codepoint; - r->next = kRegexInvalidRange; - return rangeCount_++; - } - - template - bool CharacterEscape(DecodedStream& ds, unsigned* escapedCodepoint) { - unsigned codepoint; - switch (codepoint = ds.Take()) { - case '^': - case '$': - case '|': - case '(': - case ')': - case '?': - case '*': - case '+': - case '.': - case '[': - case ']': - case '{': - case '}': - case '\\': - *escapedCodepoint = codepoint; return true; - case 'f': *escapedCodepoint = 0x000C; return true; - case 'n': *escapedCodepoint = 0x000A; return true; - case 'r': *escapedCodepoint = 0x000D; return true; - case 't': *escapedCodepoint = 0x0009; return true; - case 'v': *escapedCodepoint = 0x000B; return true; - default: - return false; // Unsupported escape character - } - } - - Allocator* ownAllocator_; - Allocator* allocator_; - Stack states_; - Stack ranges_; - SizeType root_; - SizeType stateCount_; - SizeType rangeCount_; - - static const unsigned kInfinityQuantifier = ~0u; - - // For SearchWithAnchoring() - bool anchorBegin_; - bool anchorEnd_; -}; - -template -class GenericRegexSearch { -public: - typedef typename RegexType::EncodingType Encoding; - typedef typename Encoding::Ch Ch; - - GenericRegexSearch(const RegexType& regex, Allocator* allocator = 0) : - regex_(regex), allocator_(allocator), ownAllocator_(0), - state0_(allocator, 0), state1_(allocator, 0), stateSet_() - { - RAPIDJSON_ASSERT(regex_.IsValid()); - if (!allocator_) - ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); - stateSet_ = static_cast(allocator_->Malloc(GetStateSetSize())); - state0_.template Reserve(regex_.stateCount_); - state1_.template Reserve(regex_.stateCount_); - } - - ~GenericRegexSearch() { - Allocator::Free(stateSet_); - RAPIDJSON_DELETE(ownAllocator_); - } - - template - bool Match(InputStream& is) { - return SearchWithAnchoring(is, true, true); - } - - bool Match(const Ch* s) { - GenericStringStream is(s); - return Match(is); - } - - template - bool Search(InputStream& is) { - return SearchWithAnchoring(is, regex_.anchorBegin_, regex_.anchorEnd_); - } - - bool Search(const Ch* s) { - GenericStringStream is(s); - return Search(is); - } - -private: - typedef typename RegexType::State State; - typedef typename RegexType::Range Range; - - template - bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) { - DecodedStream ds(is); - - state0_.Clear(); - Stack *current = &state0_, *next = &state1_; - const size_t stateSetSize = GetStateSetSize(); - std::memset(stateSet_, 0, stateSetSize); - - bool matched = AddState(*current, regex_.root_); - unsigned codepoint; - while (!current->Empty() && (codepoint = ds.Take()) != 0) { - std::memset(stateSet_, 0, stateSetSize); - next->Clear(); - matched = false; - for (const SizeType* s = current->template Bottom(); s != current->template End(); ++s) { - const State& sr = regex_.GetState(*s); - if (sr.codepoint == codepoint || - sr.codepoint == RegexType::kAnyCharacterClass || - (sr.codepoint == RegexType::kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint))) - { - matched = AddState(*next, sr.out) || matched; - if (!anchorEnd && matched) - return true; - } - if (!anchorBegin) - AddState(*next, regex_.root_); - } - internal::Swap(current, next); - } - - return matched; - } - - size_t GetStateSetSize() const { - return (regex_.stateCount_ + 31) / 32 * 4; - } - - // Return whether the added states is a match state - bool AddState(Stack& l, SizeType index) { - RAPIDJSON_ASSERT(index != kRegexInvalidState); - - const State& s = regex_.GetState(index); - if (s.out1 != kRegexInvalidState) { // Split - bool matched = AddState(l, s.out); - return AddState(l, s.out1) || matched; - } - else if (!(stateSet_[index >> 5] & (1u << (index & 31)))) { - stateSet_[index >> 5] |= (1u << (index & 31)); - *l.template PushUnsafe() = index; - } - return s.out == kRegexInvalidState; // by using PushUnsafe() above, we can ensure s is not validated due to reallocation. - } - - bool MatchRange(SizeType rangeIndex, unsigned codepoint) const { - bool yes = (regex_.GetRange(rangeIndex).start & RegexType::kRangeNegationFlag) == 0; - while (rangeIndex != kRegexInvalidRange) { - const Range& r = regex_.GetRange(rangeIndex); - if (codepoint >= (r.start & ~RegexType::kRangeNegationFlag) && codepoint <= r.end) - return yes; - rangeIndex = r.next; - } - return !yes; - } - - const RegexType& regex_; - Allocator* allocator_; - Allocator* ownAllocator_; - Stack state0_; - Stack state1_; - uint32_t* stateSet_; -}; - -typedef GenericRegex > Regex; -typedef GenericRegexSearch RegexSearch; - -} // namespace internal -RAPIDJSON_NAMESPACE_END - -#ifdef __GNUC__ -RAPIDJSON_DIAG_POP -#endif - -#if defined(__clang__) || defined(_MSC_VER) -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_INTERNAL_REGEX_H_ diff --git a/external/rapidjson/internal/stack.h b/external/rapidjson/internal/stack.h deleted file mode 100755 index 73abd70..0000000 --- a/external/rapidjson/internal/stack.h +++ /dev/null @@ -1,232 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_INTERNAL_STACK_H_ -#define RAPIDJSON_INTERNAL_STACK_H_ - -#include "../allocators.h" -#include "swap.h" -#include - -#if defined(__clang__) -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(c++98-compat) -#endif - -RAPIDJSON_NAMESPACE_BEGIN -namespace internal { - -/////////////////////////////////////////////////////////////////////////////// -// Stack - -//! A type-unsafe stack for storing different types of data. -/*! \tparam Allocator Allocator for allocating stack memory. -*/ -template -class Stack { -public: - // Optimization note: Do not allocate memory for stack_ in constructor. - // Do it lazily when first Push() -> Expand() -> Resize(). - Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) { - } - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - Stack(Stack&& rhs) - : allocator_(rhs.allocator_), - ownAllocator_(rhs.ownAllocator_), - stack_(rhs.stack_), - stackTop_(rhs.stackTop_), - stackEnd_(rhs.stackEnd_), - initialCapacity_(rhs.initialCapacity_) - { - rhs.allocator_ = 0; - rhs.ownAllocator_ = 0; - rhs.stack_ = 0; - rhs.stackTop_ = 0; - rhs.stackEnd_ = 0; - rhs.initialCapacity_ = 0; - } -#endif - - ~Stack() { - Destroy(); - } - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - Stack& operator=(Stack&& rhs) { - if (&rhs != this) - { - Destroy(); - - allocator_ = rhs.allocator_; - ownAllocator_ = rhs.ownAllocator_; - stack_ = rhs.stack_; - stackTop_ = rhs.stackTop_; - stackEnd_ = rhs.stackEnd_; - initialCapacity_ = rhs.initialCapacity_; - - rhs.allocator_ = 0; - rhs.ownAllocator_ = 0; - rhs.stack_ = 0; - rhs.stackTop_ = 0; - rhs.stackEnd_ = 0; - rhs.initialCapacity_ = 0; - } - return *this; - } -#endif - - void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT { - internal::Swap(allocator_, rhs.allocator_); - internal::Swap(ownAllocator_, rhs.ownAllocator_); - internal::Swap(stack_, rhs.stack_); - internal::Swap(stackTop_, rhs.stackTop_); - internal::Swap(stackEnd_, rhs.stackEnd_); - internal::Swap(initialCapacity_, rhs.initialCapacity_); - } - - void Clear() { stackTop_ = stack_; } - - void ShrinkToFit() { - if (Empty()) { - // If the stack is empty, completely deallocate the memory. - Allocator::Free(stack_); // NOLINT (+clang-analyzer-unix.Malloc) - stack_ = 0; - stackTop_ = 0; - stackEnd_ = 0; - } - else - Resize(GetSize()); - } - - // Optimization note: try to minimize the size of this function for force inline. - // Expansion is run very infrequently, so it is moved to another (probably non-inline) function. - template - RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) { - // Expand the stack if needed - if (RAPIDJSON_UNLIKELY(static_cast(sizeof(T) * count) > (stackEnd_ - stackTop_))) - Expand(count); - } - - template - RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) { - Reserve(count); - return PushUnsafe(count); - } - - template - RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) { - RAPIDJSON_ASSERT(stackTop_); - RAPIDJSON_ASSERT(static_cast(sizeof(T) * count) <= (stackEnd_ - stackTop_)); - T* ret = reinterpret_cast(stackTop_); - stackTop_ += sizeof(T) * count; - return ret; - } - - template - T* Pop(size_t count) { - RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T)); - stackTop_ -= count * sizeof(T); - return reinterpret_cast(stackTop_); - } - - template - T* Top() { - RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); - return reinterpret_cast(stackTop_ - sizeof(T)); - } - - template - const T* Top() const { - RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); - return reinterpret_cast(stackTop_ - sizeof(T)); - } - - template - T* End() { return reinterpret_cast(stackTop_); } - - template - const T* End() const { return reinterpret_cast(stackTop_); } - - template - T* Bottom() { return reinterpret_cast(stack_); } - - template - const T* Bottom() const { return reinterpret_cast(stack_); } - - bool HasAllocator() const { - return allocator_ != 0; - } - - Allocator& GetAllocator() { - RAPIDJSON_ASSERT(allocator_); - return *allocator_; - } - - bool Empty() const { return stackTop_ == stack_; } - size_t GetSize() const { return static_cast(stackTop_ - stack_); } - size_t GetCapacity() const { return static_cast(stackEnd_ - stack_); } - -private: - template - void Expand(size_t count) { - // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity. - size_t newCapacity; - if (stack_ == 0) { - if (!allocator_) - ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); - newCapacity = initialCapacity_; - } else { - newCapacity = GetCapacity(); - newCapacity += (newCapacity + 1) / 2; - } - size_t newSize = GetSize() + sizeof(T) * count; - if (newCapacity < newSize) - newCapacity = newSize; - - Resize(newCapacity); - } - - void Resize(size_t newCapacity) { - const size_t size = GetSize(); // Backup the current size - stack_ = static_cast(allocator_->Realloc(stack_, GetCapacity(), newCapacity)); - stackTop_ = stack_ + size; - stackEnd_ = stack_ + newCapacity; - } - - void Destroy() { - Allocator::Free(stack_); - RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack - } - - // Prohibit copy constructor & assignment operator. - Stack(const Stack&); - Stack& operator=(const Stack&); - - Allocator* allocator_; - Allocator* ownAllocator_; - char *stack_; - char *stackTop_; - char *stackEnd_; - size_t initialCapacity_; -}; - -} // namespace internal -RAPIDJSON_NAMESPACE_END - -#if defined(__clang__) -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_STACK_H_ diff --git a/external/rapidjson/internal/strfunc.h b/external/rapidjson/internal/strfunc.h deleted file mode 100755 index b698a8f..0000000 --- a/external/rapidjson/internal/strfunc.h +++ /dev/null @@ -1,83 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_ -#define RAPIDJSON_INTERNAL_STRFUNC_H_ - -#include "../stream.h" -#include - -RAPIDJSON_NAMESPACE_BEGIN -namespace internal { - -//! Custom strlen() which works on different character types. -/*! \tparam Ch Character type (e.g. char, wchar_t, short) - \param s Null-terminated input string. - \return Number of characters in the string. - \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints. -*/ -template -inline SizeType StrLen(const Ch* s) { - RAPIDJSON_ASSERT(s != 0); - const Ch* p = s; - while (*p) ++p; - return SizeType(p - s); -} - -template <> -inline SizeType StrLen(const char* s) { - return SizeType(std::strlen(s)); -} - -template <> -inline SizeType StrLen(const wchar_t* s) { - return SizeType(std::wcslen(s)); -} - -//! Custom strcmpn() which works on different character types. -/*! \tparam Ch Character type (e.g. char, wchar_t, short) - \param s1 Null-terminated input string. - \param s2 Null-terminated input string. - \return 0 if equal -*/ -template -inline int StrCmp(const Ch* s1, const Ch* s2) { - RAPIDJSON_ASSERT(s1 != 0); - RAPIDJSON_ASSERT(s2 != 0); - while(*s1 && (*s1 == *s2)) { s1++; s2++; } - return static_cast(*s1) < static_cast(*s2) ? -1 : static_cast(*s1) > static_cast(*s2); -} - -//! Returns number of code points in a encoded string. -template -bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) { - RAPIDJSON_ASSERT(s != 0); - RAPIDJSON_ASSERT(outCount != 0); - GenericStringStream is(s); - const typename Encoding::Ch* end = s + length; - SizeType count = 0; - while (is.src_ < end) { - unsigned codepoint; - if (!Encoding::Decode(is, &codepoint)) - return false; - count++; - } - *outCount = count; - return true; -} - -} // namespace internal -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_INTERNAL_STRFUNC_H_ diff --git a/external/rapidjson/internal/strtod.h b/external/rapidjson/internal/strtod.h deleted file mode 100755 index d61a67a..0000000 --- a/external/rapidjson/internal/strtod.h +++ /dev/null @@ -1,290 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_STRTOD_ -#define RAPIDJSON_STRTOD_ - -#include "ieee754.h" -#include "biginteger.h" -#include "diyfp.h" -#include "pow10.h" -#include -#include - -RAPIDJSON_NAMESPACE_BEGIN -namespace internal { - -inline double FastPath(double significand, int exp) { - if (exp < -308) - return 0.0; - else if (exp >= 0) - return significand * internal::Pow10(exp); - else - return significand / internal::Pow10(-exp); -} - -inline double StrtodNormalPrecision(double d, int p) { - if (p < -308) { - // Prevent expSum < -308, making Pow10(p) = 0 - d = FastPath(d, -308); - d = FastPath(d, p + 308); - } - else - d = FastPath(d, p); - return d; -} - -template -inline T Min3(T a, T b, T c) { - T m = a; - if (m > b) m = b; - if (m > c) m = c; - return m; -} - -inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) { - const Double db(b); - const uint64_t bInt = db.IntegerSignificand(); - const int bExp = db.IntegerExponent(); - const int hExp = bExp - 1; - - int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0; - - // Adjust for decimal exponent - if (dExp >= 0) { - dS_Exp2 += dExp; - dS_Exp5 += dExp; - } - else { - bS_Exp2 -= dExp; - bS_Exp5 -= dExp; - hS_Exp2 -= dExp; - hS_Exp5 -= dExp; - } - - // Adjust for binary exponent - if (bExp >= 0) - bS_Exp2 += bExp; - else { - dS_Exp2 -= bExp; - hS_Exp2 -= bExp; - } - - // Adjust for half ulp exponent - if (hExp >= 0) - hS_Exp2 += hExp; - else { - dS_Exp2 -= hExp; - bS_Exp2 -= hExp; - } - - // Remove common power of two factor from all three scaled values - int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2); - dS_Exp2 -= common_Exp2; - bS_Exp2 -= common_Exp2; - hS_Exp2 -= common_Exp2; - - BigInteger dS = d; - dS.MultiplyPow5(static_cast(dS_Exp5)) <<= static_cast(dS_Exp2); - - BigInteger bS(bInt); - bS.MultiplyPow5(static_cast(bS_Exp5)) <<= static_cast(bS_Exp2); - - BigInteger hS(1); - hS.MultiplyPow5(static_cast(hS_Exp5)) <<= static_cast(hS_Exp2); - - BigInteger delta(0); - dS.Difference(bS, &delta); - - return delta.Compare(hS); -} - -inline bool StrtodFast(double d, int p, double* result) { - // Use fast path for string-to-double conversion if possible - // see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/ - if (p > 22 && p < 22 + 16) { - // Fast Path Cases In Disguise - d *= internal::Pow10(p - 22); - p = 22; - } - - if (p >= -22 && p <= 22 && d <= 9007199254740991.0) { // 2^53 - 1 - *result = FastPath(d, p); - return true; - } - else - return false; -} - -// Compute an approximation and see if it is within 1/2 ULP -inline bool StrtodDiyFp(const char* decimals, int dLen, int dExp, double* result) { - uint64_t significand = 0; - int i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999 - for (; i < dLen; i++) { - if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || - (significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5')) - break; - significand = significand * 10u + static_cast(decimals[i] - '0'); - } - - if (i < dLen && decimals[i] >= '5') // Rounding - significand++; - - int remaining = dLen - i; - const int kUlpShift = 3; - const int kUlp = 1 << kUlpShift; - int64_t error = (remaining == 0) ? 0 : kUlp / 2; - - DiyFp v(significand, 0); - v = v.Normalize(); - error <<= -v.e; - - dExp += remaining; - - int actualExp; - DiyFp cachedPower = GetCachedPower10(dExp, &actualExp); - if (actualExp != dExp) { - static const DiyFp kPow10[] = { - DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 0x00000000), -60), // 10^1 - DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 0x00000000), -57), // 10^2 - DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 0x00000000), -54), // 10^3 - DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), -50), // 10^4 - DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 0x00000000), -47), // 10^5 - DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 0x00000000), -44), // 10^6 - DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 0x00000000), -40) // 10^7 - }; - int adjustment = dExp - actualExp; - RAPIDJSON_ASSERT(adjustment >= 1 && adjustment < 8); - v = v * kPow10[adjustment - 1]; - if (dLen + adjustment > 19) // has more digits than decimal digits in 64-bit - error += kUlp / 2; - } - - v = v * cachedPower; - - error += kUlp + (error == 0 ? 0 : 1); - - const int oldExp = v.e; - v = v.Normalize(); - error <<= oldExp - v.e; - - const int effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e); - int precisionSize = 64 - effectiveSignificandSize; - if (precisionSize + kUlpShift >= 64) { - int scaleExp = (precisionSize + kUlpShift) - 63; - v.f >>= scaleExp; - v.e += scaleExp; - error = (error >> scaleExp) + 1 + kUlp; - precisionSize -= scaleExp; - } - - DiyFp rounded(v.f >> precisionSize, v.e + precisionSize); - const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp; - const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp; - if (precisionBits >= halfWay + static_cast(error)) { - rounded.f++; - if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340) - rounded.f >>= 1; - rounded.e++; - } - } - - *result = rounded.ToDouble(); - - return halfWay - static_cast(error) >= precisionBits || precisionBits >= halfWay + static_cast(error); -} - -inline double StrtodBigInteger(double approx, const char* decimals, int dLen, int dExp) { - RAPIDJSON_ASSERT(dLen >= 0); - const BigInteger dInt(decimals, static_cast(dLen)); - Double a(approx); - int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp); - if (cmp < 0) - return a.Value(); // within half ULP - else if (cmp == 0) { - // Round towards even - if (a.Significand() & 1) - return a.NextPositiveDouble(); - else - return a.Value(); - } - else // adjustment - return a.NextPositiveDouble(); -} - -inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) { - RAPIDJSON_ASSERT(d >= 0.0); - RAPIDJSON_ASSERT(length >= 1); - - double result = 0.0; - if (StrtodFast(d, p, &result)) - return result; - - RAPIDJSON_ASSERT(length <= INT_MAX); - int dLen = static_cast(length); - - RAPIDJSON_ASSERT(length >= decimalPosition); - RAPIDJSON_ASSERT(length - decimalPosition <= INT_MAX); - int dExpAdjust = static_cast(length - decimalPosition); - - RAPIDJSON_ASSERT(exp >= INT_MIN + dExpAdjust); - int dExp = exp - dExpAdjust; - - // Make sure length+dExp does not overflow - RAPIDJSON_ASSERT(dExp <= INT_MAX - dLen); - - // Trim leading zeros - while (dLen > 0 && *decimals == '0') { - dLen--; - decimals++; - } - - // Trim trailing zeros - while (dLen > 0 && decimals[dLen - 1] == '0') { - dLen--; - dExp++; - } - - if (dLen == 0) { // Buffer only contains zeros. - return 0.0; - } - - // Trim right-most digits - const int kMaxDecimalDigit = 767 + 1; - if (dLen > kMaxDecimalDigit) { - dExp += dLen - kMaxDecimalDigit; - dLen = kMaxDecimalDigit; - } - - // If too small, underflow to zero. - // Any x <= 10^-324 is interpreted as zero. - if (dLen + dExp <= -324) - return 0.0; - - // If too large, overflow to infinity. - // Any x >= 10^309 is interpreted as +infinity. - if (dLen + dExp > 309) - return std::numeric_limits::infinity(); - - if (StrtodDiyFp(decimals, dLen, dExp, &result)) - return result; - - // Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison - return StrtodBigInteger(result, decimals, dLen, dExp); -} - -} // namespace internal -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_STRTOD_ diff --git a/external/rapidjson/internal/swap.h b/external/rapidjson/internal/swap.h deleted file mode 100755 index 2cf92f9..0000000 --- a/external/rapidjson/internal/swap.h +++ /dev/null @@ -1,46 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_INTERNAL_SWAP_H_ -#define RAPIDJSON_INTERNAL_SWAP_H_ - -#include "../rapidjson.h" - -#if defined(__clang__) -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(c++98-compat) -#endif - -RAPIDJSON_NAMESPACE_BEGIN -namespace internal { - -//! Custom swap() to avoid dependency on C++ header -/*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only. - \note This has the same semantics as std::swap(). -*/ -template -inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT { - T tmp = a; - a = b; - b = tmp; -} - -} // namespace internal -RAPIDJSON_NAMESPACE_END - -#if defined(__clang__) -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_INTERNAL_SWAP_H_ diff --git a/external/rapidjson/istreamwrapper.h b/external/rapidjson/istreamwrapper.h deleted file mode 100755 index 01437ec..0000000 --- a/external/rapidjson/istreamwrapper.h +++ /dev/null @@ -1,128 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_ISTREAMWRAPPER_H_ -#define RAPIDJSON_ISTREAMWRAPPER_H_ - -#include "stream.h" -#include -#include - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(padded) -#elif defined(_MSC_VER) -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -//! Wrapper of \c std::basic_istream into RapidJSON's Stream concept. -/*! - The classes can be wrapped including but not limited to: - - - \c std::istringstream - - \c std::stringstream - - \c std::wistringstream - - \c std::wstringstream - - \c std::ifstream - - \c std::fstream - - \c std::wifstream - - \c std::wfstream - - \tparam StreamType Class derived from \c std::basic_istream. -*/ - -template -class BasicIStreamWrapper { -public: - typedef typename StreamType::char_type Ch; - - //! Constructor. - /*! - \param stream stream opened for read. - */ - BasicIStreamWrapper(StreamType &stream) : stream_(stream), buffer_(peekBuffer_), bufferSize_(4), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { - Read(); - } - - //! Constructor. - /*! - \param stream stream opened for read. - \param buffer user-supplied buffer. - \param bufferSize size of buffer in bytes. Must >=4 bytes. - */ - BasicIStreamWrapper(StreamType &stream, char* buffer, size_t bufferSize) : stream_(stream), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { - RAPIDJSON_ASSERT(bufferSize >= 4); - Read(); - } - - Ch Peek() const { return *current_; } - Ch Take() { Ch c = *current_; Read(); return c; } - size_t Tell() const { return count_ + static_cast(current_ - buffer_); } - - // Not implemented - void Put(Ch) { RAPIDJSON_ASSERT(false); } - void Flush() { RAPIDJSON_ASSERT(false); } - Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } - - // For encoding detection only. - const Ch* Peek4() const { - return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0; - } - -private: - BasicIStreamWrapper(); - BasicIStreamWrapper(const BasicIStreamWrapper&); - BasicIStreamWrapper& operator=(const BasicIStreamWrapper&); - - void Read() { - if (current_ < bufferLast_) - ++current_; - else if (!eof_) { - count_ += readCount_; - readCount_ = bufferSize_; - bufferLast_ = buffer_ + readCount_ - 1; - current_ = buffer_; - - if (!stream_.read(buffer_, static_cast(bufferSize_))) { - readCount_ = static_cast(stream_.gcount()); - *(bufferLast_ = buffer_ + readCount_) = '\0'; - eof_ = true; - } - } - } - - StreamType &stream_; - Ch peekBuffer_[4], *buffer_; - size_t bufferSize_; - Ch *bufferLast_; - Ch *current_; - size_t readCount_; - size_t count_; //!< Number of characters read - bool eof_; -}; - -typedef BasicIStreamWrapper IStreamWrapper; -typedef BasicIStreamWrapper WIStreamWrapper; - -#if defined(__clang__) || defined(_MSC_VER) -RAPIDJSON_DIAG_POP -#endif - -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_ISTREAMWRAPPER_H_ diff --git a/external/rapidjson/memorybuffer.h b/external/rapidjson/memorybuffer.h deleted file mode 100755 index ffbc41e..0000000 --- a/external/rapidjson/memorybuffer.h +++ /dev/null @@ -1,70 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_MEMORYBUFFER_H_ -#define RAPIDJSON_MEMORYBUFFER_H_ - -#include "stream.h" -#include "internal/stack.h" - -RAPIDJSON_NAMESPACE_BEGIN - -//! Represents an in-memory output byte stream. -/*! - This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream. - - It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file. - - Differences between MemoryBuffer and StringBuffer: - 1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer. - 2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator. - - \tparam Allocator type for allocating memory buffer. - \note implements Stream concept -*/ -template -struct GenericMemoryBuffer { - typedef char Ch; // byte - - GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} - - void Put(Ch c) { *stack_.template Push() = c; } - void Flush() {} - - void Clear() { stack_.Clear(); } - void ShrinkToFit() { stack_.ShrinkToFit(); } - Ch* Push(size_t count) { return stack_.template Push(count); } - void Pop(size_t count) { stack_.template Pop(count); } - - const Ch* GetBuffer() const { - return stack_.template Bottom(); - } - - size_t GetSize() const { return stack_.GetSize(); } - - static const size_t kDefaultCapacity = 256; - mutable internal::Stack stack_; -}; - -typedef GenericMemoryBuffer<> MemoryBuffer; - -//! Implement specialized version of PutN() with memset() for better performance. -template<> -inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) { - std::memset(memoryBuffer.stack_.Push(n), c, n * sizeof(c)); -} - -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_MEMORYBUFFER_H_ diff --git a/external/rapidjson/memorystream.h b/external/rapidjson/memorystream.h deleted file mode 100755 index 77af6c9..0000000 --- a/external/rapidjson/memorystream.h +++ /dev/null @@ -1,71 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_MEMORYSTREAM_H_ -#define RAPIDJSON_MEMORYSTREAM_H_ - -#include "stream.h" - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(unreachable-code) -RAPIDJSON_DIAG_OFF(missing-noreturn) -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -//! Represents an in-memory input byte stream. -/*! - This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream. - - It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file. - - Differences between MemoryStream and StringStream: - 1. StringStream has encoding but MemoryStream is a byte stream. - 2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source. - 3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4(). - \note implements Stream concept -*/ -struct MemoryStream { - typedef char Ch; // byte - - MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {} - - Ch Peek() const { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_; } - Ch Take() { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_++; } - size_t Tell() const { return static_cast(src_ - begin_); } - - Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - void Put(Ch) { RAPIDJSON_ASSERT(false); } - void Flush() { RAPIDJSON_ASSERT(false); } - size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } - - // For encoding detection only. - const Ch* Peek4() const { - return Tell() + 4 <= size_ ? src_ : 0; - } - - const Ch* src_; //!< Current read position. - const Ch* begin_; //!< Original head of the string. - const Ch* end_; //!< End of stream. - size_t size_; //!< Size of the stream. -}; - -RAPIDJSON_NAMESPACE_END - -#ifdef __clang__ -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_MEMORYBUFFER_H_ diff --git a/external/rapidjson/msinttypes/inttypes.h b/external/rapidjson/msinttypes/inttypes.h deleted file mode 100755 index 1811128..0000000 --- a/external/rapidjson/msinttypes/inttypes.h +++ /dev/null @@ -1,316 +0,0 @@ -// ISO C9x compliant inttypes.h for Microsoft Visual Studio -// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 -// -// Copyright (c) 2006-2013 Alexander Chemeris -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// 3. Neither the name of the product nor the names of its contributors may -// be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -/////////////////////////////////////////////////////////////////////////////// - -// The above software in this distribution may have been modified by -// THL A29 Limited ("Tencent Modifications"). -// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited. - -#ifndef _MSC_VER // [ -#error "Use this header only with Microsoft Visual C++ compilers!" -#endif // _MSC_VER ] - -#ifndef _MSC_INTTYPES_H_ // [ -#define _MSC_INTTYPES_H_ - -#if _MSC_VER > 1000 -#pragma once -#endif - -#include "stdint.h" - -// miloyip: VC supports inttypes.h since VC2013 -#if _MSC_VER >= 1800 -#include -#else - -// 7.8 Format conversion of integer types - -typedef struct { - intmax_t quot; - intmax_t rem; -} imaxdiv_t; - -// 7.8.1 Macros for format specifiers - -#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198 - -// The fprintf macros for signed integers are: -#define PRId8 "d" -#define PRIi8 "i" -#define PRIdLEAST8 "d" -#define PRIiLEAST8 "i" -#define PRIdFAST8 "d" -#define PRIiFAST8 "i" - -#define PRId16 "hd" -#define PRIi16 "hi" -#define PRIdLEAST16 "hd" -#define PRIiLEAST16 "hi" -#define PRIdFAST16 "hd" -#define PRIiFAST16 "hi" - -#define PRId32 "I32d" -#define PRIi32 "I32i" -#define PRIdLEAST32 "I32d" -#define PRIiLEAST32 "I32i" -#define PRIdFAST32 "I32d" -#define PRIiFAST32 "I32i" - -#define PRId64 "I64d" -#define PRIi64 "I64i" -#define PRIdLEAST64 "I64d" -#define PRIiLEAST64 "I64i" -#define PRIdFAST64 "I64d" -#define PRIiFAST64 "I64i" - -#define PRIdMAX "I64d" -#define PRIiMAX "I64i" - -#define PRIdPTR "Id" -#define PRIiPTR "Ii" - -// The fprintf macros for unsigned integers are: -#define PRIo8 "o" -#define PRIu8 "u" -#define PRIx8 "x" -#define PRIX8 "X" -#define PRIoLEAST8 "o" -#define PRIuLEAST8 "u" -#define PRIxLEAST8 "x" -#define PRIXLEAST8 "X" -#define PRIoFAST8 "o" -#define PRIuFAST8 "u" -#define PRIxFAST8 "x" -#define PRIXFAST8 "X" - -#define PRIo16 "ho" -#define PRIu16 "hu" -#define PRIx16 "hx" -#define PRIX16 "hX" -#define PRIoLEAST16 "ho" -#define PRIuLEAST16 "hu" -#define PRIxLEAST16 "hx" -#define PRIXLEAST16 "hX" -#define PRIoFAST16 "ho" -#define PRIuFAST16 "hu" -#define PRIxFAST16 "hx" -#define PRIXFAST16 "hX" - -#define PRIo32 "I32o" -#define PRIu32 "I32u" -#define PRIx32 "I32x" -#define PRIX32 "I32X" -#define PRIoLEAST32 "I32o" -#define PRIuLEAST32 "I32u" -#define PRIxLEAST32 "I32x" -#define PRIXLEAST32 "I32X" -#define PRIoFAST32 "I32o" -#define PRIuFAST32 "I32u" -#define PRIxFAST32 "I32x" -#define PRIXFAST32 "I32X" - -#define PRIo64 "I64o" -#define PRIu64 "I64u" -#define PRIx64 "I64x" -#define PRIX64 "I64X" -#define PRIoLEAST64 "I64o" -#define PRIuLEAST64 "I64u" -#define PRIxLEAST64 "I64x" -#define PRIXLEAST64 "I64X" -#define PRIoFAST64 "I64o" -#define PRIuFAST64 "I64u" -#define PRIxFAST64 "I64x" -#define PRIXFAST64 "I64X" - -#define PRIoMAX "I64o" -#define PRIuMAX "I64u" -#define PRIxMAX "I64x" -#define PRIXMAX "I64X" - -#define PRIoPTR "Io" -#define PRIuPTR "Iu" -#define PRIxPTR "Ix" -#define PRIXPTR "IX" - -// The fscanf macros for signed integers are: -#define SCNd8 "d" -#define SCNi8 "i" -#define SCNdLEAST8 "d" -#define SCNiLEAST8 "i" -#define SCNdFAST8 "d" -#define SCNiFAST8 "i" - -#define SCNd16 "hd" -#define SCNi16 "hi" -#define SCNdLEAST16 "hd" -#define SCNiLEAST16 "hi" -#define SCNdFAST16 "hd" -#define SCNiFAST16 "hi" - -#define SCNd32 "ld" -#define SCNi32 "li" -#define SCNdLEAST32 "ld" -#define SCNiLEAST32 "li" -#define SCNdFAST32 "ld" -#define SCNiFAST32 "li" - -#define SCNd64 "I64d" -#define SCNi64 "I64i" -#define SCNdLEAST64 "I64d" -#define SCNiLEAST64 "I64i" -#define SCNdFAST64 "I64d" -#define SCNiFAST64 "I64i" - -#define SCNdMAX "I64d" -#define SCNiMAX "I64i" - -#ifdef _WIN64 // [ -# define SCNdPTR "I64d" -# define SCNiPTR "I64i" -#else // _WIN64 ][ -# define SCNdPTR "ld" -# define SCNiPTR "li" -#endif // _WIN64 ] - -// The fscanf macros for unsigned integers are: -#define SCNo8 "o" -#define SCNu8 "u" -#define SCNx8 "x" -#define SCNX8 "X" -#define SCNoLEAST8 "o" -#define SCNuLEAST8 "u" -#define SCNxLEAST8 "x" -#define SCNXLEAST8 "X" -#define SCNoFAST8 "o" -#define SCNuFAST8 "u" -#define SCNxFAST8 "x" -#define SCNXFAST8 "X" - -#define SCNo16 "ho" -#define SCNu16 "hu" -#define SCNx16 "hx" -#define SCNX16 "hX" -#define SCNoLEAST16 "ho" -#define SCNuLEAST16 "hu" -#define SCNxLEAST16 "hx" -#define SCNXLEAST16 "hX" -#define SCNoFAST16 "ho" -#define SCNuFAST16 "hu" -#define SCNxFAST16 "hx" -#define SCNXFAST16 "hX" - -#define SCNo32 "lo" -#define SCNu32 "lu" -#define SCNx32 "lx" -#define SCNX32 "lX" -#define SCNoLEAST32 "lo" -#define SCNuLEAST32 "lu" -#define SCNxLEAST32 "lx" -#define SCNXLEAST32 "lX" -#define SCNoFAST32 "lo" -#define SCNuFAST32 "lu" -#define SCNxFAST32 "lx" -#define SCNXFAST32 "lX" - -#define SCNo64 "I64o" -#define SCNu64 "I64u" -#define SCNx64 "I64x" -#define SCNX64 "I64X" -#define SCNoLEAST64 "I64o" -#define SCNuLEAST64 "I64u" -#define SCNxLEAST64 "I64x" -#define SCNXLEAST64 "I64X" -#define SCNoFAST64 "I64o" -#define SCNuFAST64 "I64u" -#define SCNxFAST64 "I64x" -#define SCNXFAST64 "I64X" - -#define SCNoMAX "I64o" -#define SCNuMAX "I64u" -#define SCNxMAX "I64x" -#define SCNXMAX "I64X" - -#ifdef _WIN64 // [ -# define SCNoPTR "I64o" -# define SCNuPTR "I64u" -# define SCNxPTR "I64x" -# define SCNXPTR "I64X" -#else // _WIN64 ][ -# define SCNoPTR "lo" -# define SCNuPTR "lu" -# define SCNxPTR "lx" -# define SCNXPTR "lX" -#endif // _WIN64 ] - -#endif // __STDC_FORMAT_MACROS ] - -// 7.8.2 Functions for greatest-width integer types - -// 7.8.2.1 The imaxabs function -#define imaxabs _abs64 - -// 7.8.2.2 The imaxdiv function - -// This is modified version of div() function from Microsoft's div.c found -// in %MSVC.NET%\crt\src\div.c -#ifdef STATIC_IMAXDIV // [ -static -#else // STATIC_IMAXDIV ][ -_inline -#endif // STATIC_IMAXDIV ] -imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom) -{ - imaxdiv_t result; - - result.quot = numer / denom; - result.rem = numer % denom; - - if (numer < 0 && result.rem > 0) { - // did division wrong; must fix up - ++result.quot; - result.rem -= denom; - } - - return result; -} - -// 7.8.2.3 The strtoimax and strtoumax functions -#define strtoimax _strtoi64 -#define strtoumax _strtoui64 - -// 7.8.2.4 The wcstoimax and wcstoumax functions -#define wcstoimax _wcstoi64 -#define wcstoumax _wcstoui64 - -#endif // _MSC_VER >= 1800 - -#endif // _MSC_INTTYPES_H_ ] diff --git a/external/rapidjson/msinttypes/stdint.h b/external/rapidjson/msinttypes/stdint.h deleted file mode 100755 index 3d4477b..0000000 --- a/external/rapidjson/msinttypes/stdint.h +++ /dev/null @@ -1,300 +0,0 @@ -// ISO C9x compliant stdint.h for Microsoft Visual Studio -// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 -// -// Copyright (c) 2006-2013 Alexander Chemeris -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// 3. Neither the name of the product nor the names of its contributors may -// be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -/////////////////////////////////////////////////////////////////////////////// - -// The above software in this distribution may have been modified by -// THL A29 Limited ("Tencent Modifications"). -// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited. - -#ifndef _MSC_VER // [ -#error "Use this header only with Microsoft Visual C++ compilers!" -#endif // _MSC_VER ] - -#ifndef _MSC_STDINT_H_ // [ -#define _MSC_STDINT_H_ - -#if _MSC_VER > 1000 -#pragma once -#endif - -// miloyip: Originally Visual Studio 2010 uses its own stdint.h. However it generates warning with INT64_C(), so change to use this file for vs2010. -#if _MSC_VER >= 1600 // [ -#include - -#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 - -#undef INT8_C -#undef INT16_C -#undef INT32_C -#undef INT64_C -#undef UINT8_C -#undef UINT16_C -#undef UINT32_C -#undef UINT64_C - -// 7.18.4.1 Macros for minimum-width integer constants - -#define INT8_C(val) val##i8 -#define INT16_C(val) val##i16 -#define INT32_C(val) val##i32 -#define INT64_C(val) val##i64 - -#define UINT8_C(val) val##ui8 -#define UINT16_C(val) val##ui16 -#define UINT32_C(val) val##ui32 -#define UINT64_C(val) val##ui64 - -// 7.18.4.2 Macros for greatest-width integer constants -// These #ifndef's are needed to prevent collisions with . -// Check out Issue 9 for the details. -#ifndef INTMAX_C // [ -# define INTMAX_C INT64_C -#endif // INTMAX_C ] -#ifndef UINTMAX_C // [ -# define UINTMAX_C UINT64_C -#endif // UINTMAX_C ] - -#endif // __STDC_CONSTANT_MACROS ] - -#else // ] _MSC_VER >= 1700 [ - -#include - -// For Visual Studio 6 in C++ mode and for many Visual Studio versions when -// compiling for ARM we have to wrap include with 'extern "C++" {}' -// or compiler would give many errors like this: -// error C2733: second C linkage of overloaded function 'wmemchr' not allowed -#if defined(__cplusplus) && !defined(_M_ARM) -extern "C" { -#endif -# include -#if defined(__cplusplus) && !defined(_M_ARM) -} -#endif - -// Define _W64 macros to mark types changing their size, like intptr_t. -#ifndef _W64 -# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 -# define _W64 __w64 -# else -# define _W64 -# endif -#endif - - -// 7.18.1 Integer types - -// 7.18.1.1 Exact-width integer types - -// Visual Studio 6 and Embedded Visual C++ 4 doesn't -// realize that, e.g. char has the same size as __int8 -// so we give up on __intX for them. -#if (_MSC_VER < 1300) - typedef signed char int8_t; - typedef signed short int16_t; - typedef signed int int32_t; - typedef unsigned char uint8_t; - typedef unsigned short uint16_t; - typedef unsigned int uint32_t; -#else - typedef signed __int8 int8_t; - typedef signed __int16 int16_t; - typedef signed __int32 int32_t; - typedef unsigned __int8 uint8_t; - typedef unsigned __int16 uint16_t; - typedef unsigned __int32 uint32_t; -#endif -typedef signed __int64 int64_t; -typedef unsigned __int64 uint64_t; - - -// 7.18.1.2 Minimum-width integer types -typedef int8_t int_least8_t; -typedef int16_t int_least16_t; -typedef int32_t int_least32_t; -typedef int64_t int_least64_t; -typedef uint8_t uint_least8_t; -typedef uint16_t uint_least16_t; -typedef uint32_t uint_least32_t; -typedef uint64_t uint_least64_t; - -// 7.18.1.3 Fastest minimum-width integer types -typedef int8_t int_fast8_t; -typedef int16_t int_fast16_t; -typedef int32_t int_fast32_t; -typedef int64_t int_fast64_t; -typedef uint8_t uint_fast8_t; -typedef uint16_t uint_fast16_t; -typedef uint32_t uint_fast32_t; -typedef uint64_t uint_fast64_t; - -// 7.18.1.4 Integer types capable of holding object pointers -#ifdef _WIN64 // [ - typedef signed __int64 intptr_t; - typedef unsigned __int64 uintptr_t; -#else // _WIN64 ][ - typedef _W64 signed int intptr_t; - typedef _W64 unsigned int uintptr_t; -#endif // _WIN64 ] - -// 7.18.1.5 Greatest-width integer types -typedef int64_t intmax_t; -typedef uint64_t uintmax_t; - - -// 7.18.2 Limits of specified-width integer types - -#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 - -// 7.18.2.1 Limits of exact-width integer types -#define INT8_MIN ((int8_t)_I8_MIN) -#define INT8_MAX _I8_MAX -#define INT16_MIN ((int16_t)_I16_MIN) -#define INT16_MAX _I16_MAX -#define INT32_MIN ((int32_t)_I32_MIN) -#define INT32_MAX _I32_MAX -#define INT64_MIN ((int64_t)_I64_MIN) -#define INT64_MAX _I64_MAX -#define UINT8_MAX _UI8_MAX -#define UINT16_MAX _UI16_MAX -#define UINT32_MAX _UI32_MAX -#define UINT64_MAX _UI64_MAX - -// 7.18.2.2 Limits of minimum-width integer types -#define INT_LEAST8_MIN INT8_MIN -#define INT_LEAST8_MAX INT8_MAX -#define INT_LEAST16_MIN INT16_MIN -#define INT_LEAST16_MAX INT16_MAX -#define INT_LEAST32_MIN INT32_MIN -#define INT_LEAST32_MAX INT32_MAX -#define INT_LEAST64_MIN INT64_MIN -#define INT_LEAST64_MAX INT64_MAX -#define UINT_LEAST8_MAX UINT8_MAX -#define UINT_LEAST16_MAX UINT16_MAX -#define UINT_LEAST32_MAX UINT32_MAX -#define UINT_LEAST64_MAX UINT64_MAX - -// 7.18.2.3 Limits of fastest minimum-width integer types -#define INT_FAST8_MIN INT8_MIN -#define INT_FAST8_MAX INT8_MAX -#define INT_FAST16_MIN INT16_MIN -#define INT_FAST16_MAX INT16_MAX -#define INT_FAST32_MIN INT32_MIN -#define INT_FAST32_MAX INT32_MAX -#define INT_FAST64_MIN INT64_MIN -#define INT_FAST64_MAX INT64_MAX -#define UINT_FAST8_MAX UINT8_MAX -#define UINT_FAST16_MAX UINT16_MAX -#define UINT_FAST32_MAX UINT32_MAX -#define UINT_FAST64_MAX UINT64_MAX - -// 7.18.2.4 Limits of integer types capable of holding object pointers -#ifdef _WIN64 // [ -# define INTPTR_MIN INT64_MIN -# define INTPTR_MAX INT64_MAX -# define UINTPTR_MAX UINT64_MAX -#else // _WIN64 ][ -# define INTPTR_MIN INT32_MIN -# define INTPTR_MAX INT32_MAX -# define UINTPTR_MAX UINT32_MAX -#endif // _WIN64 ] - -// 7.18.2.5 Limits of greatest-width integer types -#define INTMAX_MIN INT64_MIN -#define INTMAX_MAX INT64_MAX -#define UINTMAX_MAX UINT64_MAX - -// 7.18.3 Limits of other integer types - -#ifdef _WIN64 // [ -# define PTRDIFF_MIN _I64_MIN -# define PTRDIFF_MAX _I64_MAX -#else // _WIN64 ][ -# define PTRDIFF_MIN _I32_MIN -# define PTRDIFF_MAX _I32_MAX -#endif // _WIN64 ] - -#define SIG_ATOMIC_MIN INT_MIN -#define SIG_ATOMIC_MAX INT_MAX - -#ifndef SIZE_MAX // [ -# ifdef _WIN64 // [ -# define SIZE_MAX _UI64_MAX -# else // _WIN64 ][ -# define SIZE_MAX _UI32_MAX -# endif // _WIN64 ] -#endif // SIZE_MAX ] - -// WCHAR_MIN and WCHAR_MAX are also defined in -#ifndef WCHAR_MIN // [ -# define WCHAR_MIN 0 -#endif // WCHAR_MIN ] -#ifndef WCHAR_MAX // [ -# define WCHAR_MAX _UI16_MAX -#endif // WCHAR_MAX ] - -#define WINT_MIN 0 -#define WINT_MAX _UI16_MAX - -#endif // __STDC_LIMIT_MACROS ] - - -// 7.18.4 Limits of other integer types - -#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 - -// 7.18.4.1 Macros for minimum-width integer constants - -#define INT8_C(val) val##i8 -#define INT16_C(val) val##i16 -#define INT32_C(val) val##i32 -#define INT64_C(val) val##i64 - -#define UINT8_C(val) val##ui8 -#define UINT16_C(val) val##ui16 -#define UINT32_C(val) val##ui32 -#define UINT64_C(val) val##ui64 - -// 7.18.4.2 Macros for greatest-width integer constants -// These #ifndef's are needed to prevent collisions with . -// Check out Issue 9 for the details. -#ifndef INTMAX_C // [ -# define INTMAX_C INT64_C -#endif // INTMAX_C ] -#ifndef UINTMAX_C // [ -# define UINTMAX_C UINT64_C -#endif // UINTMAX_C ] - -#endif // __STDC_CONSTANT_MACROS ] - -#endif // _MSC_VER >= 1600 ] - -#endif // _MSC_STDINT_H_ ] diff --git a/external/rapidjson/ostreamwrapper.h b/external/rapidjson/ostreamwrapper.h deleted file mode 100755 index 11ed4d3..0000000 --- a/external/rapidjson/ostreamwrapper.h +++ /dev/null @@ -1,81 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_OSTREAMWRAPPER_H_ -#define RAPIDJSON_OSTREAMWRAPPER_H_ - -#include "stream.h" -#include - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(padded) -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -//! Wrapper of \c std::basic_ostream into RapidJSON's Stream concept. -/*! - The classes can be wrapped including but not limited to: - - - \c std::ostringstream - - \c std::stringstream - - \c std::wpstringstream - - \c std::wstringstream - - \c std::ifstream - - \c std::fstream - - \c std::wofstream - - \c std::wfstream - - \tparam StreamType Class derived from \c std::basic_ostream. -*/ - -template -class BasicOStreamWrapper { -public: - typedef typename StreamType::char_type Ch; - BasicOStreamWrapper(StreamType& stream) : stream_(stream) {} - - void Put(Ch c) { - stream_.put(c); - } - - void Flush() { - stream_.flush(); - } - - // Not implemented - char Peek() const { RAPIDJSON_ASSERT(false); return 0; } - char Take() { RAPIDJSON_ASSERT(false); return 0; } - size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } - char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } - -private: - BasicOStreamWrapper(const BasicOStreamWrapper&); - BasicOStreamWrapper& operator=(const BasicOStreamWrapper&); - - StreamType& stream_; -}; - -typedef BasicOStreamWrapper OStreamWrapper; -typedef BasicOStreamWrapper WOStreamWrapper; - -#ifdef __clang__ -RAPIDJSON_DIAG_POP -#endif - -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_OSTREAMWRAPPER_H_ diff --git a/external/rapidjson/pointer.h b/external/rapidjson/pointer.h deleted file mode 100755 index 67a9cb0..0000000 --- a/external/rapidjson/pointer.h +++ /dev/null @@ -1,1482 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_POINTER_H_ -#define RAPIDJSON_POINTER_H_ - -#include "document.h" -#include "uri.h" -#include "internal/itoa.h" - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(switch-enum) -#elif defined(_MSC_VER) -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -static const SizeType kPointerInvalidIndex = ~SizeType(0); //!< Represents an invalid index in GenericPointer::Token - -//! Error code of parsing. -/*! \ingroup RAPIDJSON_ERRORS - \see GenericPointer::GenericPointer, GenericPointer::GetParseErrorCode -*/ -enum PointerParseErrorCode { - kPointerParseErrorNone = 0, //!< The parse is successful - - kPointerParseErrorTokenMustBeginWithSolidus, //!< A token must begin with a '/' - kPointerParseErrorInvalidEscape, //!< Invalid escape - kPointerParseErrorInvalidPercentEncoding, //!< Invalid percent encoding in URI fragment - kPointerParseErrorCharacterMustPercentEncode //!< A character must percent encoded in URI fragment -}; - -/////////////////////////////////////////////////////////////////////////////// -// GenericPointer - -//! Represents a JSON Pointer. Use Pointer for UTF8 encoding and default allocator. -/*! - This class implements RFC 6901 "JavaScript Object Notation (JSON) Pointer" - (https://tools.ietf.org/html/rfc6901). - - A JSON pointer is for identifying a specific value in a JSON document - (GenericDocument). It can simplify coding of DOM tree manipulation, because it - can access multiple-level depth of DOM tree with single API call. - - After it parses a string representation (e.g. "/foo/0" or URI fragment - representation (e.g. "#/foo/0") into its internal representation (tokens), - it can be used to resolve a specific value in multiple documents, or sub-tree - of documents. - - Contrary to GenericValue, Pointer can be copy constructed and copy assigned. - Apart from assignment, a Pointer cannot be modified after construction. - - Although Pointer is very convenient, please aware that constructing Pointer - involves parsing and dynamic memory allocation. A special constructor with user- - supplied tokens eliminates these. - - GenericPointer depends on GenericDocument and GenericValue. - - \tparam ValueType The value type of the DOM tree. E.g. GenericValue > - \tparam Allocator The allocator type for allocating memory for internal representation. - - \note GenericPointer uses same encoding of ValueType. - However, Allocator of GenericPointer is independent of Allocator of Value. -*/ -template -class GenericPointer { -public: - typedef typename ValueType::EncodingType EncodingType; //!< Encoding type from Value - typedef typename ValueType::Ch Ch; //!< Character type from Value - typedef GenericUri UriType; - - - //! A token is the basic units of internal representation. - /*! - A JSON pointer string representation "/foo/123" is parsed to two tokens: - "foo" and 123. 123 will be represented in both numeric form and string form. - They are resolved according to the actual value type (object or array). - - For token that are not numbers, or the numeric value is out of bound - (greater than limits of SizeType), they are only treated as string form - (i.e. the token's index will be equal to kPointerInvalidIndex). - - This struct is public so that user can create a Pointer without parsing and - allocation, using a special constructor. - */ - struct Token { - const Ch* name; //!< Name of the token. It has null character at the end but it can contain null character. - SizeType length; //!< Length of the name. - SizeType index; //!< A valid array index, if it is not equal to kPointerInvalidIndex. - }; - - //!@name Constructors and destructor. - //@{ - - //! Default constructor. - GenericPointer(Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {} - - //! Constructor that parses a string or URI fragment representation. - /*! - \param source A null-terminated, string or URI fragment representation of JSON pointer. - \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one. - */ - explicit GenericPointer(const Ch* source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { - Parse(source, internal::StrLen(source)); - } - -#if RAPIDJSON_HAS_STDSTRING - //! Constructor that parses a string or URI fragment representation. - /*! - \param source A string or URI fragment representation of JSON pointer. - \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one. - \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. - */ - explicit GenericPointer(const std::basic_string& source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { - Parse(source.c_str(), source.size()); - } -#endif - - //! Constructor that parses a string or URI fragment representation, with length of the source string. - /*! - \param source A string or URI fragment representation of JSON pointer. - \param length Length of source. - \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one. - \note Slightly faster than the overload without length. - */ - GenericPointer(const Ch* source, size_t length, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { - Parse(source, length); - } - - //! Constructor with user-supplied tokens. - /*! - This constructor let user supplies const array of tokens. - This prevents the parsing process and eliminates allocation. - This is preferred for memory constrained environments. - - \param tokens An constant array of tokens representing the JSON pointer. - \param tokenCount Number of tokens. - - \b Example - \code - #define NAME(s) { s, sizeof(s) / sizeof(s[0]) - 1, kPointerInvalidIndex } - #define INDEX(i) { #i, sizeof(#i) - 1, i } - - static const Pointer::Token kTokens[] = { NAME("foo"), INDEX(123) }; - static const Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0])); - // Equivalent to static const Pointer p("/foo/123"); - - #undef NAME - #undef INDEX - \endcode - */ - GenericPointer(const Token* tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {} - - //! Copy constructor. - GenericPointer(const GenericPointer& rhs) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { - *this = rhs; - } - - //! Copy constructor. - GenericPointer(const GenericPointer& rhs, Allocator* allocator) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { - *this = rhs; - } - - //! Destructor. - ~GenericPointer() { - if (nameBuffer_) // If user-supplied tokens constructor is used, nameBuffer_ is nullptr and tokens_ are not deallocated. - Allocator::Free(tokens_); - RAPIDJSON_DELETE(ownAllocator_); - } - - //! Assignment operator. - GenericPointer& operator=(const GenericPointer& rhs) { - if (this != &rhs) { - // Do not delete ownAllcator - if (nameBuffer_) - Allocator::Free(tokens_); - - tokenCount_ = rhs.tokenCount_; - parseErrorOffset_ = rhs.parseErrorOffset_; - parseErrorCode_ = rhs.parseErrorCode_; - - if (rhs.nameBuffer_) - CopyFromRaw(rhs); // Normally parsed tokens. - else { - tokens_ = rhs.tokens_; // User supplied const tokens. - nameBuffer_ = 0; - } - } - return *this; - } - - //! Swap the content of this pointer with an other. - /*! - \param other The pointer to swap with. - \note Constant complexity. - */ - GenericPointer& Swap(GenericPointer& other) RAPIDJSON_NOEXCEPT { - internal::Swap(allocator_, other.allocator_); - internal::Swap(ownAllocator_, other.ownAllocator_); - internal::Swap(nameBuffer_, other.nameBuffer_); - internal::Swap(tokens_, other.tokens_); - internal::Swap(tokenCount_, other.tokenCount_); - internal::Swap(parseErrorOffset_, other.parseErrorOffset_); - internal::Swap(parseErrorCode_, other.parseErrorCode_); - return *this; - } - - //! free-standing swap function helper - /*! - Helper function to enable support for common swap implementation pattern based on \c std::swap: - \code - void swap(MyClass& a, MyClass& b) { - using std::swap; - swap(a.pointer, b.pointer); - // ... - } - \endcode - \see Swap() - */ - friend inline void swap(GenericPointer& a, GenericPointer& b) RAPIDJSON_NOEXCEPT { a.Swap(b); } - - //@} - - //!@name Append token - //@{ - - //! Append a token and return a new Pointer - /*! - \param token Token to be appended. - \param allocator Allocator for the newly return Pointer. - \return A new Pointer with appended token. - */ - GenericPointer Append(const Token& token, Allocator* allocator = 0) const { - GenericPointer r; - r.allocator_ = allocator; - Ch *p = r.CopyFromRaw(*this, 1, token.length + 1); - std::memcpy(p, token.name, (token.length + 1) * sizeof(Ch)); - r.tokens_[tokenCount_].name = p; - r.tokens_[tokenCount_].length = token.length; - r.tokens_[tokenCount_].index = token.index; - return r; - } - - //! Append a name token with length, and return a new Pointer - /*! - \param name Name to be appended. - \param length Length of name. - \param allocator Allocator for the newly return Pointer. - \return A new Pointer with appended token. - */ - GenericPointer Append(const Ch* name, SizeType length, Allocator* allocator = 0) const { - Token token = { name, length, kPointerInvalidIndex }; - return Append(token, allocator); - } - - //! Append a name token without length, and return a new Pointer - /*! - \param name Name (const Ch*) to be appended. - \param allocator Allocator for the newly return Pointer. - \return A new Pointer with appended token. - */ - template - RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >), (GenericPointer)) - Append(T* name, Allocator* allocator = 0) const { - return Append(name, internal::StrLen(name), allocator); - } - -#if RAPIDJSON_HAS_STDSTRING - //! Append a name token, and return a new Pointer - /*! - \param name Name to be appended. - \param allocator Allocator for the newly return Pointer. - \return A new Pointer with appended token. - */ - GenericPointer Append(const std::basic_string& name, Allocator* allocator = 0) const { - return Append(name.c_str(), static_cast(name.size()), allocator); - } -#endif - - //! Append a index token, and return a new Pointer - /*! - \param index Index to be appended. - \param allocator Allocator for the newly return Pointer. - \return A new Pointer with appended token. - */ - GenericPointer Append(SizeType index, Allocator* allocator = 0) const { - char buffer[21]; - char* end = sizeof(SizeType) == 4 ? internal::u32toa(index, buffer) : internal::u64toa(index, buffer); - SizeType length = static_cast(end - buffer); - buffer[length] = '\0'; - - if (sizeof(Ch) == 1) { - Token token = { reinterpret_cast(buffer), length, index }; - return Append(token, allocator); - } - else { - Ch name[21]; - for (size_t i = 0; i <= length; i++) - name[i] = static_cast(buffer[i]); - Token token = { name, length, index }; - return Append(token, allocator); - } - } - - //! Append a token by value, and return a new Pointer - /*! - \param token token to be appended. - \param allocator Allocator for the newly return Pointer. - \return A new Pointer with appended token. - */ - GenericPointer Append(const ValueType& token, Allocator* allocator = 0) const { - if (token.IsString()) - return Append(token.GetString(), token.GetStringLength(), allocator); - else { - RAPIDJSON_ASSERT(token.IsUint64()); - RAPIDJSON_ASSERT(token.GetUint64() <= SizeType(~0)); - return Append(static_cast(token.GetUint64()), allocator); - } - } - - //!@name Handling Parse Error - //@{ - - //! Check whether this is a valid pointer. - bool IsValid() const { return parseErrorCode_ == kPointerParseErrorNone; } - - //! Get the parsing error offset in code unit. - size_t GetParseErrorOffset() const { return parseErrorOffset_; } - - //! Get the parsing error code. - PointerParseErrorCode GetParseErrorCode() const { return parseErrorCode_; } - - //@} - - //! Get the allocator of this pointer. - Allocator& GetAllocator() { return *allocator_; } - - //!@name Tokens - //@{ - - //! Get the token array (const version only). - const Token* GetTokens() const { return tokens_; } - - //! Get the number of tokens. - size_t GetTokenCount() const { return tokenCount_; } - - //@} - - //!@name Equality/inequality operators - //@{ - - //! Equality operator. - /*! - \note When any pointers are invalid, always returns false. - */ - bool operator==(const GenericPointer& rhs) const { - if (!IsValid() || !rhs.IsValid() || tokenCount_ != rhs.tokenCount_) - return false; - - for (size_t i = 0; i < tokenCount_; i++) { - if (tokens_[i].index != rhs.tokens_[i].index || - tokens_[i].length != rhs.tokens_[i].length || - (tokens_[i].length != 0 && std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch)* tokens_[i].length) != 0)) - { - return false; - } - } - - return true; - } - - //! Inequality operator. - /*! - \note When any pointers are invalid, always returns true. - */ - bool operator!=(const GenericPointer& rhs) const { return !(*this == rhs); } - - //! Less than operator. - /*! - \note Invalid pointers are always greater than valid ones. - */ - bool operator<(const GenericPointer& rhs) const { - if (!IsValid()) - return false; - if (!rhs.IsValid()) - return true; - - if (tokenCount_ != rhs.tokenCount_) - return tokenCount_ < rhs.tokenCount_; - - for (size_t i = 0; i < tokenCount_; i++) { - if (tokens_[i].index != rhs.tokens_[i].index) - return tokens_[i].index < rhs.tokens_[i].index; - - if (tokens_[i].length != rhs.tokens_[i].length) - return tokens_[i].length < rhs.tokens_[i].length; - - if (int cmp = std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch) * tokens_[i].length)) - return cmp < 0; - } - - return false; - } - - //@} - - //!@name Stringify - //@{ - - //! Stringify the pointer into string representation. - /*! - \tparam OutputStream Type of output stream. - \param os The output stream. - */ - template - bool Stringify(OutputStream& os) const { - return Stringify(os); - } - - //! Stringify the pointer into URI fragment representation. - /*! - \tparam OutputStream Type of output stream. - \param os The output stream. - */ - template - bool StringifyUriFragment(OutputStream& os) const { - return Stringify(os); - } - - //@} - - //!@name Create value - //@{ - - //! Create a value in a subtree. - /*! - If the value is not exist, it creates all parent values and a JSON Null value. - So it always succeed and return the newly created or existing value. - - Remind that it may change types of parents according to tokens, so it - potentially removes previously stored values. For example, if a document - was an array, and "/foo" is used to create a value, then the document - will be changed to an object, and all existing array elements are lost. - - \param root Root value of a DOM subtree to be resolved. It can be any value other than document root. - \param allocator Allocator for creating the values if the specified value or its parents are not exist. - \param alreadyExist If non-null, it stores whether the resolved value is already exist. - \return The resolved newly created (a JSON Null value), or already exists value. - */ - ValueType& Create(ValueType& root, typename ValueType::AllocatorType& allocator, bool* alreadyExist = 0) const { - RAPIDJSON_ASSERT(IsValid()); - ValueType* v = &root; - bool exist = true; - for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { - if (v->IsArray() && t->name[0] == '-' && t->length == 1) { - v->PushBack(ValueType().Move(), allocator); - v = &((*v)[v->Size() - 1]); - exist = false; - } - else { - if (t->index == kPointerInvalidIndex) { // must be object name - if (!v->IsObject()) - v->SetObject(); // Change to Object - } - else { // object name or array index - if (!v->IsArray() && !v->IsObject()) - v->SetArray(); // Change to Array - } - - if (v->IsArray()) { - if (t->index >= v->Size()) { - v->Reserve(t->index + 1, allocator); - while (t->index >= v->Size()) - v->PushBack(ValueType().Move(), allocator); - exist = false; - } - v = &((*v)[t->index]); - } - else { - typename ValueType::MemberIterator m = v->FindMember(GenericValue(GenericStringRef(t->name, t->length))); - if (m == v->MemberEnd()) { - v->AddMember(ValueType(t->name, t->length, allocator).Move(), ValueType().Move(), allocator); - m = v->MemberEnd(); - v = &(--m)->value; // Assumes AddMember() appends at the end - exist = false; - } - else - v = &m->value; - } - } - } - - if (alreadyExist) - *alreadyExist = exist; - - return *v; - } - - //! Creates a value in a document. - /*! - \param document A document to be resolved. - \param alreadyExist If non-null, it stores whether the resolved value is already exist. - \return The resolved newly created, or already exists value. - */ - template - ValueType& Create(GenericDocument& document, bool* alreadyExist = 0) const { - return Create(document, document.GetAllocator(), alreadyExist); - } - - //@} - - //!@name Compute URI - //@{ - - //! Compute the in-scope URI for a subtree. - // For use with JSON pointers into JSON schema documents. - /*! - \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. - \param rootUri Root URI - \param unresolvedTokenIndex If the pointer cannot resolve a token in the pointer, this parameter can obtain the index of unresolved token. - \param allocator Allocator for Uris - \return Uri if it can be resolved. Otherwise null. - - \note - There are only 3 situations when a URI cannot be resolved: - 1. A value in the path is not an array nor object. - 2. An object value does not contain the token. - 3. A token is out of range of an array value. - - Use unresolvedTokenIndex to retrieve the token index. - */ - UriType GetUri(ValueType& root, const UriType& rootUri, size_t* unresolvedTokenIndex = 0, Allocator* allocator = 0) const { - static const Ch kIdString[] = { 'i', 'd', '\0' }; - static const ValueType kIdValue(kIdString, 2); - UriType base = UriType(rootUri, allocator); - RAPIDJSON_ASSERT(IsValid()); - ValueType* v = &root; - for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { - switch (v->GetType()) { - case kObjectType: - { - // See if we have an id, and if so resolve with the current base - typename ValueType::MemberIterator m = v->FindMember(kIdValue); - if (m != v->MemberEnd() && (m->value).IsString()) { - UriType here = UriType(m->value, allocator).Resolve(base, allocator); - base = here; - } - m = v->FindMember(GenericValue(GenericStringRef(t->name, t->length))); - if (m == v->MemberEnd()) - break; - v = &m->value; - } - continue; - case kArrayType: - if (t->index == kPointerInvalidIndex || t->index >= v->Size()) - break; - v = &((*v)[t->index]); - continue; - default: - break; - } - - // Error: unresolved token - if (unresolvedTokenIndex) - *unresolvedTokenIndex = static_cast(t - tokens_); - return UriType(allocator); - } - return base; - } - - UriType GetUri(const ValueType& root, const UriType& rootUri, size_t* unresolvedTokenIndex = 0, Allocator* allocator = 0) const { - return GetUri(const_cast(root), rootUri, unresolvedTokenIndex, allocator); - } - - - //!@name Query value - //@{ - - //! Query a value in a subtree. - /*! - \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. - \param unresolvedTokenIndex If the pointer cannot resolve a token in the pointer, this parameter can obtain the index of unresolved token. - \return Pointer to the value if it can be resolved. Otherwise null. - - \note - There are only 3 situations when a value cannot be resolved: - 1. A value in the path is not an array nor object. - 2. An object value does not contain the token. - 3. A token is out of range of an array value. - - Use unresolvedTokenIndex to retrieve the token index. - */ - ValueType* Get(ValueType& root, size_t* unresolvedTokenIndex = 0) const { - RAPIDJSON_ASSERT(IsValid()); - ValueType* v = &root; - for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { - switch (v->GetType()) { - case kObjectType: - { - typename ValueType::MemberIterator m = v->FindMember(GenericValue(GenericStringRef(t->name, t->length))); - if (m == v->MemberEnd()) - break; - v = &m->value; - } - continue; - case kArrayType: - if (t->index == kPointerInvalidIndex || t->index >= v->Size()) - break; - v = &((*v)[t->index]); - continue; - default: - break; - } - - // Error: unresolved token - if (unresolvedTokenIndex) - *unresolvedTokenIndex = static_cast(t - tokens_); - return 0; - } - return v; - } - - //! Query a const value in a const subtree. - /*! - \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. - \return Pointer to the value if it can be resolved. Otherwise null. - */ - const ValueType* Get(const ValueType& root, size_t* unresolvedTokenIndex = 0) const { - return Get(const_cast(root), unresolvedTokenIndex); - } - - //@} - - //!@name Query a value with default - //@{ - - //! Query a value in a subtree with default value. - /*! - Similar to Get(), but if the specified value do not exists, it creates all parents and clone the default value. - So that this function always succeed. - - \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. - \param defaultValue Default value to be cloned if the value was not exists. - \param allocator Allocator for creating the values if the specified value or its parents are not exist. - \see Create() - */ - ValueType& GetWithDefault(ValueType& root, const ValueType& defaultValue, typename ValueType::AllocatorType& allocator) const { - bool alreadyExist; - ValueType& v = Create(root, allocator, &alreadyExist); - return alreadyExist ? v : v.CopyFrom(defaultValue, allocator); - } - - //! Query a value in a subtree with default null-terminated string. - ValueType& GetWithDefault(ValueType& root, const Ch* defaultValue, typename ValueType::AllocatorType& allocator) const { - bool alreadyExist; - ValueType& v = Create(root, allocator, &alreadyExist); - return alreadyExist ? v : v.SetString(defaultValue, allocator); - } - -#if RAPIDJSON_HAS_STDSTRING - //! Query a value in a subtree with default std::basic_string. - ValueType& GetWithDefault(ValueType& root, const std::basic_string& defaultValue, typename ValueType::AllocatorType& allocator) const { - bool alreadyExist; - ValueType& v = Create(root, allocator, &alreadyExist); - return alreadyExist ? v : v.SetString(defaultValue, allocator); - } -#endif - - //! Query a value in a subtree with default primitive value. - /*! - \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool - */ - template - RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) - GetWithDefault(ValueType& root, T defaultValue, typename ValueType::AllocatorType& allocator) const { - return GetWithDefault(root, ValueType(defaultValue).Move(), allocator); - } - - //! Query a value in a document with default value. - template - ValueType& GetWithDefault(GenericDocument& document, const ValueType& defaultValue) const { - return GetWithDefault(document, defaultValue, document.GetAllocator()); - } - - //! Query a value in a document with default null-terminated string. - template - ValueType& GetWithDefault(GenericDocument& document, const Ch* defaultValue) const { - return GetWithDefault(document, defaultValue, document.GetAllocator()); - } - -#if RAPIDJSON_HAS_STDSTRING - //! Query a value in a document with default std::basic_string. - template - ValueType& GetWithDefault(GenericDocument& document, const std::basic_string& defaultValue) const { - return GetWithDefault(document, defaultValue, document.GetAllocator()); - } -#endif - - //! Query a value in a document with default primitive value. - /*! - \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool - */ - template - RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) - GetWithDefault(GenericDocument& document, T defaultValue) const { - return GetWithDefault(document, defaultValue, document.GetAllocator()); - } - - //@} - - //!@name Set a value - //@{ - - //! Set a value in a subtree, with move semantics. - /*! - It creates all parents if they are not exist or types are different to the tokens. - So this function always succeeds but potentially remove existing values. - - \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. - \param value Value to be set. - \param allocator Allocator for creating the values if the specified value or its parents are not exist. - \see Create() - */ - ValueType& Set(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const { - return Create(root, allocator) = value; - } - - //! Set a value in a subtree, with copy semantics. - ValueType& Set(ValueType& root, const ValueType& value, typename ValueType::AllocatorType& allocator) const { - return Create(root, allocator).CopyFrom(value, allocator); - } - - //! Set a null-terminated string in a subtree. - ValueType& Set(ValueType& root, const Ch* value, typename ValueType::AllocatorType& allocator) const { - return Create(root, allocator) = ValueType(value, allocator).Move(); - } - -#if RAPIDJSON_HAS_STDSTRING - //! Set a std::basic_string in a subtree. - ValueType& Set(ValueType& root, const std::basic_string& value, typename ValueType::AllocatorType& allocator) const { - return Create(root, allocator) = ValueType(value, allocator).Move(); - } -#endif - - //! Set a primitive value in a subtree. - /*! - \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool - */ - template - RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) - Set(ValueType& root, T value, typename ValueType::AllocatorType& allocator) const { - return Create(root, allocator) = ValueType(value).Move(); - } - - //! Set a value in a document, with move semantics. - template - ValueType& Set(GenericDocument& document, ValueType& value) const { - return Create(document) = value; - } - - //! Set a value in a document, with copy semantics. - template - ValueType& Set(GenericDocument& document, const ValueType& value) const { - return Create(document).CopyFrom(value, document.GetAllocator()); - } - - //! Set a null-terminated string in a document. - template - ValueType& Set(GenericDocument& document, const Ch* value) const { - return Create(document) = ValueType(value, document.GetAllocator()).Move(); - } - -#if RAPIDJSON_HAS_STDSTRING - //! Sets a std::basic_string in a document. - template - ValueType& Set(GenericDocument& document, const std::basic_string& value) const { - return Create(document) = ValueType(value, document.GetAllocator()).Move(); - } -#endif - - //! Set a primitive value in a document. - /*! - \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool - */ - template - RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) - Set(GenericDocument& document, T value) const { - return Create(document) = value; - } - - //@} - - //!@name Swap a value - //@{ - - //! Swap a value with a value in a subtree. - /*! - It creates all parents if they are not exist or types are different to the tokens. - So this function always succeeds but potentially remove existing values. - - \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. - \param value Value to be swapped. - \param allocator Allocator for creating the values if the specified value or its parents are not exist. - \see Create() - */ - ValueType& Swap(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const { - return Create(root, allocator).Swap(value); - } - - //! Swap a value with a value in a document. - template - ValueType& Swap(GenericDocument& document, ValueType& value) const { - return Create(document).Swap(value); - } - - //@} - - //! Erase a value in a subtree. - /*! - \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. - \return Whether the resolved value is found and erased. - - \note Erasing with an empty pointer \c Pointer(""), i.e. the root, always fail and return false. - */ - bool Erase(ValueType& root) const { - RAPIDJSON_ASSERT(IsValid()); - if (tokenCount_ == 0) // Cannot erase the root - return false; - - ValueType* v = &root; - const Token* last = tokens_ + (tokenCount_ - 1); - for (const Token *t = tokens_; t != last; ++t) { - switch (v->GetType()) { - case kObjectType: - { - typename ValueType::MemberIterator m = v->FindMember(GenericValue(GenericStringRef(t->name, t->length))); - if (m == v->MemberEnd()) - return false; - v = &m->value; - } - break; - case kArrayType: - if (t->index == kPointerInvalidIndex || t->index >= v->Size()) - return false; - v = &((*v)[t->index]); - break; - default: - return false; - } - } - - switch (v->GetType()) { - case kObjectType: - return v->EraseMember(GenericStringRef(last->name, last->length)); - case kArrayType: - if (last->index == kPointerInvalidIndex || last->index >= v->Size()) - return false; - v->Erase(v->Begin() + last->index); - return true; - default: - return false; - } - } - -private: - //! Clone the content from rhs to this. - /*! - \param rhs Source pointer. - \param extraToken Extra tokens to be allocated. - \param extraNameBufferSize Extra name buffer size (in number of Ch) to be allocated. - \return Start of non-occupied name buffer, for storing extra names. - */ - Ch* CopyFromRaw(const GenericPointer& rhs, size_t extraToken = 0, size_t extraNameBufferSize = 0) { - if (!allocator_) // allocator is independently owned. - ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); - - size_t nameBufferSize = rhs.tokenCount_; // null terminators for tokens - for (Token *t = rhs.tokens_; t != rhs.tokens_ + rhs.tokenCount_; ++t) - nameBufferSize += t->length; - - tokenCount_ = rhs.tokenCount_ + extraToken; - tokens_ = static_cast(allocator_->Malloc(tokenCount_ * sizeof(Token) + (nameBufferSize + extraNameBufferSize) * sizeof(Ch))); - nameBuffer_ = reinterpret_cast(tokens_ + tokenCount_); - if (rhs.tokenCount_ > 0) { - std::memcpy(tokens_, rhs.tokens_, rhs.tokenCount_ * sizeof(Token)); - } - if (nameBufferSize > 0) { - std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch)); - } - - // Adjust pointers to name buffer - std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_; - for (Token *t = tokens_; t != tokens_ + rhs.tokenCount_; ++t) - t->name += diff; - - return nameBuffer_ + nameBufferSize; - } - - //! Check whether a character should be percent-encoded. - /*! - According to RFC 3986 2.3 Unreserved Characters. - \param c The character (code unit) to be tested. - */ - bool NeedPercentEncode(Ch c) const { - return !((c >= '0' && c <= '9') || (c >= 'A' && c <='Z') || (c >= 'a' && c <= 'z') || c == '-' || c == '.' || c == '_' || c =='~'); - } - - //! Parse a JSON String or its URI fragment representation into tokens. -#ifndef __clang__ // -Wdocumentation - /*! - \param source Either a JSON Pointer string, or its URI fragment representation. Not need to be null terminated. - \param length Length of the source string. - \note Source cannot be JSON String Representation of JSON Pointer, e.g. In "/\u0000", \u0000 will not be unescaped. - */ -#endif - void Parse(const Ch* source, size_t length) { - RAPIDJSON_ASSERT(source != NULL); - RAPIDJSON_ASSERT(nameBuffer_ == 0); - RAPIDJSON_ASSERT(tokens_ == 0); - - // Create own allocator if user did not supply. - if (!allocator_) - ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); - - // Count number of '/' as tokenCount - tokenCount_ = 0; - for (const Ch* s = source; s != source + length; s++) - if (*s == '/') - tokenCount_++; - - Token* token = tokens_ = static_cast(allocator_->Malloc(tokenCount_ * sizeof(Token) + length * sizeof(Ch))); - Ch* name = nameBuffer_ = reinterpret_cast(tokens_ + tokenCount_); - size_t i = 0; - - // Detect if it is a URI fragment - bool uriFragment = false; - if (source[i] == '#') { - uriFragment = true; - i++; - } - - if (i != length && source[i] != '/') { - parseErrorCode_ = kPointerParseErrorTokenMustBeginWithSolidus; - goto error; - } - - while (i < length) { - RAPIDJSON_ASSERT(source[i] == '/'); - i++; // consumes '/' - - token->name = name; - bool isNumber = true; - - while (i < length && source[i] != '/') { - Ch c = source[i]; - if (uriFragment) { - // Decoding percent-encoding for URI fragment - if (c == '%') { - PercentDecodeStream is(&source[i], source + length); - GenericInsituStringStream os(name); - Ch* begin = os.PutBegin(); - if (!Transcoder, EncodingType>().Validate(is, os) || !is.IsValid()) { - parseErrorCode_ = kPointerParseErrorInvalidPercentEncoding; - goto error; - } - size_t len = os.PutEnd(begin); - i += is.Tell() - 1; - if (len == 1) - c = *name; - else { - name += len; - isNumber = false; - i++; - continue; - } - } - else if (NeedPercentEncode(c)) { - parseErrorCode_ = kPointerParseErrorCharacterMustPercentEncode; - goto error; - } - } - - i++; - - // Escaping "~0" -> '~', "~1" -> '/' - if (c == '~') { - if (i < length) { - c = source[i]; - if (c == '0') c = '~'; - else if (c == '1') c = '/'; - else { - parseErrorCode_ = kPointerParseErrorInvalidEscape; - goto error; - } - i++; - } - else { - parseErrorCode_ = kPointerParseErrorInvalidEscape; - goto error; - } - } - - // First check for index: all of characters are digit - if (c < '0' || c > '9') - isNumber = false; - - *name++ = c; - } - token->length = static_cast(name - token->name); - if (token->length == 0) - isNumber = false; - *name++ = '\0'; // Null terminator - - // Second check for index: more than one digit cannot have leading zero - if (isNumber && token->length > 1 && token->name[0] == '0') - isNumber = false; - - // String to SizeType conversion - SizeType n = 0; - if (isNumber) { - for (size_t j = 0; j < token->length; j++) { - SizeType m = n * 10 + static_cast(token->name[j] - '0'); - if (m < n) { // overflow detection - isNumber = false; - break; - } - n = m; - } - } - - token->index = isNumber ? n : kPointerInvalidIndex; - token++; - } - - RAPIDJSON_ASSERT(name <= nameBuffer_ + length); // Should not overflow buffer - parseErrorCode_ = kPointerParseErrorNone; - return; - - error: - Allocator::Free(tokens_); - nameBuffer_ = 0; - tokens_ = 0; - tokenCount_ = 0; - parseErrorOffset_ = i; - return; - } - - //! Stringify to string or URI fragment representation. - /*! - \tparam uriFragment True for stringifying to URI fragment representation. False for string representation. - \tparam OutputStream type of output stream. - \param os The output stream. - */ - template - bool Stringify(OutputStream& os) const { - RAPIDJSON_ASSERT(IsValid()); - - if (uriFragment) - os.Put('#'); - - for (Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { - os.Put('/'); - for (size_t j = 0; j < t->length; j++) { - Ch c = t->name[j]; - if (c == '~') { - os.Put('~'); - os.Put('0'); - } - else if (c == '/') { - os.Put('~'); - os.Put('1'); - } - else if (uriFragment && NeedPercentEncode(c)) { - // Transcode to UTF8 sequence - GenericStringStream source(&t->name[j]); - PercentEncodeStream target(os); - if (!Transcoder >().Validate(source, target)) - return false; - j += source.Tell() - 1; - } - else - os.Put(c); - } - } - return true; - } - - //! A helper stream for decoding a percent-encoded sequence into code unit. - /*! - This stream decodes %XY triplet into code unit (0-255). - If it encounters invalid characters, it sets output code unit as 0 and - mark invalid, and to be checked by IsValid(). - */ - class PercentDecodeStream { - public: - typedef typename ValueType::Ch Ch; - - //! Constructor - /*! - \param source Start of the stream - \param end Past-the-end of the stream. - */ - PercentDecodeStream(const Ch* source, const Ch* end) : src_(source), head_(source), end_(end), valid_(true) {} - - Ch Take() { - if (*src_ != '%' || src_ + 3 > end_) { // %XY triplet - valid_ = false; - return 0; - } - src_++; - Ch c = 0; - for (int j = 0; j < 2; j++) { - c = static_cast(c << 4); - Ch h = *src_; - if (h >= '0' && h <= '9') c = static_cast(c + h - '0'); - else if (h >= 'A' && h <= 'F') c = static_cast(c + h - 'A' + 10); - else if (h >= 'a' && h <= 'f') c = static_cast(c + h - 'a' + 10); - else { - valid_ = false; - return 0; - } - src_++; - } - return c; - } - - size_t Tell() const { return static_cast(src_ - head_); } - bool IsValid() const { return valid_; } - - private: - const Ch* src_; //!< Current read position. - const Ch* head_; //!< Original head of the string. - const Ch* end_; //!< Past-the-end position. - bool valid_; //!< Whether the parsing is valid. - }; - - //! A helper stream to encode character (UTF-8 code unit) into percent-encoded sequence. - template - class PercentEncodeStream { - public: - PercentEncodeStream(OutputStream& os) : os_(os) {} - void Put(char c) { // UTF-8 must be byte - unsigned char u = static_cast(c); - static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; - os_.Put('%'); - os_.Put(static_cast(hexDigits[u >> 4])); - os_.Put(static_cast(hexDigits[u & 15])); - } - private: - OutputStream& os_; - }; - - Allocator* allocator_; //!< The current allocator. It is either user-supplied or equal to ownAllocator_. - Allocator* ownAllocator_; //!< Allocator owned by this Pointer. - Ch* nameBuffer_; //!< A buffer containing all names in tokens. - Token* tokens_; //!< A list of tokens. - size_t tokenCount_; //!< Number of tokens in tokens_. - size_t parseErrorOffset_; //!< Offset in code unit when parsing fail. - PointerParseErrorCode parseErrorCode_; //!< Parsing error code. -}; - -//! GenericPointer for Value (UTF-8, default allocator). -typedef GenericPointer Pointer; - -//!@name Helper functions for GenericPointer -//@{ - -////////////////////////////////////////////////////////////////////////////// - -template -typename T::ValueType& CreateValueByPointer(T& root, const GenericPointer& pointer, typename T::AllocatorType& a) { - return pointer.Create(root, a); -} - -template -typename T::ValueType& CreateValueByPointer(T& root, const CharType(&source)[N], typename T::AllocatorType& a) { - return GenericPointer(source, N - 1).Create(root, a); -} - -// No allocator parameter - -template -typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const GenericPointer& pointer) { - return pointer.Create(document); -} - -template -typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const CharType(&source)[N]) { - return GenericPointer(source, N - 1).Create(document); -} - -////////////////////////////////////////////////////////////////////////////// - -template -typename T::ValueType* GetValueByPointer(T& root, const GenericPointer& pointer, size_t* unresolvedTokenIndex = 0) { - return pointer.Get(root, unresolvedTokenIndex); -} - -template -const typename T::ValueType* GetValueByPointer(const T& root, const GenericPointer& pointer, size_t* unresolvedTokenIndex = 0) { - return pointer.Get(root, unresolvedTokenIndex); -} - -template -typename T::ValueType* GetValueByPointer(T& root, const CharType (&source)[N], size_t* unresolvedTokenIndex = 0) { - return GenericPointer(source, N - 1).Get(root, unresolvedTokenIndex); -} - -template -const typename T::ValueType* GetValueByPointer(const T& root, const CharType(&source)[N], size_t* unresolvedTokenIndex = 0) { - return GenericPointer(source, N - 1).Get(root, unresolvedTokenIndex); -} - -////////////////////////////////////////////////////////////////////////////// - -template -typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer& pointer, const typename T::ValueType& defaultValue, typename T::AllocatorType& a) { - return pointer.GetWithDefault(root, defaultValue, a); -} - -template -typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer& pointer, const typename T::Ch* defaultValue, typename T::AllocatorType& a) { - return pointer.GetWithDefault(root, defaultValue, a); -} - -#if RAPIDJSON_HAS_STDSTRING -template -typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer& pointer, const std::basic_string& defaultValue, typename T::AllocatorType& a) { - return pointer.GetWithDefault(root, defaultValue, a); -} -#endif - -template -RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) -GetValueByPointerWithDefault(T& root, const GenericPointer& pointer, T2 defaultValue, typename T::AllocatorType& a) { - return pointer.GetWithDefault(root, defaultValue, a); -} - -template -typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::ValueType& defaultValue, typename T::AllocatorType& a) { - return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); -} - -template -typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::Ch* defaultValue, typename T::AllocatorType& a) { - return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); -} - -#if RAPIDJSON_HAS_STDSTRING -template -typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const std::basic_string& defaultValue, typename T::AllocatorType& a) { - return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); -} -#endif - -template -RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) -GetValueByPointerWithDefault(T& root, const CharType(&source)[N], T2 defaultValue, typename T::AllocatorType& a) { - return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); -} - -// No allocator parameter - -template -typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, const typename DocumentType::ValueType& defaultValue) { - return pointer.GetWithDefault(document, defaultValue); -} - -template -typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, const typename DocumentType::Ch* defaultValue) { - return pointer.GetWithDefault(document, defaultValue); -} - -#if RAPIDJSON_HAS_STDSTRING -template -typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, const std::basic_string& defaultValue) { - return pointer.GetWithDefault(document, defaultValue); -} -#endif - -template -RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) -GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, T2 defaultValue) { - return pointer.GetWithDefault(document, defaultValue); -} - -template -typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& defaultValue) { - return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); -} - -template -typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* defaultValue) { - return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); -} - -#if RAPIDJSON_HAS_STDSTRING -template -typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const std::basic_string& defaultValue) { - return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); -} -#endif - -template -RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) -GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], T2 defaultValue) { - return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); -} - -////////////////////////////////////////////////////////////////////////////// - -template -typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, typename T::ValueType& value, typename T::AllocatorType& a) { - return pointer.Set(root, value, a); -} - -template -typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, const typename T::ValueType& value, typename T::AllocatorType& a) { - return pointer.Set(root, value, a); -} - -template -typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, const typename T::Ch* value, typename T::AllocatorType& a) { - return pointer.Set(root, value, a); -} - -#if RAPIDJSON_HAS_STDSTRING -template -typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, const std::basic_string& value, typename T::AllocatorType& a) { - return pointer.Set(root, value, a); -} -#endif - -template -RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) -SetValueByPointer(T& root, const GenericPointer& pointer, T2 value, typename T::AllocatorType& a) { - return pointer.Set(root, value, a); -} - -template -typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) { - return GenericPointer(source, N - 1).Set(root, value, a); -} - -template -typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::ValueType& value, typename T::AllocatorType& a) { - return GenericPointer(source, N - 1).Set(root, value, a); -} - -template -typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::Ch* value, typename T::AllocatorType& a) { - return GenericPointer(source, N - 1).Set(root, value, a); -} - -#if RAPIDJSON_HAS_STDSTRING -template -typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const std::basic_string& value, typename T::AllocatorType& a) { - return GenericPointer(source, N - 1).Set(root, value, a); -} -#endif - -template -RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) -SetValueByPointer(T& root, const CharType(&source)[N], T2 value, typename T::AllocatorType& a) { - return GenericPointer(source, N - 1).Set(root, value, a); -} - -// No allocator parameter - -template -typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, typename DocumentType::ValueType& value) { - return pointer.Set(document, value); -} - -template -typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, const typename DocumentType::ValueType& value) { - return pointer.Set(document, value); -} - -template -typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, const typename DocumentType::Ch* value) { - return pointer.Set(document, value); -} - -#if RAPIDJSON_HAS_STDSTRING -template -typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, const std::basic_string& value) { - return pointer.Set(document, value); -} -#endif - -template -RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) -SetValueByPointer(DocumentType& document, const GenericPointer& pointer, T2 value) { - return pointer.Set(document, value); -} - -template -typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) { - return GenericPointer(source, N - 1).Set(document, value); -} - -template -typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& value) { - return GenericPointer(source, N - 1).Set(document, value); -} - -template -typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* value) { - return GenericPointer(source, N - 1).Set(document, value); -} - -#if RAPIDJSON_HAS_STDSTRING -template -typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const std::basic_string& value) { - return GenericPointer(source, N - 1).Set(document, value); -} -#endif - -template -RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) -SetValueByPointer(DocumentType& document, const CharType(&source)[N], T2 value) { - return GenericPointer(source, N - 1).Set(document, value); -} - -////////////////////////////////////////////////////////////////////////////// - -template -typename T::ValueType& SwapValueByPointer(T& root, const GenericPointer& pointer, typename T::ValueType& value, typename T::AllocatorType& a) { - return pointer.Swap(root, value, a); -} - -template -typename T::ValueType& SwapValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) { - return GenericPointer(source, N - 1).Swap(root, value, a); -} - -template -typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const GenericPointer& pointer, typename DocumentType::ValueType& value) { - return pointer.Swap(document, value); -} - -template -typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) { - return GenericPointer(source, N - 1).Swap(document, value); -} - -////////////////////////////////////////////////////////////////////////////// - -template -bool EraseValueByPointer(T& root, const GenericPointer& pointer) { - return pointer.Erase(root); -} - -template -bool EraseValueByPointer(T& root, const CharType(&source)[N]) { - return GenericPointer(source, N - 1).Erase(root); -} - -//@} - -RAPIDJSON_NAMESPACE_END - -#if defined(__clang__) || defined(_MSC_VER) -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_POINTER_H_ diff --git a/external/rapidjson/prettywriter.h b/external/rapidjson/prettywriter.h deleted file mode 100755 index fe45df1..0000000 --- a/external/rapidjson/prettywriter.h +++ /dev/null @@ -1,277 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_PRETTYWRITER_H_ -#define RAPIDJSON_PRETTYWRITER_H_ - -#include "writer.h" - -#ifdef __GNUC__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(effc++) -#endif - -#if defined(__clang__) -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(c++98-compat) -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -//! Combination of PrettyWriter format flags. -/*! \see PrettyWriter::SetFormatOptions - */ -enum PrettyFormatOptions { - kFormatDefault = 0, //!< Default pretty formatting. - kFormatSingleLineArray = 1 //!< Format arrays on a single line. -}; - -//! Writer with indentation and spacing. -/*! - \tparam OutputStream Type of output os. - \tparam SourceEncoding Encoding of source string. - \tparam TargetEncoding Encoding of output stream. - \tparam StackAllocator Type of allocator for allocating memory of stack. -*/ -template, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags> -class PrettyWriter : public Writer { -public: - typedef Writer Base; - typedef typename Base::Ch Ch; - - //! Constructor - /*! \param os Output stream. - \param allocator User supplied allocator. If it is null, it will create a private one. - \param levelDepth Initial capacity of stack. - */ - explicit PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : - Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {} - - - explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : - Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {} - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - PrettyWriter(PrettyWriter&& rhs) : - Base(std::forward(rhs)), indentChar_(rhs.indentChar_), indentCharCount_(rhs.indentCharCount_), formatOptions_(rhs.formatOptions_) {} -#endif - - //! Set custom indentation. - /*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r'). - \param indentCharCount Number of indent characters for each indentation level. - \note The default indentation is 4 spaces. - */ - PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) { - RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r'); - indentChar_ = indentChar; - indentCharCount_ = indentCharCount; - return *this; - } - - //! Set pretty writer formatting options. - /*! \param options Formatting options. - */ - PrettyWriter& SetFormatOptions(PrettyFormatOptions options) { - formatOptions_ = options; - return *this; - } - - /*! @name Implementation of Handler - \see Handler - */ - //@{ - - bool Null() { PrettyPrefix(kNullType); return Base::EndValue(Base::WriteNull()); } - bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::EndValue(Base::WriteBool(b)); } - bool Int(int i) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteInt(i)); } - bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteUint(u)); } - bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteInt64(i64)); } - bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteUint64(u64)); } - bool Double(double d) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteDouble(d)); } - - bool RawNumber(const Ch* str, SizeType length, bool copy = false) { - RAPIDJSON_ASSERT(str != 0); - (void)copy; - PrettyPrefix(kNumberType); - return Base::EndValue(Base::WriteString(str, length)); - } - - bool String(const Ch* str, SizeType length, bool copy = false) { - RAPIDJSON_ASSERT(str != 0); - (void)copy; - PrettyPrefix(kStringType); - return Base::EndValue(Base::WriteString(str, length)); - } - -#if RAPIDJSON_HAS_STDSTRING - bool String(const std::basic_string& str) { - return String(str.data(), SizeType(str.size())); - } -#endif - - bool StartObject() { - PrettyPrefix(kObjectType); - new (Base::level_stack_.template Push()) typename Base::Level(false); - return Base::WriteStartObject(); - } - - bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } - -#if RAPIDJSON_HAS_STDSTRING - bool Key(const std::basic_string& str) { - return Key(str.data(), SizeType(str.size())); - } -#endif - - bool EndObject(SizeType memberCount = 0) { - (void)memberCount; - RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); // not inside an Object - RAPIDJSON_ASSERT(!Base::level_stack_.template Top()->inArray); // currently inside an Array, not Object - RAPIDJSON_ASSERT(0 == Base::level_stack_.template Top()->valueCount % 2); // Object has a Key without a Value - - bool empty = Base::level_stack_.template Pop(1)->valueCount == 0; - - if (!empty) { - Base::os_->Put('\n'); - WriteIndent(); - } - bool ret = Base::EndValue(Base::WriteEndObject()); - (void)ret; - RAPIDJSON_ASSERT(ret == true); - if (Base::level_stack_.Empty()) // end of json text - Base::Flush(); - return true; - } - - bool StartArray() { - PrettyPrefix(kArrayType); - new (Base::level_stack_.template Push()) typename Base::Level(true); - return Base::WriteStartArray(); - } - - bool EndArray(SizeType memberCount = 0) { - (void)memberCount; - RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); - RAPIDJSON_ASSERT(Base::level_stack_.template Top()->inArray); - bool empty = Base::level_stack_.template Pop(1)->valueCount == 0; - - if (!empty && !(formatOptions_ & kFormatSingleLineArray)) { - Base::os_->Put('\n'); - WriteIndent(); - } - bool ret = Base::EndValue(Base::WriteEndArray()); - (void)ret; - RAPIDJSON_ASSERT(ret == true); - if (Base::level_stack_.Empty()) // end of json text - Base::Flush(); - return true; - } - - //@} - - /*! @name Convenience extensions */ - //@{ - - //! Simpler but slower overload. - bool String(const Ch* str) { return String(str, internal::StrLen(str)); } - bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); } - - //@} - - //! Write a raw JSON value. - /*! - For user to write a stringified JSON as a value. - - \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range. - \param length Length of the json. - \param type Type of the root of json. - \note When using PrettyWriter::RawValue(), the result json may not be indented correctly. - */ - bool RawValue(const Ch* json, size_t length, Type type) { - RAPIDJSON_ASSERT(json != 0); - PrettyPrefix(type); - return Base::EndValue(Base::WriteRawValue(json, length)); - } - -protected: - void PrettyPrefix(Type type) { - (void)type; - if (Base::level_stack_.GetSize() != 0) { // this value is not at root - typename Base::Level* level = Base::level_stack_.template Top(); - - if (level->inArray) { - if (level->valueCount > 0) { - Base::os_->Put(','); // add comma if it is not the first element in array - if (formatOptions_ & kFormatSingleLineArray) - Base::os_->Put(' '); - } - - if (!(formatOptions_ & kFormatSingleLineArray)) { - Base::os_->Put('\n'); - WriteIndent(); - } - } - else { // in object - if (level->valueCount > 0) { - if (level->valueCount % 2 == 0) { - Base::os_->Put(','); - Base::os_->Put('\n'); - } - else { - Base::os_->Put(':'); - Base::os_->Put(' '); - } - } - else - Base::os_->Put('\n'); - - if (level->valueCount % 2 == 0) - WriteIndent(); - } - if (!level->inArray && level->valueCount % 2 == 0) - RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name - level->valueCount++; - } - else { - RAPIDJSON_ASSERT(!Base::hasRoot_); // Should only has one and only one root. - Base::hasRoot_ = true; - } - } - - void WriteIndent() { - size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_; - PutN(*Base::os_, static_cast(indentChar_), count); - } - - Ch indentChar_; - unsigned indentCharCount_; - PrettyFormatOptions formatOptions_; - -private: - // Prohibit copy constructor & assignment operator. - PrettyWriter(const PrettyWriter&); - PrettyWriter& operator=(const PrettyWriter&); -}; - -RAPIDJSON_NAMESPACE_END - -#if defined(__clang__) -RAPIDJSON_DIAG_POP -#endif - -#ifdef __GNUC__ -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_RAPIDJSON_H_ diff --git a/external/rapidjson/rapidjson.h b/external/rapidjson/rapidjson.h deleted file mode 100755 index a4e8953..0000000 --- a/external/rapidjson/rapidjson.h +++ /dev/null @@ -1,741 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_RAPIDJSON_H_ -#define RAPIDJSON_RAPIDJSON_H_ - -/*!\file rapidjson.h - \brief common definitions and configuration - - \see RAPIDJSON_CONFIG - */ - -/*! \defgroup RAPIDJSON_CONFIG RapidJSON configuration - \brief Configuration macros for library features - - Some RapidJSON features are configurable to adapt the library to a wide - variety of platforms, environments and usage scenarios. Most of the - features can be configured in terms of overridden or predefined - preprocessor macros at compile-time. - - Some additional customization is available in the \ref RAPIDJSON_ERRORS APIs. - - \note These macros should be given on the compiler command-line - (where applicable) to avoid inconsistent values when compiling - different translation units of a single application. - */ - -#include // malloc(), realloc(), free(), size_t -#include // memset(), memcpy(), memmove(), memcmp() - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_VERSION_STRING -// -// ALWAYS synchronize the following 3 macros with corresponding variables in /CMakeLists.txt. -// - -//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN -// token stringification -#define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x) -#define RAPIDJSON_DO_STRINGIFY(x) #x - -// token concatenation -#define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y) -#define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y) -#define RAPIDJSON_DO_JOIN2(X, Y) X##Y -//!@endcond - -/*! \def RAPIDJSON_MAJOR_VERSION - \ingroup RAPIDJSON_CONFIG - \brief Major version of RapidJSON in integer. -*/ -/*! \def RAPIDJSON_MINOR_VERSION - \ingroup RAPIDJSON_CONFIG - \brief Minor version of RapidJSON in integer. -*/ -/*! \def RAPIDJSON_PATCH_VERSION - \ingroup RAPIDJSON_CONFIG - \brief Patch version of RapidJSON in integer. -*/ -/*! \def RAPIDJSON_VERSION_STRING - \ingroup RAPIDJSON_CONFIG - \brief Version of RapidJSON in ".." string format. -*/ -#define RAPIDJSON_MAJOR_VERSION 1 -#define RAPIDJSON_MINOR_VERSION 1 -#define RAPIDJSON_PATCH_VERSION 0 -#define RAPIDJSON_VERSION_STRING \ - RAPIDJSON_STRINGIFY(RAPIDJSON_MAJOR_VERSION.RAPIDJSON_MINOR_VERSION.RAPIDJSON_PATCH_VERSION) - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_NAMESPACE_(BEGIN|END) -/*! \def RAPIDJSON_NAMESPACE - \ingroup RAPIDJSON_CONFIG - \brief provide custom rapidjson namespace - - In order to avoid symbol clashes and/or "One Definition Rule" errors - between multiple inclusions of (different versions of) RapidJSON in - a single binary, users can customize the name of the main RapidJSON - namespace. - - In case of a single nesting level, defining \c RAPIDJSON_NAMESPACE - to a custom name (e.g. \c MyRapidJSON) is sufficient. If multiple - levels are needed, both \ref RAPIDJSON_NAMESPACE_BEGIN and \ref - RAPIDJSON_NAMESPACE_END need to be defined as well: - - \code - // in some .cpp file - #define RAPIDJSON_NAMESPACE my::rapidjson - #define RAPIDJSON_NAMESPACE_BEGIN namespace my { namespace rapidjson { - #define RAPIDJSON_NAMESPACE_END } } - #include "rapidjson/..." - \endcode - - \see rapidjson - */ -/*! \def RAPIDJSON_NAMESPACE_BEGIN - \ingroup RAPIDJSON_CONFIG - \brief provide custom rapidjson namespace (opening expression) - \see RAPIDJSON_NAMESPACE -*/ -/*! \def RAPIDJSON_NAMESPACE_END - \ingroup RAPIDJSON_CONFIG - \brief provide custom rapidjson namespace (closing expression) - \see RAPIDJSON_NAMESPACE -*/ -#ifndef RAPIDJSON_NAMESPACE -#define RAPIDJSON_NAMESPACE rapidjson -#endif -#ifndef RAPIDJSON_NAMESPACE_BEGIN -#define RAPIDJSON_NAMESPACE_BEGIN namespace RAPIDJSON_NAMESPACE { -#endif -#ifndef RAPIDJSON_NAMESPACE_END -#define RAPIDJSON_NAMESPACE_END } -#endif - -/////////////////////////////////////////////////////////////////////////////// -// __cplusplus macro - -//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN - -#if defined(_MSC_VER) -#define RAPIDJSON_CPLUSPLUS _MSVC_LANG -#else -#define RAPIDJSON_CPLUSPLUS __cplusplus -#endif - -//!@endcond - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_HAS_STDSTRING - -#ifndef RAPIDJSON_HAS_STDSTRING -#ifdef RAPIDJSON_DOXYGEN_RUNNING -#define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation -#else -#define RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default -#endif -/*! \def RAPIDJSON_HAS_STDSTRING - \ingroup RAPIDJSON_CONFIG - \brief Enable RapidJSON support for \c std::string - - By defining this preprocessor symbol to \c 1, several convenience functions for using - \ref rapidjson::GenericValue with \c std::string are enabled, especially - for construction and comparison. - - \hideinitializer -*/ -#endif // !defined(RAPIDJSON_HAS_STDSTRING) - -#if RAPIDJSON_HAS_STDSTRING -#include -#endif // RAPIDJSON_HAS_STDSTRING - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_USE_MEMBERSMAP - -/*! \def RAPIDJSON_USE_MEMBERSMAP - \ingroup RAPIDJSON_CONFIG - \brief Enable RapidJSON support for object members handling in a \c std::multimap - - By defining this preprocessor symbol to \c 1, \ref rapidjson::GenericValue object - members are stored in a \c std::multimap for faster lookup and deletion times, a - trade off with a slightly slower insertion time and a small object allocat(or)ed - memory overhead. - - \hideinitializer -*/ -#ifndef RAPIDJSON_USE_MEMBERSMAP -#define RAPIDJSON_USE_MEMBERSMAP 0 // not by default -#endif - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_NO_INT64DEFINE - -/*! \def RAPIDJSON_NO_INT64DEFINE - \ingroup RAPIDJSON_CONFIG - \brief Use external 64-bit integer types. - - RapidJSON requires the 64-bit integer types \c int64_t and \c uint64_t types - to be available at global scope. - - If users have their own definition, define RAPIDJSON_NO_INT64DEFINE to - prevent RapidJSON from defining its own types. -*/ -#ifndef RAPIDJSON_NO_INT64DEFINE -//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN -#if defined(_MSC_VER) && (_MSC_VER < 1800) // Visual Studio 2013 -#include "msinttypes/stdint.h" -#include "msinttypes/inttypes.h" -#else -// Other compilers should have this. -#include -#include -#endif -//!@endcond -#ifdef RAPIDJSON_DOXYGEN_RUNNING -#define RAPIDJSON_NO_INT64DEFINE -#endif -#endif // RAPIDJSON_NO_INT64TYPEDEF - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_FORCEINLINE - -#ifndef RAPIDJSON_FORCEINLINE -//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN -#if defined(_MSC_VER) && defined(NDEBUG) -#define RAPIDJSON_FORCEINLINE __forceinline -#elif defined(__GNUC__) && __GNUC__ >= 4 && defined(NDEBUG) -#define RAPIDJSON_FORCEINLINE __attribute__((always_inline)) -#else -#define RAPIDJSON_FORCEINLINE -#endif -//!@endcond -#endif // RAPIDJSON_FORCEINLINE - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_ENDIAN -#define RAPIDJSON_LITTLEENDIAN 0 //!< Little endian machine -#define RAPIDJSON_BIGENDIAN 1 //!< Big endian machine - -//! Endianness of the machine. -/*! - \def RAPIDJSON_ENDIAN - \ingroup RAPIDJSON_CONFIG - - GCC 4.6 provided macro for detecting endianness of the target machine. But other - compilers may not have this. User can define RAPIDJSON_ENDIAN to either - \ref RAPIDJSON_LITTLEENDIAN or \ref RAPIDJSON_BIGENDIAN. - - Default detection implemented with reference to - \li https://gcc.gnu.org/onlinedocs/gcc-4.6.0/cpp/Common-Predefined-Macros.html - \li http://www.boost.org/doc/libs/1_42_0/boost/detail/endian.hpp -*/ -#ifndef RAPIDJSON_ENDIAN -// Detect with GCC 4.6's macro -# ifdef __BYTE_ORDER__ -# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN -# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ -# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN -# else -# error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN. -# endif // __BYTE_ORDER__ -// Detect with GLIBC's endian.h -# elif defined(__GLIBC__) -# include -# if (__BYTE_ORDER == __LITTLE_ENDIAN) -# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN -# elif (__BYTE_ORDER == __BIG_ENDIAN) -# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN -# else -# error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN. -# endif // __GLIBC__ -// Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro -# elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN) -# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN -# elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN) -# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN -// Detect with architecture macros -# elif defined(__sparc) || defined(__sparc__) || defined(_POWER) || defined(__powerpc__) || defined(__ppc__) || defined(__hpux) || defined(__hppa) || defined(_MIPSEB) || defined(_POWER) || defined(__s390__) -# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN -# elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__) -# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN -# elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64)) -# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN -# elif defined(RAPIDJSON_DOXYGEN_RUNNING) -# define RAPIDJSON_ENDIAN -# else -# error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN. -# endif -#endif // RAPIDJSON_ENDIAN - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_64BIT - -//! Whether using 64-bit architecture -#ifndef RAPIDJSON_64BIT -#if defined(__LP64__) || (defined(__x86_64__) && defined(__ILP32__)) || defined(_WIN64) || defined(__EMSCRIPTEN__) -#define RAPIDJSON_64BIT 1 -#else -#define RAPIDJSON_64BIT 0 -#endif -#endif // RAPIDJSON_64BIT - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_ALIGN - -//! Data alignment of the machine. -/*! \ingroup RAPIDJSON_CONFIG - \param x pointer to align - - Some machines require strict data alignment. The default is 8 bytes. - User can customize by defining the RAPIDJSON_ALIGN function macro. -*/ -#ifndef RAPIDJSON_ALIGN -#define RAPIDJSON_ALIGN(x) (((x) + static_cast(7u)) & ~static_cast(7u)) -#endif - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_UINT64_C2 - -//! Construct a 64-bit literal by a pair of 32-bit integer. -/*! - 64-bit literal with or without ULL suffix is prone to compiler warnings. - UINT64_C() is C macro which cause compilation problems. - Use this macro to define 64-bit constants by a pair of 32-bit integer. -*/ -#ifndef RAPIDJSON_UINT64_C2 -#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast(high32) << 32) | static_cast(low32)) -#endif - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_48BITPOINTER_OPTIMIZATION - -//! Use only lower 48-bit address for some pointers. -/*! - \ingroup RAPIDJSON_CONFIG - - This optimization uses the fact that current X86-64 architecture only implement lower 48-bit virtual address. - The higher 16-bit can be used for storing other data. - \c GenericValue uses this optimization to reduce its size form 24 bytes to 16 bytes in 64-bit architecture. -*/ -#ifndef RAPIDJSON_48BITPOINTER_OPTIMIZATION -#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64) -#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 1 -#else -#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 0 -#endif -#endif // RAPIDJSON_48BITPOINTER_OPTIMIZATION - -#if RAPIDJSON_48BITPOINTER_OPTIMIZATION == 1 -#if RAPIDJSON_64BIT != 1 -#error RAPIDJSON_48BITPOINTER_OPTIMIZATION can only be set to 1 when RAPIDJSON_64BIT=1 -#endif -#define RAPIDJSON_SETPOINTER(type, p, x) (p = reinterpret_cast((reinterpret_cast(p) & static_cast(RAPIDJSON_UINT64_C2(0xFFFF0000, 0x00000000))) | reinterpret_cast(reinterpret_cast(x)))) -#define RAPIDJSON_GETPOINTER(type, p) (reinterpret_cast(reinterpret_cast(p) & static_cast(RAPIDJSON_UINT64_C2(0x0000FFFF, 0xFFFFFFFF)))) -#else -#define RAPIDJSON_SETPOINTER(type, p, x) (p = (x)) -#define RAPIDJSON_GETPOINTER(type, p) (p) -#endif - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_NEON/RAPIDJSON_SIMD - -/*! \def RAPIDJSON_SIMD - \ingroup RAPIDJSON_CONFIG - \brief Enable SSE2/SSE4.2/Neon optimization. - - RapidJSON supports optimized implementations for some parsing operations - based on the SSE2, SSE4.2 or NEon SIMD extensions on modern Intel - or ARM compatible processors. - - To enable these optimizations, three different symbols can be defined; - \code - // Enable SSE2 optimization. - #define RAPIDJSON_SSE2 - - // Enable SSE4.2 optimization. - #define RAPIDJSON_SSE42 - \endcode - - // Enable ARM Neon optimization. - #define RAPIDJSON_NEON - \endcode - - \c RAPIDJSON_SSE42 takes precedence over SSE2, if both are defined. - - If any of these symbols is defined, RapidJSON defines the macro - \c RAPIDJSON_SIMD to indicate the availability of the optimized code. -*/ -#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) \ - || defined(RAPIDJSON_NEON) || defined(RAPIDJSON_DOXYGEN_RUNNING) -#define RAPIDJSON_SIMD -#endif - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_NO_SIZETYPEDEFINE - -#ifndef RAPIDJSON_NO_SIZETYPEDEFINE -/*! \def RAPIDJSON_NO_SIZETYPEDEFINE - \ingroup RAPIDJSON_CONFIG - \brief User-provided \c SizeType definition. - - In order to avoid using 32-bit size types for indexing strings and arrays, - define this preprocessor symbol and provide the type rapidjson::SizeType - before including RapidJSON: - \code - #define RAPIDJSON_NO_SIZETYPEDEFINE - namespace rapidjson { typedef ::std::size_t SizeType; } - #include "rapidjson/..." - \endcode - - \see rapidjson::SizeType -*/ -#ifdef RAPIDJSON_DOXYGEN_RUNNING -#define RAPIDJSON_NO_SIZETYPEDEFINE -#endif -RAPIDJSON_NAMESPACE_BEGIN -//! Size type (for string lengths, array sizes, etc.) -/*! RapidJSON uses 32-bit array/string indices even on 64-bit platforms, - instead of using \c size_t. Users may override the SizeType by defining - \ref RAPIDJSON_NO_SIZETYPEDEFINE. -*/ -typedef unsigned SizeType; -RAPIDJSON_NAMESPACE_END -#endif - -// always import std::size_t to rapidjson namespace -RAPIDJSON_NAMESPACE_BEGIN -using std::size_t; -RAPIDJSON_NAMESPACE_END - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_ASSERT - -//! Assertion. -/*! \ingroup RAPIDJSON_CONFIG - By default, rapidjson uses C \c assert() for internal assertions. - User can override it by defining RAPIDJSON_ASSERT(x) macro. - - \note Parsing errors are handled and can be customized by the - \ref RAPIDJSON_ERRORS APIs. -*/ -#ifndef RAPIDJSON_ASSERT -#include -#define RAPIDJSON_ASSERT(x) assert(x) -#endif // RAPIDJSON_ASSERT - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_STATIC_ASSERT - -// Prefer C++11 static_assert, if available -#ifndef RAPIDJSON_STATIC_ASSERT -#if RAPIDJSON_CPLUSPLUS >= 201103L || ( defined(_MSC_VER) && _MSC_VER >= 1800 ) -#define RAPIDJSON_STATIC_ASSERT(x) \ - static_assert(x, RAPIDJSON_STRINGIFY(x)) -#endif // C++11 -#endif // RAPIDJSON_STATIC_ASSERT - -// Adopt C++03 implementation from boost -#ifndef RAPIDJSON_STATIC_ASSERT -#ifndef __clang__ -//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN -#endif -RAPIDJSON_NAMESPACE_BEGIN -template struct STATIC_ASSERTION_FAILURE; -template <> struct STATIC_ASSERTION_FAILURE { enum { value = 1 }; }; -template struct StaticAssertTest {}; -RAPIDJSON_NAMESPACE_END - -#if defined(__GNUC__) || defined(__clang__) -#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused)) -#else -#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE -#endif -#ifndef __clang__ -//!@endcond -#endif - -/*! \def RAPIDJSON_STATIC_ASSERT - \brief (Internal) macro to check for conditions at compile-time - \param x compile-time condition - \hideinitializer - */ -#define RAPIDJSON_STATIC_ASSERT(x) \ - typedef ::RAPIDJSON_NAMESPACE::StaticAssertTest< \ - sizeof(::RAPIDJSON_NAMESPACE::STATIC_ASSERTION_FAILURE)> \ - RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE -#endif // RAPIDJSON_STATIC_ASSERT - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_LIKELY, RAPIDJSON_UNLIKELY - -//! Compiler branching hint for expression with high probability to be true. -/*! - \ingroup RAPIDJSON_CONFIG - \param x Boolean expression likely to be true. -*/ -#ifndef RAPIDJSON_LIKELY -#if defined(__GNUC__) || defined(__clang__) -#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1) -#else -#define RAPIDJSON_LIKELY(x) (x) -#endif -#endif - -//! Compiler branching hint for expression with low probability to be true. -/*! - \ingroup RAPIDJSON_CONFIG - \param x Boolean expression unlikely to be true. -*/ -#ifndef RAPIDJSON_UNLIKELY -#if defined(__GNUC__) || defined(__clang__) -#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0) -#else -#define RAPIDJSON_UNLIKELY(x) (x) -#endif -#endif - -/////////////////////////////////////////////////////////////////////////////// -// Helpers - -//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN - -#define RAPIDJSON_MULTILINEMACRO_BEGIN do { -#define RAPIDJSON_MULTILINEMACRO_END \ -} while((void)0, 0) - -// adopted from Boost -#define RAPIDJSON_VERSION_CODE(x,y,z) \ - (((x)*100000) + ((y)*100) + (z)) - -#if defined(__has_builtin) -#define RAPIDJSON_HAS_BUILTIN(x) __has_builtin(x) -#else -#define RAPIDJSON_HAS_BUILTIN(x) 0 -#endif - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF - -#if defined(__GNUC__) -#define RAPIDJSON_GNUC \ - RAPIDJSON_VERSION_CODE(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__) -#endif - -#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,2,0)) - -#define RAPIDJSON_PRAGMA(x) _Pragma(RAPIDJSON_STRINGIFY(x)) -#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(GCC diagnostic x) -#define RAPIDJSON_DIAG_OFF(x) \ - RAPIDJSON_DIAG_PRAGMA(ignored RAPIDJSON_STRINGIFY(RAPIDJSON_JOIN(-W,x))) - -// push/pop support in Clang and GCC>=4.6 -#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) -#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push) -#define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop) -#else // GCC >= 4.2, < 4.6 -#define RAPIDJSON_DIAG_PUSH /* ignored */ -#define RAPIDJSON_DIAG_POP /* ignored */ -#endif - -#elif defined(_MSC_VER) - -// pragma (MSVC specific) -#define RAPIDJSON_PRAGMA(x) __pragma(x) -#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(warning(x)) - -#define RAPIDJSON_DIAG_OFF(x) RAPIDJSON_DIAG_PRAGMA(disable: x) -#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push) -#define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop) - -#else - -#define RAPIDJSON_DIAG_OFF(x) /* ignored */ -#define RAPIDJSON_DIAG_PUSH /* ignored */ -#define RAPIDJSON_DIAG_POP /* ignored */ - -#endif // RAPIDJSON_DIAG_* - -/////////////////////////////////////////////////////////////////////////////// -// C++11 features - -#ifndef RAPIDJSON_HAS_CXX11 -#define RAPIDJSON_HAS_CXX11 (RAPIDJSON_CPLUSPLUS >= 201103L) -#endif - -#ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS -#if RAPIDJSON_HAS_CXX11 -#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 -#elif defined(__clang__) -#if __has_feature(cxx_rvalue_references) && \ - (defined(_MSC_VER) || defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306) -#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 -#else -#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0 -#endif -#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ - (defined(_MSC_VER) && _MSC_VER >= 1600) || \ - (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__)) - -#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 -#else -#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0 -#endif -#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS -#include // std::move -#endif - -#ifndef RAPIDJSON_HAS_CXX11_NOEXCEPT -#if RAPIDJSON_HAS_CXX11 -#define RAPIDJSON_HAS_CXX11_NOEXCEPT 1 -#elif defined(__clang__) -#define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept) -#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ - (defined(_MSC_VER) && _MSC_VER >= 1900) || \ - (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__)) -#define RAPIDJSON_HAS_CXX11_NOEXCEPT 1 -#else -#define RAPIDJSON_HAS_CXX11_NOEXCEPT 0 -#endif -#endif -#ifndef RAPIDJSON_NOEXCEPT -#if RAPIDJSON_HAS_CXX11_NOEXCEPT -#define RAPIDJSON_NOEXCEPT noexcept -#else -#define RAPIDJSON_NOEXCEPT throw() -#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT -#endif - -// no automatic detection, yet -#ifndef RAPIDJSON_HAS_CXX11_TYPETRAITS -#if (defined(_MSC_VER) && _MSC_VER >= 1700) -#define RAPIDJSON_HAS_CXX11_TYPETRAITS 1 -#else -#define RAPIDJSON_HAS_CXX11_TYPETRAITS 0 -#endif -#endif - -#ifndef RAPIDJSON_HAS_CXX11_RANGE_FOR -#if defined(__clang__) -#define RAPIDJSON_HAS_CXX11_RANGE_FOR __has_feature(cxx_range_for) -#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ - (defined(_MSC_VER) && _MSC_VER >= 1700) || \ - (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__)) -#define RAPIDJSON_HAS_CXX11_RANGE_FOR 1 -#else -#define RAPIDJSON_HAS_CXX11_RANGE_FOR 0 -#endif -#endif // RAPIDJSON_HAS_CXX11_RANGE_FOR - -/////////////////////////////////////////////////////////////////////////////// -// C++17 features - -#ifndef RAPIDJSON_HAS_CXX17 -#define RAPIDJSON_HAS_CXX17 (RAPIDJSON_CPLUSPLUS >= 201703L) -#endif - -#if RAPIDJSON_HAS_CXX17 -# define RAPIDJSON_DELIBERATE_FALLTHROUGH [[fallthrough]] -#elif defined(__has_cpp_attribute) -# if __has_cpp_attribute(clang::fallthrough) -# define RAPIDJSON_DELIBERATE_FALLTHROUGH [[clang::fallthrough]] -# elif __has_cpp_attribute(fallthrough) -# define RAPIDJSON_DELIBERATE_FALLTHROUGH __attribute__((fallthrough)) -# else -# define RAPIDJSON_DELIBERATE_FALLTHROUGH -# endif -#else -# define RAPIDJSON_DELIBERATE_FALLTHROUGH -#endif - -//!@endcond - -//! Assertion (in non-throwing contexts). - /*! \ingroup RAPIDJSON_CONFIG - Some functions provide a \c noexcept guarantee, if the compiler supports it. - In these cases, the \ref RAPIDJSON_ASSERT macro cannot be overridden to - throw an exception. This macro adds a separate customization point for - such cases. - - Defaults to C \c assert() (as \ref RAPIDJSON_ASSERT), if \c noexcept is - supported, and to \ref RAPIDJSON_ASSERT otherwise. - */ - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_NOEXCEPT_ASSERT - -#ifndef RAPIDJSON_NOEXCEPT_ASSERT -#ifdef RAPIDJSON_ASSERT_THROWS -#include -#define RAPIDJSON_NOEXCEPT_ASSERT(x) assert(x) -#else -#define RAPIDJSON_NOEXCEPT_ASSERT(x) RAPIDJSON_ASSERT(x) -#endif // RAPIDJSON_ASSERT_THROWS -#endif // RAPIDJSON_NOEXCEPT_ASSERT - -/////////////////////////////////////////////////////////////////////////////// -// malloc/realloc/free - -#ifndef RAPIDJSON_MALLOC -///! customization point for global \c malloc -#define RAPIDJSON_MALLOC(size) std::malloc(size) -#endif -#ifndef RAPIDJSON_REALLOC -///! customization point for global \c realloc -#define RAPIDJSON_REALLOC(ptr, new_size) std::realloc(ptr, new_size) -#endif -#ifndef RAPIDJSON_FREE -///! customization point for global \c free -#define RAPIDJSON_FREE(ptr) std::free(ptr) -#endif - -/////////////////////////////////////////////////////////////////////////////// -// new/delete - -#ifndef RAPIDJSON_NEW -///! customization point for global \c new -#define RAPIDJSON_NEW(TypeName) new TypeName -#endif -#ifndef RAPIDJSON_DELETE -///! customization point for global \c delete -#define RAPIDJSON_DELETE(x) delete x -#endif - -/////////////////////////////////////////////////////////////////////////////// -// Type - -/*! \namespace rapidjson - \brief main RapidJSON namespace - \see RAPIDJSON_NAMESPACE -*/ -RAPIDJSON_NAMESPACE_BEGIN - -//! Type of JSON value -enum Type { - kNullType = 0, //!< null - kFalseType = 1, //!< false - kTrueType = 2, //!< true - kObjectType = 3, //!< object - kArrayType = 4, //!< array - kStringType = 5, //!< string - kNumberType = 6 //!< number -}; - -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_RAPIDJSON_H_ diff --git a/external/rapidjson/reader.h b/external/rapidjson/reader.h deleted file mode 100755 index 09ace4e..0000000 --- a/external/rapidjson/reader.h +++ /dev/null @@ -1,2244 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_READER_H_ -#define RAPIDJSON_READER_H_ - -/*! \file reader.h */ - -#include "allocators.h" -#include "stream.h" -#include "encodedstream.h" -#include "internal/clzll.h" -#include "internal/meta.h" -#include "internal/stack.h" -#include "internal/strtod.h" -#include - -#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER) -#include -#pragma intrinsic(_BitScanForward) -#endif -#ifdef RAPIDJSON_SSE42 -#include -#elif defined(RAPIDJSON_SSE2) -#include -#elif defined(RAPIDJSON_NEON) -#include -#endif - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(old-style-cast) -RAPIDJSON_DIAG_OFF(padded) -RAPIDJSON_DIAG_OFF(switch-enum) -#elif defined(_MSC_VER) -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant -RAPIDJSON_DIAG_OFF(4702) // unreachable code -#endif - -#ifdef __GNUC__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(effc++) -#endif - -//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN -#define RAPIDJSON_NOTHING /* deliberately empty */ -#ifndef RAPIDJSON_PARSE_ERROR_EARLY_RETURN -#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN(value) \ - RAPIDJSON_MULTILINEMACRO_BEGIN \ - if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \ - RAPIDJSON_MULTILINEMACRO_END -#endif -#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID \ - RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING) -//!@endcond - -/*! \def RAPIDJSON_PARSE_ERROR_NORETURN - \ingroup RAPIDJSON_ERRORS - \brief Macro to indicate a parse error. - \param parseErrorCode \ref rapidjson::ParseErrorCode of the error - \param offset position of the error in JSON input (\c size_t) - - This macros can be used as a customization point for the internal - error handling mechanism of RapidJSON. - - A common usage model is to throw an exception instead of requiring the - caller to explicitly check the \ref rapidjson::GenericReader::Parse's - return value: - - \code - #define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode,offset) \ - throw ParseException(parseErrorCode, #parseErrorCode, offset) - - #include // std::runtime_error - #include "rapidjson/error/error.h" // rapidjson::ParseResult - - struct ParseException : std::runtime_error, rapidjson::ParseResult { - ParseException(rapidjson::ParseErrorCode code, const char* msg, size_t offset) - : std::runtime_error(msg), ParseResult(code, offset) {} - }; - - #include "rapidjson/reader.h" - \endcode - - \see RAPIDJSON_PARSE_ERROR, rapidjson::GenericReader::Parse - */ -#ifndef RAPIDJSON_PARSE_ERROR_NORETURN -#define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset) \ - RAPIDJSON_MULTILINEMACRO_BEGIN \ - RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \ - SetParseError(parseErrorCode, offset); \ - RAPIDJSON_MULTILINEMACRO_END -#endif - -/*! \def RAPIDJSON_PARSE_ERROR - \ingroup RAPIDJSON_ERRORS - \brief (Internal) macro to indicate and handle a parse error. - \param parseErrorCode \ref rapidjson::ParseErrorCode of the error - \param offset position of the error in JSON input (\c size_t) - - Invokes RAPIDJSON_PARSE_ERROR_NORETURN and stops the parsing. - - \see RAPIDJSON_PARSE_ERROR_NORETURN - \hideinitializer - */ -#ifndef RAPIDJSON_PARSE_ERROR -#define RAPIDJSON_PARSE_ERROR(parseErrorCode, offset) \ - RAPIDJSON_MULTILINEMACRO_BEGIN \ - RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \ - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \ - RAPIDJSON_MULTILINEMACRO_END -#endif - -#include "error/error.h" // ParseErrorCode, ParseResult - -RAPIDJSON_NAMESPACE_BEGIN - -/////////////////////////////////////////////////////////////////////////////// -// ParseFlag - -/*! \def RAPIDJSON_PARSE_DEFAULT_FLAGS - \ingroup RAPIDJSON_CONFIG - \brief User-defined kParseDefaultFlags definition. - - User can define this as any \c ParseFlag combinations. -*/ -#ifndef RAPIDJSON_PARSE_DEFAULT_FLAGS -#define RAPIDJSON_PARSE_DEFAULT_FLAGS kParseNoFlags -#endif - -//! Combination of parseFlags -/*! \see Reader::Parse, Document::Parse, Document::ParseInsitu, Document::ParseStream - */ -enum ParseFlag { - kParseNoFlags = 0, //!< No flags are set. - kParseInsituFlag = 1, //!< In-situ(destructive) parsing. - kParseValidateEncodingFlag = 2, //!< Validate encoding of JSON strings. - kParseIterativeFlag = 4, //!< Iterative(constant complexity in terms of function call stack size) parsing. - kParseStopWhenDoneFlag = 8, //!< After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate kParseErrorDocumentRootNotSingular error. - kParseFullPrecisionFlag = 16, //!< Parse number in full precision (but slower). - kParseCommentsFlag = 32, //!< Allow one-line (//) and multi-line (/**/) comments. - kParseNumbersAsStringsFlag = 64, //!< Parse all numbers (ints/doubles) as strings. - kParseTrailingCommasFlag = 128, //!< Allow trailing commas at the end of objects and arrays. - kParseNanAndInfFlag = 256, //!< Allow parsing NaN, Inf, Infinity, -Inf and -Infinity as doubles. - kParseEscapedApostropheFlag = 512, //!< Allow escaped apostrophe in strings. - kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS -}; - -/////////////////////////////////////////////////////////////////////////////// -// Handler - -/*! \class rapidjson::Handler - \brief Concept for receiving events from GenericReader upon parsing. - The functions return true if no error occurs. If they return false, - the event publisher should terminate the process. -\code -concept Handler { - typename Ch; - - bool Null(); - bool Bool(bool b); - bool Int(int i); - bool Uint(unsigned i); - bool Int64(int64_t i); - bool Uint64(uint64_t i); - bool Double(double d); - /// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (use length) - bool RawNumber(const Ch* str, SizeType length, bool copy); - bool String(const Ch* str, SizeType length, bool copy); - bool StartObject(); - bool Key(const Ch* str, SizeType length, bool copy); - bool EndObject(SizeType memberCount); - bool StartArray(); - bool EndArray(SizeType elementCount); -}; -\endcode -*/ -/////////////////////////////////////////////////////////////////////////////// -// BaseReaderHandler - -//! Default implementation of Handler. -/*! This can be used as base class of any reader handler. - \note implements Handler concept -*/ -template, typename Derived = void> -struct BaseReaderHandler { - typedef typename Encoding::Ch Ch; - - typedef typename internal::SelectIf, BaseReaderHandler, Derived>::Type Override; - - bool Default() { return true; } - bool Null() { return static_cast(*this).Default(); } - bool Bool(bool) { return static_cast(*this).Default(); } - bool Int(int) { return static_cast(*this).Default(); } - bool Uint(unsigned) { return static_cast(*this).Default(); } - bool Int64(int64_t) { return static_cast(*this).Default(); } - bool Uint64(uint64_t) { return static_cast(*this).Default(); } - bool Double(double) { return static_cast(*this).Default(); } - /// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (use length) - bool RawNumber(const Ch* str, SizeType len, bool copy) { return static_cast(*this).String(str, len, copy); } - bool String(const Ch*, SizeType, bool) { return static_cast(*this).Default(); } - bool StartObject() { return static_cast(*this).Default(); } - bool Key(const Ch* str, SizeType len, bool copy) { return static_cast(*this).String(str, len, copy); } - bool EndObject(SizeType) { return static_cast(*this).Default(); } - bool StartArray() { return static_cast(*this).Default(); } - bool EndArray(SizeType) { return static_cast(*this).Default(); } -}; - -/////////////////////////////////////////////////////////////////////////////// -// StreamLocalCopy - -namespace internal { - -template::copyOptimization> -class StreamLocalCopy; - -//! Do copy optimization. -template -class StreamLocalCopy { -public: - StreamLocalCopy(Stream& original) : s(original), original_(original) {} - ~StreamLocalCopy() { original_ = s; } - - Stream s; - -private: - StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */; - - Stream& original_; -}; - -//! Keep reference. -template -class StreamLocalCopy { -public: - StreamLocalCopy(Stream& original) : s(original) {} - - Stream& s; - -private: - StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */; -}; - -} // namespace internal - -/////////////////////////////////////////////////////////////////////////////// -// SkipWhitespace - -//! Skip the JSON white spaces in a stream. -/*! \param is A input stream for skipping white spaces. - \note This function has SSE2/SSE4.2 specialization. -*/ -template -void SkipWhitespace(InputStream& is) { - internal::StreamLocalCopy copy(is); - InputStream& s(copy.s); - - typename InputStream::Ch c; - while ((c = s.Peek()) == ' ' || c == '\n' || c == '\r' || c == '\t') - s.Take(); -} - -inline const char* SkipWhitespace(const char* p, const char* end) { - while (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) - ++p; - return p; -} - -#ifdef RAPIDJSON_SSE42 -//! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once. -inline const char *SkipWhitespace_SIMD(const char* p) { - // Fast return for single non-whitespace - if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') - ++p; - else - return p; - - // 16-byte align to the next boundary - const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); - while (p != nextAligned) - if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') - ++p; - else - return p; - - // The rest of string using SIMD - static const char whitespace[16] = " \n\r\t"; - const __m128i w = _mm_loadu_si128(reinterpret_cast(&whitespace[0])); - - for (;; p += 16) { - const __m128i s = _mm_load_si128(reinterpret_cast(p)); - const int r = _mm_cmpistri(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT | _SIDD_NEGATIVE_POLARITY); - if (r != 16) // some of characters is non-whitespace - return p + r; - } -} - -inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { - // Fast return for single non-whitespace - if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) - ++p; - else - return p; - - // The middle of string using SIMD - static const char whitespace[16] = " \n\r\t"; - const __m128i w = _mm_loadu_si128(reinterpret_cast(&whitespace[0])); - - for (; p <= end - 16; p += 16) { - const __m128i s = _mm_loadu_si128(reinterpret_cast(p)); - const int r = _mm_cmpistri(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT | _SIDD_NEGATIVE_POLARITY); - if (r != 16) // some of characters is non-whitespace - return p + r; - } - - return SkipWhitespace(p, end); -} - -#elif defined(RAPIDJSON_SSE2) - -//! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once. -inline const char *SkipWhitespace_SIMD(const char* p) { - // Fast return for single non-whitespace - if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') - ++p; - else - return p; - - // 16-byte align to the next boundary - const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); - while (p != nextAligned) - if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') - ++p; - else - return p; - - // The rest of string - #define C16(c) { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c } - static const char whitespaces[4][16] = { C16(' '), C16('\n'), C16('\r'), C16('\t') }; - #undef C16 - - const __m128i w0 = _mm_loadu_si128(reinterpret_cast(&whitespaces[0][0])); - const __m128i w1 = _mm_loadu_si128(reinterpret_cast(&whitespaces[1][0])); - const __m128i w2 = _mm_loadu_si128(reinterpret_cast(&whitespaces[2][0])); - const __m128i w3 = _mm_loadu_si128(reinterpret_cast(&whitespaces[3][0])); - - for (;; p += 16) { - const __m128i s = _mm_load_si128(reinterpret_cast(p)); - __m128i x = _mm_cmpeq_epi8(s, w0); - x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1)); - x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2)); - x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3)); - unsigned short r = static_cast(~_mm_movemask_epi8(x)); - if (r != 0) { // some of characters may be non-whitespace -#ifdef _MSC_VER // Find the index of first non-whitespace - unsigned long offset; - _BitScanForward(&offset, r); - return p + offset; -#else - return p + __builtin_ffs(r) - 1; -#endif - } - } -} - -inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { - // Fast return for single non-whitespace - if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) - ++p; - else - return p; - - // The rest of string - #define C16(c) { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c } - static const char whitespaces[4][16] = { C16(' '), C16('\n'), C16('\r'), C16('\t') }; - #undef C16 - - const __m128i w0 = _mm_loadu_si128(reinterpret_cast(&whitespaces[0][0])); - const __m128i w1 = _mm_loadu_si128(reinterpret_cast(&whitespaces[1][0])); - const __m128i w2 = _mm_loadu_si128(reinterpret_cast(&whitespaces[2][0])); - const __m128i w3 = _mm_loadu_si128(reinterpret_cast(&whitespaces[3][0])); - - for (; p <= end - 16; p += 16) { - const __m128i s = _mm_loadu_si128(reinterpret_cast(p)); - __m128i x = _mm_cmpeq_epi8(s, w0); - x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1)); - x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2)); - x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3)); - unsigned short r = static_cast(~_mm_movemask_epi8(x)); - if (r != 0) { // some of characters may be non-whitespace -#ifdef _MSC_VER // Find the index of first non-whitespace - unsigned long offset; - _BitScanForward(&offset, r); - return p + offset; -#else - return p + __builtin_ffs(r) - 1; -#endif - } - } - - return SkipWhitespace(p, end); -} - -#elif defined(RAPIDJSON_NEON) - -//! Skip whitespace with ARM Neon instructions, testing 16 8-byte characters at once. -inline const char *SkipWhitespace_SIMD(const char* p) { - // Fast return for single non-whitespace - if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') - ++p; - else - return p; - - // 16-byte align to the next boundary - const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); - while (p != nextAligned) - if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') - ++p; - else - return p; - - const uint8x16_t w0 = vmovq_n_u8(' '); - const uint8x16_t w1 = vmovq_n_u8('\n'); - const uint8x16_t w2 = vmovq_n_u8('\r'); - const uint8x16_t w3 = vmovq_n_u8('\t'); - - for (;; p += 16) { - const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); - uint8x16_t x = vceqq_u8(s, w0); - x = vorrq_u8(x, vceqq_u8(s, w1)); - x = vorrq_u8(x, vceqq_u8(s, w2)); - x = vorrq_u8(x, vceqq_u8(s, w3)); - - x = vmvnq_u8(x); // Negate - x = vrev64q_u8(x); // Rev in 64 - uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract - uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract - - if (low == 0) { - if (high != 0) { - uint32_t lz = internal::clzll(high); - return p + 8 + (lz >> 3); - } - } else { - uint32_t lz = internal::clzll(low); - return p + (lz >> 3); - } - } -} - -inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { - // Fast return for single non-whitespace - if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) - ++p; - else - return p; - - const uint8x16_t w0 = vmovq_n_u8(' '); - const uint8x16_t w1 = vmovq_n_u8('\n'); - const uint8x16_t w2 = vmovq_n_u8('\r'); - const uint8x16_t w3 = vmovq_n_u8('\t'); - - for (; p <= end - 16; p += 16) { - const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); - uint8x16_t x = vceqq_u8(s, w0); - x = vorrq_u8(x, vceqq_u8(s, w1)); - x = vorrq_u8(x, vceqq_u8(s, w2)); - x = vorrq_u8(x, vceqq_u8(s, w3)); - - x = vmvnq_u8(x); // Negate - x = vrev64q_u8(x); // Rev in 64 - uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract - uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract - - if (low == 0) { - if (high != 0) { - uint32_t lz = internal::clzll(high); - return p + 8 + (lz >> 3); - } - } else { - uint32_t lz = internal::clzll(low); - return p + (lz >> 3); - } - } - - return SkipWhitespace(p, end); -} - -#endif // RAPIDJSON_NEON - -#ifdef RAPIDJSON_SIMD -//! Template function specialization for InsituStringStream -template<> inline void SkipWhitespace(InsituStringStream& is) { - is.src_ = const_cast(SkipWhitespace_SIMD(is.src_)); -} - -//! Template function specialization for StringStream -template<> inline void SkipWhitespace(StringStream& is) { - is.src_ = SkipWhitespace_SIMD(is.src_); -} - -template<> inline void SkipWhitespace(EncodedInputStream, MemoryStream>& is) { - is.is_.src_ = SkipWhitespace_SIMD(is.is_.src_, is.is_.end_); -} -#endif // RAPIDJSON_SIMD - -/////////////////////////////////////////////////////////////////////////////// -// GenericReader - -//! SAX-style JSON parser. Use \ref Reader for UTF8 encoding and default allocator. -/*! GenericReader parses JSON text from a stream, and send events synchronously to an - object implementing Handler concept. - - It needs to allocate a stack for storing a single decoded string during - non-destructive parsing. - - For in-situ parsing, the decoded string is directly written to the source - text string, no temporary buffer is required. - - A GenericReader object can be reused for parsing multiple JSON text. - - \tparam SourceEncoding Encoding of the input stream. - \tparam TargetEncoding Encoding of the parse output. - \tparam StackAllocator Allocator type for stack. -*/ -template -class GenericReader { -public: - typedef typename SourceEncoding::Ch Ch; //!< SourceEncoding character type - - //! Constructor. - /*! \param stackAllocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing) - \param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing) - */ - GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) : - stack_(stackAllocator, stackCapacity), parseResult_(), state_(IterativeParsingStartState) {} - - //! Parse JSON text. - /*! \tparam parseFlags Combination of \ref ParseFlag. - \tparam InputStream Type of input stream, implementing Stream concept. - \tparam Handler Type of handler, implementing Handler concept. - \param is Input stream to be parsed. - \param handler The handler to receive events. - \return Whether the parsing is successful. - */ - template - ParseResult Parse(InputStream& is, Handler& handler) { - if (parseFlags & kParseIterativeFlag) - return IterativeParse(is, handler); - - parseResult_.Clear(); - - ClearStackOnExit scope(*this); - - SkipWhitespaceAndComments(is); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); - - if (RAPIDJSON_UNLIKELY(is.Peek() == '\0')) { - RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell()); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); - } - else { - ParseValue(is, handler); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); - - if (!(parseFlags & kParseStopWhenDoneFlag)) { - SkipWhitespaceAndComments(is); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); - - if (RAPIDJSON_UNLIKELY(is.Peek() != '\0')) { - RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell()); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); - } - } - } - - return parseResult_; - } - - //! Parse JSON text (with \ref kParseDefaultFlags) - /*! \tparam InputStream Type of input stream, implementing Stream concept - \tparam Handler Type of handler, implementing Handler concept. - \param is Input stream to be parsed. - \param handler The handler to receive events. - \return Whether the parsing is successful. - */ - template - ParseResult Parse(InputStream& is, Handler& handler) { - return Parse(is, handler); - } - - //! Initialize JSON text token-by-token parsing - /*! - */ - void IterativeParseInit() { - parseResult_.Clear(); - state_ = IterativeParsingStartState; - } - - //! Parse one token from JSON text - /*! \tparam InputStream Type of input stream, implementing Stream concept - \tparam Handler Type of handler, implementing Handler concept. - \param is Input stream to be parsed. - \param handler The handler to receive events. - \return Whether the parsing is successful. - */ - template - bool IterativeParseNext(InputStream& is, Handler& handler) { - while (RAPIDJSON_LIKELY(is.Peek() != '\0')) { - SkipWhitespaceAndComments(is); - - Token t = Tokenize(is.Peek()); - IterativeParsingState n = Predict(state_, t); - IterativeParsingState d = Transit(state_, t, n, is, handler); - - // If we've finished or hit an error... - if (RAPIDJSON_UNLIKELY(IsIterativeParsingCompleteState(d))) { - // Report errors. - if (d == IterativeParsingErrorState) { - HandleError(state_, is); - return false; - } - - // Transition to the finish state. - RAPIDJSON_ASSERT(d == IterativeParsingFinishState); - state_ = d; - - // If StopWhenDone is not set... - if (!(parseFlags & kParseStopWhenDoneFlag)) { - // ... and extra non-whitespace data is found... - SkipWhitespaceAndComments(is); - if (is.Peek() != '\0') { - // ... this is considered an error. - HandleError(state_, is); - return false; - } - } - - // Success! We are done! - return true; - } - - // Transition to the new state. - state_ = d; - - // If we parsed anything other than a delimiter, we invoked the handler, so we can return true now. - if (!IsIterativeParsingDelimiterState(n)) - return true; - } - - // We reached the end of file. - stack_.Clear(); - - if (state_ != IterativeParsingFinishState) { - HandleError(state_, is); - return false; - } - - return true; - } - - //! Check if token-by-token parsing JSON text is complete - /*! \return Whether the JSON has been fully decoded. - */ - RAPIDJSON_FORCEINLINE bool IterativeParseComplete() const { - return IsIterativeParsingCompleteState(state_); - } - - //! Whether a parse error has occurred in the last parsing. - bool HasParseError() const { return parseResult_.IsError(); } - - //! Get the \ref ParseErrorCode of last parsing. - ParseErrorCode GetParseErrorCode() const { return parseResult_.Code(); } - - //! Get the position of last parsing error in input, 0 otherwise. - size_t GetErrorOffset() const { return parseResult_.Offset(); } - -protected: - void SetParseError(ParseErrorCode code, size_t offset) { parseResult_.Set(code, offset); } - -private: - // Prohibit copy constructor & assignment operator. - GenericReader(const GenericReader&); - GenericReader& operator=(const GenericReader&); - - void ClearStack() { stack_.Clear(); } - - // clear stack on any exit from ParseStream, e.g. due to exception - struct ClearStackOnExit { - explicit ClearStackOnExit(GenericReader& r) : r_(r) {} - ~ClearStackOnExit() { r_.ClearStack(); } - private: - GenericReader& r_; - ClearStackOnExit(const ClearStackOnExit&); - ClearStackOnExit& operator=(const ClearStackOnExit&); - }; - - template - void SkipWhitespaceAndComments(InputStream& is) { - SkipWhitespace(is); - - if (parseFlags & kParseCommentsFlag) { - while (RAPIDJSON_UNLIKELY(Consume(is, '/'))) { - if (Consume(is, '*')) { - while (true) { - if (RAPIDJSON_UNLIKELY(is.Peek() == '\0')) - RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); - else if (Consume(is, '*')) { - if (Consume(is, '/')) - break; - } - else - is.Take(); - } - } - else if (RAPIDJSON_LIKELY(Consume(is, '/'))) - while (is.Peek() != '\0' && is.Take() != '\n') {} - else - RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); - - SkipWhitespace(is); - } - } - } - - // Parse object: { string : value, ... } - template - void ParseObject(InputStream& is, Handler& handler) { - RAPIDJSON_ASSERT(is.Peek() == '{'); - is.Take(); // Skip '{' - - if (RAPIDJSON_UNLIKELY(!handler.StartObject())) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - - SkipWhitespaceAndComments(is); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - - if (Consume(is, '}')) { - if (RAPIDJSON_UNLIKELY(!handler.EndObject(0))) // empty object - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - return; - } - - for (SizeType memberCount = 0;;) { - if (RAPIDJSON_UNLIKELY(is.Peek() != '"')) - RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); - - ParseString(is, handler, true); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - - SkipWhitespaceAndComments(is); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - - if (RAPIDJSON_UNLIKELY(!Consume(is, ':'))) - RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); - - SkipWhitespaceAndComments(is); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - - ParseValue(is, handler); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - - SkipWhitespaceAndComments(is); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - - ++memberCount; - - switch (is.Peek()) { - case ',': - is.Take(); - SkipWhitespaceAndComments(is); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - break; - case '}': - is.Take(); - if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount))) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - return; - default: - RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); break; // This useless break is only for making warning and coverage happy - } - - if (parseFlags & kParseTrailingCommasFlag) { - if (is.Peek() == '}') { - if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount))) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - is.Take(); - return; - } - } - } - } - - // Parse array: [ value, ... ] - template - void ParseArray(InputStream& is, Handler& handler) { - RAPIDJSON_ASSERT(is.Peek() == '['); - is.Take(); // Skip '[' - - if (RAPIDJSON_UNLIKELY(!handler.StartArray())) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - - SkipWhitespaceAndComments(is); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - - if (Consume(is, ']')) { - if (RAPIDJSON_UNLIKELY(!handler.EndArray(0))) // empty array - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - return; - } - - for (SizeType elementCount = 0;;) { - ParseValue(is, handler); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - - ++elementCount; - SkipWhitespaceAndComments(is); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - - if (Consume(is, ',')) { - SkipWhitespaceAndComments(is); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - } - else if (Consume(is, ']')) { - if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount))) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - return; - } - else - RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); - - if (parseFlags & kParseTrailingCommasFlag) { - if (is.Peek() == ']') { - if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount))) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - is.Take(); - return; - } - } - } - } - - template - void ParseNull(InputStream& is, Handler& handler) { - RAPIDJSON_ASSERT(is.Peek() == 'n'); - is.Take(); - - if (RAPIDJSON_LIKELY(Consume(is, 'u') && Consume(is, 'l') && Consume(is, 'l'))) { - if (RAPIDJSON_UNLIKELY(!handler.Null())) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - } - else - RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); - } - - template - void ParseTrue(InputStream& is, Handler& handler) { - RAPIDJSON_ASSERT(is.Peek() == 't'); - is.Take(); - - if (RAPIDJSON_LIKELY(Consume(is, 'r') && Consume(is, 'u') && Consume(is, 'e'))) { - if (RAPIDJSON_UNLIKELY(!handler.Bool(true))) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - } - else - RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); - } - - template - void ParseFalse(InputStream& is, Handler& handler) { - RAPIDJSON_ASSERT(is.Peek() == 'f'); - is.Take(); - - if (RAPIDJSON_LIKELY(Consume(is, 'a') && Consume(is, 'l') && Consume(is, 's') && Consume(is, 'e'))) { - if (RAPIDJSON_UNLIKELY(!handler.Bool(false))) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - } - else - RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); - } - - template - RAPIDJSON_FORCEINLINE static bool Consume(InputStream& is, typename InputStream::Ch expect) { - if (RAPIDJSON_LIKELY(is.Peek() == expect)) { - is.Take(); - return true; - } - else - return false; - } - - // Helper function to parse four hexadecimal digits in \uXXXX in ParseString(). - template - unsigned ParseHex4(InputStream& is, size_t escapeOffset) { - unsigned codepoint = 0; - for (int i = 0; i < 4; i++) { - Ch c = is.Peek(); - codepoint <<= 4; - codepoint += static_cast(c); - if (c >= '0' && c <= '9') - codepoint -= '0'; - else if (c >= 'A' && c <= 'F') - codepoint -= 'A' - 10; - else if (c >= 'a' && c <= 'f') - codepoint -= 'a' - 10; - else { - RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex, escapeOffset); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN(0); - } - is.Take(); - } - return codepoint; - } - - template - class StackStream { - public: - typedef CharType Ch; - - StackStream(internal::Stack& stack) : stack_(stack), length_(0) {} - RAPIDJSON_FORCEINLINE void Put(Ch c) { - *stack_.template Push() = c; - ++length_; - } - - RAPIDJSON_FORCEINLINE void* Push(SizeType count) { - length_ += count; - return stack_.template Push(count); - } - - size_t Length() const { return length_; } - - Ch* Pop() { - return stack_.template Pop(length_); - } - - private: - StackStream(const StackStream&); - StackStream& operator=(const StackStream&); - - internal::Stack& stack_; - SizeType length_; - }; - - // Parse string and generate String event. Different code paths for kParseInsituFlag. - template - void ParseString(InputStream& is, Handler& handler, bool isKey = false) { - internal::StreamLocalCopy copy(is); - InputStream& s(copy.s); - - RAPIDJSON_ASSERT(s.Peek() == '\"'); - s.Take(); // Skip '\"' - - bool success = false; - if (parseFlags & kParseInsituFlag) { - typename InputStream::Ch *head = s.PutBegin(); - ParseStringToStream(s, s); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - size_t length = s.PutEnd(head) - 1; - RAPIDJSON_ASSERT(length <= 0xFFFFFFFF); - const typename TargetEncoding::Ch* const str = reinterpret_cast(head); - success = (isKey ? handler.Key(str, SizeType(length), false) : handler.String(str, SizeType(length), false)); - } - else { - StackStream stackStream(stack_); - ParseStringToStream(s, stackStream); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - SizeType length = static_cast(stackStream.Length()) - 1; - const typename TargetEncoding::Ch* const str = stackStream.Pop(); - success = (isKey ? handler.Key(str, length, true) : handler.String(str, length, true)); - } - if (RAPIDJSON_UNLIKELY(!success)) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell()); - } - - // Parse string to an output is - // This function handles the prefix/suffix double quotes, escaping, and optional encoding validation. - template - RAPIDJSON_FORCEINLINE void ParseStringToStream(InputStream& is, OutputStream& os) { -//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN -#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - static const char escape[256] = { - Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '/', - Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, - 0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0, - 0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 - }; -#undef Z16 -//!@endcond - - for (;;) { - // Scan and copy string before "\\\"" or < 0x20. This is an optional optimzation. - if (!(parseFlags & kParseValidateEncodingFlag)) - ScanCopyUnescapedString(is, os); - - Ch c = is.Peek(); - if (RAPIDJSON_UNLIKELY(c == '\\')) { // Escape - size_t escapeOffset = is.Tell(); // For invalid escaping, report the initial '\\' as error offset - is.Take(); - Ch e = is.Peek(); - if ((sizeof(Ch) == 1 || unsigned(e) < 256) && RAPIDJSON_LIKELY(escape[static_cast(e)])) { - is.Take(); - os.Put(static_cast(escape[static_cast(e)])); - } - else if ((parseFlags & kParseEscapedApostropheFlag) && RAPIDJSON_LIKELY(e == '\'')) { // Allow escaped apostrophe - is.Take(); - os.Put('\''); - } - else if (RAPIDJSON_LIKELY(e == 'u')) { // Unicode - is.Take(); - unsigned codepoint = ParseHex4(is, escapeOffset); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDFFF)) { - // high surrogate, check if followed by valid low surrogate - if (RAPIDJSON_LIKELY(codepoint <= 0xDBFF)) { - // Handle UTF-16 surrogate pair - if (RAPIDJSON_UNLIKELY(!Consume(is, '\\') || !Consume(is, 'u'))) - RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset); - unsigned codepoint2 = ParseHex4(is, escapeOffset); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - if (RAPIDJSON_UNLIKELY(codepoint2 < 0xDC00 || codepoint2 > 0xDFFF)) - RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset); - codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000; - } - // single low surrogate - else - { - RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset); - } - } - TEncoding::Encode(os, codepoint); - } - else - RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, escapeOffset); - } - else if (RAPIDJSON_UNLIKELY(c == '"')) { // Closing double quote - is.Take(); - os.Put('\0'); // null-terminate the string - return; - } - else if (RAPIDJSON_UNLIKELY(static_cast(c) < 0x20)) { // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF - if (c == '\0') - RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell()); - else - RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, is.Tell()); - } - else { - size_t offset = is.Tell(); - if (RAPIDJSON_UNLIKELY((parseFlags & kParseValidateEncodingFlag ? - !Transcoder::Validate(is, os) : - !Transcoder::Transcode(is, os)))) - RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, offset); - } - } - } - - template - static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InputStream&, OutputStream&) { - // Do nothing for generic version - } - -#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) - // StringStream -> StackStream - static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream& os) { - const char* p = is.src_; - - // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) - const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); - while (p != nextAligned) - if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { - is.src_ = p; - return; - } - else - os.Put(*p++); - - // The rest of string using SIMD - static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; - static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; - static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; - const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); - const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); - const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); - - for (;; p += 16) { - const __m128i s = _mm_load_si128(reinterpret_cast(p)); - const __m128i t1 = _mm_cmpeq_epi8(s, dq); - const __m128i t2 = _mm_cmpeq_epi8(s, bs); - const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F - const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); - unsigned short r = static_cast(_mm_movemask_epi8(x)); - if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped - SizeType length; - #ifdef _MSC_VER // Find the index of first escaped - unsigned long offset; - _BitScanForward(&offset, r); - length = offset; - #else - length = static_cast(__builtin_ffs(r) - 1); - #endif - if (length != 0) { - char* q = reinterpret_cast(os.Push(length)); - for (size_t i = 0; i < length; i++) - q[i] = p[i]; - - p += length; - } - break; - } - _mm_storeu_si128(reinterpret_cast<__m128i *>(os.Push(16)), s); - } - - is.src_ = p; - } - - // InsituStringStream -> InsituStringStream - static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InsituStringStream& is, InsituStringStream& os) { - RAPIDJSON_ASSERT(&is == &os); - (void)os; - - if (is.src_ == is.dst_) { - SkipUnescapedString(is); - return; - } - - char* p = is.src_; - char *q = is.dst_; - - // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) - const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); - while (p != nextAligned) - if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { - is.src_ = p; - is.dst_ = q; - return; - } - else - *q++ = *p++; - - // The rest of string using SIMD - static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; - static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; - static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; - const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); - const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); - const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); - - for (;; p += 16, q += 16) { - const __m128i s = _mm_load_si128(reinterpret_cast(p)); - const __m128i t1 = _mm_cmpeq_epi8(s, dq); - const __m128i t2 = _mm_cmpeq_epi8(s, bs); - const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F - const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); - unsigned short r = static_cast(_mm_movemask_epi8(x)); - if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped - size_t length; -#ifdef _MSC_VER // Find the index of first escaped - unsigned long offset; - _BitScanForward(&offset, r); - length = offset; -#else - length = static_cast(__builtin_ffs(r) - 1); -#endif - for (const char* pend = p + length; p != pend; ) - *q++ = *p++; - break; - } - _mm_storeu_si128(reinterpret_cast<__m128i *>(q), s); - } - - is.src_ = p; - is.dst_ = q; - } - - // When read/write pointers are the same for insitu stream, just skip unescaped characters - static RAPIDJSON_FORCEINLINE void SkipUnescapedString(InsituStringStream& is) { - RAPIDJSON_ASSERT(is.src_ == is.dst_); - char* p = is.src_; - - // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) - const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); - for (; p != nextAligned; p++) - if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { - is.src_ = is.dst_ = p; - return; - } - - // The rest of string using SIMD - static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; - static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; - static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; - const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); - const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); - const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); - - for (;; p += 16) { - const __m128i s = _mm_load_si128(reinterpret_cast(p)); - const __m128i t1 = _mm_cmpeq_epi8(s, dq); - const __m128i t2 = _mm_cmpeq_epi8(s, bs); - const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F - const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); - unsigned short r = static_cast(_mm_movemask_epi8(x)); - if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped - size_t length; -#ifdef _MSC_VER // Find the index of first escaped - unsigned long offset; - _BitScanForward(&offset, r); - length = offset; -#else - length = static_cast(__builtin_ffs(r) - 1); -#endif - p += length; - break; - } - } - - is.src_ = is.dst_ = p; - } -#elif defined(RAPIDJSON_NEON) - // StringStream -> StackStream - static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream& os) { - const char* p = is.src_; - - // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) - const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); - while (p != nextAligned) - if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { - is.src_ = p; - return; - } - else - os.Put(*p++); - - // The rest of string using SIMD - const uint8x16_t s0 = vmovq_n_u8('"'); - const uint8x16_t s1 = vmovq_n_u8('\\'); - const uint8x16_t s2 = vmovq_n_u8('\b'); - const uint8x16_t s3 = vmovq_n_u8(32); - - for (;; p += 16) { - const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); - uint8x16_t x = vceqq_u8(s, s0); - x = vorrq_u8(x, vceqq_u8(s, s1)); - x = vorrq_u8(x, vceqq_u8(s, s2)); - x = vorrq_u8(x, vcltq_u8(s, s3)); - - x = vrev64q_u8(x); // Rev in 64 - uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract - uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract - - SizeType length = 0; - bool escaped = false; - if (low == 0) { - if (high != 0) { - uint32_t lz = internal::clzll(high); - length = 8 + (lz >> 3); - escaped = true; - } - } else { - uint32_t lz = internal::clzll(low); - length = lz >> 3; - escaped = true; - } - if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped - if (length != 0) { - char* q = reinterpret_cast(os.Push(length)); - for (size_t i = 0; i < length; i++) - q[i] = p[i]; - - p += length; - } - break; - } - vst1q_u8(reinterpret_cast(os.Push(16)), s); - } - - is.src_ = p; - } - - // InsituStringStream -> InsituStringStream - static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InsituStringStream& is, InsituStringStream& os) { - RAPIDJSON_ASSERT(&is == &os); - (void)os; - - if (is.src_ == is.dst_) { - SkipUnescapedString(is); - return; - } - - char* p = is.src_; - char *q = is.dst_; - - // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) - const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); - while (p != nextAligned) - if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { - is.src_ = p; - is.dst_ = q; - return; - } - else - *q++ = *p++; - - // The rest of string using SIMD - const uint8x16_t s0 = vmovq_n_u8('"'); - const uint8x16_t s1 = vmovq_n_u8('\\'); - const uint8x16_t s2 = vmovq_n_u8('\b'); - const uint8x16_t s3 = vmovq_n_u8(32); - - for (;; p += 16, q += 16) { - const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); - uint8x16_t x = vceqq_u8(s, s0); - x = vorrq_u8(x, vceqq_u8(s, s1)); - x = vorrq_u8(x, vceqq_u8(s, s2)); - x = vorrq_u8(x, vcltq_u8(s, s3)); - - x = vrev64q_u8(x); // Rev in 64 - uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract - uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract - - SizeType length = 0; - bool escaped = false; - if (low == 0) { - if (high != 0) { - uint32_t lz = internal::clzll(high); - length = 8 + (lz >> 3); - escaped = true; - } - } else { - uint32_t lz = internal::clzll(low); - length = lz >> 3; - escaped = true; - } - if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped - for (const char* pend = p + length; p != pend; ) { - *q++ = *p++; - } - break; - } - vst1q_u8(reinterpret_cast(q), s); - } - - is.src_ = p; - is.dst_ = q; - } - - // When read/write pointers are the same for insitu stream, just skip unescaped characters - static RAPIDJSON_FORCEINLINE void SkipUnescapedString(InsituStringStream& is) { - RAPIDJSON_ASSERT(is.src_ == is.dst_); - char* p = is.src_; - - // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) - const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); - for (; p != nextAligned; p++) - if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { - is.src_ = is.dst_ = p; - return; - } - - // The rest of string using SIMD - const uint8x16_t s0 = vmovq_n_u8('"'); - const uint8x16_t s1 = vmovq_n_u8('\\'); - const uint8x16_t s2 = vmovq_n_u8('\b'); - const uint8x16_t s3 = vmovq_n_u8(32); - - for (;; p += 16) { - const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); - uint8x16_t x = vceqq_u8(s, s0); - x = vorrq_u8(x, vceqq_u8(s, s1)); - x = vorrq_u8(x, vceqq_u8(s, s2)); - x = vorrq_u8(x, vcltq_u8(s, s3)); - - x = vrev64q_u8(x); // Rev in 64 - uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract - uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract - - if (low == 0) { - if (high != 0) { - uint32_t lz = internal::clzll(high); - p += 8 + (lz >> 3); - break; - } - } else { - uint32_t lz = internal::clzll(low); - p += lz >> 3; - break; - } - } - - is.src_ = is.dst_ = p; - } -#endif // RAPIDJSON_NEON - - template - class NumberStream; - - template - class NumberStream { - public: - typedef typename InputStream::Ch Ch; - - NumberStream(GenericReader& reader, InputStream& s) : is(s) { (void)reader; } - - RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); } - RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); } - RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); } - RAPIDJSON_FORCEINLINE void Push(char) {} - - size_t Tell() { return is.Tell(); } - size_t Length() { return 0; } - const char* Pop() { return 0; } - - protected: - NumberStream& operator=(const NumberStream&); - - InputStream& is; - }; - - template - class NumberStream : public NumberStream { - typedef NumberStream Base; - public: - NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is), stackStream(reader.stack_) {} - - RAPIDJSON_FORCEINLINE Ch TakePush() { - stackStream.Put(static_cast(Base::is.Peek())); - return Base::is.Take(); - } - - RAPIDJSON_FORCEINLINE void Push(char c) { - stackStream.Put(c); - } - - size_t Length() { return stackStream.Length(); } - - const char* Pop() { - stackStream.Put('\0'); - return stackStream.Pop(); - } - - private: - StackStream stackStream; - }; - - template - class NumberStream : public NumberStream { - typedef NumberStream Base; - public: - NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is) {} - - RAPIDJSON_FORCEINLINE Ch Take() { return Base::TakePush(); } - }; - - template - void ParseNumber(InputStream& is, Handler& handler) { - internal::StreamLocalCopy copy(is); - NumberStream s(*this, copy.s); - - size_t startOffset = s.Tell(); - double d = 0.0; - bool useNanOrInf = false; - - // Parse minus - bool minus = Consume(s, '-'); - - // Parse int: zero / ( digit1-9 *DIGIT ) - unsigned i = 0; - uint64_t i64 = 0; - bool use64bit = false; - int significandDigit = 0; - if (RAPIDJSON_UNLIKELY(s.Peek() == '0')) { - i = 0; - s.TakePush(); - } - else if (RAPIDJSON_LIKELY(s.Peek() >= '1' && s.Peek() <= '9')) { - i = static_cast(s.TakePush() - '0'); - - if (minus) - while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { - if (RAPIDJSON_UNLIKELY(i >= 214748364)) { // 2^31 = 2147483648 - if (RAPIDJSON_LIKELY(i != 214748364 || s.Peek() > '8')) { - i64 = i; - use64bit = true; - break; - } - } - i = i * 10 + static_cast(s.TakePush() - '0'); - significandDigit++; - } - else - while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { - if (RAPIDJSON_UNLIKELY(i >= 429496729)) { // 2^32 - 1 = 4294967295 - if (RAPIDJSON_LIKELY(i != 429496729 || s.Peek() > '5')) { - i64 = i; - use64bit = true; - break; - } - } - i = i * 10 + static_cast(s.TakePush() - '0'); - significandDigit++; - } - } - // Parse NaN or Infinity here - else if ((parseFlags & kParseNanAndInfFlag) && RAPIDJSON_LIKELY((s.Peek() == 'I' || s.Peek() == 'N'))) { - if (Consume(s, 'N')) { - if (Consume(s, 'a') && Consume(s, 'N')) { - d = std::numeric_limits::quiet_NaN(); - useNanOrInf = true; - } - } - else if (RAPIDJSON_LIKELY(Consume(s, 'I'))) { - if (Consume(s, 'n') && Consume(s, 'f')) { - d = (minus ? -std::numeric_limits::infinity() : std::numeric_limits::infinity()); - useNanOrInf = true; - - if (RAPIDJSON_UNLIKELY(s.Peek() == 'i' && !(Consume(s, 'i') && Consume(s, 'n') - && Consume(s, 'i') && Consume(s, 't') && Consume(s, 'y')))) { - RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); - } - } - } - - if (RAPIDJSON_UNLIKELY(!useNanOrInf)) { - RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); - } - } - else - RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); - - // Parse 64bit int - bool useDouble = false; - if (use64bit) { - if (minus) - while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { - if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC))) // 2^63 = 9223372036854775808 - if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8')) { - d = static_cast(i64); - useDouble = true; - break; - } - i64 = i64 * 10 + static_cast(s.TakePush() - '0'); - significandDigit++; - } - else - while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { - if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999))) // 2^64 - 1 = 18446744073709551615 - if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || s.Peek() > '5')) { - d = static_cast(i64); - useDouble = true; - break; - } - i64 = i64 * 10 + static_cast(s.TakePush() - '0'); - significandDigit++; - } - } - - // Force double for big integer - if (useDouble) { - while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { - d = d * 10 + (s.TakePush() - '0'); - } - } - - // Parse frac = decimal-point 1*DIGIT - int expFrac = 0; - size_t decimalPosition; - if (Consume(s, '.')) { - decimalPosition = s.Length(); - - if (RAPIDJSON_UNLIKELY(!(s.Peek() >= '0' && s.Peek() <= '9'))) - RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell()); - - if (!useDouble) { -#if RAPIDJSON_64BIT - // Use i64 to store significand in 64-bit architecture - if (!use64bit) - i64 = i; - - while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { - if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) // 2^53 - 1 for fast path - break; - else { - i64 = i64 * 10 + static_cast(s.TakePush() - '0'); - --expFrac; - if (i64 != 0) - significandDigit++; - } - } - - d = static_cast(i64); -#else - // Use double to store significand in 32-bit architecture - d = static_cast(use64bit ? i64 : i); -#endif - useDouble = true; - } - - while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { - if (significandDigit < 17) { - d = d * 10.0 + (s.TakePush() - '0'); - --expFrac; - if (RAPIDJSON_LIKELY(d > 0.0)) - significandDigit++; - } - else - s.TakePush(); - } - } - else - decimalPosition = s.Length(); // decimal position at the end of integer. - - // Parse exp = e [ minus / plus ] 1*DIGIT - int exp = 0; - if (Consume(s, 'e') || Consume(s, 'E')) { - if (!useDouble) { - d = static_cast(use64bit ? i64 : i); - useDouble = true; - } - - bool expMinus = false; - if (Consume(s, '+')) - ; - else if (Consume(s, '-')) - expMinus = true; - - if (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { - exp = static_cast(s.Take() - '0'); - if (expMinus) { - // (exp + expFrac) must not underflow int => we're detecting when -exp gets - // dangerously close to INT_MIN (a pessimistic next digit 9 would push it into - // underflow territory): - // - // -(exp * 10 + 9) + expFrac >= INT_MIN - // <=> exp <= (expFrac - INT_MIN - 9) / 10 - RAPIDJSON_ASSERT(expFrac <= 0); - int maxExp = (expFrac + 2147483639) / 10; - - while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { - exp = exp * 10 + static_cast(s.Take() - '0'); - if (RAPIDJSON_UNLIKELY(exp > maxExp)) { - while (RAPIDJSON_UNLIKELY(s.Peek() >= '0' && s.Peek() <= '9')) // Consume the rest of exponent - s.Take(); - } - } - } - else { // positive exp - int maxExp = 308 - expFrac; - while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { - exp = exp * 10 + static_cast(s.Take() - '0'); - if (RAPIDJSON_UNLIKELY(exp > maxExp)) - RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset); - } - } - } - else - RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissExponent, s.Tell()); - - if (expMinus) - exp = -exp; - } - - // Finish parsing, call event according to the type of number. - bool cont = true; - - if (parseFlags & kParseNumbersAsStringsFlag) { - if (parseFlags & kParseInsituFlag) { - s.Pop(); // Pop stack no matter if it will be used or not. - typename InputStream::Ch* head = is.PutBegin(); - const size_t length = s.Tell() - startOffset; - RAPIDJSON_ASSERT(length <= 0xFFFFFFFF); - // unable to insert the \0 character here, it will erase the comma after this number - const typename TargetEncoding::Ch* const str = reinterpret_cast(head); - cont = handler.RawNumber(str, SizeType(length), false); - } - else { - SizeType numCharsToCopy = static_cast(s.Length()); - StringStream srcStream(s.Pop()); - StackStream dstStream(stack_); - while (numCharsToCopy--) { - Transcoder, TargetEncoding>::Transcode(srcStream, dstStream); - } - dstStream.Put('\0'); - const typename TargetEncoding::Ch* str = dstStream.Pop(); - const SizeType length = static_cast(dstStream.Length()) - 1; - cont = handler.RawNumber(str, SizeType(length), true); - } - } - else { - size_t length = s.Length(); - const char* decimal = s.Pop(); // Pop stack no matter if it will be used or not. - - if (useDouble) { - int p = exp + expFrac; - if (parseFlags & kParseFullPrecisionFlag) - d = internal::StrtodFullPrecision(d, p, decimal, length, decimalPosition, exp); - else - d = internal::StrtodNormalPrecision(d, p); - - // Use > max, instead of == inf, to fix bogus warning -Wfloat-equal - if (d > (std::numeric_limits::max)()) { - // Overflow - // TODO: internal::StrtodX should report overflow (or underflow) - RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset); - } - - cont = handler.Double(minus ? -d : d); - } - else if (useNanOrInf) { - cont = handler.Double(d); - } - else { - if (use64bit) { - if (minus) - cont = handler.Int64(static_cast(~i64 + 1)); - else - cont = handler.Uint64(i64); - } - else { - if (minus) - cont = handler.Int(static_cast(~i + 1)); - else - cont = handler.Uint(i); - } - } - } - if (RAPIDJSON_UNLIKELY(!cont)) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, startOffset); - } - - // Parse any JSON value - template - void ParseValue(InputStream& is, Handler& handler) { - switch (is.Peek()) { - case 'n': ParseNull (is, handler); break; - case 't': ParseTrue (is, handler); break; - case 'f': ParseFalse (is, handler); break; - case '"': ParseString(is, handler); break; - case '{': ParseObject(is, handler); break; - case '[': ParseArray (is, handler); break; - default : - ParseNumber(is, handler); - break; - - } - } - - // Iterative Parsing - - // States - enum IterativeParsingState { - IterativeParsingFinishState = 0, // sink states at top - IterativeParsingErrorState, // sink states at top - IterativeParsingStartState, - - // Object states - IterativeParsingObjectInitialState, - IterativeParsingMemberKeyState, - IterativeParsingMemberValueState, - IterativeParsingObjectFinishState, - - // Array states - IterativeParsingArrayInitialState, - IterativeParsingElementState, - IterativeParsingArrayFinishState, - - // Single value state - IterativeParsingValueState, - - // Delimiter states (at bottom) - IterativeParsingElementDelimiterState, - IterativeParsingMemberDelimiterState, - IterativeParsingKeyValueDelimiterState, - - cIterativeParsingStateCount - }; - - // Tokens - enum Token { - LeftBracketToken = 0, - RightBracketToken, - - LeftCurlyBracketToken, - RightCurlyBracketToken, - - CommaToken, - ColonToken, - - StringToken, - FalseToken, - TrueToken, - NullToken, - NumberToken, - - kTokenCount - }; - - RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) const { - -//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN -#define N NumberToken -#define N16 N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N - // Maps from ASCII to Token - static const unsigned char tokenMap[256] = { - N16, // 00~0F - N16, // 10~1F - N, N, StringToken, N, N, N, N, N, N, N, N, N, CommaToken, N, N, N, // 20~2F - N, N, N, N, N, N, N, N, N, N, ColonToken, N, N, N, N, N, // 30~3F - N16, // 40~4F - N, N, N, N, N, N, N, N, N, N, N, LeftBracketToken, N, RightBracketToken, N, N, // 50~5F - N, N, N, N, N, N, FalseToken, N, N, N, N, N, N, N, NullToken, N, // 60~6F - N, N, N, N, TrueToken, N, N, N, N, N, N, LeftCurlyBracketToken, N, RightCurlyBracketToken, N, N, // 70~7F - N16, N16, N16, N16, N16, N16, N16, N16 // 80~FF - }; -#undef N -#undef N16 -//!@endcond - - if (sizeof(Ch) == 1 || static_cast(c) < 256) - return static_cast(tokenMap[static_cast(c)]); - else - return NumberToken; - } - - RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) const { - // current state x one lookahead token -> new state - static const char G[cIterativeParsingStateCount][kTokenCount] = { - // Finish(sink state) - { - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState - }, - // Error(sink state) - { - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState - }, - // Start - { - IterativeParsingArrayInitialState, // Left bracket - IterativeParsingErrorState, // Right bracket - IterativeParsingObjectInitialState, // Left curly bracket - IterativeParsingErrorState, // Right curly bracket - IterativeParsingErrorState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingValueState, // String - IterativeParsingValueState, // False - IterativeParsingValueState, // True - IterativeParsingValueState, // Null - IterativeParsingValueState // Number - }, - // ObjectInitial - { - IterativeParsingErrorState, // Left bracket - IterativeParsingErrorState, // Right bracket - IterativeParsingErrorState, // Left curly bracket - IterativeParsingObjectFinishState, // Right curly bracket - IterativeParsingErrorState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingMemberKeyState, // String - IterativeParsingErrorState, // False - IterativeParsingErrorState, // True - IterativeParsingErrorState, // Null - IterativeParsingErrorState // Number - }, - // MemberKey - { - IterativeParsingErrorState, // Left bracket - IterativeParsingErrorState, // Right bracket - IterativeParsingErrorState, // Left curly bracket - IterativeParsingErrorState, // Right curly bracket - IterativeParsingErrorState, // Comma - IterativeParsingKeyValueDelimiterState, // Colon - IterativeParsingErrorState, // String - IterativeParsingErrorState, // False - IterativeParsingErrorState, // True - IterativeParsingErrorState, // Null - IterativeParsingErrorState // Number - }, - // MemberValue - { - IterativeParsingErrorState, // Left bracket - IterativeParsingErrorState, // Right bracket - IterativeParsingErrorState, // Left curly bracket - IterativeParsingObjectFinishState, // Right curly bracket - IterativeParsingMemberDelimiterState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingErrorState, // String - IterativeParsingErrorState, // False - IterativeParsingErrorState, // True - IterativeParsingErrorState, // Null - IterativeParsingErrorState // Number - }, - // ObjectFinish(sink state) - { - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState - }, - // ArrayInitial - { - IterativeParsingArrayInitialState, // Left bracket(push Element state) - IterativeParsingArrayFinishState, // Right bracket - IterativeParsingObjectInitialState, // Left curly bracket(push Element state) - IterativeParsingErrorState, // Right curly bracket - IterativeParsingErrorState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingElementState, // String - IterativeParsingElementState, // False - IterativeParsingElementState, // True - IterativeParsingElementState, // Null - IterativeParsingElementState // Number - }, - // Element - { - IterativeParsingErrorState, // Left bracket - IterativeParsingArrayFinishState, // Right bracket - IterativeParsingErrorState, // Left curly bracket - IterativeParsingErrorState, // Right curly bracket - IterativeParsingElementDelimiterState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingErrorState, // String - IterativeParsingErrorState, // False - IterativeParsingErrorState, // True - IterativeParsingErrorState, // Null - IterativeParsingErrorState // Number - }, - // ArrayFinish(sink state) - { - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState - }, - // Single Value (sink state) - { - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState - }, - // ElementDelimiter - { - IterativeParsingArrayInitialState, // Left bracket(push Element state) - IterativeParsingArrayFinishState, // Right bracket - IterativeParsingObjectInitialState, // Left curly bracket(push Element state) - IterativeParsingErrorState, // Right curly bracket - IterativeParsingErrorState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingElementState, // String - IterativeParsingElementState, // False - IterativeParsingElementState, // True - IterativeParsingElementState, // Null - IterativeParsingElementState // Number - }, - // MemberDelimiter - { - IterativeParsingErrorState, // Left bracket - IterativeParsingErrorState, // Right bracket - IterativeParsingErrorState, // Left curly bracket - IterativeParsingObjectFinishState, // Right curly bracket - IterativeParsingErrorState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingMemberKeyState, // String - IterativeParsingErrorState, // False - IterativeParsingErrorState, // True - IterativeParsingErrorState, // Null - IterativeParsingErrorState // Number - }, - // KeyValueDelimiter - { - IterativeParsingArrayInitialState, // Left bracket(push MemberValue state) - IterativeParsingErrorState, // Right bracket - IterativeParsingObjectInitialState, // Left curly bracket(push MemberValue state) - IterativeParsingErrorState, // Right curly bracket - IterativeParsingErrorState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingMemberValueState, // String - IterativeParsingMemberValueState, // False - IterativeParsingMemberValueState, // True - IterativeParsingMemberValueState, // Null - IterativeParsingMemberValueState // Number - }, - }; // End of G - - return static_cast(G[state][token]); - } - - // Make an advance in the token stream and state based on the candidate destination state which was returned by Transit(). - // May return a new state on state pop. - template - RAPIDJSON_FORCEINLINE IterativeParsingState Transit(IterativeParsingState src, Token token, IterativeParsingState dst, InputStream& is, Handler& handler) { - (void)token; - - switch (dst) { - case IterativeParsingErrorState: - return dst; - - case IterativeParsingObjectInitialState: - case IterativeParsingArrayInitialState: - { - // Push the state(Element or MemeberValue) if we are nested in another array or value of member. - // In this way we can get the correct state on ObjectFinish or ArrayFinish by frame pop. - IterativeParsingState n = src; - if (src == IterativeParsingArrayInitialState || src == IterativeParsingElementDelimiterState) - n = IterativeParsingElementState; - else if (src == IterativeParsingKeyValueDelimiterState) - n = IterativeParsingMemberValueState; - // Push current state. - *stack_.template Push(1) = n; - // Initialize and push the member/element count. - *stack_.template Push(1) = 0; - // Call handler - bool hr = (dst == IterativeParsingObjectInitialState) ? handler.StartObject() : handler.StartArray(); - // On handler short circuits the parsing. - if (!hr) { - RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); - return IterativeParsingErrorState; - } - else { - is.Take(); - return dst; - } - } - - case IterativeParsingMemberKeyState: - ParseString(is, handler, true); - if (HasParseError()) - return IterativeParsingErrorState; - else - return dst; - - case IterativeParsingKeyValueDelimiterState: - RAPIDJSON_ASSERT(token == ColonToken); - is.Take(); - return dst; - - case IterativeParsingMemberValueState: - // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. - ParseValue(is, handler); - if (HasParseError()) { - return IterativeParsingErrorState; - } - return dst; - - case IterativeParsingElementState: - // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. - ParseValue(is, handler); - if (HasParseError()) { - return IterativeParsingErrorState; - } - return dst; - - case IterativeParsingMemberDelimiterState: - case IterativeParsingElementDelimiterState: - is.Take(); - // Update member/element count. - *stack_.template Top() = *stack_.template Top() + 1; - return dst; - - case IterativeParsingObjectFinishState: - { - // Transit from delimiter is only allowed when trailing commas are enabled - if (!(parseFlags & kParseTrailingCommasFlag) && src == IterativeParsingMemberDelimiterState) { - RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorObjectMissName, is.Tell()); - return IterativeParsingErrorState; - } - // Get member count. - SizeType c = *stack_.template Pop(1); - // If the object is not empty, count the last member. - if (src == IterativeParsingMemberValueState) - ++c; - // Restore the state. - IterativeParsingState n = static_cast(*stack_.template Pop(1)); - // Transit to Finish state if this is the topmost scope. - if (n == IterativeParsingStartState) - n = IterativeParsingFinishState; - // Call handler - bool hr = handler.EndObject(c); - // On handler short circuits the parsing. - if (!hr) { - RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); - return IterativeParsingErrorState; - } - else { - is.Take(); - return n; - } - } - - case IterativeParsingArrayFinishState: - { - // Transit from delimiter is only allowed when trailing commas are enabled - if (!(parseFlags & kParseTrailingCommasFlag) && src == IterativeParsingElementDelimiterState) { - RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorValueInvalid, is.Tell()); - return IterativeParsingErrorState; - } - // Get element count. - SizeType c = *stack_.template Pop(1); - // If the array is not empty, count the last element. - if (src == IterativeParsingElementState) - ++c; - // Restore the state. - IterativeParsingState n = static_cast(*stack_.template Pop(1)); - // Transit to Finish state if this is the topmost scope. - if (n == IterativeParsingStartState) - n = IterativeParsingFinishState; - // Call handler - bool hr = handler.EndArray(c); - // On handler short circuits the parsing. - if (!hr) { - RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); - return IterativeParsingErrorState; - } - else { - is.Take(); - return n; - } - } - - default: - // This branch is for IterativeParsingValueState actually. - // Use `default:` rather than - // `case IterativeParsingValueState:` is for code coverage. - - // The IterativeParsingStartState is not enumerated in this switch-case. - // It is impossible for that case. And it can be caught by following assertion. - - // The IterativeParsingFinishState is not enumerated in this switch-case either. - // It is a "derivative" state which cannot triggered from Predict() directly. - // Therefore it cannot happen here. And it can be caught by following assertion. - RAPIDJSON_ASSERT(dst == IterativeParsingValueState); - - // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. - ParseValue(is, handler); - if (HasParseError()) { - return IterativeParsingErrorState; - } - return IterativeParsingFinishState; - } - } - - template - void HandleError(IterativeParsingState src, InputStream& is) { - if (HasParseError()) { - // Error flag has been set. - return; - } - - switch (src) { - case IterativeParsingStartState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell()); return; - case IterativeParsingFinishState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell()); return; - case IterativeParsingObjectInitialState: - case IterativeParsingMemberDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); return; - case IterativeParsingMemberKeyState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); return; - case IterativeParsingMemberValueState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); return; - case IterativeParsingKeyValueDelimiterState: - case IterativeParsingArrayInitialState: - case IterativeParsingElementDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); return; - default: RAPIDJSON_ASSERT(src == IterativeParsingElementState); RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return; - } - } - - RAPIDJSON_FORCEINLINE bool IsIterativeParsingDelimiterState(IterativeParsingState s) const { - return s >= IterativeParsingElementDelimiterState; - } - - RAPIDJSON_FORCEINLINE bool IsIterativeParsingCompleteState(IterativeParsingState s) const { - return s <= IterativeParsingErrorState; - } - - template - ParseResult IterativeParse(InputStream& is, Handler& handler) { - parseResult_.Clear(); - ClearStackOnExit scope(*this); - IterativeParsingState state = IterativeParsingStartState; - - SkipWhitespaceAndComments(is); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); - while (is.Peek() != '\0') { - Token t = Tokenize(is.Peek()); - IterativeParsingState n = Predict(state, t); - IterativeParsingState d = Transit(state, t, n, is, handler); - - if (d == IterativeParsingErrorState) { - HandleError(state, is); - break; - } - - state = d; - - // Do not further consume streams if a root JSON has been parsed. - if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState) - break; - - SkipWhitespaceAndComments(is); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); - } - - // Handle the end of file. - if (state != IterativeParsingFinishState) - HandleError(state, is); - - return parseResult_; - } - - static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string. - internal::Stack stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing. - ParseResult parseResult_; - IterativeParsingState state_; -}; // class GenericReader - -//! Reader with UTF8 encoding and default allocator. -typedef GenericReader, UTF8<> > Reader; - -RAPIDJSON_NAMESPACE_END - -#if defined(__clang__) || defined(_MSC_VER) -RAPIDJSON_DIAG_POP -#endif - - -#ifdef __GNUC__ -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_READER_H_ diff --git a/external/rapidjson/schema.h b/external/rapidjson/schema.h deleted file mode 100755 index f0759ff..0000000 --- a/external/rapidjson/schema.h +++ /dev/null @@ -1,2795 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available-> -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip-> All rights reserved-> -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License-> You may obtain a copy of the License at -// -// http://opensource->org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied-> See the License for the -// specific language governing permissions and limitations under the License-> - -#ifndef RAPIDJSON_SCHEMA_H_ -#define RAPIDJSON_SCHEMA_H_ - -#include "document.h" -#include "pointer.h" -#include "stringbuffer.h" -#include "error/en.h" -#include "uri.h" -#include // abs, floor - -#if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX) -#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1 -#else -#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0 -#endif - -#if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800)) -#define RAPIDJSON_SCHEMA_USE_STDREGEX 1 -#else -#define RAPIDJSON_SCHEMA_USE_STDREGEX 0 -#endif - -#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX -#include "internal/regex.h" -#elif RAPIDJSON_SCHEMA_USE_STDREGEX -#include -#endif - -#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX || RAPIDJSON_SCHEMA_USE_STDREGEX -#define RAPIDJSON_SCHEMA_HAS_REGEX 1 -#else -#define RAPIDJSON_SCHEMA_HAS_REGEX 0 -#endif - -#ifndef RAPIDJSON_SCHEMA_VERBOSE -#define RAPIDJSON_SCHEMA_VERBOSE 0 -#endif - -#if RAPIDJSON_SCHEMA_VERBOSE -#include "stringbuffer.h" -#endif - -RAPIDJSON_DIAG_PUSH - -#if defined(__GNUC__) -RAPIDJSON_DIAG_OFF(effc++) -#endif - -#ifdef __clang__ -RAPIDJSON_DIAG_OFF(weak-vtables) -RAPIDJSON_DIAG_OFF(exit-time-destructors) -RAPIDJSON_DIAG_OFF(c++98-compat-pedantic) -RAPIDJSON_DIAG_OFF(variadic-macros) -#elif defined(_MSC_VER) -RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -/////////////////////////////////////////////////////////////////////////////// -// Verbose Utilities - -#if RAPIDJSON_SCHEMA_VERBOSE - -namespace internal { - -inline void PrintInvalidKeyword(const char* keyword) { - printf("Fail keyword: %s\n", keyword); -} - -inline void PrintInvalidKeyword(const wchar_t* keyword) { - wprintf(L"Fail keyword: %ls\n", keyword); -} - -inline void PrintInvalidDocument(const char* document) { - printf("Fail document: %s\n\n", document); -} - -inline void PrintInvalidDocument(const wchar_t* document) { - wprintf(L"Fail document: %ls\n\n", document); -} - -inline void PrintValidatorPointers(unsigned depth, const char* s, const char* d) { - printf("S: %*s%s\nD: %*s%s\n\n", depth * 4, " ", s, depth * 4, " ", d); -} - -inline void PrintValidatorPointers(unsigned depth, const wchar_t* s, const wchar_t* d) { - wprintf(L"S: %*ls%ls\nD: %*ls%ls\n\n", depth * 4, L" ", s, depth * 4, L" ", d); -} - -} // namespace internal - -#endif // RAPIDJSON_SCHEMA_VERBOSE - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_INVALID_KEYWORD_RETURN - -#if RAPIDJSON_SCHEMA_VERBOSE -#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) internal::PrintInvalidKeyword(keyword) -#else -#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) -#endif - -#define RAPIDJSON_INVALID_KEYWORD_RETURN(code)\ -RAPIDJSON_MULTILINEMACRO_BEGIN\ - context.invalidCode = code;\ - context.invalidKeyword = SchemaType::GetValidateErrorKeyword(code).GetString();\ - RAPIDJSON_INVALID_KEYWORD_VERBOSE(context.invalidKeyword);\ - return false;\ -RAPIDJSON_MULTILINEMACRO_END - -/////////////////////////////////////////////////////////////////////////////// -// ValidateFlag - -/*! \def RAPIDJSON_VALIDATE_DEFAULT_FLAGS - \ingroup RAPIDJSON_CONFIG - \brief User-defined kValidateDefaultFlags definition. - - User can define this as any \c ValidateFlag combinations. -*/ -#ifndef RAPIDJSON_VALIDATE_DEFAULT_FLAGS -#define RAPIDJSON_VALIDATE_DEFAULT_FLAGS kValidateNoFlags -#endif - -//! Combination of validate flags -/*! \see - */ -enum ValidateFlag { - kValidateNoFlags = 0, //!< No flags are set. - kValidateContinueOnErrorFlag = 1, //!< Don't stop after first validation error. - kValidateDefaultFlags = RAPIDJSON_VALIDATE_DEFAULT_FLAGS //!< Default validate flags. Can be customized by defining RAPIDJSON_VALIDATE_DEFAULT_FLAGS -}; - -/////////////////////////////////////////////////////////////////////////////// -// Forward declarations - -template -class GenericSchemaDocument; - -namespace internal { - -template -class Schema; - -/////////////////////////////////////////////////////////////////////////////// -// ISchemaValidator - -class ISchemaValidator { -public: - virtual ~ISchemaValidator() {} - virtual bool IsValid() const = 0; - virtual void SetValidateFlags(unsigned flags) = 0; - virtual unsigned GetValidateFlags() const = 0; -}; - -/////////////////////////////////////////////////////////////////////////////// -// ISchemaStateFactory - -template -class ISchemaStateFactory { -public: - virtual ~ISchemaStateFactory() {} - virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&, const bool inheritContinueOnErrors) = 0; - virtual void DestroySchemaValidator(ISchemaValidator* validator) = 0; - virtual void* CreateHasher() = 0; - virtual uint64_t GetHashCode(void* hasher) = 0; - virtual void DestroryHasher(void* hasher) = 0; - virtual void* MallocState(size_t size) = 0; - virtual void FreeState(void* p) = 0; -}; - -/////////////////////////////////////////////////////////////////////////////// -// IValidationErrorHandler - -template -class IValidationErrorHandler { -public: - typedef typename SchemaType::Ch Ch; - typedef typename SchemaType::SValue SValue; - - virtual ~IValidationErrorHandler() {} - - virtual void NotMultipleOf(int64_t actual, const SValue& expected) = 0; - virtual void NotMultipleOf(uint64_t actual, const SValue& expected) = 0; - virtual void NotMultipleOf(double actual, const SValue& expected) = 0; - virtual void AboveMaximum(int64_t actual, const SValue& expected, bool exclusive) = 0; - virtual void AboveMaximum(uint64_t actual, const SValue& expected, bool exclusive) = 0; - virtual void AboveMaximum(double actual, const SValue& expected, bool exclusive) = 0; - virtual void BelowMinimum(int64_t actual, const SValue& expected, bool exclusive) = 0; - virtual void BelowMinimum(uint64_t actual, const SValue& expected, bool exclusive) = 0; - virtual void BelowMinimum(double actual, const SValue& expected, bool exclusive) = 0; - - virtual void TooLong(const Ch* str, SizeType length, SizeType expected) = 0; - virtual void TooShort(const Ch* str, SizeType length, SizeType expected) = 0; - virtual void DoesNotMatch(const Ch* str, SizeType length) = 0; - - virtual void DisallowedItem(SizeType index) = 0; - virtual void TooFewItems(SizeType actualCount, SizeType expectedCount) = 0; - virtual void TooManyItems(SizeType actualCount, SizeType expectedCount) = 0; - virtual void DuplicateItems(SizeType index1, SizeType index2) = 0; - - virtual void TooManyProperties(SizeType actualCount, SizeType expectedCount) = 0; - virtual void TooFewProperties(SizeType actualCount, SizeType expectedCount) = 0; - virtual void StartMissingProperties() = 0; - virtual void AddMissingProperty(const SValue& name) = 0; - virtual bool EndMissingProperties() = 0; - virtual void PropertyViolations(ISchemaValidator** subvalidators, SizeType count) = 0; - virtual void DisallowedProperty(const Ch* name, SizeType length) = 0; - - virtual void StartDependencyErrors() = 0; - virtual void StartMissingDependentProperties() = 0; - virtual void AddMissingDependentProperty(const SValue& targetName) = 0; - virtual void EndMissingDependentProperties(const SValue& sourceName) = 0; - virtual void AddDependencySchemaError(const SValue& souceName, ISchemaValidator* subvalidator) = 0; - virtual bool EndDependencyErrors() = 0; - - virtual void DisallowedValue(const ValidateErrorCode code) = 0; - virtual void StartDisallowedType() = 0; - virtual void AddExpectedType(const typename SchemaType::ValueType& expectedType) = 0; - virtual void EndDisallowedType(const typename SchemaType::ValueType& actualType) = 0; - virtual void NotAllOf(ISchemaValidator** subvalidators, SizeType count) = 0; - virtual void NoneOf(ISchemaValidator** subvalidators, SizeType count) = 0; - virtual void NotOneOf(ISchemaValidator** subvalidators, SizeType count, bool matched) = 0; - virtual void Disallowed() = 0; -}; - - -/////////////////////////////////////////////////////////////////////////////// -// Hasher - -// For comparison of compound value -template -class Hasher { -public: - typedef typename Encoding::Ch Ch; - - Hasher(Allocator* allocator = 0, size_t stackCapacity = kDefaultSize) : stack_(allocator, stackCapacity) {} - - bool Null() { return WriteType(kNullType); } - bool Bool(bool b) { return WriteType(b ? kTrueType : kFalseType); } - bool Int(int i) { Number n; n.u.i = i; n.d = static_cast(i); return WriteNumber(n); } - bool Uint(unsigned u) { Number n; n.u.u = u; n.d = static_cast(u); return WriteNumber(n); } - bool Int64(int64_t i) { Number n; n.u.i = i; n.d = static_cast(i); return WriteNumber(n); } - bool Uint64(uint64_t u) { Number n; n.u.u = u; n.d = static_cast(u); return WriteNumber(n); } - bool Double(double d) { - Number n; - if (d < 0) n.u.i = static_cast(d); - else n.u.u = static_cast(d); - n.d = d; - return WriteNumber(n); - } - - bool RawNumber(const Ch* str, SizeType len, bool) { - WriteBuffer(kNumberType, str, len * sizeof(Ch)); - return true; - } - - bool String(const Ch* str, SizeType len, bool) { - WriteBuffer(kStringType, str, len * sizeof(Ch)); - return true; - } - - bool StartObject() { return true; } - bool Key(const Ch* str, SizeType len, bool copy) { return String(str, len, copy); } - bool EndObject(SizeType memberCount) { - uint64_t h = Hash(0, kObjectType); - uint64_t* kv = stack_.template Pop(memberCount * 2); - for (SizeType i = 0; i < memberCount; i++) - h ^= Hash(kv[i * 2], kv[i * 2 + 1]); // Use xor to achieve member order insensitive - *stack_.template Push() = h; - return true; - } - - bool StartArray() { return true; } - bool EndArray(SizeType elementCount) { - uint64_t h = Hash(0, kArrayType); - uint64_t* e = stack_.template Pop(elementCount); - for (SizeType i = 0; i < elementCount; i++) - h = Hash(h, e[i]); // Use hash to achieve element order sensitive - *stack_.template Push() = h; - return true; - } - - bool IsValid() const { return stack_.GetSize() == sizeof(uint64_t); } - - uint64_t GetHashCode() const { - RAPIDJSON_ASSERT(IsValid()); - return *stack_.template Top(); - } - -private: - static const size_t kDefaultSize = 256; - struct Number { - union U { - uint64_t u; - int64_t i; - }u; - double d; - }; - - bool WriteType(Type type) { return WriteBuffer(type, 0, 0); } - - bool WriteNumber(const Number& n) { return WriteBuffer(kNumberType, &n, sizeof(n)); } - - bool WriteBuffer(Type type, const void* data, size_t len) { - // FNV-1a from http://isthe.com/chongo/tech/comp/fnv/ - uint64_t h = Hash(RAPIDJSON_UINT64_C2(0x84222325, 0xcbf29ce4), type); - const unsigned char* d = static_cast(data); - for (size_t i = 0; i < len; i++) - h = Hash(h, d[i]); - *stack_.template Push() = h; - return true; - } - - static uint64_t Hash(uint64_t h, uint64_t d) { - static const uint64_t kPrime = RAPIDJSON_UINT64_C2(0x00000100, 0x000001b3); - h ^= d; - h *= kPrime; - return h; - } - - Stack stack_; -}; - -/////////////////////////////////////////////////////////////////////////////// -// SchemaValidationContext - -template -struct SchemaValidationContext { - typedef Schema SchemaType; - typedef ISchemaStateFactory SchemaValidatorFactoryType; - typedef IValidationErrorHandler ErrorHandlerType; - typedef typename SchemaType::ValueType ValueType; - typedef typename ValueType::Ch Ch; - - enum PatternValidatorType { - kPatternValidatorOnly, - kPatternValidatorWithProperty, - kPatternValidatorWithAdditionalProperty - }; - - SchemaValidationContext(SchemaValidatorFactoryType& f, ErrorHandlerType& eh, const SchemaType* s) : - factory(f), - error_handler(eh), - schema(s), - valueSchema(), - invalidKeyword(), - invalidCode(), - hasher(), - arrayElementHashCodes(), - validators(), - validatorCount(), - patternPropertiesValidators(), - patternPropertiesValidatorCount(), - patternPropertiesSchemas(), - patternPropertiesSchemaCount(), - valuePatternValidatorType(kPatternValidatorOnly), - propertyExist(), - inArray(false), - valueUniqueness(false), - arrayUniqueness(false) - { - } - - ~SchemaValidationContext() { - if (hasher) - factory.DestroryHasher(hasher); - if (validators) { - for (SizeType i = 0; i < validatorCount; i++) - factory.DestroySchemaValidator(validators[i]); - factory.FreeState(validators); - } - if (patternPropertiesValidators) { - for (SizeType i = 0; i < patternPropertiesValidatorCount; i++) - factory.DestroySchemaValidator(patternPropertiesValidators[i]); - factory.FreeState(patternPropertiesValidators); - } - if (patternPropertiesSchemas) - factory.FreeState(patternPropertiesSchemas); - if (propertyExist) - factory.FreeState(propertyExist); - } - - SchemaValidatorFactoryType& factory; - ErrorHandlerType& error_handler; - const SchemaType* schema; - const SchemaType* valueSchema; - const Ch* invalidKeyword; - ValidateErrorCode invalidCode; - void* hasher; // Only validator access - void* arrayElementHashCodes; // Only validator access this - ISchemaValidator** validators; - SizeType validatorCount; - ISchemaValidator** patternPropertiesValidators; - SizeType patternPropertiesValidatorCount; - const SchemaType** patternPropertiesSchemas; - SizeType patternPropertiesSchemaCount; - PatternValidatorType valuePatternValidatorType; - PatternValidatorType objectPatternValidatorType; - SizeType arrayElementIndex; - bool* propertyExist; - bool inArray; - bool valueUniqueness; - bool arrayUniqueness; -}; - -/////////////////////////////////////////////////////////////////////////////// -// Schema - -template -class Schema { -public: - typedef typename SchemaDocumentType::ValueType ValueType; - typedef typename SchemaDocumentType::AllocatorType AllocatorType; - typedef typename SchemaDocumentType::PointerType PointerType; - typedef typename ValueType::EncodingType EncodingType; - typedef typename EncodingType::Ch Ch; - typedef SchemaValidationContext Context; - typedef Schema SchemaType; - typedef GenericValue SValue; - typedef IValidationErrorHandler ErrorHandler; - typedef GenericUri UriType; - friend class GenericSchemaDocument; - - Schema(SchemaDocumentType* schemaDocument, const PointerType& p, const ValueType& value, const ValueType& document, AllocatorType* allocator, const UriType& id = UriType()) : - allocator_(allocator), - uri_(schemaDocument->GetURI(), *allocator), - id_(id), - pointer_(p, allocator), - typeless_(schemaDocument->GetTypeless()), - enum_(), - enumCount_(), - not_(), - type_((1 << kTotalSchemaType) - 1), // typeless - validatorCount_(), - notValidatorIndex_(), - properties_(), - additionalPropertiesSchema_(), - patternProperties_(), - patternPropertyCount_(), - propertyCount_(), - minProperties_(), - maxProperties_(SizeType(~0)), - additionalProperties_(true), - hasDependencies_(), - hasRequired_(), - hasSchemaDependencies_(), - additionalItemsSchema_(), - itemsList_(), - itemsTuple_(), - itemsTupleCount_(), - minItems_(), - maxItems_(SizeType(~0)), - additionalItems_(true), - uniqueItems_(false), - pattern_(), - minLength_(0), - maxLength_(~SizeType(0)), - exclusiveMinimum_(false), - exclusiveMaximum_(false), - defaultValueLength_(0) - { - typedef typename ValueType::ConstValueIterator ConstValueIterator; - typedef typename ValueType::ConstMemberIterator ConstMemberIterator; - - // PR #1393 - // Early add this Schema and its $ref(s) in schemaDocument's map to avoid infinite - // recursion (with recursive schemas), since schemaDocument->getSchema() is always - // checked before creating a new one. Don't cache typeless_, though. - if (this != typeless_) { - typedef typename SchemaDocumentType::SchemaEntry SchemaEntry; - SchemaEntry *entry = schemaDocument->schemaMap_.template Push(); - new (entry) SchemaEntry(pointer_, this, true, allocator_); - schemaDocument->AddSchemaRefs(this); - } - - if (!value.IsObject()) - return; - - // If we have an id property, resolve it with the in-scope id - if (const ValueType* v = GetMember(value, GetIdString())) { - if (v->IsString()) { - UriType local(*v, allocator); - id_ = local.Resolve(id_, allocator); - } - } - - if (const ValueType* v = GetMember(value, GetTypeString())) { - type_ = 0; - if (v->IsString()) - AddType(*v); - else if (v->IsArray()) - for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) - AddType(*itr); - } - - if (const ValueType* v = GetMember(value, GetEnumString())) { - if (v->IsArray() && v->Size() > 0) { - enum_ = static_cast(allocator_->Malloc(sizeof(uint64_t) * v->Size())); - for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) { - typedef Hasher > EnumHasherType; - char buffer[256u + 24]; - MemoryPoolAllocator<> hasherAllocator(buffer, sizeof(buffer)); - EnumHasherType h(&hasherAllocator, 256); - itr->Accept(h); - enum_[enumCount_++] = h.GetHashCode(); - } - } - } - - if (schemaDocument) { - AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document); - AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document); - AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document); - - if (const ValueType* v = GetMember(value, GetNotString())) { - schemaDocument->CreateSchema(¬_, p.Append(GetNotString(), allocator_), *v, document, id_); - notValidatorIndex_ = validatorCount_; - validatorCount_++; - } - } - - // Object - - const ValueType* properties = GetMember(value, GetPropertiesString()); - const ValueType* required = GetMember(value, GetRequiredString()); - const ValueType* dependencies = GetMember(value, GetDependenciesString()); - { - // Gather properties from properties/required/dependencies - SValue allProperties(kArrayType); - - if (properties && properties->IsObject()) - for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) - AddUniqueElement(allProperties, itr->name); - - if (required && required->IsArray()) - for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr) - if (itr->IsString()) - AddUniqueElement(allProperties, *itr); - - if (dependencies && dependencies->IsObject()) - for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) { - AddUniqueElement(allProperties, itr->name); - if (itr->value.IsArray()) - for (ConstValueIterator i = itr->value.Begin(); i != itr->value.End(); ++i) - if (i->IsString()) - AddUniqueElement(allProperties, *i); - } - - if (allProperties.Size() > 0) { - propertyCount_ = allProperties.Size(); - properties_ = static_cast(allocator_->Malloc(sizeof(Property) * propertyCount_)); - for (SizeType i = 0; i < propertyCount_; i++) { - new (&properties_[i]) Property(); - properties_[i].name = allProperties[i]; - properties_[i].schema = typeless_; - } - } - } - - if (properties && properties->IsObject()) { - PointerType q = p.Append(GetPropertiesString(), allocator_); - for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) { - SizeType index; - if (FindPropertyIndex(itr->name, &index)) - schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document, id_); - } - } - - if (const ValueType* v = GetMember(value, GetPatternPropertiesString())) { - PointerType q = p.Append(GetPatternPropertiesString(), allocator_); - patternProperties_ = static_cast(allocator_->Malloc(sizeof(PatternProperty) * v->MemberCount())); - patternPropertyCount_ = 0; - - for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) { - new (&patternProperties_[patternPropertyCount_]) PatternProperty(); - patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name); - schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, q.Append(itr->name, allocator_), itr->value, document, id_); - patternPropertyCount_++; - } - } - - if (required && required->IsArray()) - for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr) - if (itr->IsString()) { - SizeType index; - if (FindPropertyIndex(*itr, &index)) { - properties_[index].required = true; - hasRequired_ = true; - } - } - - if (dependencies && dependencies->IsObject()) { - PointerType q = p.Append(GetDependenciesString(), allocator_); - hasDependencies_ = true; - for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) { - SizeType sourceIndex; - if (FindPropertyIndex(itr->name, &sourceIndex)) { - if (itr->value.IsArray()) { - properties_[sourceIndex].dependencies = static_cast(allocator_->Malloc(sizeof(bool) * propertyCount_)); - std::memset(properties_[sourceIndex].dependencies, 0, sizeof(bool)* propertyCount_); - for (ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) { - SizeType targetIndex; - if (FindPropertyIndex(*targetItr, &targetIndex)) - properties_[sourceIndex].dependencies[targetIndex] = true; - } - } - else if (itr->value.IsObject()) { - hasSchemaDependencies_ = true; - schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document, id_); - properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_; - validatorCount_++; - } - } - } - } - - if (const ValueType* v = GetMember(value, GetAdditionalPropertiesString())) { - if (v->IsBool()) - additionalProperties_ = v->GetBool(); - else if (v->IsObject()) - schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document, id_); - } - - AssignIfExist(minProperties_, value, GetMinPropertiesString()); - AssignIfExist(maxProperties_, value, GetMaxPropertiesString()); - - // Array - if (const ValueType* v = GetMember(value, GetItemsString())) { - PointerType q = p.Append(GetItemsString(), allocator_); - if (v->IsObject()) // List validation - schemaDocument->CreateSchema(&itemsList_, q, *v, document, id_); - else if (v->IsArray()) { // Tuple validation - itemsTuple_ = static_cast(allocator_->Malloc(sizeof(const Schema*) * v->Size())); - SizeType index = 0; - for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++) - schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document, id_); - } - } - - AssignIfExist(minItems_, value, GetMinItemsString()); - AssignIfExist(maxItems_, value, GetMaxItemsString()); - - if (const ValueType* v = GetMember(value, GetAdditionalItemsString())) { - if (v->IsBool()) - additionalItems_ = v->GetBool(); - else if (v->IsObject()) - schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document, id_); - } - - AssignIfExist(uniqueItems_, value, GetUniqueItemsString()); - - // String - AssignIfExist(minLength_, value, GetMinLengthString()); - AssignIfExist(maxLength_, value, GetMaxLengthString()); - - if (const ValueType* v = GetMember(value, GetPatternString())) - pattern_ = CreatePattern(*v); - - // Number - if (const ValueType* v = GetMember(value, GetMinimumString())) - if (v->IsNumber()) - minimum_.CopyFrom(*v, *allocator_); - - if (const ValueType* v = GetMember(value, GetMaximumString())) - if (v->IsNumber()) - maximum_.CopyFrom(*v, *allocator_); - - AssignIfExist(exclusiveMinimum_, value, GetExclusiveMinimumString()); - AssignIfExist(exclusiveMaximum_, value, GetExclusiveMaximumString()); - - if (const ValueType* v = GetMember(value, GetMultipleOfString())) - if (v->IsNumber() && v->GetDouble() > 0.0) - multipleOf_.CopyFrom(*v, *allocator_); - - // Default - if (const ValueType* v = GetMember(value, GetDefaultValueString())) - if (v->IsString()) - defaultValueLength_ = v->GetStringLength(); - - } - - ~Schema() { - AllocatorType::Free(enum_); - if (properties_) { - for (SizeType i = 0; i < propertyCount_; i++) - properties_[i].~Property(); - AllocatorType::Free(properties_); - } - if (patternProperties_) { - for (SizeType i = 0; i < patternPropertyCount_; i++) - patternProperties_[i].~PatternProperty(); - AllocatorType::Free(patternProperties_); - } - AllocatorType::Free(itemsTuple_); -#if RAPIDJSON_SCHEMA_HAS_REGEX - if (pattern_) { - pattern_->~RegexType(); - AllocatorType::Free(pattern_); - } -#endif - } - - const SValue& GetURI() const { - return uri_; - } - - const UriType& GetId() const { - return id_; - } - - const PointerType& GetPointer() const { - return pointer_; - } - - bool BeginValue(Context& context) const { - if (context.inArray) { - if (uniqueItems_) - context.valueUniqueness = true; - - if (itemsList_) - context.valueSchema = itemsList_; - else if (itemsTuple_) { - if (context.arrayElementIndex < itemsTupleCount_) - context.valueSchema = itemsTuple_[context.arrayElementIndex]; - else if (additionalItemsSchema_) - context.valueSchema = additionalItemsSchema_; - else if (additionalItems_) - context.valueSchema = typeless_; - else { - context.error_handler.DisallowedItem(context.arrayElementIndex); - // Must set valueSchema for when kValidateContinueOnErrorFlag is set, else reports spurious type error - context.valueSchema = typeless_; - // Must bump arrayElementIndex for when kValidateContinueOnErrorFlag is set - context.arrayElementIndex++; - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAdditionalItems); - } - } - else - context.valueSchema = typeless_; - - context.arrayElementIndex++; - } - return true; - } - - RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const { - // Only check pattern properties if we have validators - if (context.patternPropertiesValidatorCount > 0) { - bool otherValid = false; - SizeType count = context.patternPropertiesValidatorCount; - if (context.objectPatternValidatorType != Context::kPatternValidatorOnly) - otherValid = context.patternPropertiesValidators[--count]->IsValid(); - - bool patternValid = true; - for (SizeType i = 0; i < count; i++) - if (!context.patternPropertiesValidators[i]->IsValid()) { - patternValid = false; - break; - } - - if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) { - if (!patternValid) { - context.error_handler.PropertyViolations(context.patternPropertiesValidators, count); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPatternProperties); - } - } - else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) { - if (!patternValid || !otherValid) { - context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPatternProperties); - } - } - else if (!patternValid && !otherValid) { // kPatternValidatorWithAdditionalProperty) - context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPatternProperties); - } - } - - // For enums only check if we have a hasher - if (enum_ && context.hasher) { - const uint64_t h = context.factory.GetHashCode(context.hasher); - for (SizeType i = 0; i < enumCount_; i++) - if (enum_[i] == h) - goto foundEnum; - context.error_handler.DisallowedValue(kValidateErrorEnum); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorEnum); - foundEnum:; - } - - // Only check allOf etc if we have validators - if (context.validatorCount > 0) { - if (allOf_.schemas) - for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++) - if (!context.validators[i]->IsValid()) { - context.error_handler.NotAllOf(&context.validators[allOf_.begin], allOf_.count); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAllOf); - } - - if (anyOf_.schemas) { - for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++) - if (context.validators[i]->IsValid()) - goto foundAny; - context.error_handler.NoneOf(&context.validators[anyOf_.begin], anyOf_.count); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAnyOf); - foundAny:; - } - - if (oneOf_.schemas) { - bool oneValid = false; - for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++) - if (context.validators[i]->IsValid()) { - if (oneValid) { - context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count, true); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorOneOfMatch); - } else - oneValid = true; - } - if (!oneValid) { - context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count, false); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorOneOf); - } - } - - if (not_ && context.validators[notValidatorIndex_]->IsValid()) { - context.error_handler.Disallowed(); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorNot); - } - } - - return true; - } - - bool Null(Context& context) const { - if (!(type_ & (1 << kNullSchemaType))) { - DisallowedType(context, GetNullString()); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); - } - return CreateParallelValidator(context); - } - - bool Bool(Context& context, bool) const { - if (!(type_ & (1 << kBooleanSchemaType))) { - DisallowedType(context, GetBooleanString()); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); - } - return CreateParallelValidator(context); - } - - bool Int(Context& context, int i) const { - if (!CheckInt(context, i)) - return false; - return CreateParallelValidator(context); - } - - bool Uint(Context& context, unsigned u) const { - if (!CheckUint(context, u)) - return false; - return CreateParallelValidator(context); - } - - bool Int64(Context& context, int64_t i) const { - if (!CheckInt(context, i)) - return false; - return CreateParallelValidator(context); - } - - bool Uint64(Context& context, uint64_t u) const { - if (!CheckUint(context, u)) - return false; - return CreateParallelValidator(context); - } - - bool Double(Context& context, double d) const { - if (!(type_ & (1 << kNumberSchemaType))) { - DisallowedType(context, GetNumberString()); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); - } - - if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d)) - return false; - - if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d)) - return false; - - if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d)) - return false; - - return CreateParallelValidator(context); - } - - bool String(Context& context, const Ch* str, SizeType length, bool) const { - if (!(type_ & (1 << kStringSchemaType))) { - DisallowedType(context, GetStringString()); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); - } - - if (minLength_ != 0 || maxLength_ != SizeType(~0)) { - SizeType count; - if (internal::CountStringCodePoint(str, length, &count)) { - if (count < minLength_) { - context.error_handler.TooShort(str, length, minLength_); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMinLength); - } - if (count > maxLength_) { - context.error_handler.TooLong(str, length, maxLength_); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMaxLength); - } - } - } - - if (pattern_ && !IsPatternMatch(pattern_, str, length)) { - context.error_handler.DoesNotMatch(str, length); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPattern); - } - - return CreateParallelValidator(context); - } - - bool StartObject(Context& context) const { - if (!(type_ & (1 << kObjectSchemaType))) { - DisallowedType(context, GetObjectString()); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); - } - - if (hasDependencies_ || hasRequired_) { - context.propertyExist = static_cast(context.factory.MallocState(sizeof(bool) * propertyCount_)); - std::memset(context.propertyExist, 0, sizeof(bool) * propertyCount_); - } - - if (patternProperties_) { // pre-allocate schema array - SizeType count = patternPropertyCount_ + 1; // extra for valuePatternValidatorType - context.patternPropertiesSchemas = static_cast(context.factory.MallocState(sizeof(const SchemaType*) * count)); - context.patternPropertiesSchemaCount = 0; - std::memset(context.patternPropertiesSchemas, 0, sizeof(SchemaType*) * count); - } - - return CreateParallelValidator(context); - } - - bool Key(Context& context, const Ch* str, SizeType len, bool) const { - if (patternProperties_) { - context.patternPropertiesSchemaCount = 0; - for (SizeType i = 0; i < patternPropertyCount_; i++) - if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len)) { - context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema; - context.valueSchema = typeless_; - } - } - - SizeType index = 0; - if (FindPropertyIndex(ValueType(str, len).Move(), &index)) { - if (context.patternPropertiesSchemaCount > 0) { - context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema; - context.valueSchema = typeless_; - context.valuePatternValidatorType = Context::kPatternValidatorWithProperty; - } - else - context.valueSchema = properties_[index].schema; - - if (context.propertyExist) - context.propertyExist[index] = true; - - return true; - } - - if (additionalPropertiesSchema_) { - if (context.patternPropertiesSchemaCount > 0) { - context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_; - context.valueSchema = typeless_; - context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty; - } - else - context.valueSchema = additionalPropertiesSchema_; - return true; - } - else if (additionalProperties_) { - context.valueSchema = typeless_; - return true; - } - - if (context.patternPropertiesSchemaCount == 0) { // patternProperties are not additional properties - // Must set valueSchema for when kValidateContinueOnErrorFlag is set, else reports spurious type error - context.valueSchema = typeless_; - context.error_handler.DisallowedProperty(str, len); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAdditionalProperties); - } - - return true; - } - - bool EndObject(Context& context, SizeType memberCount) const { - if (hasRequired_) { - context.error_handler.StartMissingProperties(); - for (SizeType index = 0; index < propertyCount_; index++) - if (properties_[index].required && !context.propertyExist[index]) - if (properties_[index].schema->defaultValueLength_ == 0 ) - context.error_handler.AddMissingProperty(properties_[index].name); - if (context.error_handler.EndMissingProperties()) - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorRequired); - } - - if (memberCount < minProperties_) { - context.error_handler.TooFewProperties(memberCount, minProperties_); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMinProperties); - } - - if (memberCount > maxProperties_) { - context.error_handler.TooManyProperties(memberCount, maxProperties_); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMaxProperties); - } - - if (hasDependencies_) { - context.error_handler.StartDependencyErrors(); - for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++) { - const Property& source = properties_[sourceIndex]; - if (context.propertyExist[sourceIndex]) { - if (source.dependencies) { - context.error_handler.StartMissingDependentProperties(); - for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++) - if (source.dependencies[targetIndex] && !context.propertyExist[targetIndex]) - context.error_handler.AddMissingDependentProperty(properties_[targetIndex].name); - context.error_handler.EndMissingDependentProperties(source.name); - } - else if (source.dependenciesSchema) { - ISchemaValidator* dependenciesValidator = context.validators[source.dependenciesValidatorIndex]; - if (!dependenciesValidator->IsValid()) - context.error_handler.AddDependencySchemaError(source.name, dependenciesValidator); - } - } - } - if (context.error_handler.EndDependencyErrors()) - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorDependencies); - } - - return true; - } - - bool StartArray(Context& context) const { - context.arrayElementIndex = 0; - context.inArray = true; // Ensure we note that we are in an array - - if (!(type_ & (1 << kArraySchemaType))) { - DisallowedType(context, GetArrayString()); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); - } - - return CreateParallelValidator(context); - } - - bool EndArray(Context& context, SizeType elementCount) const { - context.inArray = false; - - if (elementCount < minItems_) { - context.error_handler.TooFewItems(elementCount, minItems_); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMinItems); - } - - if (elementCount > maxItems_) { - context.error_handler.TooManyItems(elementCount, maxItems_); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMaxItems); - } - - return true; - } - - static const ValueType& GetValidateErrorKeyword(ValidateErrorCode validateErrorCode) { - switch (validateErrorCode) { - case kValidateErrorMultipleOf: return GetMultipleOfString(); - case kValidateErrorMaximum: return GetMaximumString(); - case kValidateErrorExclusiveMaximum: return GetMaximumString(); // Same - case kValidateErrorMinimum: return GetMinimumString(); - case kValidateErrorExclusiveMinimum: return GetMinimumString(); // Same - - case kValidateErrorMaxLength: return GetMaxLengthString(); - case kValidateErrorMinLength: return GetMinLengthString(); - case kValidateErrorPattern: return GetPatternString(); - - case kValidateErrorMaxItems: return GetMaxItemsString(); - case kValidateErrorMinItems: return GetMinItemsString(); - case kValidateErrorUniqueItems: return GetUniqueItemsString(); - case kValidateErrorAdditionalItems: return GetAdditionalItemsString(); - - case kValidateErrorMaxProperties: return GetMaxPropertiesString(); - case kValidateErrorMinProperties: return GetMinPropertiesString(); - case kValidateErrorRequired: return GetRequiredString(); - case kValidateErrorAdditionalProperties: return GetAdditionalPropertiesString(); - case kValidateErrorPatternProperties: return GetPatternPropertiesString(); - case kValidateErrorDependencies: return GetDependenciesString(); - - case kValidateErrorEnum: return GetEnumString(); - case kValidateErrorType: return GetTypeString(); - - case kValidateErrorOneOf: return GetOneOfString(); - case kValidateErrorOneOfMatch: return GetOneOfString(); // Same - case kValidateErrorAllOf: return GetAllOfString(); - case kValidateErrorAnyOf: return GetAnyOfString(); - case kValidateErrorNot: return GetNotString(); - - default: return GetNullString(); - } - } - - - // Generate functions for string literal according to Ch -#define RAPIDJSON_STRING_(name, ...) \ - static const ValueType& Get##name##String() {\ - static const Ch s[] = { __VA_ARGS__, '\0' };\ - static const ValueType v(s, static_cast(sizeof(s) / sizeof(Ch) - 1));\ - return v;\ - } - - RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l') - RAPIDJSON_STRING_(Boolean, 'b', 'o', 'o', 'l', 'e', 'a', 'n') - RAPIDJSON_STRING_(Object, 'o', 'b', 'j', 'e', 'c', 't') - RAPIDJSON_STRING_(Array, 'a', 'r', 'r', 'a', 'y') - RAPIDJSON_STRING_(String, 's', 't', 'r', 'i', 'n', 'g') - RAPIDJSON_STRING_(Number, 'n', 'u', 'm', 'b', 'e', 'r') - RAPIDJSON_STRING_(Integer, 'i', 'n', 't', 'e', 'g', 'e', 'r') - RAPIDJSON_STRING_(Type, 't', 'y', 'p', 'e') - RAPIDJSON_STRING_(Enum, 'e', 'n', 'u', 'm') - RAPIDJSON_STRING_(AllOf, 'a', 'l', 'l', 'O', 'f') - RAPIDJSON_STRING_(AnyOf, 'a', 'n', 'y', 'O', 'f') - RAPIDJSON_STRING_(OneOf, 'o', 'n', 'e', 'O', 'f') - RAPIDJSON_STRING_(Not, 'n', 'o', 't') - RAPIDJSON_STRING_(Properties, 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') - RAPIDJSON_STRING_(Required, 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'd') - RAPIDJSON_STRING_(Dependencies, 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'i', 'e', 's') - RAPIDJSON_STRING_(PatternProperties, 'p', 'a', 't', 't', 'e', 'r', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') - RAPIDJSON_STRING_(AdditionalProperties, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') - RAPIDJSON_STRING_(MinProperties, 'm', 'i', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') - RAPIDJSON_STRING_(MaxProperties, 'm', 'a', 'x', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') - RAPIDJSON_STRING_(Items, 'i', 't', 'e', 'm', 's') - RAPIDJSON_STRING_(MinItems, 'm', 'i', 'n', 'I', 't', 'e', 'm', 's') - RAPIDJSON_STRING_(MaxItems, 'm', 'a', 'x', 'I', 't', 'e', 'm', 's') - RAPIDJSON_STRING_(AdditionalItems, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'I', 't', 'e', 'm', 's') - RAPIDJSON_STRING_(UniqueItems, 'u', 'n', 'i', 'q', 'u', 'e', 'I', 't', 'e', 'm', 's') - RAPIDJSON_STRING_(MinLength, 'm', 'i', 'n', 'L', 'e', 'n', 'g', 't', 'h') - RAPIDJSON_STRING_(MaxLength, 'm', 'a', 'x', 'L', 'e', 'n', 'g', 't', 'h') - RAPIDJSON_STRING_(Pattern, 'p', 'a', 't', 't', 'e', 'r', 'n') - RAPIDJSON_STRING_(Minimum, 'm', 'i', 'n', 'i', 'm', 'u', 'm') - RAPIDJSON_STRING_(Maximum, 'm', 'a', 'x', 'i', 'm', 'u', 'm') - RAPIDJSON_STRING_(ExclusiveMinimum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'i', 'n', 'i', 'm', 'u', 'm') - RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm') - RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f') - RAPIDJSON_STRING_(DefaultValue, 'd', 'e', 'f', 'a', 'u', 'l', 't') - RAPIDJSON_STRING_(Ref, '$', 'r', 'e', 'f') - RAPIDJSON_STRING_(Id, 'i', 'd') - - RAPIDJSON_STRING_(SchemeEnd, ':') - RAPIDJSON_STRING_(AuthStart, '/', '/') - RAPIDJSON_STRING_(QueryStart, '?') - RAPIDJSON_STRING_(FragStart, '#') - RAPIDJSON_STRING_(Slash, '/') - RAPIDJSON_STRING_(Dot, '.') - -#undef RAPIDJSON_STRING_ - -private: - enum SchemaValueType { - kNullSchemaType, - kBooleanSchemaType, - kObjectSchemaType, - kArraySchemaType, - kStringSchemaType, - kNumberSchemaType, - kIntegerSchemaType, - kTotalSchemaType - }; - -#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX - typedef internal::GenericRegex RegexType; -#elif RAPIDJSON_SCHEMA_USE_STDREGEX - typedef std::basic_regex RegexType; -#else - typedef char RegexType; -#endif - - struct SchemaArray { - SchemaArray() : schemas(), count() {} - ~SchemaArray() { AllocatorType::Free(schemas); } - const SchemaType** schemas; - SizeType begin; // begin index of context.validators - SizeType count; - }; - - template - void AddUniqueElement(V1& a, const V2& v) { - for (typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr) - if (*itr == v) - return; - V1 c(v, *allocator_); - a.PushBack(c, *allocator_); - } - - static const ValueType* GetMember(const ValueType& value, const ValueType& name) { - typename ValueType::ConstMemberIterator itr = value.FindMember(name); - return itr != value.MemberEnd() ? &(itr->value) : 0; - } - - static void AssignIfExist(bool& out, const ValueType& value, const ValueType& name) { - if (const ValueType* v = GetMember(value, name)) - if (v->IsBool()) - out = v->GetBool(); - } - - static void AssignIfExist(SizeType& out, const ValueType& value, const ValueType& name) { - if (const ValueType* v = GetMember(value, name)) - if (v->IsUint64() && v->GetUint64() <= SizeType(~0)) - out = static_cast(v->GetUint64()); - } - - void AssignIfExist(SchemaArray& out, SchemaDocumentType& schemaDocument, const PointerType& p, const ValueType& value, const ValueType& name, const ValueType& document) { - if (const ValueType* v = GetMember(value, name)) { - if (v->IsArray() && v->Size() > 0) { - PointerType q = p.Append(name, allocator_); - out.count = v->Size(); - out.schemas = static_cast(allocator_->Malloc(out.count * sizeof(const Schema*))); - memset(out.schemas, 0, sizeof(Schema*)* out.count); - for (SizeType i = 0; i < out.count; i++) - schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document, id_); - out.begin = validatorCount_; - validatorCount_ += out.count; - } - } - } - -#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX - template - RegexType* CreatePattern(const ValueType& value) { - if (value.IsString()) { - RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), allocator_); - if (!r->IsValid()) { - r->~RegexType(); - AllocatorType::Free(r); - r = 0; - } - return r; - } - return 0; - } - - static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType) { - GenericRegexSearch rs(*pattern); - return rs.Search(str); - } -#elif RAPIDJSON_SCHEMA_USE_STDREGEX - template - RegexType* CreatePattern(const ValueType& value) { - if (value.IsString()) { - RegexType *r = static_cast(allocator_->Malloc(sizeof(RegexType))); - try { - return new (r) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript); - } - catch (const std::regex_error&) { - AllocatorType::Free(r); - } - } - return 0; - } - - static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType length) { - std::match_results r; - return std::regex_search(str, str + length, r, *pattern); - } -#else - template - RegexType* CreatePattern(const ValueType&) { return 0; } - - static bool IsPatternMatch(const RegexType*, const Ch *, SizeType) { return true; } -#endif // RAPIDJSON_SCHEMA_USE_STDREGEX - - void AddType(const ValueType& type) { - if (type == GetNullString() ) type_ |= 1 << kNullSchemaType; - else if (type == GetBooleanString()) type_ |= 1 << kBooleanSchemaType; - else if (type == GetObjectString() ) type_ |= 1 << kObjectSchemaType; - else if (type == GetArrayString() ) type_ |= 1 << kArraySchemaType; - else if (type == GetStringString() ) type_ |= 1 << kStringSchemaType; - else if (type == GetIntegerString()) type_ |= 1 << kIntegerSchemaType; - else if (type == GetNumberString() ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType); - } - - bool CreateParallelValidator(Context& context) const { - if (enum_ || context.arrayUniqueness) - context.hasher = context.factory.CreateHasher(); - - if (validatorCount_) { - RAPIDJSON_ASSERT(context.validators == 0); - context.validators = static_cast(context.factory.MallocState(sizeof(ISchemaValidator*) * validatorCount_)); - context.validatorCount = validatorCount_; - - // Always return after first failure for these sub-validators - if (allOf_.schemas) - CreateSchemaValidators(context, allOf_, false); - - if (anyOf_.schemas) - CreateSchemaValidators(context, anyOf_, false); - - if (oneOf_.schemas) - CreateSchemaValidators(context, oneOf_, false); - - if (not_) - context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_, false); - - if (hasSchemaDependencies_) { - for (SizeType i = 0; i < propertyCount_; i++) - if (properties_[i].dependenciesSchema) - context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema, false); - } - } - - return true; - } - - void CreateSchemaValidators(Context& context, const SchemaArray& schemas, const bool inheritContinueOnErrors) const { - for (SizeType i = 0; i < schemas.count; i++) - context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i], inheritContinueOnErrors); - } - - // O(n) - bool FindPropertyIndex(const ValueType& name, SizeType* outIndex) const { - SizeType len = name.GetStringLength(); - const Ch* str = name.GetString(); - for (SizeType index = 0; index < propertyCount_; index++) - if (properties_[index].name.GetStringLength() == len && - (std::memcmp(properties_[index].name.GetString(), str, sizeof(Ch) * len) == 0)) - { - *outIndex = index; - return true; - } - return false; - } - - bool CheckInt(Context& context, int64_t i) const { - if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) { - DisallowedType(context, GetIntegerString()); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); - } - - if (!minimum_.IsNull()) { - if (minimum_.IsInt64()) { - if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64()) { - context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_); - RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum); - } - } - else if (minimum_.IsUint64()) { - context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_); - RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum); // i <= max(int64_t) < minimum.GetUint64() - } - else if (!CheckDoubleMinimum(context, static_cast(i))) - return false; - } - - if (!maximum_.IsNull()) { - if (maximum_.IsInt64()) { - if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) { - context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_); - RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum); - } - } - else if (maximum_.IsUint64()) { } - /* do nothing */ // i <= max(int64_t) < maximum_.GetUint64() - else if (!CheckDoubleMaximum(context, static_cast(i))) - return false; - } - - if (!multipleOf_.IsNull()) { - if (multipleOf_.IsUint64()) { - if (static_cast(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0) { - context.error_handler.NotMultipleOf(i, multipleOf_); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMultipleOf); - } - } - else if (!CheckDoubleMultipleOf(context, static_cast(i))) - return false; - } - - return true; - } - - bool CheckUint(Context& context, uint64_t i) const { - if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) { - DisallowedType(context, GetIntegerString()); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); - } - - if (!minimum_.IsNull()) { - if (minimum_.IsUint64()) { - if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64()) { - context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_); - RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum); - } - } - else if (minimum_.IsInt64()) - /* do nothing */; // i >= 0 > minimum.Getint64() - else if (!CheckDoubleMinimum(context, static_cast(i))) - return false; - } - - if (!maximum_.IsNull()) { - if (maximum_.IsUint64()) { - if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64()) { - context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_); - RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum); - } - } - else if (maximum_.IsInt64()) { - context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_); - RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum); // i >= 0 > maximum_ - } - else if (!CheckDoubleMaximum(context, static_cast(i))) - return false; - } - - if (!multipleOf_.IsNull()) { - if (multipleOf_.IsUint64()) { - if (i % multipleOf_.GetUint64() != 0) { - context.error_handler.NotMultipleOf(i, multipleOf_); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMultipleOf); - } - } - else if (!CheckDoubleMultipleOf(context, static_cast(i))) - return false; - } - - return true; - } - - bool CheckDoubleMinimum(Context& context, double d) const { - if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble()) { - context.error_handler.BelowMinimum(d, minimum_, exclusiveMinimum_); - RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum); - } - return true; - } - - bool CheckDoubleMaximum(Context& context, double d) const { - if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble()) { - context.error_handler.AboveMaximum(d, maximum_, exclusiveMaximum_); - RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum); - } - return true; - } - - bool CheckDoubleMultipleOf(Context& context, double d) const { - double a = std::abs(d), b = std::abs(multipleOf_.GetDouble()); - double q = std::floor(a / b); - double r = a - q * b; - if (r > 0.0) { - context.error_handler.NotMultipleOf(d, multipleOf_); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMultipleOf); - } - return true; - } - - void DisallowedType(Context& context, const ValueType& actualType) const { - ErrorHandler& eh = context.error_handler; - eh.StartDisallowedType(); - - if (type_ & (1 << kNullSchemaType)) eh.AddExpectedType(GetNullString()); - if (type_ & (1 << kBooleanSchemaType)) eh.AddExpectedType(GetBooleanString()); - if (type_ & (1 << kObjectSchemaType)) eh.AddExpectedType(GetObjectString()); - if (type_ & (1 << kArraySchemaType)) eh.AddExpectedType(GetArrayString()); - if (type_ & (1 << kStringSchemaType)) eh.AddExpectedType(GetStringString()); - - if (type_ & (1 << kNumberSchemaType)) eh.AddExpectedType(GetNumberString()); - else if (type_ & (1 << kIntegerSchemaType)) eh.AddExpectedType(GetIntegerString()); - - eh.EndDisallowedType(actualType); - } - - struct Property { - Property() : schema(), dependenciesSchema(), dependenciesValidatorIndex(), dependencies(), required(false) {} - ~Property() { AllocatorType::Free(dependencies); } - SValue name; - const SchemaType* schema; - const SchemaType* dependenciesSchema; - SizeType dependenciesValidatorIndex; - bool* dependencies; - bool required; - }; - - struct PatternProperty { - PatternProperty() : schema(), pattern() {} - ~PatternProperty() { - if (pattern) { - pattern->~RegexType(); - AllocatorType::Free(pattern); - } - } - const SchemaType* schema; - RegexType* pattern; - }; - - AllocatorType* allocator_; - SValue uri_; - UriType id_; - PointerType pointer_; - const SchemaType* typeless_; - uint64_t* enum_; - SizeType enumCount_; - SchemaArray allOf_; - SchemaArray anyOf_; - SchemaArray oneOf_; - const SchemaType* not_; - unsigned type_; // bitmask of kSchemaType - SizeType validatorCount_; - SizeType notValidatorIndex_; - - Property* properties_; - const SchemaType* additionalPropertiesSchema_; - PatternProperty* patternProperties_; - SizeType patternPropertyCount_; - SizeType propertyCount_; - SizeType minProperties_; - SizeType maxProperties_; - bool additionalProperties_; - bool hasDependencies_; - bool hasRequired_; - bool hasSchemaDependencies_; - - const SchemaType* additionalItemsSchema_; - const SchemaType* itemsList_; - const SchemaType** itemsTuple_; - SizeType itemsTupleCount_; - SizeType minItems_; - SizeType maxItems_; - bool additionalItems_; - bool uniqueItems_; - - RegexType* pattern_; - SizeType minLength_; - SizeType maxLength_; - - SValue minimum_; - SValue maximum_; - SValue multipleOf_; - bool exclusiveMinimum_; - bool exclusiveMaximum_; - - SizeType defaultValueLength_; -}; - -template -struct TokenHelper { - RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) { - *documentStack.template Push() = '/'; - char buffer[21]; - size_t length = static_cast((sizeof(SizeType) == 4 ? u32toa(index, buffer) : u64toa(index, buffer)) - buffer); - for (size_t i = 0; i < length; i++) - *documentStack.template Push() = static_cast(buffer[i]); - } -}; - -// Partial specialized version for char to prevent buffer copying. -template -struct TokenHelper { - RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) { - if (sizeof(SizeType) == 4) { - char *buffer = documentStack.template Push(1 + 10); // '/' + uint - *buffer++ = '/'; - const char* end = internal::u32toa(index, buffer); - documentStack.template Pop(static_cast(10 - (end - buffer))); - } - else { - char *buffer = documentStack.template Push(1 + 20); // '/' + uint64 - *buffer++ = '/'; - const char* end = internal::u64toa(index, buffer); - documentStack.template Pop(static_cast(20 - (end - buffer))); - } - } -}; - -} // namespace internal - -/////////////////////////////////////////////////////////////////////////////// -// IGenericRemoteSchemaDocumentProvider - -template -class IGenericRemoteSchemaDocumentProvider { -public: - typedef typename SchemaDocumentType::Ch Ch; - typedef typename SchemaDocumentType::ValueType ValueType; - typedef typename SchemaDocumentType::AllocatorType AllocatorType; - - virtual ~IGenericRemoteSchemaDocumentProvider() {} - virtual const SchemaDocumentType* GetRemoteDocument(const Ch* uri, SizeType length) = 0; - virtual const SchemaDocumentType* GetRemoteDocument(GenericUri uri) { return GetRemoteDocument(uri.GetBaseString(), uri.GetBaseStringLength()); } -}; - -/////////////////////////////////////////////////////////////////////////////// -// GenericSchemaDocument - -//! JSON schema document. -/*! - A JSON schema document is a compiled version of a JSON schema. - It is basically a tree of internal::Schema. - - \note This is an immutable class (i.e. its instance cannot be modified after construction). - \tparam ValueT Type of JSON value (e.g. \c Value ), which also determine the encoding. - \tparam Allocator Allocator type for allocating memory of this document. -*/ -template -class GenericSchemaDocument { -public: - typedef ValueT ValueType; - typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProviderType; - typedef Allocator AllocatorType; - typedef typename ValueType::EncodingType EncodingType; - typedef typename EncodingType::Ch Ch; - typedef internal::Schema SchemaType; - typedef GenericPointer PointerType; - typedef GenericValue SValue; - typedef GenericUri UriType; - friend class internal::Schema; - template - friend class GenericSchemaValidator; - - //! Constructor. - /*! - Compile a JSON document into schema document. - - \param document A JSON document as source. - \param uri The base URI of this schema document for purposes of violation reporting. - \param uriLength Length of \c name, in code points. - \param remoteProvider An optional remote schema document provider for resolving remote reference. Can be null. - \param allocator An optional allocator instance for allocating memory. Can be null. - \param pointer An optional JSON pointer to the start of the schema document - */ - explicit GenericSchemaDocument(const ValueType& document, const Ch* uri = 0, SizeType uriLength = 0, - IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0, - const PointerType& pointer = PointerType()) : // PR #1393 - remoteProvider_(remoteProvider), - allocator_(allocator), - ownAllocator_(), - root_(), - typeless_(), - schemaMap_(allocator, kInitialSchemaMapSize), - schemaRef_(allocator, kInitialSchemaRefSize) - { - if (!allocator_) - ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); - - Ch noUri[1] = {0}; - uri_.SetString(uri ? uri : noUri, uriLength, *allocator_); - docId_ = UriType(uri_, allocator_); - - typeless_ = static_cast(allocator_->Malloc(sizeof(SchemaType))); - new (typeless_) SchemaType(this, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), allocator_, docId_); - - // Generate root schema, it will call CreateSchema() to create sub-schemas, - // And call HandleRefSchema() if there are $ref. - // PR #1393 use input pointer if supplied - root_ = typeless_; - if (pointer.GetTokenCount() == 0) { - CreateSchemaRecursive(&root_, pointer, document, document, docId_); - } - else if (const ValueType* v = pointer.Get(document)) { - CreateSchema(&root_, pointer, *v, document, docId_); - } - - RAPIDJSON_ASSERT(root_ != 0); - - schemaRef_.ShrinkToFit(); // Deallocate all memory for ref - } - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - //! Move constructor in C++11 - GenericSchemaDocument(GenericSchemaDocument&& rhs) RAPIDJSON_NOEXCEPT : - remoteProvider_(rhs.remoteProvider_), - allocator_(rhs.allocator_), - ownAllocator_(rhs.ownAllocator_), - root_(rhs.root_), - typeless_(rhs.typeless_), - schemaMap_(std::move(rhs.schemaMap_)), - schemaRef_(std::move(rhs.schemaRef_)), - uri_(std::move(rhs.uri_)), - docId_(rhs.docId_) - { - rhs.remoteProvider_ = 0; - rhs.allocator_ = 0; - rhs.ownAllocator_ = 0; - rhs.typeless_ = 0; - } -#endif - - //! Destructor - ~GenericSchemaDocument() { - while (!schemaMap_.Empty()) - schemaMap_.template Pop(1)->~SchemaEntry(); - - if (typeless_) { - typeless_->~SchemaType(); - Allocator::Free(typeless_); - } - - RAPIDJSON_DELETE(ownAllocator_); - } - - const SValue& GetURI() const { return uri_; } - - //! Get the root schema. - const SchemaType& GetRoot() const { return *root_; } - -private: - //! Prohibit copying - GenericSchemaDocument(const GenericSchemaDocument&); - //! Prohibit assignment - GenericSchemaDocument& operator=(const GenericSchemaDocument&); - - typedef const PointerType* SchemaRefPtr; // PR #1393 - - struct SchemaEntry { - SchemaEntry(const PointerType& p, SchemaType* s, bool o, Allocator* allocator) : pointer(p, allocator), schema(s), owned(o) {} - ~SchemaEntry() { - if (owned) { - schema->~SchemaType(); - Allocator::Free(schema); - } - } - PointerType pointer; - SchemaType* schema; - bool owned; - }; - - // Changed by PR #1393 - void CreateSchemaRecursive(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document, const UriType& id) { - if (v.GetType() == kObjectType) { - UriType newid = UriType(CreateSchema(schema, pointer, v, document, id), allocator_); - - for (typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr) - CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document, newid); - } - else if (v.GetType() == kArrayType) - for (SizeType i = 0; i < v.Size(); i++) - CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document, id); - } - - // Changed by PR #1393 - const UriType& CreateSchema(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document, const UriType& id) { - RAPIDJSON_ASSERT(pointer.IsValid()); - if (v.IsObject()) { - if (const SchemaType* sc = GetSchema(pointer)) { - if (schema) - *schema = sc; - AddSchemaRefs(const_cast(sc)); - } - else if (!HandleRefSchema(pointer, schema, v, document, id)) { - // The new schema constructor adds itself and its $ref(s) to schemaMap_ - SchemaType* s = new (allocator_->Malloc(sizeof(SchemaType))) SchemaType(this, pointer, v, document, allocator_, id); - if (schema) - *schema = s; - return s->GetId(); - } - } - else { - if (schema) - *schema = typeless_; - AddSchemaRefs(typeless_); - } - return id; - } - - // Changed by PR #1393 - // TODO should this return a UriType& ? - bool HandleRefSchema(const PointerType& source, const SchemaType** schema, const ValueType& v, const ValueType& document, const UriType& id) { - typename ValueType::ConstMemberIterator itr = v.FindMember(SchemaType::GetRefString()); - if (itr == v.MemberEnd()) - return false; - - // Resolve the source pointer to the $ref'ed schema (finally) - new (schemaRef_.template Push()) SchemaRefPtr(&source); - - if (itr->value.IsString()) { - SizeType len = itr->value.GetStringLength(); - if (len > 0) { - // First resolve $ref against the in-scope id - UriType scopeId = UriType(id, allocator_); - UriType ref = UriType(itr->value, allocator_).Resolve(scopeId, allocator_); - // See if the resolved $ref minus the fragment matches a resolved id in this document - // Search from the root. Returns the subschema in the document and its absolute JSON pointer. - PointerType basePointer = PointerType(); - const ValueType *base = FindId(document, ref, basePointer, docId_, false); - if (!base) { - // Remote reference - call the remote document provider - if (remoteProvider_) { - if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(ref)) { - const Ch* s = ref.GetFragString(); - len = ref.GetFragStringLength(); - if (len <= 1 || s[1] == '/') { - // JSON pointer fragment, absolute in the remote schema - const PointerType pointer(s, len, allocator_); - if (pointer.IsValid()) { - // Get the subschema - if (const SchemaType *sc = remoteDocument->GetSchema(pointer)) { - if (schema) - *schema = sc; - AddSchemaRefs(const_cast(sc)); - return true; - } - } - } else { - // Plain name fragment, not allowed - } - } - } - } - else { // Local reference - const Ch* s = ref.GetFragString(); - len = ref.GetFragStringLength(); - if (len <= 1 || s[1] == '/') { - // JSON pointer fragment, relative to the resolved URI - const PointerType relPointer(s, len, allocator_); - if (relPointer.IsValid()) { - // Get the subschema - if (const ValueType *pv = relPointer.Get(*base)) { - // Now get the absolute JSON pointer by adding relative to base - PointerType pointer(basePointer); - for (SizeType i = 0; i < relPointer.GetTokenCount(); i++) - pointer = pointer.Append(relPointer.GetTokens()[i], allocator_); - //GenericStringBuffer sb; - //pointer.StringifyUriFragment(sb); - if (pointer.IsValid() && !IsCyclicRef(pointer)) { - // Call CreateSchema recursively, but first compute the in-scope id for the $ref target as we have jumped there - // TODO: cache pointer <-> id mapping - size_t unresolvedTokenIndex; - scopeId = pointer.GetUri(document, docId_, &unresolvedTokenIndex, allocator_); - CreateSchema(schema, pointer, *pv, document, scopeId); - return true; - } - } - } - } else { - // Plain name fragment, relative to the resolved URI - // See if the fragment matches an id in this document. - // Search from the base we just established. Returns the subschema in the document and its absolute JSON pointer. - PointerType pointer = PointerType(); - if (const ValueType *pv = FindId(*base, ref, pointer, UriType(ref.GetBaseString(), ref.GetBaseStringLength(), allocator_), true, basePointer)) { - if (!IsCyclicRef(pointer)) { - //GenericStringBuffer sb; - //pointer.StringifyUriFragment(sb); - // Call CreateSchema recursively, but first compute the in-scope id for the $ref target as we have jumped there - // TODO: cache pointer <-> id mapping - size_t unresolvedTokenIndex; - scopeId = pointer.GetUri(document, docId_, &unresolvedTokenIndex, allocator_); - CreateSchema(schema, pointer, *pv, document, scopeId); - return true; - } - } - } - } - } - } - - // Invalid/Unknown $ref - if (schema) - *schema = typeless_; - AddSchemaRefs(typeless_); - return true; - } - - //! Find the first subschema with a resolved 'id' that matches the specified URI. - // If full specified use all URI else ignore fragment. - // If found, return a pointer to the subschema and its JSON pointer. - // TODO cache pointer <-> id mapping - ValueType* FindId(const ValueType& doc, const UriType& finduri, PointerType& resptr, const UriType& baseuri, bool full, const PointerType& here = PointerType()) const { - SizeType i = 0; - ValueType* resval = 0; - UriType tempuri = UriType(finduri, allocator_); - UriType localuri = UriType(baseuri, allocator_); - if (doc.GetType() == kObjectType) { - // Establish the base URI of this object - typename ValueType::ConstMemberIterator m = doc.FindMember(SchemaType::GetIdString()); - if (m != doc.MemberEnd() && m->value.GetType() == kStringType) { - localuri = UriType(m->value, allocator_).Resolve(baseuri, allocator_); - } - // See if it matches - if (localuri.Match(finduri, full)) { - resval = const_cast(&doc); - resptr = here; - return resval; - } - // No match, continue looking - for (m = doc.MemberBegin(); m != doc.MemberEnd(); ++m) { - if (m->value.GetType() == kObjectType || m->value.GetType() == kArrayType) { - resval = FindId(m->value, finduri, resptr, localuri, full, here.Append(m->name.GetString(), m->name.GetStringLength(), allocator_)); - } - if (resval) break; - } - } else if (doc.GetType() == kArrayType) { - // Continue looking - for (typename ValueType::ConstValueIterator v = doc.Begin(); v != doc.End(); ++v) { - if (v->GetType() == kObjectType || v->GetType() == kArrayType) { - resval = FindId(*v, finduri, resptr, localuri, full, here.Append(i, allocator_)); - } - if (resval) break; - i++; - } - } - return resval; - } - - // Added by PR #1393 - void AddSchemaRefs(SchemaType* schema) { - while (!schemaRef_.Empty()) { - SchemaRefPtr *ref = schemaRef_.template Pop(1); - SchemaEntry *entry = schemaMap_.template Push(); - new (entry) SchemaEntry(**ref, schema, false, allocator_); - } - } - - // Added by PR #1393 - bool IsCyclicRef(const PointerType& pointer) const { - for (const SchemaRefPtr* ref = schemaRef_.template Bottom(); ref != schemaRef_.template End(); ++ref) - if (pointer == **ref) - return true; - return false; - } - - const SchemaType* GetSchema(const PointerType& pointer) const { - for (const SchemaEntry* target = schemaMap_.template Bottom(); target != schemaMap_.template End(); ++target) - if (pointer == target->pointer) - return target->schema; - return 0; - } - - PointerType GetPointer(const SchemaType* schema) const { - for (const SchemaEntry* target = schemaMap_.template Bottom(); target != schemaMap_.template End(); ++target) - if (schema == target->schema) - return target->pointer; - return PointerType(); - } - - const SchemaType* GetTypeless() const { return typeless_; } - - static const size_t kInitialSchemaMapSize = 64; - static const size_t kInitialSchemaRefSize = 64; - - IRemoteSchemaDocumentProviderType* remoteProvider_; - Allocator *allocator_; - Allocator *ownAllocator_; - const SchemaType* root_; //!< Root schema. - SchemaType* typeless_; - internal::Stack schemaMap_; // Stores created Pointer -> Schemas - internal::Stack schemaRef_; // Stores Pointer(s) from $ref(s) until resolved - SValue uri_; // Schema document URI - UriType docId_; -}; - -//! GenericSchemaDocument using Value type. -typedef GenericSchemaDocument SchemaDocument; -//! IGenericRemoteSchemaDocumentProvider using SchemaDocument. -typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProvider; - -/////////////////////////////////////////////////////////////////////////////// -// GenericSchemaValidator - -//! JSON Schema Validator. -/*! - A SAX style JSON schema validator. - It uses a \c GenericSchemaDocument to validate SAX events. - It delegates the incoming SAX events to an output handler. - The default output handler does nothing. - It can be reused multiple times by calling \c Reset(). - - \tparam SchemaDocumentType Type of schema document. - \tparam OutputHandler Type of output handler. Default handler does nothing. - \tparam StateAllocator Allocator for storing the internal validation states. -*/ -template < - typename SchemaDocumentType, - typename OutputHandler = BaseReaderHandler, - typename StateAllocator = CrtAllocator> -class GenericSchemaValidator : - public internal::ISchemaStateFactory, - public internal::ISchemaValidator, - public internal::IValidationErrorHandler { -public: - typedef typename SchemaDocumentType::SchemaType SchemaType; - typedef typename SchemaDocumentType::PointerType PointerType; - typedef typename SchemaType::EncodingType EncodingType; - typedef typename SchemaType::SValue SValue; - typedef typename EncodingType::Ch Ch; - typedef GenericStringRef StringRefType; - typedef GenericValue ValueType; - - //! Constructor without output handler. - /*! - \param schemaDocument The schema document to conform to. - \param allocator Optional allocator for storing internal validation states. - \param schemaStackCapacity Optional initial capacity of schema path stack. - \param documentStackCapacity Optional initial capacity of document path stack. - */ - GenericSchemaValidator( - const SchemaDocumentType& schemaDocument, - StateAllocator* allocator = 0, - size_t schemaStackCapacity = kDefaultSchemaStackCapacity, - size_t documentStackCapacity = kDefaultDocumentStackCapacity) - : - schemaDocument_(&schemaDocument), - root_(schemaDocument.GetRoot()), - stateAllocator_(allocator), - ownStateAllocator_(0), - schemaStack_(allocator, schemaStackCapacity), - documentStack_(allocator, documentStackCapacity), - outputHandler_(0), - error_(kObjectType), - currentError_(), - missingDependents_(), - valid_(true), - flags_(kValidateDefaultFlags) -#if RAPIDJSON_SCHEMA_VERBOSE - , depth_(0) -#endif - { - } - - //! Constructor with output handler. - /*! - \param schemaDocument The schema document to conform to. - \param allocator Optional allocator for storing internal validation states. - \param schemaStackCapacity Optional initial capacity of schema path stack. - \param documentStackCapacity Optional initial capacity of document path stack. - */ - GenericSchemaValidator( - const SchemaDocumentType& schemaDocument, - OutputHandler& outputHandler, - StateAllocator* allocator = 0, - size_t schemaStackCapacity = kDefaultSchemaStackCapacity, - size_t documentStackCapacity = kDefaultDocumentStackCapacity) - : - schemaDocument_(&schemaDocument), - root_(schemaDocument.GetRoot()), - stateAllocator_(allocator), - ownStateAllocator_(0), - schemaStack_(allocator, schemaStackCapacity), - documentStack_(allocator, documentStackCapacity), - outputHandler_(&outputHandler), - error_(kObjectType), - currentError_(), - missingDependents_(), - valid_(true), - flags_(kValidateDefaultFlags) -#if RAPIDJSON_SCHEMA_VERBOSE - , depth_(0) -#endif - { - } - - //! Destructor. - ~GenericSchemaValidator() { - Reset(); - RAPIDJSON_DELETE(ownStateAllocator_); - } - - //! Reset the internal states. - void Reset() { - while (!schemaStack_.Empty()) - PopSchema(); - documentStack_.Clear(); - ResetError(); - } - - //! Reset the error state. - void ResetError() { - error_.SetObject(); - currentError_.SetNull(); - missingDependents_.SetNull(); - valid_ = true; - } - - //! Implementation of ISchemaValidator - void SetValidateFlags(unsigned flags) { - flags_ = flags; - } - virtual unsigned GetValidateFlags() const { - return flags_; - } - - //! Checks whether the current state is valid. - // Implementation of ISchemaValidator - virtual bool IsValid() const { - if (!valid_) return false; - if (GetContinueOnErrors() && !error_.ObjectEmpty()) return false; - return true; - } - - //! Gets the error object. - ValueType& GetError() { return error_; } - const ValueType& GetError() const { return error_; } - - //! Gets the JSON pointer pointed to the invalid schema. - // If reporting all errors, the stack will be empty. - PointerType GetInvalidSchemaPointer() const { - return schemaStack_.Empty() ? PointerType() : CurrentSchema().GetPointer(); - } - - //! Gets the keyword of invalid schema. - // If reporting all errors, the stack will be empty, so return "errors". - const Ch* GetInvalidSchemaKeyword() const { - if (!schemaStack_.Empty()) return CurrentContext().invalidKeyword; - if (GetContinueOnErrors() && !error_.ObjectEmpty()) return (const Ch*)GetErrorsString(); - return 0; - } - - //! Gets the error code of invalid schema. - // If reporting all errors, the stack will be empty, so return kValidateErrors. - ValidateErrorCode GetInvalidSchemaCode() const { - if (!schemaStack_.Empty()) return CurrentContext().invalidCode; - if (GetContinueOnErrors() && !error_.ObjectEmpty()) return kValidateErrors; - return kValidateErrorNone; - } - - //! Gets the JSON pointer pointed to the invalid value. - // If reporting all errors, the stack will be empty. - PointerType GetInvalidDocumentPointer() const { - if (documentStack_.Empty()) { - return PointerType(); - } - else { - return PointerType(documentStack_.template Bottom(), documentStack_.GetSize() / sizeof(Ch)); - } - } - - void NotMultipleOf(int64_t actual, const SValue& expected) { - AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected); - } - void NotMultipleOf(uint64_t actual, const SValue& expected) { - AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected); - } - void NotMultipleOf(double actual, const SValue& expected) { - AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected); - } - void AboveMaximum(int64_t actual, const SValue& expected, bool exclusive) { - AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum, ValueType(actual).Move(), expected, - exclusive ? &SchemaType::GetExclusiveMaximumString : 0); - } - void AboveMaximum(uint64_t actual, const SValue& expected, bool exclusive) { - AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum, ValueType(actual).Move(), expected, - exclusive ? &SchemaType::GetExclusiveMaximumString : 0); - } - void AboveMaximum(double actual, const SValue& expected, bool exclusive) { - AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum, ValueType(actual).Move(), expected, - exclusive ? &SchemaType::GetExclusiveMaximumString : 0); - } - void BelowMinimum(int64_t actual, const SValue& expected, bool exclusive) { - AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum, ValueType(actual).Move(), expected, - exclusive ? &SchemaType::GetExclusiveMinimumString : 0); - } - void BelowMinimum(uint64_t actual, const SValue& expected, bool exclusive) { - AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum, ValueType(actual).Move(), expected, - exclusive ? &SchemaType::GetExclusiveMinimumString : 0); - } - void BelowMinimum(double actual, const SValue& expected, bool exclusive) { - AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum, ValueType(actual).Move(), expected, - exclusive ? &SchemaType::GetExclusiveMinimumString : 0); - } - - void TooLong(const Ch* str, SizeType length, SizeType expected) { - AddNumberError(kValidateErrorMaxLength, - ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move()); - } - void TooShort(const Ch* str, SizeType length, SizeType expected) { - AddNumberError(kValidateErrorMinLength, - ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move()); - } - void DoesNotMatch(const Ch* str, SizeType length) { - currentError_.SetObject(); - currentError_.AddMember(GetActualString(), ValueType(str, length, GetStateAllocator()).Move(), GetStateAllocator()); - AddCurrentError(kValidateErrorPattern); - } - - void DisallowedItem(SizeType index) { - currentError_.SetObject(); - currentError_.AddMember(GetDisallowedString(), ValueType(index).Move(), GetStateAllocator()); - AddCurrentError(kValidateErrorAdditionalItems, true); - } - void TooFewItems(SizeType actualCount, SizeType expectedCount) { - AddNumberError(kValidateErrorMinItems, - ValueType(actualCount).Move(), SValue(expectedCount).Move()); - } - void TooManyItems(SizeType actualCount, SizeType expectedCount) { - AddNumberError(kValidateErrorMaxItems, - ValueType(actualCount).Move(), SValue(expectedCount).Move()); - } - void DuplicateItems(SizeType index1, SizeType index2) { - ValueType duplicates(kArrayType); - duplicates.PushBack(index1, GetStateAllocator()); - duplicates.PushBack(index2, GetStateAllocator()); - currentError_.SetObject(); - currentError_.AddMember(GetDuplicatesString(), duplicates, GetStateAllocator()); - AddCurrentError(kValidateErrorUniqueItems, true); - } - - void TooManyProperties(SizeType actualCount, SizeType expectedCount) { - AddNumberError(kValidateErrorMaxProperties, - ValueType(actualCount).Move(), SValue(expectedCount).Move()); - } - void TooFewProperties(SizeType actualCount, SizeType expectedCount) { - AddNumberError(kValidateErrorMinProperties, - ValueType(actualCount).Move(), SValue(expectedCount).Move()); - } - void StartMissingProperties() { - currentError_.SetArray(); - } - void AddMissingProperty(const SValue& name) { - currentError_.PushBack(ValueType(name, GetStateAllocator()).Move(), GetStateAllocator()); - } - bool EndMissingProperties() { - if (currentError_.Empty()) - return false; - ValueType error(kObjectType); - error.AddMember(GetMissingString(), currentError_, GetStateAllocator()); - currentError_ = error; - AddCurrentError(kValidateErrorRequired); - return true; - } - void PropertyViolations(ISchemaValidator** subvalidators, SizeType count) { - for (SizeType i = 0; i < count; ++i) - MergeError(static_cast(subvalidators[i])->GetError()); - } - void DisallowedProperty(const Ch* name, SizeType length) { - currentError_.SetObject(); - currentError_.AddMember(GetDisallowedString(), ValueType(name, length, GetStateAllocator()).Move(), GetStateAllocator()); - AddCurrentError(kValidateErrorAdditionalProperties, true); - } - - void StartDependencyErrors() { - currentError_.SetObject(); - } - void StartMissingDependentProperties() { - missingDependents_.SetArray(); - } - void AddMissingDependentProperty(const SValue& targetName) { - missingDependents_.PushBack(ValueType(targetName, GetStateAllocator()).Move(), GetStateAllocator()); - } - void EndMissingDependentProperties(const SValue& sourceName) { - if (!missingDependents_.Empty()) { - // Create equivalent 'required' error - ValueType error(kObjectType); - ValidateErrorCode code = kValidateErrorRequired; - error.AddMember(GetMissingString(), missingDependents_.Move(), GetStateAllocator()); - AddErrorCode(error, code); - AddErrorInstanceLocation(error, false); - // When appending to a pointer ensure its allocator is used - PointerType schemaRef = GetInvalidSchemaPointer().Append(SchemaType::GetValidateErrorKeyword(kValidateErrorDependencies), &GetInvalidSchemaPointer().GetAllocator()); - AddErrorSchemaLocation(error, schemaRef.Append(sourceName.GetString(), sourceName.GetStringLength(), &GetInvalidSchemaPointer().GetAllocator())); - ValueType wrapper(kObjectType); - wrapper.AddMember(ValueType(SchemaType::GetValidateErrorKeyword(code), GetStateAllocator()).Move(), error, GetStateAllocator()); - currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(), wrapper, GetStateAllocator()); - } - } - void AddDependencySchemaError(const SValue& sourceName, ISchemaValidator* subvalidator) { - currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(), - static_cast(subvalidator)->GetError(), GetStateAllocator()); - } - bool EndDependencyErrors() { - if (currentError_.ObjectEmpty()) - return false; - ValueType error(kObjectType); - error.AddMember(GetErrorsString(), currentError_, GetStateAllocator()); - currentError_ = error; - AddCurrentError(kValidateErrorDependencies); - return true; - } - - void DisallowedValue(const ValidateErrorCode code = kValidateErrorEnum) { - currentError_.SetObject(); - AddCurrentError(code); - } - void StartDisallowedType() { - currentError_.SetArray(); - } - void AddExpectedType(const typename SchemaType::ValueType& expectedType) { - currentError_.PushBack(ValueType(expectedType, GetStateAllocator()).Move(), GetStateAllocator()); - } - void EndDisallowedType(const typename SchemaType::ValueType& actualType) { - ValueType error(kObjectType); - error.AddMember(GetExpectedString(), currentError_, GetStateAllocator()); - error.AddMember(GetActualString(), ValueType(actualType, GetStateAllocator()).Move(), GetStateAllocator()); - currentError_ = error; - AddCurrentError(kValidateErrorType); - } - void NotAllOf(ISchemaValidator** subvalidators, SizeType count) { - // Treat allOf like oneOf and anyOf to match https://rapidjson.org/md_doc_schema.html#allOf-anyOf-oneOf - AddErrorArray(kValidateErrorAllOf, subvalidators, count); - //for (SizeType i = 0; i < count; ++i) { - // MergeError(static_cast(subvalidators[i])->GetError()); - //} - } - void NoneOf(ISchemaValidator** subvalidators, SizeType count) { - AddErrorArray(kValidateErrorAnyOf, subvalidators, count); - } - void NotOneOf(ISchemaValidator** subvalidators, SizeType count, bool matched = false) { - AddErrorArray(matched ? kValidateErrorOneOfMatch : kValidateErrorOneOf, subvalidators, count); - } - void Disallowed() { - currentError_.SetObject(); - AddCurrentError(kValidateErrorNot); - } - -#define RAPIDJSON_STRING_(name, ...) \ - static const StringRefType& Get##name##String() {\ - static const Ch s[] = { __VA_ARGS__, '\0' };\ - static const StringRefType v(s, static_cast(sizeof(s) / sizeof(Ch) - 1)); \ - return v;\ - } - - RAPIDJSON_STRING_(InstanceRef, 'i', 'n', 's', 't', 'a', 'n', 'c', 'e', 'R', 'e', 'f') - RAPIDJSON_STRING_(SchemaRef, 's', 'c', 'h', 'e', 'm', 'a', 'R', 'e', 'f') - RAPIDJSON_STRING_(Expected, 'e', 'x', 'p', 'e', 'c', 't', 'e', 'd') - RAPIDJSON_STRING_(Actual, 'a', 'c', 't', 'u', 'a', 'l') - RAPIDJSON_STRING_(Disallowed, 'd', 'i', 's', 'a', 'l', 'l', 'o', 'w', 'e', 'd') - RAPIDJSON_STRING_(Missing, 'm', 'i', 's', 's', 'i', 'n', 'g') - RAPIDJSON_STRING_(Errors, 'e', 'r', 'r', 'o', 'r', 's') - RAPIDJSON_STRING_(ErrorCode, 'e', 'r', 'r', 'o', 'r', 'C', 'o', 'd', 'e') - RAPIDJSON_STRING_(ErrorMessage, 'e', 'r', 'r', 'o', 'r', 'M', 'e', 's', 's', 'a', 'g', 'e') - RAPIDJSON_STRING_(Duplicates, 'd', 'u', 'p', 'l', 'i', 'c', 'a', 't', 'e', 's') - -#undef RAPIDJSON_STRING_ - -#if RAPIDJSON_SCHEMA_VERBOSE -#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() \ -RAPIDJSON_MULTILINEMACRO_BEGIN\ - *documentStack_.template Push() = '\0';\ - documentStack_.template Pop(1);\ - internal::PrintInvalidDocument(documentStack_.template Bottom());\ -RAPIDJSON_MULTILINEMACRO_END -#else -#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() -#endif - -#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\ - if (!valid_) return false; \ - if ((!BeginValue() && !GetContinueOnErrors()) || (!CurrentSchema().method arg1 && !GetContinueOnErrors())) {\ - RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_();\ - return valid_ = false;\ - } - -#define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\ - for (Context* context = schemaStack_.template Bottom(); context != schemaStack_.template End(); context++) {\ - if (context->hasher)\ - static_cast(context->hasher)->method arg2;\ - if (context->validators)\ - for (SizeType i_ = 0; i_ < context->validatorCount; i_++)\ - static_cast(context->validators[i_])->method arg2;\ - if (context->patternPropertiesValidators)\ - for (SizeType i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++)\ - static_cast(context->patternPropertiesValidators[i_])->method arg2;\ - } - -#define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\ - valid_ = (EndValue() || GetContinueOnErrors()) && (!outputHandler_ || outputHandler_->method arg2);\ - return valid_; - -#define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \ - RAPIDJSON_SCHEMA_HANDLE_BEGIN_ (method, arg1);\ - RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\ - RAPIDJSON_SCHEMA_HANDLE_END_ (method, arg2) - - bool Null() { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext()), ( )); } - bool Bool(bool b) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool, (CurrentContext(), b), (b)); } - bool Int(int i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int, (CurrentContext(), i), (i)); } - bool Uint(unsigned u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint, (CurrentContext(), u), (u)); } - bool Int64(int64_t i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), i), (i)); } - bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); } - bool Double(double d) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); } - bool RawNumber(const Ch* str, SizeType length, bool copy) - { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); } - bool String(const Ch* str, SizeType length, bool copy) - { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); } - - bool StartObject() { - RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext())); - RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ()); - return valid_ = !outputHandler_ || outputHandler_->StartObject(); - } - - bool Key(const Ch* str, SizeType len, bool copy) { - if (!valid_) return false; - AppendToken(str, len); - if (!CurrentSchema().Key(CurrentContext(), str, len, copy) && !GetContinueOnErrors()) return valid_ = false; - RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy)); - return valid_ = !outputHandler_ || outputHandler_->Key(str, len, copy); - } - - bool EndObject(SizeType memberCount) { - if (!valid_) return false; - RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount)); - if (!CurrentSchema().EndObject(CurrentContext(), memberCount) && !GetContinueOnErrors()) return valid_ = false; - RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount)); - } - - bool StartArray() { - RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext())); - RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ()); - return valid_ = !outputHandler_ || outputHandler_->StartArray(); - } - - bool EndArray(SizeType elementCount) { - if (!valid_) return false; - RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount)); - if (!CurrentSchema().EndArray(CurrentContext(), elementCount) && !GetContinueOnErrors()) return valid_ = false; - RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount)); - } - -#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_ -#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_ -#undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_ -#undef RAPIDJSON_SCHEMA_HANDLE_VALUE_ - - // Implementation of ISchemaStateFactory - virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root, const bool inheritContinueOnErrors) { - ISchemaValidator* sv = new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root, documentStack_.template Bottom(), documentStack_.GetSize(), -#if RAPIDJSON_SCHEMA_VERBOSE - depth_ + 1, -#endif - &GetStateAllocator()); - sv->SetValidateFlags(inheritContinueOnErrors ? GetValidateFlags() : GetValidateFlags() & ~(unsigned)kValidateContinueOnErrorFlag); - return sv; - } - - virtual void DestroySchemaValidator(ISchemaValidator* validator) { - GenericSchemaValidator* v = static_cast(validator); - v->~GenericSchemaValidator(); - StateAllocator::Free(v); - } - - virtual void* CreateHasher() { - return new (GetStateAllocator().Malloc(sizeof(HasherType))) HasherType(&GetStateAllocator()); - } - - virtual uint64_t GetHashCode(void* hasher) { - return static_cast(hasher)->GetHashCode(); - } - - virtual void DestroryHasher(void* hasher) { - HasherType* h = static_cast(hasher); - h->~HasherType(); - StateAllocator::Free(h); - } - - virtual void* MallocState(size_t size) { - return GetStateAllocator().Malloc(size); - } - - virtual void FreeState(void* p) { - StateAllocator::Free(p); - } - -private: - typedef typename SchemaType::Context Context; - typedef GenericValue, StateAllocator> HashCodeArray; - typedef internal::Hasher HasherType; - - GenericSchemaValidator( - const SchemaDocumentType& schemaDocument, - const SchemaType& root, - const char* basePath, size_t basePathSize, -#if RAPIDJSON_SCHEMA_VERBOSE - unsigned depth, -#endif - StateAllocator* allocator = 0, - size_t schemaStackCapacity = kDefaultSchemaStackCapacity, - size_t documentStackCapacity = kDefaultDocumentStackCapacity) - : - schemaDocument_(&schemaDocument), - root_(root), - stateAllocator_(allocator), - ownStateAllocator_(0), - schemaStack_(allocator, schemaStackCapacity), - documentStack_(allocator, documentStackCapacity), - outputHandler_(0), - error_(kObjectType), - currentError_(), - missingDependents_(), - valid_(true), - flags_(kValidateDefaultFlags) -#if RAPIDJSON_SCHEMA_VERBOSE - , depth_(depth) -#endif - { - if (basePath && basePathSize) - memcpy(documentStack_.template Push(basePathSize), basePath, basePathSize); - } - - StateAllocator& GetStateAllocator() { - if (!stateAllocator_) - stateAllocator_ = ownStateAllocator_ = RAPIDJSON_NEW(StateAllocator)(); - return *stateAllocator_; - } - - bool GetContinueOnErrors() const { - return flags_ & kValidateContinueOnErrorFlag; - } - - bool BeginValue() { - if (schemaStack_.Empty()) - PushSchema(root_); - else { - if (CurrentContext().inArray) - internal::TokenHelper, Ch>::AppendIndexToken(documentStack_, CurrentContext().arrayElementIndex); - - if (!CurrentSchema().BeginValue(CurrentContext()) && !GetContinueOnErrors()) - return false; - - SizeType count = CurrentContext().patternPropertiesSchemaCount; - const SchemaType** sa = CurrentContext().patternPropertiesSchemas; - typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType; - bool valueUniqueness = CurrentContext().valueUniqueness; - RAPIDJSON_ASSERT(CurrentContext().valueSchema); - PushSchema(*CurrentContext().valueSchema); - - if (count > 0) { - CurrentContext().objectPatternValidatorType = patternValidatorType; - ISchemaValidator**& va = CurrentContext().patternPropertiesValidators; - SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount; - va = static_cast(MallocState(sizeof(ISchemaValidator*) * count)); - for (SizeType i = 0; i < count; i++) - va[validatorCount++] = CreateSchemaValidator(*sa[i], true); // Inherit continueOnError - } - - CurrentContext().arrayUniqueness = valueUniqueness; - } - return true; - } - - bool EndValue() { - if (!CurrentSchema().EndValue(CurrentContext()) && !GetContinueOnErrors()) - return false; - -#if RAPIDJSON_SCHEMA_VERBOSE - GenericStringBuffer sb; - schemaDocument_->GetPointer(&CurrentSchema()).Stringify(sb); - - *documentStack_.template Push() = '\0'; - documentStack_.template Pop(1); - internal::PrintValidatorPointers(depth_, sb.GetString(), documentStack_.template Bottom()); -#endif - void* hasher = CurrentContext().hasher; - uint64_t h = hasher && CurrentContext().arrayUniqueness ? static_cast(hasher)->GetHashCode() : 0; - - PopSchema(); - - if (!schemaStack_.Empty()) { - Context& context = CurrentContext(); - // Only check uniqueness if there is a hasher - if (hasher && context.valueUniqueness) { - HashCodeArray* a = static_cast(context.arrayElementHashCodes); - if (!a) - CurrentContext().arrayElementHashCodes = a = new (GetStateAllocator().Malloc(sizeof(HashCodeArray))) HashCodeArray(kArrayType); - for (typename HashCodeArray::ConstValueIterator itr = a->Begin(); itr != a->End(); ++itr) - if (itr->GetUint64() == h) { - DuplicateItems(static_cast(itr - a->Begin()), a->Size()); - // Cleanup before returning if continuing - if (GetContinueOnErrors()) { - a->PushBack(h, GetStateAllocator()); - while (!documentStack_.Empty() && *documentStack_.template Pop(1) != '/'); - } - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorUniqueItems); - } - a->PushBack(h, GetStateAllocator()); - } - } - - // Remove the last token of document pointer - while (!documentStack_.Empty() && *documentStack_.template Pop(1) != '/') - ; - - return true; - } - - void AppendToken(const Ch* str, SizeType len) { - documentStack_.template Reserve(1 + len * 2); // worst case all characters are escaped as two characters - *documentStack_.template PushUnsafe() = '/'; - for (SizeType i = 0; i < len; i++) { - if (str[i] == '~') { - *documentStack_.template PushUnsafe() = '~'; - *documentStack_.template PushUnsafe() = '0'; - } - else if (str[i] == '/') { - *documentStack_.template PushUnsafe() = '~'; - *documentStack_.template PushUnsafe() = '1'; - } - else - *documentStack_.template PushUnsafe() = str[i]; - } - } - - RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push()) Context(*this, *this, &schema); } - - RAPIDJSON_FORCEINLINE void PopSchema() { - Context* c = schemaStack_.template Pop(1); - if (HashCodeArray* a = static_cast(c->arrayElementHashCodes)) { - a->~HashCodeArray(); - StateAllocator::Free(a); - } - c->~Context(); - } - - void AddErrorInstanceLocation(ValueType& result, bool parent) { - GenericStringBuffer sb; - PointerType instancePointer = GetInvalidDocumentPointer(); - ((parent && instancePointer.GetTokenCount() > 0) - ? PointerType(instancePointer.GetTokens(), instancePointer.GetTokenCount() - 1) - : instancePointer).StringifyUriFragment(sb); - ValueType instanceRef(sb.GetString(), static_cast(sb.GetSize() / sizeof(Ch)), - GetStateAllocator()); - result.AddMember(GetInstanceRefString(), instanceRef, GetStateAllocator()); - } - - void AddErrorSchemaLocation(ValueType& result, PointerType schema = PointerType()) { - GenericStringBuffer sb; - SizeType len = CurrentSchema().GetURI().GetStringLength(); - if (len) memcpy(sb.Push(len), CurrentSchema().GetURI().GetString(), len * sizeof(Ch)); - if (schema.GetTokenCount()) schema.StringifyUriFragment(sb); - else GetInvalidSchemaPointer().StringifyUriFragment(sb); - ValueType schemaRef(sb.GetString(), static_cast(sb.GetSize() / sizeof(Ch)), - GetStateAllocator()); - result.AddMember(GetSchemaRefString(), schemaRef, GetStateAllocator()); - } - - void AddErrorCode(ValueType& result, const ValidateErrorCode code) { - result.AddMember(GetErrorCodeString(), code, GetStateAllocator()); - } - - void AddError(ValueType& keyword, ValueType& error) { - typename ValueType::MemberIterator member = error_.FindMember(keyword); - if (member == error_.MemberEnd()) - error_.AddMember(keyword, error, GetStateAllocator()); - else { - if (member->value.IsObject()) { - ValueType errors(kArrayType); - errors.PushBack(member->value, GetStateAllocator()); - member->value = errors; - } - member->value.PushBack(error, GetStateAllocator()); - } - } - - void AddCurrentError(const ValidateErrorCode code, bool parent = false) { - AddErrorCode(currentError_, code); - AddErrorInstanceLocation(currentError_, parent); - AddErrorSchemaLocation(currentError_); - AddError(ValueType(SchemaType::GetValidateErrorKeyword(code), GetStateAllocator(), false).Move(), currentError_); - } - - void MergeError(ValueType& other) { - for (typename ValueType::MemberIterator it = other.MemberBegin(), end = other.MemberEnd(); it != end; ++it) { - AddError(it->name, it->value); - } - } - - void AddNumberError(const ValidateErrorCode code, ValueType& actual, const SValue& expected, - const typename SchemaType::ValueType& (*exclusive)() = 0) { - currentError_.SetObject(); - currentError_.AddMember(GetActualString(), actual, GetStateAllocator()); - currentError_.AddMember(GetExpectedString(), ValueType(expected, GetStateAllocator()).Move(), GetStateAllocator()); - if (exclusive) - currentError_.AddMember(ValueType(exclusive(), GetStateAllocator()).Move(), true, GetStateAllocator()); - AddCurrentError(code); - } - - void AddErrorArray(const ValidateErrorCode code, - ISchemaValidator** subvalidators, SizeType count) { - ValueType errors(kArrayType); - for (SizeType i = 0; i < count; ++i) - errors.PushBack(static_cast(subvalidators[i])->GetError(), GetStateAllocator()); - currentError_.SetObject(); - currentError_.AddMember(GetErrorsString(), errors, GetStateAllocator()); - AddCurrentError(code); - } - - const SchemaType& CurrentSchema() const { return *schemaStack_.template Top()->schema; } - Context& CurrentContext() { return *schemaStack_.template Top(); } - const Context& CurrentContext() const { return *schemaStack_.template Top(); } - - static const size_t kDefaultSchemaStackCapacity = 1024; - static const size_t kDefaultDocumentStackCapacity = 256; - const SchemaDocumentType* schemaDocument_; - const SchemaType& root_; - StateAllocator* stateAllocator_; - StateAllocator* ownStateAllocator_; - internal::Stack schemaStack_; //!< stack to store the current path of schema (BaseSchemaType *) - internal::Stack documentStack_; //!< stack to store the current path of validating document (Ch) - OutputHandler* outputHandler_; - ValueType error_; - ValueType currentError_; - ValueType missingDependents_; - bool valid_; - unsigned flags_; -#if RAPIDJSON_SCHEMA_VERBOSE - unsigned depth_; -#endif -}; - -typedef GenericSchemaValidator SchemaValidator; - -/////////////////////////////////////////////////////////////////////////////// -// SchemaValidatingReader - -//! A helper class for parsing with validation. -/*! - This helper class is a functor, designed as a parameter of \ref GenericDocument::Populate(). - - \tparam parseFlags Combination of \ref ParseFlag. - \tparam InputStream Type of input stream, implementing Stream concept. - \tparam SourceEncoding Encoding of the input stream. - \tparam SchemaDocumentType Type of schema document. - \tparam StackAllocator Allocator type for stack. -*/ -template < - unsigned parseFlags, - typename InputStream, - typename SourceEncoding, - typename SchemaDocumentType = SchemaDocument, - typename StackAllocator = CrtAllocator> -class SchemaValidatingReader { -public: - typedef typename SchemaDocumentType::PointerType PointerType; - typedef typename InputStream::Ch Ch; - typedef GenericValue ValueType; - - //! Constructor - /*! - \param is Input stream. - \param sd Schema document. - */ - SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), invalidSchemaCode_(kValidateErrorNone), error_(kObjectType), isValid_(true) {} - - template - bool operator()(Handler& handler) { - GenericReader reader; - GenericSchemaValidator validator(sd_, handler); - parseResult_ = reader.template Parse(is_, validator); - - isValid_ = validator.IsValid(); - if (isValid_) { - invalidSchemaPointer_ = PointerType(); - invalidSchemaKeyword_ = 0; - invalidDocumentPointer_ = PointerType(); - error_.SetObject(); - } - else { - invalidSchemaPointer_ = validator.GetInvalidSchemaPointer(); - invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword(); - invalidSchemaCode_ = validator.GetInvalidSchemaCode(); - invalidDocumentPointer_ = validator.GetInvalidDocumentPointer(); - error_.CopyFrom(validator.GetError(), allocator_); - } - - return parseResult_; - } - - const ParseResult& GetParseResult() const { return parseResult_; } - bool IsValid() const { return isValid_; } - const PointerType& GetInvalidSchemaPointer() const { return invalidSchemaPointer_; } - const Ch* GetInvalidSchemaKeyword() const { return invalidSchemaKeyword_; } - const PointerType& GetInvalidDocumentPointer() const { return invalidDocumentPointer_; } - const ValueType& GetError() const { return error_; } - ValidateErrorCode GetInvalidSchemaCode() const { return invalidSchemaCode_; } - -private: - InputStream& is_; - const SchemaDocumentType& sd_; - - ParseResult parseResult_; - PointerType invalidSchemaPointer_; - const Ch* invalidSchemaKeyword_; - PointerType invalidDocumentPointer_; - ValidateErrorCode invalidSchemaCode_; - StackAllocator allocator_; - ValueType error_; - bool isValid_; -}; - -RAPIDJSON_NAMESPACE_END -RAPIDJSON_DIAG_POP - -#endif // RAPIDJSON_SCHEMA_H_ diff --git a/external/rapidjson/stream.h b/external/rapidjson/stream.h deleted file mode 100755 index 1fd7091..0000000 --- a/external/rapidjson/stream.h +++ /dev/null @@ -1,223 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#include "rapidjson.h" - -#ifndef RAPIDJSON_STREAM_H_ -#define RAPIDJSON_STREAM_H_ - -#include "encodings.h" - -RAPIDJSON_NAMESPACE_BEGIN - -/////////////////////////////////////////////////////////////////////////////// -// Stream - -/*! \class rapidjson::Stream - \brief Concept for reading and writing characters. - - For read-only stream, no need to implement PutBegin(), Put(), Flush() and PutEnd(). - - For write-only stream, only need to implement Put() and Flush(). - -\code -concept Stream { - typename Ch; //!< Character type of the stream. - - //! Read the current character from stream without moving the read cursor. - Ch Peek() const; - - //! Read the current character from stream and moving the read cursor to next character. - Ch Take(); - - //! Get the current read cursor. - //! \return Number of characters read from start. - size_t Tell(); - - //! Begin writing operation at the current read pointer. - //! \return The begin writer pointer. - Ch* PutBegin(); - - //! Write a character. - void Put(Ch c); - - //! Flush the buffer. - void Flush(); - - //! End the writing operation. - //! \param begin The begin write pointer returned by PutBegin(). - //! \return Number of characters written. - size_t PutEnd(Ch* begin); -} -\endcode -*/ - -//! Provides additional information for stream. -/*! - By using traits pattern, this type provides a default configuration for stream. - For custom stream, this type can be specialized for other configuration. - See TEST(Reader, CustomStringStream) in readertest.cpp for example. -*/ -template -struct StreamTraits { - //! Whether to make local copy of stream for optimization during parsing. - /*! - By default, for safety, streams do not use local copy optimization. - Stream that can be copied fast should specialize this, like StreamTraits. - */ - enum { copyOptimization = 0 }; -}; - -//! Reserve n characters for writing to a stream. -template -inline void PutReserve(Stream& stream, size_t count) { - (void)stream; - (void)count; -} - -//! Write character to a stream, presuming buffer is reserved. -template -inline void PutUnsafe(Stream& stream, typename Stream::Ch c) { - stream.Put(c); -} - -//! Put N copies of a character to a stream. -template -inline void PutN(Stream& stream, Ch c, size_t n) { - PutReserve(stream, n); - for (size_t i = 0; i < n; i++) - PutUnsafe(stream, c); -} - -/////////////////////////////////////////////////////////////////////////////// -// GenericStreamWrapper - -//! A Stream Wrapper -/*! \tThis string stream is a wrapper for any stream by just forwarding any - \treceived message to the origin stream. - \note implements Stream concept -*/ - -#if defined(_MSC_VER) && _MSC_VER <= 1800 -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(4702) // unreachable code -RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated -#endif - -template > -class GenericStreamWrapper { -public: - typedef typename Encoding::Ch Ch; - GenericStreamWrapper(InputStream& is): is_(is) {} - - Ch Peek() const { return is_.Peek(); } - Ch Take() { return is_.Take(); } - size_t Tell() { return is_.Tell(); } - Ch* PutBegin() { return is_.PutBegin(); } - void Put(Ch ch) { is_.Put(ch); } - void Flush() { is_.Flush(); } - size_t PutEnd(Ch* ch) { return is_.PutEnd(ch); } - - // wrapper for MemoryStream - const Ch* Peek4() const { return is_.Peek4(); } - - // wrapper for AutoUTFInputStream - UTFType GetType() const { return is_.GetType(); } - bool HasBOM() const { return is_.HasBOM(); } - -protected: - InputStream& is_; -}; - -#if defined(_MSC_VER) && _MSC_VER <= 1800 -RAPIDJSON_DIAG_POP -#endif - -/////////////////////////////////////////////////////////////////////////////// -// StringStream - -//! Read-only string stream. -/*! \note implements Stream concept -*/ -template -struct GenericStringStream { - typedef typename Encoding::Ch Ch; - - GenericStringStream(const Ch *src) : src_(src), head_(src) {} - - Ch Peek() const { return *src_; } - Ch Take() { return *src_++; } - size_t Tell() const { return static_cast(src_ - head_); } - - Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - void Put(Ch) { RAPIDJSON_ASSERT(false); } - void Flush() { RAPIDJSON_ASSERT(false); } - size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } - - const Ch* src_; //!< Current read position. - const Ch* head_; //!< Original head of the string. -}; - -template -struct StreamTraits > { - enum { copyOptimization = 1 }; -}; - -//! String stream with UTF8 encoding. -typedef GenericStringStream > StringStream; - -/////////////////////////////////////////////////////////////////////////////// -// InsituStringStream - -//! A read-write string stream. -/*! This string stream is particularly designed for in-situ parsing. - \note implements Stream concept -*/ -template -struct GenericInsituStringStream { - typedef typename Encoding::Ch Ch; - - GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {} - - // Read - Ch Peek() { return *src_; } - Ch Take() { return *src_++; } - size_t Tell() { return static_cast(src_ - head_); } - - // Write - void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; } - - Ch* PutBegin() { return dst_ = src_; } - size_t PutEnd(Ch* begin) { return static_cast(dst_ - begin); } - void Flush() {} - - Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; } - void Pop(size_t count) { dst_ -= count; } - - Ch* src_; - Ch* dst_; - Ch* head_; -}; - -template -struct StreamTraits > { - enum { copyOptimization = 1 }; -}; - -//! Insitu string stream with UTF8 encoding. -typedef GenericInsituStringStream > InsituStringStream; - -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_STREAM_H_ diff --git a/external/rapidjson/stringbuffer.h b/external/rapidjson/stringbuffer.h deleted file mode 100755 index 82ad3ca..0000000 --- a/external/rapidjson/stringbuffer.h +++ /dev/null @@ -1,121 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_STRINGBUFFER_H_ -#define RAPIDJSON_STRINGBUFFER_H_ - -#include "stream.h" -#include "internal/stack.h" - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS -#include // std::move -#endif - -#include "internal/stack.h" - -#if defined(__clang__) -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(c++98-compat) -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -//! Represents an in-memory output stream. -/*! - \tparam Encoding Encoding of the stream. - \tparam Allocator type for allocating memory buffer. - \note implements Stream concept -*/ -template -class GenericStringBuffer { -public: - typedef typename Encoding::Ch Ch; - - GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {} - GenericStringBuffer& operator=(GenericStringBuffer&& rhs) { - if (&rhs != this) - stack_ = std::move(rhs.stack_); - return *this; - } -#endif - - void Put(Ch c) { *stack_.template Push() = c; } - void PutUnsafe(Ch c) { *stack_.template PushUnsafe() = c; } - void Flush() {} - - void Clear() { stack_.Clear(); } - void ShrinkToFit() { - // Push and pop a null terminator. This is safe. - *stack_.template Push() = '\0'; - stack_.ShrinkToFit(); - stack_.template Pop(1); - } - - void Reserve(size_t count) { stack_.template Reserve(count); } - Ch* Push(size_t count) { return stack_.template Push(count); } - Ch* PushUnsafe(size_t count) { return stack_.template PushUnsafe(count); } - void Pop(size_t count) { stack_.template Pop(count); } - - const Ch* GetString() const { - // Push and pop a null terminator. This is safe. - *stack_.template Push() = '\0'; - stack_.template Pop(1); - - return stack_.template Bottom(); - } - - //! Get the size of string in bytes in the string buffer. - size_t GetSize() const { return stack_.GetSize(); } - - //! Get the length of string in Ch in the string buffer. - size_t GetLength() const { return stack_.GetSize() / sizeof(Ch); } - - static const size_t kDefaultCapacity = 256; - mutable internal::Stack stack_; - -private: - // Prohibit copy constructor & assignment operator. - GenericStringBuffer(const GenericStringBuffer&); - GenericStringBuffer& operator=(const GenericStringBuffer&); -}; - -//! String buffer with UTF8 encoding -typedef GenericStringBuffer > StringBuffer; - -template -inline void PutReserve(GenericStringBuffer& stream, size_t count) { - stream.Reserve(count); -} - -template -inline void PutUnsafe(GenericStringBuffer& stream, typename Encoding::Ch c) { - stream.PutUnsafe(c); -} - -//! Implement specialized version of PutN() with memset() for better performance. -template<> -inline void PutN(GenericStringBuffer >& stream, char c, size_t n) { - std::memset(stream.stack_.Push(n), c, n * sizeof(c)); -} - -RAPIDJSON_NAMESPACE_END - -#if defined(__clang__) -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_STRINGBUFFER_H_ diff --git a/external/rapidjson/uri.h b/external/rapidjson/uri.h deleted file mode 100755 index 7de7b80..0000000 --- a/external/rapidjson/uri.h +++ /dev/null @@ -1,466 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// (C) Copyright IBM Corporation 2021 -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_URI_H_ -#define RAPIDJSON_URI_H_ - -#include "internal/strfunc.h" - -#if defined(__clang__) -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(c++98-compat) -#elif defined(_MSC_VER) -RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -/////////////////////////////////////////////////////////////////////////////// -// GenericUri - -template -class GenericUri { -public: - typedef typename ValueType::Ch Ch; -#if RAPIDJSON_HAS_STDSTRING - typedef std::basic_string String; -#endif - - //! Constructors - GenericUri(Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() { - } - - GenericUri(const Ch* uri, SizeType len, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() { - Parse(uri, len); - } - - GenericUri(const Ch* uri, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() { - Parse(uri, internal::StrLen(uri)); - } - - // Use with specializations of GenericValue - template GenericUri(const T& uri, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() { - const Ch* u = uri.template Get(); // TypeHelper from document.h - Parse(u, internal::StrLen(u)); - } - -#if RAPIDJSON_HAS_STDSTRING - GenericUri(const String& uri, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() { - Parse(uri.c_str(), internal::StrLen(uri.c_str())); - } -#endif - - //! Copy constructor - GenericUri(const GenericUri& rhs) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(), ownAllocator_() { - *this = rhs; - } - - //! Copy constructor - GenericUri(const GenericUri& rhs, Allocator* allocator) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() { - *this = rhs; - } - - //! Destructor. - ~GenericUri() { - Free(); - RAPIDJSON_DELETE(ownAllocator_); - } - - //! Assignment operator - GenericUri& operator=(const GenericUri& rhs) { - if (this != &rhs) { - // Do not delete ownAllocator - Free(); - Allocate(rhs.GetStringLength()); - auth_ = CopyPart(scheme_, rhs.scheme_, rhs.GetSchemeStringLength()); - path_ = CopyPart(auth_, rhs.auth_, rhs.GetAuthStringLength()); - query_ = CopyPart(path_, rhs.path_, rhs.GetPathStringLength()); - frag_ = CopyPart(query_, rhs.query_, rhs.GetQueryStringLength()); - base_ = CopyPart(frag_, rhs.frag_, rhs.GetFragStringLength()); - uri_ = CopyPart(base_, rhs.base_, rhs.GetBaseStringLength()); - CopyPart(uri_, rhs.uri_, rhs.GetStringLength()); - } - return *this; - } - - //! Getters - // Use with specializations of GenericValue - template void Get(T& uri, Allocator& allocator) { - uri.template Set(this->GetString(), allocator); // TypeHelper from document.h - } - - const Ch* GetString() const { return uri_; } - SizeType GetStringLength() const { return uri_ == 0 ? 0 : internal::StrLen(uri_); } - const Ch* GetBaseString() const { return base_; } - SizeType GetBaseStringLength() const { return base_ == 0 ? 0 : internal::StrLen(base_); } - const Ch* GetSchemeString() const { return scheme_; } - SizeType GetSchemeStringLength() const { return scheme_ == 0 ? 0 : internal::StrLen(scheme_); } - const Ch* GetAuthString() const { return auth_; } - SizeType GetAuthStringLength() const { return auth_ == 0 ? 0 : internal::StrLen(auth_); } - const Ch* GetPathString() const { return path_; } - SizeType GetPathStringLength() const { return path_ == 0 ? 0 : internal::StrLen(path_); } - const Ch* GetQueryString() const { return query_; } - SizeType GetQueryStringLength() const { return query_ == 0 ? 0 : internal::StrLen(query_); } - const Ch* GetFragString() const { return frag_; } - SizeType GetFragStringLength() const { return frag_ == 0 ? 0 : internal::StrLen(frag_); } - -#if RAPIDJSON_HAS_STDSTRING - static String Get(const GenericUri& uri) { return String(uri.GetString(), uri.GetStringLength()); } - static String GetBase(const GenericUri& uri) { return String(uri.GetBaseString(), uri.GetBaseStringLength()); } - static String GetScheme(const GenericUri& uri) { return String(uri.GetSchemeString(), uri.GetSchemeStringLength()); } - static String GetAuth(const GenericUri& uri) { return String(uri.GetAuthString(), uri.GetAuthStringLength()); } - static String GetPath(const GenericUri& uri) { return String(uri.GetPathString(), uri.GetPathStringLength()); } - static String GetQuery(const GenericUri& uri) { return String(uri.GetQueryString(), uri.GetQueryStringLength()); } - static String GetFrag(const GenericUri& uri) { return String(uri.GetFragString(), uri.GetFragStringLength()); } -#endif - - //! Equality operators - bool operator==(const GenericUri& rhs) const { - return Match(rhs, true); - } - - bool operator!=(const GenericUri& rhs) const { - return !Match(rhs, true); - } - - bool Match(const GenericUri& uri, bool full = true) const { - Ch* s1; - Ch* s2; - if (full) { - s1 = uri_; - s2 = uri.uri_; - } else { - s1 = base_; - s2 = uri.base_; - } - if (s1 == s2) return true; - if (s1 == 0 || s2 == 0) return false; - return internal::StrCmp(s1, s2) == 0; - } - - //! Resolve this URI against another (base) URI in accordance with URI resolution rules. - // See https://tools.ietf.org/html/rfc3986 - // Use for resolving an id or $ref with an in-scope id. - // Returns a new GenericUri for the resolved URI. - GenericUri Resolve(const GenericUri& baseuri, Allocator* allocator = 0) { - GenericUri resuri; - resuri.allocator_ = allocator; - // Ensure enough space for combining paths - resuri.Allocate(GetStringLength() + baseuri.GetStringLength() + 1); // + 1 for joining slash - - if (!(GetSchemeStringLength() == 0)) { - // Use all of this URI - resuri.auth_ = CopyPart(resuri.scheme_, scheme_, GetSchemeStringLength()); - resuri.path_ = CopyPart(resuri.auth_, auth_, GetAuthStringLength()); - resuri.query_ = CopyPart(resuri.path_, path_, GetPathStringLength()); - resuri.frag_ = CopyPart(resuri.query_, query_, GetQueryStringLength()); - resuri.RemoveDotSegments(); - } else { - // Use the base scheme - resuri.auth_ = CopyPart(resuri.scheme_, baseuri.scheme_, baseuri.GetSchemeStringLength()); - if (!(GetAuthStringLength() == 0)) { - // Use this auth, path, query - resuri.path_ = CopyPart(resuri.auth_, auth_, GetAuthStringLength()); - resuri.query_ = CopyPart(resuri.path_, path_, GetPathStringLength()); - resuri.frag_ = CopyPart(resuri.query_, query_, GetQueryStringLength()); - resuri.RemoveDotSegments(); - } else { - // Use the base auth - resuri.path_ = CopyPart(resuri.auth_, baseuri.auth_, baseuri.GetAuthStringLength()); - if (GetPathStringLength() == 0) { - // Use the base path - resuri.query_ = CopyPart(resuri.path_, baseuri.path_, baseuri.GetPathStringLength()); - if (GetQueryStringLength() == 0) { - // Use the base query - resuri.frag_ = CopyPart(resuri.query_, baseuri.query_, baseuri.GetQueryStringLength()); - } else { - // Use this query - resuri.frag_ = CopyPart(resuri.query_, query_, GetQueryStringLength()); - } - } else { - if (path_[0] == '/') { - // Absolute path - use all of this path - resuri.query_ = CopyPart(resuri.path_, path_, GetPathStringLength()); - resuri.RemoveDotSegments(); - } else { - // Relative path - append this path to base path after base path's last slash - size_t pos = 0; - if (!(baseuri.GetAuthStringLength() == 0) && baseuri.GetPathStringLength() == 0) { - resuri.path_[pos] = '/'; - pos++; - } - size_t lastslashpos = baseuri.GetPathStringLength(); - while (lastslashpos > 0) { - if (baseuri.path_[lastslashpos - 1] == '/') break; - lastslashpos--; - } - std::memcpy(&resuri.path_[pos], baseuri.path_, lastslashpos * sizeof(Ch)); - pos += lastslashpos; - resuri.query_ = CopyPart(&resuri.path_[pos], path_, GetPathStringLength()); - resuri.RemoveDotSegments(); - } - // Use this query - resuri.frag_ = CopyPart(resuri.query_, query_, GetQueryStringLength()); - } - } - } - // Always use this frag - resuri.base_ = CopyPart(resuri.frag_, frag_, GetFragStringLength()); - - // Re-constitute base_ and uri_ - resuri.SetBase(); - resuri.uri_ = resuri.base_ + resuri.GetBaseStringLength() + 1; - resuri.SetUri(); - return resuri; - } - - //! Get the allocator of this GenericUri. - Allocator& GetAllocator() { return *allocator_; } - -private: - // Allocate memory for a URI - // Returns total amount allocated - std::size_t Allocate(std::size_t len) { - // Create own allocator if user did not supply. - if (!allocator_) - ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); - - // Allocate one block containing each part of the URI (5) plus base plus full URI, all null terminated. - // Order: scheme, auth, path, query, frag, base, uri - size_t total = (3 * len + 7) * sizeof(Ch); - scheme_ = static_cast(allocator_->Malloc(total)); - *scheme_ = '\0'; - auth_ = scheme_ + 1; - *auth_ = '\0'; - path_ = auth_ + 1; - *path_ = '\0'; - query_ = path_ + 1; - *query_ = '\0'; - frag_ = query_ + 1; - *frag_ = '\0'; - base_ = frag_ + 1; - *base_ = '\0'; - uri_ = base_ + 1; - *uri_ = '\0'; - return total; - } - - // Free memory for a URI - void Free() { - if (scheme_) { - Allocator::Free(scheme_); - scheme_ = 0; - } - } - - // Parse a URI into constituent scheme, authority, path, query, & fragment parts - // Supports URIs that match regex ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))? as per - // https://tools.ietf.org/html/rfc3986 - void Parse(const Ch* uri, std::size_t len) { - std::size_t start = 0, pos1 = 0, pos2 = 0; - Allocate(len); - - // Look for scheme ([^:/?#]+):)? - if (start < len) { - while (pos1 < len) { - if (uri[pos1] == ':') break; - pos1++; - } - if (pos1 != len) { - while (pos2 < len) { - if (uri[pos2] == '/') break; - if (uri[pos2] == '?') break; - if (uri[pos2] == '#') break; - pos2++; - } - if (pos1 < pos2) { - pos1++; - std::memcpy(scheme_, &uri[start], pos1 * sizeof(Ch)); - scheme_[pos1] = '\0'; - start = pos1; - } - } - } - // Look for auth (//([^/?#]*))? - auth_ = scheme_ + GetSchemeStringLength() + 1; - *auth_ = '\0'; - if (start < len - 1 && uri[start] == '/' && uri[start + 1] == '/') { - pos2 = start + 2; - while (pos2 < len) { - if (uri[pos2] == '/') break; - if (uri[pos2] == '?') break; - if (uri[pos2] == '#') break; - pos2++; - } - std::memcpy(auth_, &uri[start], (pos2 - start) * sizeof(Ch)); - auth_[pos2 - start] = '\0'; - start = pos2; - } - // Look for path ([^?#]*) - path_ = auth_ + GetAuthStringLength() + 1; - *path_ = '\0'; - if (start < len) { - pos2 = start; - while (pos2 < len) { - if (uri[pos2] == '?') break; - if (uri[pos2] == '#') break; - pos2++; - } - if (start != pos2) { - std::memcpy(path_, &uri[start], (pos2 - start) * sizeof(Ch)); - path_[pos2 - start] = '\0'; - if (path_[0] == '/') - RemoveDotSegments(); // absolute path - normalize - start = pos2; - } - } - // Look for query (\?([^#]*))? - query_ = path_ + GetPathStringLength() + 1; - *query_ = '\0'; - if (start < len && uri[start] == '?') { - pos2 = start + 1; - while (pos2 < len) { - if (uri[pos2] == '#') break; - pos2++; - } - if (start != pos2) { - std::memcpy(query_, &uri[start], (pos2 - start) * sizeof(Ch)); - query_[pos2 - start] = '\0'; - start = pos2; - } - } - // Look for fragment (#(.*))? - frag_ = query_ + GetQueryStringLength() + 1; - *frag_ = '\0'; - if (start < len && uri[start] == '#') { - std::memcpy(frag_, &uri[start], (len - start) * sizeof(Ch)); - frag_[len - start] = '\0'; - } - - // Re-constitute base_ and uri_ - base_ = frag_ + GetFragStringLength() + 1; - SetBase(); - uri_ = base_ + GetBaseStringLength() + 1; - SetUri(); - } - - // Reconstitute base - void SetBase() { - Ch* next = base_; - std::memcpy(next, scheme_, GetSchemeStringLength() * sizeof(Ch)); - next+= GetSchemeStringLength(); - std::memcpy(next, auth_, GetAuthStringLength() * sizeof(Ch)); - next+= GetAuthStringLength(); - std::memcpy(next, path_, GetPathStringLength() * sizeof(Ch)); - next+= GetPathStringLength(); - std::memcpy(next, query_, GetQueryStringLength() * sizeof(Ch)); - next+= GetQueryStringLength(); - *next = '\0'; - } - - // Reconstitute uri - void SetUri() { - Ch* next = uri_; - std::memcpy(next, base_, GetBaseStringLength() * sizeof(Ch)); - next+= GetBaseStringLength(); - std::memcpy(next, frag_, GetFragStringLength() * sizeof(Ch)); - next+= GetFragStringLength(); - *next = '\0'; - } - - // Copy a part from one GenericUri to another - // Return the pointer to the next part to be copied to - Ch* CopyPart(Ch* to, Ch* from, std::size_t len) { - RAPIDJSON_ASSERT(to != 0); - RAPIDJSON_ASSERT(from != 0); - std::memcpy(to, from, len * sizeof(Ch)); - to[len] = '\0'; - Ch* next = to + len + 1; - return next; - } - - // Remove . and .. segments from the path_ member. - // https://tools.ietf.org/html/rfc3986 - // This is done in place as we are only removing segments. - void RemoveDotSegments() { - std::size_t pathlen = GetPathStringLength(); - std::size_t pathpos = 0; // Position in path_ - std::size_t newpos = 0; // Position in new path_ - - // Loop through each segment in original path_ - while (pathpos < pathlen) { - // Get next segment, bounded by '/' or end - size_t slashpos = 0; - while ((pathpos + slashpos) < pathlen) { - if (path_[pathpos + slashpos] == '/') break; - slashpos++; - } - // Check for .. and . segments - if (slashpos == 2 && path_[pathpos] == '.' && path_[pathpos + 1] == '.') { - // Backup a .. segment in the new path_ - // We expect to find a previously added slash at the end or nothing - RAPIDJSON_ASSERT(newpos == 0 || path_[newpos - 1] == '/'); - size_t lastslashpos = newpos; - // Make sure we don't go beyond the start segment - if (lastslashpos > 1) { - // Find the next to last slash and back up to it - lastslashpos--; - while (lastslashpos > 0) { - if (path_[lastslashpos - 1] == '/') break; - lastslashpos--; - } - // Set the new path_ position - newpos = lastslashpos; - } - } else if (slashpos == 1 && path_[pathpos] == '.') { - // Discard . segment, leaves new path_ unchanged - } else { - // Move any other kind of segment to the new path_ - RAPIDJSON_ASSERT(newpos <= pathpos); - std::memmove(&path_[newpos], &path_[pathpos], slashpos * sizeof(Ch)); - newpos += slashpos; - // Add slash if not at end - if ((pathpos + slashpos) < pathlen) { - path_[newpos] = '/'; - newpos++; - } - } - // Move to next segment - pathpos += slashpos + 1; - } - path_[newpos] = '\0'; - } - - Ch* uri_; // Everything - Ch* base_; // Everything except fragment - Ch* scheme_; // Includes the : - Ch* auth_; // Includes the // - Ch* path_; // Absolute if starts with / - Ch* query_; // Includes the ? - Ch* frag_; // Includes the # - - Allocator* allocator_; //!< The current allocator. It is either user-supplied or equal to ownAllocator_. - Allocator* ownAllocator_; //!< Allocator owned by this Uri. -}; - -//! GenericUri for Value (UTF-8, default allocator). -typedef GenericUri Uri; - -RAPIDJSON_NAMESPACE_END - -#if defined(__clang__) -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_URI_H_ diff --git a/external/rapidjson/writer.h b/external/rapidjson/writer.h deleted file mode 100755 index 8b38921..0000000 --- a/external/rapidjson/writer.h +++ /dev/null @@ -1,710 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_WRITER_H_ -#define RAPIDJSON_WRITER_H_ - -#include "stream.h" -#include "internal/clzll.h" -#include "internal/meta.h" -#include "internal/stack.h" -#include "internal/strfunc.h" -#include "internal/dtoa.h" -#include "internal/itoa.h" -#include "stringbuffer.h" -#include // placement new - -#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER) -#include -#pragma intrinsic(_BitScanForward) -#endif -#ifdef RAPIDJSON_SSE42 -#include -#elif defined(RAPIDJSON_SSE2) -#include -#elif defined(RAPIDJSON_NEON) -#include -#endif - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(padded) -RAPIDJSON_DIAG_OFF(unreachable-code) -RAPIDJSON_DIAG_OFF(c++98-compat) -#elif defined(_MSC_VER) -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -/////////////////////////////////////////////////////////////////////////////// -// WriteFlag - -/*! \def RAPIDJSON_WRITE_DEFAULT_FLAGS - \ingroup RAPIDJSON_CONFIG - \brief User-defined kWriteDefaultFlags definition. - - User can define this as any \c WriteFlag combinations. -*/ -#ifndef RAPIDJSON_WRITE_DEFAULT_FLAGS -#define RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNoFlags -#endif - -//! Combination of writeFlags -enum WriteFlag { - kWriteNoFlags = 0, //!< No flags are set. - kWriteValidateEncodingFlag = 1, //!< Validate encoding of JSON strings. - kWriteNanAndInfFlag = 2, //!< Allow writing of Infinity, -Infinity and NaN. - kWriteDefaultFlags = RAPIDJSON_WRITE_DEFAULT_FLAGS //!< Default write flags. Can be customized by defining RAPIDJSON_WRITE_DEFAULT_FLAGS -}; - -//! JSON writer -/*! Writer implements the concept Handler. - It generates JSON text by events to an output os. - - User may programmatically calls the functions of a writer to generate JSON text. - - On the other side, a writer can also be passed to objects that generates events, - - for example Reader::Parse() and Document::Accept(). - - \tparam OutputStream Type of output stream. - \tparam SourceEncoding Encoding of source string. - \tparam TargetEncoding Encoding of output stream. - \tparam StackAllocator Type of allocator for allocating memory of stack. - \note implements Handler concept -*/ -template, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags> -class Writer { -public: - typedef typename SourceEncoding::Ch Ch; - - static const int kDefaultMaxDecimalPlaces = 324; - - //! Constructor - /*! \param os Output stream. - \param stackAllocator User supplied allocator. If it is null, it will create a private one. - \param levelDepth Initial capacity of stack. - */ - explicit - Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) : - os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {} - - explicit - Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) : - os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {} - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - Writer(Writer&& rhs) : - os_(rhs.os_), level_stack_(std::move(rhs.level_stack_)), maxDecimalPlaces_(rhs.maxDecimalPlaces_), hasRoot_(rhs.hasRoot_) { - rhs.os_ = 0; - } -#endif - - //! Reset the writer with a new stream. - /*! - This function reset the writer with a new stream and default settings, - in order to make a Writer object reusable for output multiple JSONs. - - \param os New output stream. - \code - Writer writer(os1); - writer.StartObject(); - // ... - writer.EndObject(); - - writer.Reset(os2); - writer.StartObject(); - // ... - writer.EndObject(); - \endcode - */ - void Reset(OutputStream& os) { - os_ = &os; - hasRoot_ = false; - level_stack_.Clear(); - } - - //! Checks whether the output is a complete JSON. - /*! - A complete JSON has a complete root object or array. - */ - bool IsComplete() const { - return hasRoot_ && level_stack_.Empty(); - } - - int GetMaxDecimalPlaces() const { - return maxDecimalPlaces_; - } - - //! Sets the maximum number of decimal places for double output. - /*! - This setting truncates the output with specified number of decimal places. - - For example, - - \code - writer.SetMaxDecimalPlaces(3); - writer.StartArray(); - writer.Double(0.12345); // "0.123" - writer.Double(0.0001); // "0.0" - writer.Double(1.234567890123456e30); // "1.234567890123456e30" (do not truncate significand for positive exponent) - writer.Double(1.23e-4); // "0.0" (do truncate significand for negative exponent) - writer.EndArray(); - \endcode - - The default setting does not truncate any decimal places. You can restore to this setting by calling - \code - writer.SetMaxDecimalPlaces(Writer::kDefaultMaxDecimalPlaces); - \endcode - */ - void SetMaxDecimalPlaces(int maxDecimalPlaces) { - maxDecimalPlaces_ = maxDecimalPlaces; - } - - /*!@name Implementation of Handler - \see Handler - */ - //@{ - - bool Null() { Prefix(kNullType); return EndValue(WriteNull()); } - bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return EndValue(WriteBool(b)); } - bool Int(int i) { Prefix(kNumberType); return EndValue(WriteInt(i)); } - bool Uint(unsigned u) { Prefix(kNumberType); return EndValue(WriteUint(u)); } - bool Int64(int64_t i64) { Prefix(kNumberType); return EndValue(WriteInt64(i64)); } - bool Uint64(uint64_t u64) { Prefix(kNumberType); return EndValue(WriteUint64(u64)); } - - //! Writes the given \c double value to the stream - /*! - \param d The value to be written. - \return Whether it is succeed. - */ - bool Double(double d) { Prefix(kNumberType); return EndValue(WriteDouble(d)); } - - bool RawNumber(const Ch* str, SizeType length, bool copy = false) { - RAPIDJSON_ASSERT(str != 0); - (void)copy; - Prefix(kNumberType); - return EndValue(WriteString(str, length)); - } - - bool String(const Ch* str, SizeType length, bool copy = false) { - RAPIDJSON_ASSERT(str != 0); - (void)copy; - Prefix(kStringType); - return EndValue(WriteString(str, length)); - } - -#if RAPIDJSON_HAS_STDSTRING - bool String(const std::basic_string& str) { - return String(str.data(), SizeType(str.size())); - } -#endif - - bool StartObject() { - Prefix(kObjectType); - new (level_stack_.template Push()) Level(false); - return WriteStartObject(); - } - - bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } - -#if RAPIDJSON_HAS_STDSTRING - bool Key(const std::basic_string& str) - { - return Key(str.data(), SizeType(str.size())); - } -#endif - - bool EndObject(SizeType memberCount = 0) { - (void)memberCount; - RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); // not inside an Object - RAPIDJSON_ASSERT(!level_stack_.template Top()->inArray); // currently inside an Array, not Object - RAPIDJSON_ASSERT(0 == level_stack_.template Top()->valueCount % 2); // Object has a Key without a Value - level_stack_.template Pop(1); - return EndValue(WriteEndObject()); - } - - bool StartArray() { - Prefix(kArrayType); - new (level_stack_.template Push()) Level(true); - return WriteStartArray(); - } - - bool EndArray(SizeType elementCount = 0) { - (void)elementCount; - RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); - RAPIDJSON_ASSERT(level_stack_.template Top()->inArray); - level_stack_.template Pop(1); - return EndValue(WriteEndArray()); - } - //@} - - /*! @name Convenience extensions */ - //@{ - - //! Simpler but slower overload. - bool String(const Ch* const& str) { return String(str, internal::StrLen(str)); } - bool Key(const Ch* const& str) { return Key(str, internal::StrLen(str)); } - - //@} - - //! Write a raw JSON value. - /*! - For user to write a stringified JSON as a value. - - \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range. - \param length Length of the json. - \param type Type of the root of json. - */ - bool RawValue(const Ch* json, size_t length, Type type) { - RAPIDJSON_ASSERT(json != 0); - Prefix(type); - return EndValue(WriteRawValue(json, length)); - } - - //! Flush the output stream. - /*! - Allows the user to flush the output stream immediately. - */ - void Flush() { - os_->Flush(); - } - - static const size_t kDefaultLevelDepth = 32; - -protected: - //! Information for each nested level - struct Level { - Level(bool inArray_) : valueCount(0), inArray(inArray_) {} - size_t valueCount; //!< number of values in this level - bool inArray; //!< true if in array, otherwise in object - }; - - bool WriteNull() { - PutReserve(*os_, 4); - PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true; - } - - bool WriteBool(bool b) { - if (b) { - PutReserve(*os_, 4); - PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'r'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'e'); - } - else { - PutReserve(*os_, 5); - PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 's'); PutUnsafe(*os_, 'e'); - } - return true; - } - - bool WriteInt(int i) { - char buffer[11]; - const char* end = internal::i32toa(i, buffer); - PutReserve(*os_, static_cast(end - buffer)); - for (const char* p = buffer; p != end; ++p) - PutUnsafe(*os_, static_cast(*p)); - return true; - } - - bool WriteUint(unsigned u) { - char buffer[10]; - const char* end = internal::u32toa(u, buffer); - PutReserve(*os_, static_cast(end - buffer)); - for (const char* p = buffer; p != end; ++p) - PutUnsafe(*os_, static_cast(*p)); - return true; - } - - bool WriteInt64(int64_t i64) { - char buffer[21]; - const char* end = internal::i64toa(i64, buffer); - PutReserve(*os_, static_cast(end - buffer)); - for (const char* p = buffer; p != end; ++p) - PutUnsafe(*os_, static_cast(*p)); - return true; - } - - bool WriteUint64(uint64_t u64) { - char buffer[20]; - char* end = internal::u64toa(u64, buffer); - PutReserve(*os_, static_cast(end - buffer)); - for (char* p = buffer; p != end; ++p) - PutUnsafe(*os_, static_cast(*p)); - return true; - } - - bool WriteDouble(double d) { - if (internal::Double(d).IsNanOrInf()) { - if (!(writeFlags & kWriteNanAndInfFlag)) - return false; - if (internal::Double(d).IsNan()) { - PutReserve(*os_, 3); - PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N'); - return true; - } - if (internal::Double(d).Sign()) { - PutReserve(*os_, 9); - PutUnsafe(*os_, '-'); - } - else - PutReserve(*os_, 8); - PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f'); - PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y'); - return true; - } - - char buffer[25]; - char* end = internal::dtoa(d, buffer, maxDecimalPlaces_); - PutReserve(*os_, static_cast(end - buffer)); - for (char* p = buffer; p != end; ++p) - PutUnsafe(*os_, static_cast(*p)); - return true; - } - - bool WriteString(const Ch* str, SizeType length) { - static const typename OutputStream::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; - static const char escape[256] = { -#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - //0 1 2 3 4 5 6 7 8 9 A B C D E F - 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00 - 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10 - 0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20 - Z16, Z16, // 30~4F - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50 - Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF -#undef Z16 - }; - - if (TargetEncoding::supportUnicode) - PutReserve(*os_, 2 + length * 6); // "\uxxxx..." - else - PutReserve(*os_, 2 + length * 12); // "\uxxxx\uyyyy..." - - PutUnsafe(*os_, '\"'); - GenericStringStream is(str); - while (ScanWriteUnescapedString(is, length)) { - const Ch c = is.Peek(); - if (!TargetEncoding::supportUnicode && static_cast(c) >= 0x80) { - // Unicode escaping - unsigned codepoint; - if (RAPIDJSON_UNLIKELY(!SourceEncoding::Decode(is, &codepoint))) - return false; - PutUnsafe(*os_, '\\'); - PutUnsafe(*os_, 'u'); - if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) { - PutUnsafe(*os_, hexDigits[(codepoint >> 12) & 15]); - PutUnsafe(*os_, hexDigits[(codepoint >> 8) & 15]); - PutUnsafe(*os_, hexDigits[(codepoint >> 4) & 15]); - PutUnsafe(*os_, hexDigits[(codepoint ) & 15]); - } - else { - RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF); - // Surrogate pair - unsigned s = codepoint - 0x010000; - unsigned lead = (s >> 10) + 0xD800; - unsigned trail = (s & 0x3FF) + 0xDC00; - PutUnsafe(*os_, hexDigits[(lead >> 12) & 15]); - PutUnsafe(*os_, hexDigits[(lead >> 8) & 15]); - PutUnsafe(*os_, hexDigits[(lead >> 4) & 15]); - PutUnsafe(*os_, hexDigits[(lead ) & 15]); - PutUnsafe(*os_, '\\'); - PutUnsafe(*os_, 'u'); - PutUnsafe(*os_, hexDigits[(trail >> 12) & 15]); - PutUnsafe(*os_, hexDigits[(trail >> 8) & 15]); - PutUnsafe(*os_, hexDigits[(trail >> 4) & 15]); - PutUnsafe(*os_, hexDigits[(trail ) & 15]); - } - } - else if ((sizeof(Ch) == 1 || static_cast(c) < 256) && RAPIDJSON_UNLIKELY(escape[static_cast(c)])) { - is.Take(); - PutUnsafe(*os_, '\\'); - PutUnsafe(*os_, static_cast(escape[static_cast(c)])); - if (escape[static_cast(c)] == 'u') { - PutUnsafe(*os_, '0'); - PutUnsafe(*os_, '0'); - PutUnsafe(*os_, hexDigits[static_cast(c) >> 4]); - PutUnsafe(*os_, hexDigits[static_cast(c) & 0xF]); - } - } - else if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ? - Transcoder::Validate(is, *os_) : - Transcoder::TranscodeUnsafe(is, *os_)))) - return false; - } - PutUnsafe(*os_, '\"'); - return true; - } - - bool ScanWriteUnescapedString(GenericStringStream& is, size_t length) { - return RAPIDJSON_LIKELY(is.Tell() < length); - } - - bool WriteStartObject() { os_->Put('{'); return true; } - bool WriteEndObject() { os_->Put('}'); return true; } - bool WriteStartArray() { os_->Put('['); return true; } - bool WriteEndArray() { os_->Put(']'); return true; } - - bool WriteRawValue(const Ch* json, size_t length) { - PutReserve(*os_, length); - GenericStringStream is(json); - while (RAPIDJSON_LIKELY(is.Tell() < length)) { - RAPIDJSON_ASSERT(is.Peek() != '\0'); - if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ? - Transcoder::Validate(is, *os_) : - Transcoder::TranscodeUnsafe(is, *os_)))) - return false; - } - return true; - } - - void Prefix(Type type) { - (void)type; - if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is not at root - Level* level = level_stack_.template Top(); - if (level->valueCount > 0) { - if (level->inArray) - os_->Put(','); // add comma if it is not the first element in array - else // in object - os_->Put((level->valueCount % 2 == 0) ? ',' : ':'); - } - if (!level->inArray && level->valueCount % 2 == 0) - RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name - level->valueCount++; - } - else { - RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root. - hasRoot_ = true; - } - } - - // Flush the value if it is the top level one. - bool EndValue(bool ret) { - if (RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text - Flush(); - return ret; - } - - OutputStream* os_; - internal::Stack level_stack_; - int maxDecimalPlaces_; - bool hasRoot_; - -private: - // Prohibit copy constructor & assignment operator. - Writer(const Writer&); - Writer& operator=(const Writer&); -}; - -// Full specialization for StringStream to prevent memory copying - -template<> -inline bool Writer::WriteInt(int i) { - char *buffer = os_->Push(11); - const char* end = internal::i32toa(i, buffer); - os_->Pop(static_cast(11 - (end - buffer))); - return true; -} - -template<> -inline bool Writer::WriteUint(unsigned u) { - char *buffer = os_->Push(10); - const char* end = internal::u32toa(u, buffer); - os_->Pop(static_cast(10 - (end - buffer))); - return true; -} - -template<> -inline bool Writer::WriteInt64(int64_t i64) { - char *buffer = os_->Push(21); - const char* end = internal::i64toa(i64, buffer); - os_->Pop(static_cast(21 - (end - buffer))); - return true; -} - -template<> -inline bool Writer::WriteUint64(uint64_t u) { - char *buffer = os_->Push(20); - const char* end = internal::u64toa(u, buffer); - os_->Pop(static_cast(20 - (end - buffer))); - return true; -} - -template<> -inline bool Writer::WriteDouble(double d) { - if (internal::Double(d).IsNanOrInf()) { - // Note: This code path can only be reached if (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag). - if (!(kWriteDefaultFlags & kWriteNanAndInfFlag)) - return false; - if (internal::Double(d).IsNan()) { - PutReserve(*os_, 3); - PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N'); - return true; - } - if (internal::Double(d).Sign()) { - PutReserve(*os_, 9); - PutUnsafe(*os_, '-'); - } - else - PutReserve(*os_, 8); - PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f'); - PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y'); - return true; - } - - char *buffer = os_->Push(25); - char* end = internal::dtoa(d, buffer, maxDecimalPlaces_); - os_->Pop(static_cast(25 - (end - buffer))); - return true; -} - -#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) -template<> -inline bool Writer::ScanWriteUnescapedString(StringStream& is, size_t length) { - if (length < 16) - return RAPIDJSON_LIKELY(is.Tell() < length); - - if (!RAPIDJSON_LIKELY(is.Tell() < length)) - return false; - - const char* p = is.src_; - const char* end = is.head_ + length; - const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); - const char* endAligned = reinterpret_cast(reinterpret_cast(end) & static_cast(~15)); - if (nextAligned > end) - return true; - - while (p != nextAligned) - if (*p < 0x20 || *p == '\"' || *p == '\\') { - is.src_ = p; - return RAPIDJSON_LIKELY(is.Tell() < length); - } - else - os_->PutUnsafe(*p++); - - // The rest of string using SIMD - static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; - static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; - static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; - const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); - const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); - const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); - - for (; p != endAligned; p += 16) { - const __m128i s = _mm_load_si128(reinterpret_cast(p)); - const __m128i t1 = _mm_cmpeq_epi8(s, dq); - const __m128i t2 = _mm_cmpeq_epi8(s, bs); - const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F - const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); - unsigned short r = static_cast(_mm_movemask_epi8(x)); - if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped - SizeType len; -#ifdef _MSC_VER // Find the index of first escaped - unsigned long offset; - _BitScanForward(&offset, r); - len = offset; -#else - len = static_cast(__builtin_ffs(r) - 1); -#endif - char* q = reinterpret_cast(os_->PushUnsafe(len)); - for (size_t i = 0; i < len; i++) - q[i] = p[i]; - - p += len; - break; - } - _mm_storeu_si128(reinterpret_cast<__m128i *>(os_->PushUnsafe(16)), s); - } - - is.src_ = p; - return RAPIDJSON_LIKELY(is.Tell() < length); -} -#elif defined(RAPIDJSON_NEON) -template<> -inline bool Writer::ScanWriteUnescapedString(StringStream& is, size_t length) { - if (length < 16) - return RAPIDJSON_LIKELY(is.Tell() < length); - - if (!RAPIDJSON_LIKELY(is.Tell() < length)) - return false; - - const char* p = is.src_; - const char* end = is.head_ + length; - const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); - const char* endAligned = reinterpret_cast(reinterpret_cast(end) & static_cast(~15)); - if (nextAligned > end) - return true; - - while (p != nextAligned) - if (*p < 0x20 || *p == '\"' || *p == '\\') { - is.src_ = p; - return RAPIDJSON_LIKELY(is.Tell() < length); - } - else - os_->PutUnsafe(*p++); - - // The rest of string using SIMD - const uint8x16_t s0 = vmovq_n_u8('"'); - const uint8x16_t s1 = vmovq_n_u8('\\'); - const uint8x16_t s2 = vmovq_n_u8('\b'); - const uint8x16_t s3 = vmovq_n_u8(32); - - for (; p != endAligned; p += 16) { - const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); - uint8x16_t x = vceqq_u8(s, s0); - x = vorrq_u8(x, vceqq_u8(s, s1)); - x = vorrq_u8(x, vceqq_u8(s, s2)); - x = vorrq_u8(x, vcltq_u8(s, s3)); - - x = vrev64q_u8(x); // Rev in 64 - uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract - uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract - - SizeType len = 0; - bool escaped = false; - if (low == 0) { - if (high != 0) { - uint32_t lz = internal::clzll(high); - len = 8 + (lz >> 3); - escaped = true; - } - } else { - uint32_t lz = internal::clzll(low); - len = lz >> 3; - escaped = true; - } - if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped - char* q = reinterpret_cast(os_->PushUnsafe(len)); - for (size_t i = 0; i < len; i++) - q[i] = p[i]; - - p += len; - break; - } - vst1q_u8(reinterpret_cast(os_->PushUnsafe(16)), s); - } - - is.src_ = p; - return RAPIDJSON_LIKELY(is.Tell() < length); -} -#endif // RAPIDJSON_NEON - -RAPIDJSON_NAMESPACE_END - -#if defined(_MSC_VER) || defined(__clang__) -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_RAPIDJSON_H_ diff --git a/external/readme.md b/external/readme.md new file mode 100644 index 0000000..e69de29 From 78f78fff935a4f557039439298f4b5d323d68384 Mon Sep 17 00:00:00 2001 From: changliao1025 Date: Tue, 16 Apr 2024 08:52:39 -0700 Subject: [PATCH 4/4] remove c++ source code --- CITATION.cff | 2 +- conda-recipe/conda_build_config.yaml | 2 +- conda-recipe/meta.yaml | 2 +- pyhexwatershed/classes/pycase.py | 4 +- setup.cfg | 2 +- setup.py | 134 +---------------- setup_with_hexwatershed.py | 208 +++++++++++++++++++++++++++ 7 files changed, 216 insertions(+), 138 deletions(-) create mode 100644 setup_with_hexwatershed.py diff --git a/CITATION.cff b/CITATION.cff index 4ad6273..b3a2945 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -5,6 +5,6 @@ authors: given-names: Chang orcid: https://orcid.org/0000-0002-7348-8858 title: "HexWatershed: a mesh-independent flow direction model for hydrologic models" -version: 0.2.25 +version: 0.2.26 doi: 10.5281/zenodo.6425881 date-released: 2022-03-31 \ No newline at end of file diff --git a/conda-recipe/conda_build_config.yaml b/conda-recipe/conda_build_config.yaml index cd20b88..b250c6c 100644 --- a/conda-recipe/conda_build_config.yaml +++ b/conda-recipe/conda_build_config.yaml @@ -23,7 +23,7 @@ metadata: # Package name name: hexwatershed # Package version - version: "0.2.25" + version: "0.2.26" # Package summary summary: A mesh-independent flow direction model for hydrologic models # Package homepage diff --git a/conda-recipe/meta.yaml b/conda-recipe/meta.yaml index a2dc4ea..1827d27 100644 --- a/conda-recipe/meta.yaml +++ b/conda-recipe/meta.yaml @@ -1,6 +1,6 @@ {% set name = "hexwatershed" %} {% set git_rev = "main" %} -{% set version = "0.2.25" %} +{% set version = "0.2.26" %} package: name: {{ name|lower }} diff --git a/pyhexwatershed/classes/pycase.py b/pyhexwatershed/classes/pycase.py index 80494a6..7d4a8cf 100644 --- a/pyhexwatershed/classes/pycase.py +++ b/pyhexwatershed/classes/pycase.py @@ -833,8 +833,8 @@ def pyhexwatershed_export(self): else: #if the pyflowline does not turn on flowline, #then we need to include at least one watershed - #self.pyhexwatershed_export_flow_direction() - #self.pyhexwatershed_export_stream_segment() + self.pyhexwatershed_export_flow_direction() + self.pyhexwatershed_export_stream_segment() #polygon #self.pyhexwatershed_export_elevation() diff --git a/setup.cfg b/setup.cfg index f8dbb55..a004a6d 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 0.2.25 +current_version = 0.2.26 commit = True tag = True diff --git a/setup.py b/setup.py index 8b7016a..24c6219 100644 --- a/setup.py +++ b/setup.py @@ -11,7 +11,7 @@ AUTHOR = "Chang Liao" AUTHOR_EMAIL = "chang.liao@pnnl.gov" URL = "https://github.com/changliao1025/pyhexwatershed" -VERSION = "0.2.25" +VERSION = "0.2.26" REQUIRES_PYTHON = ">=3.8.0" KEYWORDS = ["hexwatershed", "hydrology", @@ -38,28 +38,7 @@ "Topic :: Scientific/Engineering :: Hydrology", "Topic :: Scientific/Engineering :: GIS", "Topic :: Scientific/Engineering :: Physics" -] - -def get_data_files(sFolder_in): - data_files_tmp = [] - for root, dirs, files in os.walk(sFolder_in): - for file in files: - data_files_tmp.append(os.path.join(root, file)) - - #print(data_files_tmp) - return data_files_tmp - - -data_files=[ ( 'external/hexwatershed/', ["external/hexwatershed/CMakeLists.txt"] ) , - ( "external/rapidjson/" , get_data_files('external/rapidjson') ), - ( "external/rapidjson/error/" , get_data_files('external/rapidjson/error/') ), - ( "external/rapidjson/internal/" , get_data_files('external/rapidjson/internal') ), - ( "external/rapidjson/msinttypes/" , get_data_files('external/rapidjson/msinttypes') ), - ( "external/hexwatershed/src" , get_data_files('external/hexwatershed/src') ), - ( "external/hexwatershed/src/compset/", get_data_files('external/hexwatershed/src/compset') ), - ( "external/hexwatershed/src/domain/" , get_data_files('external/hexwatershed/src/domain') ), - ( "external/hexwatershed/src/json/" , get_data_files('external/hexwatershed/src/json') ) - ] +] HERE = os.path.abspath(os.path.dirname(__file__)) HERE = os.path.expandvars(HERE) @@ -77,111 +56,6 @@ def get_data_files(sFolder_in): except FileNotFoundError: LONG_DESCRIPTION = DESCRIPTION -def get_cmake_version(): - try: - out = subprocess.check_output( - ["cmake", "--version"]).decode("utf-8") - sln = out.splitlines()[0] - ver = sln.split()[2] - return ver - - except: - print("cmake not found!") - -class build_external(Command): - - description = "build external hexwatershed dependencies" - - user_options = [] - - def initialize_options(self): pass - - def finalize_options(self): pass - - def run(self): - """ - The actual cmake-based build steps for hexwatershed - - """ - if (self.dry_run): return - - cwd_pointer = os.getcwd() - - try: - self.announce("cmake config.", level=3) - - source_path = os.path.join( - HERE, "external", "hexwatershed") - - source_path = os.path.expandvars(source_path) - - # Check if the expanded path exists - if os.path.exists(source_path): - print('Path exists:', source_path) - else: - print('Path does not exist:', source_path) - - builds_path = os.path.join(source_path, "build") - - if os.path.exists(builds_path): - sFilename_cache = os.path.join(builds_path, "CMakeCache.txt") - if os.path.exists(sFilename_cache): - os.remove(sFilename_cache) - else: - #print('File or directory does not exist') - pass - pass - else: - os.mkdir(builds_path) - - exesrc_path = \ - os.path.join(source_path, "bin") - - libsrc_path = \ - os.path.join(source_path, "lib") - - exedst_path = os.path.join( - HERE, "pyhexwatershed", "_bin") - - libdst_path = os.path.join( - HERE, "pyhexwatershed", "_lib") - - shutil.rmtree( - exedst_path, ignore_errors=True) - shutil.rmtree( - libdst_path, ignore_errors=True) - - os.chdir(builds_path) - #copy cmakelistx.txt to the build folder - dst = os.getcwd() - shutil.copy("../CMakeLists.txt", dst) - config_call = ["cmake", "CMakeLists.txt"] - #' -G "Unix Makefiles"', - subprocess.run(config_call, check=True) - - self.announce("cmake complie", level=3) - - ver = get_cmake_version() - - compilecall = [ - "cmake", "--build", ".", - "--config", "Release", - "--target", "install" - ] - - - subprocess.run(compilecall, check=True) - - self.announce("cmake cleanup", level=3) - - shutil.copytree(exesrc_path, exedst_path) - #shutil.copytree(libsrc_path, libdst_path) - - finally: - os.chdir(cwd_pointer) - shutil.rmtree(builds_path) - - setup( name=NAME, version=VERSION, @@ -196,11 +70,7 @@ def run(self): url=URL, setup_requires=['setuptools'], packages=find_packages(), - package_data={ - "pyhexwatershed": ["_bin/*", "_lib/*"] - }, install_requires=REQUIRED, - cmdclass={"build_external": build_external}, classifiers=CLASSIFY, extras_require={ 'visualization': ['cython', 'matplotlib', 'cartopy>=0.21.0'] diff --git a/setup_with_hexwatershed.py b/setup_with_hexwatershed.py new file mode 100644 index 0000000..82c9434 --- /dev/null +++ b/setup_with_hexwatershed.py @@ -0,0 +1,208 @@ + +import io +import os +import subprocess +import shutil +from setuptools import setup, Command, find_packages + +NAME = "hexwatershed" +DESCRIPTION = \ + "A mesh-independent flow direction model for hydrologic models" +AUTHOR = "Chang Liao" +AUTHOR_EMAIL = "chang.liao@pnnl.gov" +URL = "https://github.com/changliao1025/pyhexwatershed" +VERSION = "0.2.26" +REQUIRES_PYTHON = ">=3.8.0" +KEYWORDS = ["hexwatershed", + "hydrology", + "hydrologic modeling", + "hydrologic model", + "flow direction", + "hexagon"] + +REQUIRED = [ + "numpy", + "gdal", + "shapely", + "pyflowline" +] + +CLASSIFY = [ + "Development Status :: 4 - Beta", + "Operating System :: OS Independent", + "Intended Audience :: Science/Research", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: C++", + "Topic :: Scientific/Engineering", + "Topic :: Scientific/Engineering :: Hydrology", + "Topic :: Scientific/Engineering :: GIS", + "Topic :: Scientific/Engineering :: Physics" +] + +def get_data_files(sFolder_in): + data_files_tmp = [] + for root, dirs, files in os.walk(sFolder_in): + for file in files: + data_files_tmp.append(os.path.join(root, file)) + + #print(data_files_tmp) + return data_files_tmp + + +data_files=[ ( 'external/hexwatershed/', ["external/hexwatershed/CMakeLists.txt"] ) , + ( "external/rapidjson/" , get_data_files('external/rapidjson') ), + ( "external/rapidjson/error/" , get_data_files('external/rapidjson/error/') ), + ( "external/rapidjson/internal/" , get_data_files('external/rapidjson/internal') ), + ( "external/rapidjson/msinttypes/" , get_data_files('external/rapidjson/msinttypes') ), + ( "external/hexwatershed/src" , get_data_files('external/hexwatershed/src') ), + ( "external/hexwatershed/src/compset/", get_data_files('external/hexwatershed/src/compset') ), + ( "external/hexwatershed/src/domain/" , get_data_files('external/hexwatershed/src/domain') ), + ( "external/hexwatershed/src/json/" , get_data_files('external/hexwatershed/src/json') ) + ] + +HERE = os.path.abspath(os.path.dirname(__file__)) +HERE = os.path.expandvars(HERE) +# Check if the expanded path exists +if os.path.exists(HERE): + print('Path exists:', HERE) +else: + print('Path does not exist:', HERE) + +try: + with io.open(os.path.join( + HERE, "README.md"), encoding="utf-8") as f: + LONG_DESCRIPTION = "\n" + f.read() + +except FileNotFoundError: + LONG_DESCRIPTION = DESCRIPTION + +def get_cmake_version(): + try: + out = subprocess.check_output( + ["cmake", "--version"]).decode("utf-8") + sln = out.splitlines()[0] + ver = sln.split()[2] + return ver + + except: + print("cmake not found!") + +class build_external(Command): + + description = "build external hexwatershed dependencies" + + user_options = [] + + def initialize_options(self): pass + + def finalize_options(self): pass + + def run(self): + """ + The actual cmake-based build steps for hexwatershed + + """ + if (self.dry_run): return + + cwd_pointer = os.getcwd() + + try: + self.announce("cmake config.", level=3) + + source_path = os.path.join( + HERE, "external", "hexwatershed") + + source_path = os.path.expandvars(source_path) + + # Check if the expanded path exists + if os.path.exists(source_path): + print('Path exists:', source_path) + else: + print('Path does not exist:', source_path) + + builds_path = os.path.join(source_path, "build") + + if os.path.exists(builds_path): + sFilename_cache = os.path.join(builds_path, "CMakeCache.txt") + if os.path.exists(sFilename_cache): + os.remove(sFilename_cache) + else: + #print('File or directory does not exist') + pass + pass + else: + os.mkdir(builds_path) + + exesrc_path = \ + os.path.join(source_path, "bin") + + libsrc_path = \ + os.path.join(source_path, "lib") + + exedst_path = os.path.join( + HERE, "pyhexwatershed", "_bin") + + libdst_path = os.path.join( + HERE, "pyhexwatershed", "_lib") + + shutil.rmtree( + exedst_path, ignore_errors=True) + shutil.rmtree( + libdst_path, ignore_errors=True) + + os.chdir(builds_path) + #copy cmakelistx.txt to the build folder + dst = os.getcwd() + shutil.copy("../CMakeLists.txt", dst) + config_call = ["cmake", "CMakeLists.txt"] + #' -G "Unix Makefiles"', + subprocess.run(config_call, check=True) + + self.announce("cmake complie", level=3) + + ver = get_cmake_version() + + compilecall = [ + "cmake", "--build", ".", + "--config", "Release", + "--target", "install" + ] + + + subprocess.run(compilecall, check=True) + + self.announce("cmake cleanup", level=3) + + shutil.copytree(exesrc_path, exedst_path) + #shutil.copytree(libsrc_path, libdst_path) + + finally: + os.chdir(cwd_pointer) + shutil.rmtree(builds_path) + + +setup( + name=NAME, + version=VERSION, + description=DESCRIPTION, + long_description=LONG_DESCRIPTION, + long_description_content_type="text/markdown", + license="custom", + author=AUTHOR, + author_email=AUTHOR_EMAIL, + python_requires=REQUIRES_PYTHON, + keywords=KEYWORDS, + url=URL, + setup_requires=['setuptools'], + packages=find_packages(), + package_data={ + "pyhexwatershed": ["_bin/*", "_lib/*"] + }, + install_requires=REQUIRED, + cmdclass={"build_external": build_external}, + classifiers=CLASSIFY, + extras_require={ + 'visualization': ['cython', 'matplotlib', 'cartopy>=0.21.0'] + } +)