├── .clang-format ├── .clusterfuzzlite ├── Dockerfile ├── README.md ├── build.sh ├── project.yaml └── reformat_fuzzer.cpp ├── .github ├── actions │ └── docker-build-action │ │ └── action.yml └── workflows │ ├── build_and_test_with_sanitizers.yml │ ├── cflite_pr.yml │ ├── codeql.yml │ └── msvc.yml ├── .gitignore ├── .travis.yml ├── CMakeLists.txt ├── CMakePresets.json ├── COPYING ├── Doxyfile ├── README.md ├── appveyor.yml ├── build.sh ├── cmake └── GenPkgConfig │ ├── GenPkgConfig.cmake │ └── buildTimeScripts │ └── getObjectFilesBaseNames.cmake ├── conanfile.py ├── docker └── ubuntu22.04 │ ├── Dockerfile │ ├── llvm-snapshot.gpg.key.gpg │ └── llvm.list ├── examples ├── 01_simple_struct.cpp ├── 02_alias.cpp ├── 03_optional_types.cpp ├── 04_subclasses.cpp ├── 05_enums.cpp ├── 06_map.cpp ├── 07_stdtypes.cpp ├── 08_custom_types.cpp ├── 09_nested_types.cpp ├── 10_simple_tokenize.cpp ├── 11_calling_functions.cpp ├── 12_simple_diff.cpp ├── 13_diff_missing_data.cpp ├── CMakeLists.txt └── reformat.cpp ├── include └── json_struct │ ├── json_struct.h │ └── json_struct_diff.h ├── package.xml ├── performance ├── CMakeLists.txt ├── benchmark.cpp ├── catch-main.cpp ├── catch2 │ └── catch.hpp ├── generated.json.h ├── glaze_benchmark.cpp └── include │ ├── nlohmann │ └── json.hpp │ ├── rapidjson │ ├── allocators.h │ ├── cursorstreamwrapper.h │ ├── document.h │ ├── encodedstream.h │ ├── encodings.h │ ├── error │ │ ├── en.h │ │ └── error.h │ ├── filereadstream.h │ ├── filewritestream.h │ ├── fwd.h │ ├── internal │ │ ├── biginteger.h │ │ ├── clzll.h │ │ ├── diyfp.h │ │ ├── dtoa.h │ │ ├── ieee754.h │ │ ├── itoa.h │ │ ├── meta.h │ │ ├── pow10.h │ │ ├── regex.h │ │ ├── stack.h │ │ ├── strfunc.h │ │ ├── strtod.h │ │ └── swap.h │ ├── istreamwrapper.h │ ├── memorybuffer.h │ ├── memorystream.h │ ├── msinttypes │ │ ├── inttypes.h │ │ └── stdint.h │ ├── ostreamwrapper.h │ ├── pointer.h │ ├── prettywriter.h │ ├── rapidjson.h │ ├── reader.h │ ├── schema.h │ ├── stream.h │ ├── stringbuffer.h │ └── writer.h │ └── simdjson │ ├── simdjson.cpp │ └── simdjson.h ├── test_package ├── CMakeLists.txt ├── conanfile.py └── main.cpp └── tests ├── CMakeLists.txt ├── CMakeRC.cmake ├── catch-main.cpp ├── catch2 └── catch.hpp ├── compiler-test.cpp ├── generated.json ├── json-copy-test.cpp ├── json-enum-test.cpp ├── json-function-error-test.cpp ├── json-function-external-test-new.cpp ├── json-function-external-test.cpp ├── json-function-test-new.cpp ├── json-function-test.cpp ├── json-meta-test.cpp ├── json-mias-mat.cpp ├── json-nullable-test.cpp ├── json-optional.cpp ├── json-reformat.cpp ├── json-scope.cpp ├── json-string-with-nullterminator-test.cpp ├── json-struct-aliases-test.cpp ├── json-struct-array-varlength.cpp ├── json-struct-big-test.cpp ├── json-struct-diff.cpp ├── json-struct-error-string.cpp ├── json-struct-escape.cpp ├── json-struct-external.cpp ├── json-struct-fail.cpp ├── json-struct-float.cpp ├── json-struct-map-typehandler.cpp ├── json-struct-nested.cpp ├── json-struct-optional.cpp ├── json-struct-polymorphic-map.cpp ├── json-struct-serialize-test.cpp ├── json-struct-serialize-tuple.cpp ├── json-struct-small-test.cpp ├── json-struct-stdint.cpp ├── json-struct-test-new.cpp ├── json-struct-test.cpp ├── json-struct-utf8.cpp ├── json-struct-verify.cpp ├── json-test-data.h ├── json-timepoint.cpp ├── json-tokenizer-fail-test.cpp ├── json-tokenizer-invalid-json.cpp ├── json-tokenizer-partial-test.cpp ├── json-tokenizer-test.cpp ├── json-tree-printer-test.cpp ├── json-unordered-map.cpp ├── members-size-test.cpp ├── meta-for-tokens.cpp ├── multi-compilation-units-1.cpp ├── multi-compilation-units-2.cpp ├── multi-compilation-units-main.cpp ├── tokenizer-test-util.h └── zero-value-test.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: Microsoft 4 | AccessModifierOffset: -2 5 | AlignAfterOpenBracket: Align 6 | AlignConsecutiveMacros: false 7 | AlignConsecutiveAssignments: false 8 | AlignConsecutiveDeclarations: false 9 | AlignEscapedNewlines: Right 10 | AlignOperands: true 11 | AlignTrailingComments: true 12 | AllowAllArgumentsOnNextLine: true 13 | AllowAllConstructorInitializersOnNextLine: true 14 | AllowAllParametersOfDeclarationOnNextLine: true 15 | AllowShortBlocksOnASingleLine: Never 16 | AllowShortCaseLabelsOnASingleLine: false 17 | AllowShortFunctionsOnASingleLine: None 18 | AllowShortLambdasOnASingleLine: All 19 | AllowShortIfStatementsOnASingleLine: Never 20 | AllowShortLoopsOnASingleLine: false 21 | AlwaysBreakAfterDefinitionReturnType: None 22 | AlwaysBreakAfterReturnType: None 23 | AlwaysBreakBeforeMultilineStrings: false 24 | AlwaysBreakTemplateDeclarations: true 25 | BinPackArguments: true 26 | BinPackParameters: true 27 | BraceWrapping: 28 | AfterCaseLabel: false 29 | AfterClass: true 30 | AfterControlStatement: true 31 | AfterEnum: true 32 | AfterFunction: true 33 | AfterNamespace: true 34 | AfterObjCDeclaration: true 35 | AfterStruct: true 36 | AfterUnion: true 37 | AfterExternBlock: true 38 | BeforeCatch: true 39 | BeforeElse: true 40 | IndentBraces: false 41 | SplitEmptyFunction: true 42 | SplitEmptyRecord: true 43 | SplitEmptyNamespace: true 44 | BreakBeforeBinaryOperators: None 45 | BreakBeforeBraces: Custom 46 | BreakBeforeInheritanceComma: false 47 | BreakInheritanceList: BeforeColon 48 | BreakBeforeTernaryOperators: true 49 | BreakConstructorInitializersBeforeComma: true 50 | BreakConstructorInitializers: BeforeColon 51 | BreakAfterJavaFieldAnnotations: false 52 | BreakStringLiterals: true 53 | ColumnLimit: 120 54 | CommentPragmas: '^ IWYU pragma:' 55 | CompactNamespaces: false 56 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 57 | ConstructorInitializerIndentWidth: 2 58 | ContinuationIndentWidth: 2 59 | Cpp11BracedListStyle: true 60 | DeriveLineEnding: true 61 | DerivePointerAlignment: false 62 | DisableFormat: false 63 | ExperimentalAutoDetectBinPacking: false 64 | FixNamespaceComments: true 65 | ForEachMacros: 66 | - foreach 67 | - Q_FOREACH 68 | - BOOST_FOREACH 69 | IncludeBlocks: Preserve 70 | IncludeCategories: 71 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/' 72 | Priority: 2 73 | SortPriority: 0 74 | - Regex: '^(<|"(gtest|gmock|isl|json)/)' 75 | Priority: 3 76 | SortPriority: 0 77 | - Regex: '.*' 78 | Priority: 1 79 | SortPriority: 0 80 | IncludeIsMainRegex: '(Test)?$' 81 | IncludeIsMainSourceRegex: '' 82 | IndentCaseLabels: false 83 | IndentGotoLabels: true 84 | IndentPPDirectives: None 85 | IndentWidth: 2 86 | IndentWrappedFunctionNames: false 87 | JavaScriptQuotes: Leave 88 | JavaScriptWrapImports: true 89 | KeepEmptyLinesAtTheStartOfBlocks: true 90 | MacroBlockBegin: '' 91 | MacroBlockEnd: '' 92 | MaxEmptyLinesToKeep: 1 93 | NamespaceIndentation: None 94 | ObjCBinPackProtocolList: Auto 95 | ObjCBlockIndentWidth: 2 96 | ObjCSpaceAfterProperty: false 97 | ObjCSpaceBeforeProtocolList: true 98 | PenaltyBreakAssignment: 2 99 | PenaltyBreakBeforeFirstCallParameter: 19 100 | PenaltyBreakComment: 300 101 | PenaltyBreakFirstLessLess: 120 102 | PenaltyBreakString: 1000 103 | PenaltyBreakTemplateDeclaration: 10 104 | PenaltyExcessCharacter: 1000000 105 | PenaltyReturnTypeOnItsOwnLine: 1000 106 | PointerAlignment: Right 107 | ReflowComments: true 108 | SortIncludes: true 109 | SortUsingDeclarations: true 110 | SpaceAfterCStyleCast: false 111 | SpaceAfterLogicalNot: false 112 | SpaceAfterTemplateKeyword: true 113 | SpaceBeforeAssignmentOperators: true 114 | SpaceBeforeCpp11BracedList: false 115 | SpaceBeforeCtorInitializerColon: true 116 | SpaceBeforeInheritanceColon: true 117 | SpaceBeforeParens: ControlStatements 118 | SpaceBeforeRangeBasedForLoopColon: true 119 | SpaceInEmptyBlock: false 120 | SpaceInEmptyParentheses: false 121 | SpacesBeforeTrailingComments: 1 122 | SpacesInAngles: false 123 | SpacesInConditionalStatement: false 124 | SpacesInContainerLiterals: true 125 | SpacesInCStyleCastParentheses: false 126 | SpacesInParentheses: false 127 | SpacesInSquareBrackets: false 128 | SpaceBeforeSquareBrackets: false 129 | Standard: Latest 130 | StatementMacros: 131 | - Q_UNUSED 132 | - QT_REQUIRE_VERSION 133 | TabWidth: 2 134 | UseCRLF: false 135 | UseTab: Never 136 | ... 137 | 138 | -------------------------------------------------------------------------------- /.clusterfuzzlite/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM gcr.io/oss-fuzz-base/base-builder 2 | RUN apt-get update && apt-get install -y make autoconf automake libtool 3 | 4 | COPY . $SRC/json_struct 5 | COPY .clusterfuzzlite/build.sh $SRC/build.sh 6 | WORKDIR $SRC/json_struct -------------------------------------------------------------------------------- /.clusterfuzzlite/README.md: -------------------------------------------------------------------------------- 1 | # ClusterFuzzLite set up 2 | 3 | This folder contains a fuzzing set for [ClusterFuzzLite](https://google.github.io/clusterfuzzlite). 4 | -------------------------------------------------------------------------------- /.clusterfuzzlite/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eu 2 | # Copy fuzzer executables to $OUT/ 3 | $CXX $CXXFLAGS -fsanitize=fuzzer $SRC/json_struct/.clusterfuzzlite/reformat_fuzzer.cpp -o $OUT/reformat_fuzzer -I$SRC/json_struct/include 4 | -------------------------------------------------------------------------------- /.clusterfuzzlite/project.yaml: -------------------------------------------------------------------------------- 1 | language: c++ -------------------------------------------------------------------------------- /.clusterfuzzlite/reformat_fuzzer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) 5 | { 6 | std::string pretty; 7 | JS::reformat((const char *)data, size, pretty); 8 | 9 | return 0; 10 | } -------------------------------------------------------------------------------- /.github/actions/docker-build-action/action.yml: -------------------------------------------------------------------------------- 1 | name: 'Docker Build and Push' 2 | description: 'Builds and pushes Docker images to GitHub Container Registry' 3 | 4 | inputs: 5 | imageName: 6 | description: 'Name of the image to build and push' 7 | required: true 8 | dockerFile: 9 | description: 'Filepath relative to the repository root' 10 | required: true 11 | user: 12 | description: 'User name used for ghcr' 13 | required: true 14 | password: 15 | description: 'Password for user when logging in to ghcr' 16 | required: true 17 | outputs: 18 | imageTag: 19 | description: 'The tag of the built Docker image' 20 | value: ghcr.io/${{ github.repository_owner }}/${{ inputs.imageName }} 21 | runs: 22 | using: 'composite' 23 | steps: 24 | - name: Set up environment variables 25 | shell: bash 26 | run: echo "FULL_IMAGE_NAME=ghcr.io/${{ github.repository_owner }}/${{ inputs.imageName }}" >> $GITHUB_ENV 27 | 28 | - name: Checkout code 29 | uses: actions/checkout@v2 30 | 31 | - name: Log in to GitHub Container Registry 32 | shell: bash 33 | run: docker login ghcr.io -u ${{ inputs.user }} -p ${{ inputs.password }} 34 | 35 | - name: Check if Docker image exists 36 | id: check_image 37 | shell: bash 38 | run: | 39 | if docker manifest inspect $FULL_IMAGE_NAME; then 40 | echo "IMAGE_EXISTS=true" >> $GITHUB_ENV 41 | else 42 | echo "IMAGE_EXISTS=false" >> $GITHUB_ENV 43 | fi 44 | 45 | - name: Build Docker image 46 | if: env.IMAGE_EXISTS == 'false' 47 | shell: bash 48 | run: docker build -t $FULL_IMAGE_NAME -f ${{ inputs.dockerFile }} . 49 | 50 | - name: Push Docker image 51 | if: env.IMAGE_EXISTS == 'false' 52 | shell: bash 53 | run: docker push $FULL_IMAGE_NAME 54 | 55 | -------------------------------------------------------------------------------- /.github/workflows/build_and_test_with_sanitizers.yml: -------------------------------------------------------------------------------- 1 | name: Build and Test with Clang sanitizers 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build-and-push-docker-image: 7 | runs-on: ubuntu-latest 8 | outputs: 9 | imageTag: ${{ steps.docker-build.outputs.imageTag }} 10 | steps: 11 | - uses: actions/checkout@v2 12 | - name: Build and Push Docker Image 13 | id: docker-build 14 | uses: ./.github/actions/docker-build-action 15 | with: 16 | imageName: json_struct_sanitizer_docker:2 17 | dockerFile: docker/ubuntu22.04/Dockerfile 18 | user: ${{ github.actor }} 19 | password: ${{ secrets.GITHUB_TOKEN }} 20 | 21 | test-address-sanitizer: 22 | runs-on: ubuntu-latest 23 | needs: build-and-push-docker-image 24 | container: ${{ needs.build-and-push-docker-image.outputs.imageTag }} 25 | steps: 26 | - uses: actions/checkout@v2 27 | - name: Run AddressSanitizer 28 | run: | 29 | mkdir build && cd build 30 | cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS="-fsanitize=address,undefined" -GNinja .. 31 | ninja 32 | ctest . 33 | 34 | test-memory-sanitizer: 35 | runs-on: ubuntu-latest 36 | needs: build-and-push-docker-image 37 | container: ${{ needs.build-and-push-docker-image.outputs.imageTag }} 38 | steps: 39 | - uses: actions/checkout@v2 40 | - name: Run MemorySanitizer 41 | run: | 42 | mkdir build && cd build 43 | cmake -DCMAKE_CXX_FLAGS="$MSAN_CFLAGS" -DCMAKE_EXE_LINKER_FLAGS="$MSAN_LFLAGS" -DCMAKE_BUILD_TYPE=Debug -GNinja .. 44 | ninja 45 | ctest . 46 | -------------------------------------------------------------------------------- /.github/workflows/cflite_pr.yml: -------------------------------------------------------------------------------- 1 | name: ClusterFuzzLite PR fuzzing 2 | on: 3 | workflow_dispatch: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | permissions: read-all 9 | jobs: 10 | PR: 11 | runs-on: ubuntu-latest 12 | strategy: 13 | fail-fast: false 14 | matrix: 15 | sanitizer: [address] 16 | steps: 17 | - name: Build Fuzzers (${{ matrix.sanitizer }}) 18 | id: build 19 | uses: google/clusterfuzzlite/actions/build_fuzzers@v1 20 | with: 21 | sanitizer: ${{ matrix.sanitizer }} 22 | language: c++ 23 | bad-build-check: false 24 | - name: Run Fuzzers (${{ matrix.sanitizer }}) 25 | id: run 26 | uses: google/clusterfuzzlite/actions/run_fuzzers@v1 27 | with: 28 | fuzz-seconds: 100 29 | mode: 'code-change' 30 | report-unreproducible-crashes: false 31 | sanitizer: ${{ matrix.sanitizer }} 32 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | env: 15 | JSON_STRUCT_DISABLE_PCH: ON 16 | 17 | on: 18 | push: 19 | branches: [ "master" ] 20 | pull_request: 21 | branches: [ "master" ] 22 | schedule: 23 | - cron: '44 12 * * 6' 24 | 25 | jobs: 26 | analyze: 27 | name: Analyze 28 | # Runner size impacts CodeQL analysis time. To learn more, please see: 29 | # - https://gh.io/recommended-hardware-resources-for-running-codeql 30 | # - https://gh.io/supported-runners-and-hardware-resources 31 | # - https://gh.io/using-larger-runners 32 | # Consider using larger runners for possible analysis time improvements. 33 | runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} 34 | timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }} 35 | permissions: 36 | actions: read 37 | contents: read 38 | security-events: write 39 | 40 | strategy: 41 | fail-fast: false 42 | matrix: 43 | language: [ 'c-cpp' ] 44 | 45 | steps: 46 | - name: Checkout repository 47 | uses: actions/checkout@v4 48 | 49 | # Initializes the CodeQL tools for scanning. 50 | - name: Initialize CodeQL 51 | uses: github/codeql-action/init@v3 52 | with: 53 | languages: ${{ matrix.language }} 54 | # If you wish to specify custom queries, you can do so here or in a config file. 55 | # By default, queries listed here will override any specified in a config file. 56 | # Prefix the list here with "+" to use these queries and those in the config file. 57 | 58 | # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 59 | # queries: security-extended,security-and-quality 60 | 61 | 62 | # Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift). 63 | # If this step fails, then you should remove it and run the build manually (see below) 64 | - name: Autobuild 65 | uses: github/codeql-action/autobuild@v3 66 | 67 | # ℹ️ Command-line programs to run using the OS shell. 68 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 69 | 70 | # If the Autobuild fails above, remove it and uncomment the following three lines. 71 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. 72 | 73 | # - run: | 74 | # echo "Run, Build Application using script" 75 | # ./location_of_script_within_repo/buildscript.sh 76 | 77 | - name: Perform CodeQL Analysis 78 | uses: github/codeql-action/analyze@v3 79 | with: 80 | category: "/language:${{matrix.language}}" 81 | -------------------------------------------------------------------------------- /.github/workflows/msvc.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. 2 | # They are provided by a third-party and are governed by 3 | # separate terms of service, privacy policy, and support 4 | # documentation. 5 | # 6 | # Find more information at: 7 | # https://github.com/microsoft/msvc-code-analysis-action 8 | 9 | name: Microsoft C++ Code Analysis 10 | 11 | on: 12 | push: 13 | branches: [ "master" ] 14 | pull_request: 15 | branches: [ "master" ] 16 | schedule: 17 | - cron: '16 3 * * 0' 18 | 19 | env: 20 | # Path to the CMake build directory. 21 | build: '${{ github.workspace }}/build' 22 | config: 'Debug' 23 | 24 | permissions: 25 | contents: read 26 | 27 | jobs: 28 | analyze: 29 | permissions: 30 | contents: read # for actions/checkout to fetch code 31 | security-events: write # for github/codeql-action/upload-sarif to upload SARIF results 32 | actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status 33 | name: Analyze 34 | runs-on: windows-latest 35 | 36 | steps: 37 | - name: Checkout repository 38 | uses: actions/checkout@v3 39 | 40 | - name: Configure CMake 41 | run: cmake -B ${{ env.build }} -DCMAKE_BUILD_TYPE=${{ env.config }} -DJSON_STRUCT_OPT_DISABLE_PCH=ON 42 | 43 | - name: Build CMake 44 | run: cmake --build ${{ env.build }} 45 | 46 | - name: Initialize MSVC Code Analysis 47 | uses: microsoft/msvc-code-analysis-action@v0.1.1 48 | # Provide a unique ID to access the sarif output path 49 | id: run-analysis 50 | with: 51 | cmakeBuildDirectory: ${{ env.build }} 52 | buildConfiguration: ${{ env.config }} 53 | # Ruleset file that will determine what checks will be run 54 | ruleset: NativeRecommendedRules.ruleset 55 | 56 | # Upload SARIF file to GitHub Code Scanning Alerts 57 | - name: Upload SARIF to GitHub 58 | uses: github/codeql-action/upload-sarif@v2 59 | with: 60 | sarif_file: ${{ steps.run-analysis.outputs.sarif }} 61 | 62 | # Upload SARIF file as an Artifact to download and view 63 | # - name: Upload SARIF as an Artifact 64 | # uses: actions/upload-artifact@v3 65 | # with: 66 | # name: sarif-file 67 | # path: ${{ steps.run-analysis.outputs.sarif }} 68 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Makefile 2 | Makefile.in 3 | aclocal.m4 4 | autom4te.cache/ 5 | config.guess 6 | config.h 7 | config.h.in 8 | config.log 9 | config.status 10 | config.sub 11 | configure 12 | depcomp 13 | install-sh 14 | libtool 15 | ltmain.sh 16 | m4/ 17 | missing 18 | stamp-h1 19 | .deps/ 20 | .libs/ 21 | *.lo 22 | *.o 23 | *.la 24 | tests/json-tokenizer-test 25 | *.swp 26 | *.swo 27 | tests/json-tokenizer-fail-test 28 | tests/json-tokenizer-partial-test 29 | tests/json-tree-test 30 | tests/json-tree-printer-test 31 | 32 | *CMakeUserPresets.json 33 | build/ 34 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | 3 | matrix: 4 | include: 5 | - os: linux 6 | script: ./build.sh 7 | - os: osx 8 | script: ./build.sh 9 | - os: windows 10 | script: ./build.sh 11 | -------------------------------------------------------------------------------- /CMakePresets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "cmakeMinimumRequired": { 4 | "major": 3, 5 | "minor": 20, 6 | "patch": 0 7 | }, 8 | "configurePresets": [ 9 | { 10 | "name": "base", 11 | "binaryDir": "${sourceDir}/out/build/${presetName}", 12 | "hidden": true, 13 | "cacheVariables": { 14 | "CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}" 15 | } 16 | }, 17 | { 18 | "name": "single_config", 19 | "inherits": "base", 20 | "generator": "Ninja", 21 | "hidden": true 22 | }, 23 | { 24 | "name": "homebrew_clang", 25 | "hidden": true, 26 | "cacheVariables": { 27 | "CMAKE_C_COMPILER": "/usr/local/opt/llvm/bin/clang", 28 | "CMAKE_CXX_COMPILER": "/usr/local/opt/llvm/bin/clang++", 29 | "CMAKE_EXPORT_COMPILE_COMMANDS": "ON" 30 | } 31 | }, 32 | { 33 | "name": "debug", 34 | "inherits": "single_config", 35 | "cacheVariables": { 36 | "CMAKE_BUILD_TYPE": "Debug" 37 | } 38 | }, 39 | { 40 | "name": "debug_brew", 41 | "inherits": [ 42 | "single_config", 43 | "homebrew_clang" 44 | ], 45 | "cacheVariables": { 46 | "CMAKE_BUILD_TYPE": "Debug" 47 | } 48 | }, 49 | { 50 | "name": "release_brew", 51 | "inherits": [ 52 | "single_config", 53 | "homebrew_clang" 54 | ], 55 | "cacheVariables": { 56 | "CMAKE_BUILD_TYPE": "Release" 57 | } 58 | }, 59 | { 60 | "name": "release", 61 | "inherits": "single_config", 62 | "cacheVariables": { 63 | "CMAKE_BUILD_TYPE": "Release" 64 | } 65 | }, 66 | { 67 | "name": "multi_config", 68 | "generator": "Ninja Multi-Config", 69 | "inherits": "base", 70 | "cacheVariables": { 71 | "CMAKE_CONFIGURATION_TYPES": "Release;Debug", 72 | "CMAKE_CROSS_CONFIGS": "all", 73 | "CMAKE_DEFAULT_CONFIGS": "all" 74 | } 75 | } 76 | ], 77 | "buildPresets": [ 78 | { 79 | "name": "debug_brew", 80 | "description": "", 81 | "displayName": "", 82 | "configurePreset": "debug_brew" 83 | } 84 | ], 85 | "testPresets": [ 86 | { 87 | "name": "debug_brew", 88 | "description": "", 89 | "displayName": "", 90 | "configurePreset": "debug_brew" 91 | } 92 | ] 93 | } -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright © 2012 Jørgen Lind 2 | 3 | Permission to use, copy, modify, distribute, and sell this software and its 4 | documentation for any purpose is hereby granted without fee, provided that 5 | the above copyright notice appear in all copies and that both that copyright 6 | notice and this permission notice appear in supporting documentation, and 7 | that the name of the copyright holders not be used in advertising or 8 | publicity pertaining to distribution of the software without specific, 9 | written prior permission. The copyright holders make no representations 10 | about the suitability of this software for any purpose. It is provided "as 11 | is" without express or implied warranty. 12 | 13 | THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 14 | INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 15 | EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 16 | CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 17 | DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 18 | TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 19 | OF THIS SOFTWARE. 20 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 1.0.{build} 2 | 3 | image: 4 | - Ubuntu2004 5 | - Visual Studio 2015 6 | - Visual Studio 2017 7 | - Visual Studio 2019 8 | # - macos 9 | 10 | platform: 11 | - x86 12 | - x64 13 | 14 | configuration: 15 | - Debug 16 | 17 | for: 18 | - 19 | matrix: 20 | only: 21 | - image: Visual Studio 2019 22 | platform: x86 23 | before_build: call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars32.bat" 24 | - 25 | matrix: 26 | only: 27 | - image: Visual Studio 2019 28 | platform: x64 29 | before_build: call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat" 30 | - 31 | matrix: 32 | only: 33 | - image: Visual Studio 2017 34 | platform: x86 35 | before_build: call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars32.bat" 36 | - 37 | matrix: 38 | only: 39 | - image: Visual Studio 2017 40 | platform: x64 41 | before_build: call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat" 42 | - 43 | matrix: 44 | only: 45 | - image: Visual Studio 2015 46 | platform: x86 47 | before_build: 48 | - call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86 49 | - 50 | matrix: 51 | only: 52 | - image: Visual Studio 2015 53 | platform: x64 54 | before_build: 55 | - call "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" /x64 56 | - call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86_amd64 57 | 58 | matrix: 59 | exclude: 60 | - image: Ubuntu2004 61 | platform: x86 62 | 63 | build_script: 64 | - cmake -H. -B./build -DJSON_STRUCT_OPT_BUILD_BENCHMARKS=OFF -GNinja 65 | - ninja -C build 66 | 67 | test_script: 68 | - ctest --test-dir build 69 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -vx 2 | set -e 3 | 4 | if [ -e "build" ]; then 5 | rm -rf "build" 6 | fi 7 | 8 | mkdir build 9 | cd build 10 | 11 | if [[ "$OS" == "Windows_NT" ]]; then 12 | cmake .. 13 | cmake --build . --config Release 14 | ctest -C Release --output-on-failure . 15 | else 16 | cmake -DCMAKE_BUILD_TYPE=Release .. 17 | cmake --build . 18 | ctest -C Release --output-on-failure . 19 | fi 20 | -------------------------------------------------------------------------------- /cmake/GenPkgConfig/buildTimeScripts/getObjectFilesBaseNames.cmake: -------------------------------------------------------------------------------- 1 | 2 | message(STATUS "objectsFile ${objectsFile}") 3 | message(STATUS "pkgConfigFileFinal ${pkgConfigFileFinal}") 4 | message(STATUS "pkgConfigFileUnlinished ${pkgConfigFileUnlinished}") 5 | 6 | file(READ "${objectsFile}" TARGET_OBJECTS) 7 | 8 | set(PROPERLY_JOINED_TARGET_OBJECTS "") 9 | 10 | foreach(objFullPath ${TARGET_OBJECTS}) 11 | get_filename_component(objFullPath "${objFullPath}" NAME) 12 | list(APPEND PROPERLY_JOINED_TARGET_OBJECTS "${objFullPath}") 13 | endforeach() 14 | list(JOIN PROPERLY_JOINED_TARGET_OBJECTS " " PROPERLY_JOINED_TARGET_OBJECTS) 15 | 16 | message(STATUS "PROPERLY_JOINED_TARGET_OBJECTS AFTER ${PROPERLY_JOINED_TARGET_OBJECTS}") 17 | 18 | configure_file("${pkgConfigFileUnlinished}" "${pkgConfigFileFinal}" @ONLY) 19 | -------------------------------------------------------------------------------- /conanfile.py: -------------------------------------------------------------------------------- 1 | from conan import ConanFile 2 | from conan.tools.cmake import CMakeToolchain, CMakeDeps, CMake, cmake_layout 3 | from conan.tools.env import VirtualBuildEnv, VirtualRunEnv 4 | from conan.tools.scm import Git, Version 5 | from conan.tools.files import copy 6 | 7 | import os 8 | 9 | class JsonStructLibrary(ConanFile): 10 | name = "json_struct" 11 | 12 | # Metadata 13 | license = "MIT" 14 | version = "1.0.0" 15 | author = "Jørgen Lind " 16 | url = "https://github.com/jorgen/json_struct" 17 | description = "json_struct is a single header only C++ library for parsing JSON directly to C++ structs and vice versa" 18 | 19 | topics = ("serialization", "deserialization", "reflection", "json") 20 | 21 | settings = "os", "compiler", "build_type", "arch" 22 | pacgake_type = "header-library" 23 | implements = ["auto_header_only"] 24 | exports_sources = "include/*", "cmake/*", "CMakeLists.txt", "COPYING", "README.md", "package.xml" 25 | 26 | options = { 27 | "opt_build_benchmarks": [True, False], 28 | "opt_build_examples": [True, False], 29 | "opt_build_tests": [True, False], 30 | "opt_disable_pch": [True, False], 31 | "opt_install": [True, False], 32 | } 33 | 34 | default_options = { 35 | "opt_build_benchmarks": False, 36 | "opt_build_examples": False, 37 | "opt_build_tests": False, 38 | "opt_disable_pch": False, 39 | "opt_install": True, 40 | } 41 | 42 | def generate(self): 43 | toolchain = CMakeToolchain(self) 44 | 45 | toolchain.variables["JSON_STRUCT_OPT_BUILD_BENCHMARKS"] = self.options.opt_build_benchmarks.value 46 | toolchain.variables["JSON_STRUCT_OPT_BUILD_EXAMPLES"] = self.options.opt_build_examples.value 47 | toolchain.variables["JSON_STRUCT_OPT_BUILD_TESTS"] = self.options.opt_build_tests.value 48 | toolchain.variables["JSON_STRUCT_OPT_DISABLE_PCH"] = self.options.opt_disable_pch.value 49 | toolchain.variables["JSON_STRUCT_OPT_INSTALL"] = self.options.opt_install 50 | 51 | toolchain.generate() 52 | 53 | def build(self): 54 | cmake = CMake(self) 55 | cmake.configure() 56 | cmake.build() 57 | 58 | def package(self): 59 | # Invoke cmake --install 60 | cmake = CMake(self) 61 | cmake.install() 62 | 63 | def layout(self): 64 | cmake_layout(self) 65 | -------------------------------------------------------------------------------- /docker/ubuntu22.04/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:jammy 2 | ARG llvmver=17 3 | 4 | RUN apt update && \ 5 | apt-get install -y software-properties-common gnupg apt-transport-https ca-certificates 6 | 7 | ADD docker/ubuntu22.04/llvm.list /etc/apt/sources.list.d/ 8 | ADD docker/ubuntu22.04/llvm-snapshot.gpg.key.gpg /etc/apt/trusted.gpg.d/ 9 | 10 | RUN apt update && \ 11 | apt-get install -y ca-certificates build-essential clang-$llvmver libc++-$llvmver-dev libc++abi-$llvmver-dev libunwind-$llvmver-dev && \ 12 | ln -s /usr/bin/clang++-$llvmver /usr/bin/clang++ && \ 13 | ln -s /usr/bin/clang-$llvmver /usr/bin/clang 14 | 15 | ENV CXX=clang++ 16 | ENV CC=clang 17 | 18 | RUN apt install -y cmake ninja-build git vim 19 | 20 | RUN git clone --depth=1 https://github.com/llvm/llvm-project && \ 21 | cd llvm-project && \ 22 | mkdir build; \ 23 | cmake -G Ninja -S runtimes -B build -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi" -DLLVM_USE_SANITIZER=MemoryWithOrigins -DCMAKE_INSTALL_PREFIX=/opt && \ 24 | ninja -C build cxx cxxabi && \ 25 | ninja -C build install-cxx install-cxxabi 26 | 27 | env MSAN_CFLAGS="-std=c++20 -fsanitize=memory -nostdinc++ -I/opt/include -I/opt/include/c++/v1" 28 | env MSAN_LFLAGS="-fsanitize=memory -stdlib=libc++ -L/opt/lib -lc++abi -Wl,-rpath,/opt/lib" 29 | -------------------------------------------------------------------------------- /docker/ubuntu22.04/llvm-snapshot.gpg.key.gpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jorgen/json_struct/6e69e4a280552fa962a446154798626e4e3871b1/docker/ubuntu22.04/llvm-snapshot.gpg.key.gpg -------------------------------------------------------------------------------- /docker/ubuntu22.04/llvm.list: -------------------------------------------------------------------------------- 1 | deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-17 main 2 | deb-src http://apt.llvm.org/jammy/ llvm-toolchain-jammy-17 main 3 | 4 | -------------------------------------------------------------------------------- /examples/01_simple_struct.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | const char json[] = R"json( 5 | { 6 | "vec" : [ 7 | { "key" : 4, "value": 1.0 }, 8 | { "key" : 5, "value": 2.0 }, 9 | { "key" : 6, "value": 3.0 } 10 | ] 11 | } 12 | )json"; 13 | 14 | struct VecMember 15 | { 16 | std::string key; 17 | double value = 0.0; 18 | 19 | JS_OBJ(key, value); 20 | }; 21 | 22 | 23 | struct ModuleList 24 | { 25 | enum 26 | { 27 | ReservedSize = 16 28 | }; 29 | VecMember modules[ReservedSize]; 30 | int size = 0; 31 | }; 32 | 33 | namespace JS 34 | { 35 | template <> 36 | struct TypeHandler 37 | { 38 | static inline Error to(ModuleList &to_type, ParseContext &context) 39 | { 40 | if (context.token.value_type != Type::ArrayStart) 41 | return JS::Error::ExpectedArrayStart; 42 | 43 | context.nextToken(); 44 | for (int i = 0; i < int(ModuleList::ReservedSize); i++) 45 | { 46 | if (context.error != JS::Error::NoError) 47 | return context.error; 48 | if (context.token.value_type == Type::ArrayEnd) 49 | { 50 | to_type.size = i; 51 | break; 52 | } 53 | context.error = TypeHandler::to(to_type.modules[i], context); 54 | if (context.error != JS::Error::NoError) 55 | return context.error; 56 | 57 | context.nextToken(); 58 | } 59 | 60 | if (context.token.value_type != Type::ArrayEnd) 61 | return JS::Error::ExpectedArrayEnd; 62 | return context.error; 63 | } 64 | 65 | static inline void from(const ModuleList &from_type, Token &token, Serializer &serializer) 66 | { 67 | token.value_type = Type::ArrayStart; 68 | token.value = DataRef("["); 69 | serializer.write(token); 70 | 71 | token.name = DataRef(""); 72 | for (int i = 0; i < from_type.size; i++) 73 | TypeHandler::from(from_type.modules[i], token, serializer); 74 | 75 | token.name = DataRef(""); 76 | token.value_type = Type::ArrayEnd; 77 | token.value = DataRef("]"); 78 | serializer.write(token); 79 | } 80 | }; 81 | } // namespace JS 82 | 83 | struct JsonObject 84 | { 85 | ModuleList vec; 86 | JS_OBJ(vec); 87 | }; 88 | 89 | 90 | int main() 91 | { 92 | JsonObject obj; 93 | JS::ParseContext parseContext(json); 94 | if (parseContext.parseTo(obj) != JS::Error::NoError) 95 | { 96 | std::string errorStr = parseContext.makeErrorString(); 97 | fprintf(stderr, "Error parsing struct %s\n", errorStr.c_str()); 98 | return -1; 99 | } 100 | 101 | fprintf(stdout, "Vec has size %d\n", obj.vec.size); 102 | 103 | return 0; 104 | } 105 | 106 | -------------------------------------------------------------------------------- /examples/02_alias.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | const char json[] = R"json( 5 | { 6 | "key" : "value", 7 | "number" : 100, 8 | "bool" : true 9 | } 10 | )json"; 11 | 12 | struct JsonData 13 | { 14 | std::string key; 15 | int n; 16 | bool boolean; 17 | 18 | JS_OBJECT(JS_MEMBER(key), 19 | JS_MEMBER_ALIASES(n, "number", "num", "or_something_else"), 20 | JS_MEMBER_WITH_NAME(boolean, "bool")); 21 | }; 22 | 23 | // JS_MEMBER_ALIASES adds additional names to a member 24 | // JS_MEMBER_WITH_NAME replaces the lookup name 25 | 26 | int main() 27 | { 28 | JsonData dataStruct; 29 | JS::ParseContext parseContext(json); 30 | if (parseContext.parseTo(dataStruct) != JS::Error::NoError) 31 | { 32 | std::string errorStr = parseContext.makeErrorString(); 33 | fprintf(stderr, "Error parsing struct %s\n", errorStr.c_str()); 34 | return -1; 35 | } 36 | 37 | fprintf(stdout, "Key is: %s, number is %d bool is %d\n", 38 | dataStruct.key.c_str(), 39 | dataStruct.n, 40 | dataStruct.boolean); 41 | 42 | return 0; 43 | } 44 | 45 | -------------------------------------------------------------------------------- /examples/03_optional_types.cpp: -------------------------------------------------------------------------------- 1 | //Please see example 06_stdtypes for std::optional support 2 | #include 3 | #include 4 | 5 | const char json[] = R"json( 6 | { 7 | "key" : "value", 8 | "number" : 100, 9 | "boolean" : true, 10 | "opt_checked" : 1.5, 11 | "member_not_in_c++" : "some_value" 12 | } 13 | )json"; 14 | 15 | struct JsonData 16 | { 17 | std::string key; 18 | int number = 0; 19 | bool boolean = false; 20 | //sizeof(JS::Optional) == sizeof(double) however if you want to see 21 | //if it has been modified there is the JS::OptionalChecked. It has an "assigned" member 22 | //allowing the user to inspect if the type has been assigned 23 | JS::Optional opt = 32.5; 24 | JS::OptionalChecked opt_checked = 100; 25 | 26 | std::string member_not_in_json; 27 | 28 | JS_OBJ(key, number, boolean, opt, opt_checked, member_not_in_json); 29 | }; 30 | 31 | int main() 32 | { 33 | JsonData dataStruct; 34 | JS::ParseContext parseContext(json); 35 | 36 | //default values, but can be set to false to make parseTo return an error value 37 | parseContext.allow_missing_members = true; 38 | parseContext.allow_unasigned_required_members = true; 39 | 40 | //JS::ParseContext has the member 41 | if (parseContext.parseTo(dataStruct) != JS::Error::NoError) 42 | { 43 | std::string errorStr = parseContext.makeErrorString(); 44 | fprintf(stderr, "Error parsing struct %s\n", errorStr.c_str()); 45 | return -1; 46 | } 47 | 48 | //missing C++ struct members found in the json can be retrieved with 49 | for (std::string &member : parseContext.missing_members) 50 | { 51 | fprintf(stderr, "missing member: %s\n", member.c_str()); 52 | } 53 | 54 | //missing JSON member required by non optional C++ members can be retrieved with 55 | for (std::string &member : parseContext.unassigned_required_members) 56 | { 57 | fprintf(stderr, "unassigned required c++ member %s\n", member.c_str()); 58 | } 59 | 60 | fprintf(stdout, "Key is: %s, number is %d bool is %d" 61 | "optional value is %f optional checked %d <-> %f\n", 62 | dataStruct.key.c_str(), 63 | dataStruct.number, 64 | dataStruct.boolean, 65 | dataStruct.opt.data, 66 | dataStruct.opt_checked.assigned, 67 | dataStruct.opt_checked.data); 68 | 69 | return 0; 70 | } 71 | 72 | -------------------------------------------------------------------------------- /examples/04_subclasses.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | const char json[] = R"json( 5 | { 6 | "key" : "value", 7 | "number" : 100, 8 | "boolean" : true, 9 | "additional" : "This is defined in the superclass", 10 | "data" : 1234 11 | } 12 | )json"; 13 | 14 | struct JsonData 15 | { 16 | std::string key; 17 | int number; 18 | bool boolean; 19 | 20 | JS_OBJ(key, number, boolean); 21 | }; 22 | 23 | struct SubClass : public JsonData 24 | { 25 | std::string additional; 26 | double data; 27 | 28 | JS_OBJ_SUPER(JS_SUPER(JsonData), additional, data); 29 | }; 30 | 31 | int main() 32 | { 33 | SubClass dataStruct; 34 | JS::ParseContext parseContext(json); 35 | if (parseContext.parseTo(dataStruct) != JS::Error::NoError) 36 | { 37 | std::string errorStr = parseContext.makeErrorString(); 38 | fprintf(stderr, "Error parsing struct %s\n", errorStr.c_str()); 39 | return -1; 40 | } 41 | 42 | fprintf(stdout, "Key is: %s, number is %d bool is %d additional is %s data is %f\n", 43 | dataStruct.key.c_str(), 44 | dataStruct.number, 45 | dataStruct.boolean, 46 | dataStruct.additional.c_str(), 47 | dataStruct.data); 48 | 49 | return 0; 50 | } 51 | 52 | -------------------------------------------------------------------------------- /examples/05_enums.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | JS_ENUM(Color, Red , Green , Blue, Yellow4 , Purple ) 5 | 6 | struct ColorData 7 | { 8 | Color color; 9 | 10 | JS_OBJ(color); 11 | }; 12 | JS_ENUM_DECLARE_STRING_PARSER(Color) 13 | 14 | const char json[] = R"json({ 15 | "color" : "Green" 16 | })json"; 17 | 18 | int main() 19 | { 20 | ColorData dataStruct; 21 | JS::ParseContext parseContext(json); 22 | if (parseContext.parseTo(dataStruct) != JS::Error::NoError) 23 | { 24 | std::string errorStr = parseContext.makeErrorString(); 25 | fprintf(stderr, "Error parsing struct %s\n", errorStr.c_str()); 26 | return -1; 27 | } 28 | 29 | fprintf(stdout, "Color data is: %d, enum green has value %d\n", 30 | (int)dataStruct.color, 31 | (int)Color::Green); 32 | 33 | return 0; 34 | } 35 | 36 | -------------------------------------------------------------------------------- /examples/06_map.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | const char car_json[] = R"json( 5 | { 6 | "type" : "car", 7 | "wheels" : 4, 8 | "electric" : true, 9 | "engine_count" : 4 10 | } 11 | )json"; 12 | const char sailboat_json[] = R"json( 13 | { 14 | "type" : "sailboat", 15 | "sail_area_m2" : 106.5, 16 | "swimming_platform": true, 17 | "cabins_count" : 4 18 | } 19 | )json"; 20 | 21 | JS_ENUM(VehicleType, car, sailboat) 22 | JS_ENUM_DECLARE_STRING_PARSER(VehicleType) 23 | 24 | struct Car 25 | { 26 | std::string type; 27 | int wheels; 28 | bool electric; 29 | int engine_count; 30 | JS_OBJ(type, wheels, electric, engine_count); 31 | }; 32 | 33 | struct Sailboat 34 | { 35 | std::string type; 36 | double sail_area_m2; 37 | bool swimming_platform; 38 | int cabins_count; 39 | JS_OBJ(type, sail_area_m2, swimming_platform, cabins_count); 40 | }; 41 | 42 | void handle_car(Car &car) 43 | { 44 | (void) car; 45 | //do stuff with the car 46 | } 47 | 48 | void handle_sailboat(Sailboat &sailboat) 49 | { 50 | (void) sailboat; 51 | //do stuff with the sailboat 52 | } 53 | 54 | void handle_data(const char *data, size_t size) 55 | { 56 | JS::Map map; 57 | JS::ParseContext parseContext(data, size, map); 58 | if (parseContext.error != JS::Error::NoError) 59 | { 60 | fprintf(stderr, "Failed to parse Json:\n%s\n", parseContext.makeErrorString().c_str()); 61 | return; 62 | } 63 | VehicleType vehicleType = map.castTo("type", parseContext); 64 | if (parseContext.error != JS::Error::NoError) 65 | { 66 | fprintf(stderr, "Failed to extract type:\n%s\n", parseContext.makeErrorString().c_str()); 67 | return; 68 | } 69 | switch (vehicleType) 70 | { 71 | case VehicleType::car: 72 | { 73 | Car car = map.castTo(parseContext); 74 | if (parseContext.error != JS::Error::NoError) 75 | { 76 | //error handling 77 | } 78 | handle_car(car); 79 | break; 80 | } 81 | case VehicleType::sailboat: 82 | Sailboat sailboat; 83 | map.castToType(parseContext, sailboat); 84 | if (parseContext.error != JS::Error::NoError) 85 | { 86 | //error handling 87 | } 88 | handle_sailboat(sailboat); 89 | break; 90 | } 91 | 92 | } 93 | 94 | int main() 95 | { 96 | handle_data(car_json, sizeof(car_json)); 97 | handle_data(sailboat_json, sizeof(sailboat_json)); 98 | return 0; 99 | } 100 | 101 | -------------------------------------------------------------------------------- /examples/07_stdtypes.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | //these two have to be ifdef guarded becuase JS support compiler versions where 5 | //they are not implemented, hence if you use unordered_map or optional in your code there is no need for the guards. 6 | #ifdef JS_STD_UNORDERED_MAP 7 | #include 8 | #endif 9 | #ifdef JS_STD_OPTIONAL 10 | #include 11 | #endif 12 | 13 | 14 | const char json[] = R"json( 15 | { 16 | "vector" : [ 9,7,5,3,1 ], 17 | "string" : "hello world", 18 | "tuple" : [ "hello", 32.0, { "member" : 1 } ], 19 | "unordered_map" : { 20 | "foo" : 1, 21 | "bar" : 2 22 | }, 23 | "optional" : "optioal string value", 24 | "uint8_number" : 234, 25 | "uint16_number" : 1234, 26 | "uint32_number" : 234567, 27 | "uint64_number" : 5000000000 28 | } 29 | )json"; 30 | 31 | struct SubType 32 | { 33 | int member; 34 | JS_OBJ(member); 35 | }; 36 | 37 | struct JsonData 38 | { 39 | std::vector vector; 40 | std::string string; 41 | std::tuple tuple; 42 | #ifdef JS_STD_UNORDERED_MAP 43 | std::unordered_map unordered_map; 44 | #else 45 | JS::JsonObject unordered_map; 46 | #endif 47 | #ifdef JS_STD_OPTIONAL 48 | std::optional optional; 49 | #else 50 | JS::Optional optional; 51 | #endif 52 | 53 | uint8_t uint8_number; 54 | uint16_t uint16_number; 55 | uint32_t uint32_number; 56 | uint64_t uint64_number; 57 | 58 | JS_OBJ(vector, 59 | string, 60 | tuple, 61 | unordered_map, 62 | optional, 63 | uint8_number, 64 | uint16_number, 65 | uint32_number, 66 | uint64_number); 67 | }; 68 | 69 | int main() 70 | { 71 | JsonData dataStruct; 72 | JS::ParseContext parseContext(json); 73 | if (parseContext.parseTo(dataStruct) != JS::Error::NoError) 74 | { 75 | std::string errorStr = parseContext.makeErrorString(); 76 | fprintf(stderr, "Error parsing struct %s\n", errorStr.c_str()); 77 | return -1; 78 | } 79 | 80 | for(int i = 0; i < int(dataStruct.vector.size()); i++) 81 | fprintf(stderr, "vector: %d %d\n", i, dataStruct.vector[i]); 82 | fprintf(stderr, "string %s\n", dataStruct.string.c_str()); 83 | fprintf(stderr, "tuple:\n"); 84 | fprintf(stderr, "\t%s\n", std::get<0>(dataStruct.tuple).c_str()); 85 | fprintf(stderr, "\t%f\n", std::get<1>(dataStruct.tuple)); 86 | fprintf(stderr, "\tmember: %d\n", std::get<2>(dataStruct.tuple).member); 87 | #ifdef JS_STD_UNORDERED_MAP 88 | fprintf(stderr, "unordered_map:\n"); 89 | for (auto it : dataStruct.unordered_map) 90 | fprintf(stderr, "\t%s : %f\n", it.first.c_str(), it.second); 91 | #endif 92 | #ifdef JS_STD_OPTIONAL 93 | fprintf(stderr, "%s\n", dataStruct.optional.value()); 94 | #endif 95 | fprintf(stderr, "uint8_number %" PRIu8 "\n", dataStruct.uint8_number); 96 | fprintf(stderr, "uint16_number %" PRIu16 "\n", dataStruct.uint16_number); 97 | fprintf(stderr, "uint32_number %" PRIu32 "\n", dataStruct.uint32_number); 98 | fprintf(stderr, "uint64_number %" PRIu64 "\n", dataStruct.uint64_number); 99 | return 0; 100 | } 101 | 102 | -------------------------------------------------------------------------------- /examples/08_custom_types.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct Vec3 5 | { 6 | double data[3]; 7 | }; 8 | 9 | //We have to define a specialisation of the struct JS::TypeHandler 10 | //This struct handle how types populate c++ types and how c++ types are serialized 11 | namespace JS 12 | { 13 | template<> 14 | struct TypeHandler 15 | { 16 | static inline Error to(Vec3 &to_type, ParseContext &context) 17 | { 18 | //There exists a TypeHandler for T[N] already, so all we have to do is unwrap the 19 | //data and call the other TypeHandler specialisation 20 | return TypeHandler::to(to_type.data, context); 21 | } 22 | 23 | static inline void from(const Vec3 &from_type, Token &token, Serializer &serializer) 24 | { 25 | return TypeHandler::from(from_type.data, token, serializer); 26 | } 27 | }; 28 | } 29 | 30 | const char json[] = R"json( 31 | { 32 | "key" : "value", 33 | "vec" : [ 3, 6, 9] 34 | } 35 | )json"; 36 | 37 | struct JsonData 38 | { 39 | std::string key; 40 | Vec3 vec; 41 | 42 | JS_OBJ(key, vec); 43 | }; 44 | 45 | int main() 46 | { 47 | JsonData dataStruct; 48 | JS::ParseContext parseContext(json); 49 | if (parseContext.parseTo(dataStruct) != JS::Error::NoError) 50 | { 51 | std::string errorStr = parseContext.makeErrorString(); 52 | fprintf(stderr, "Error parsing struct %s\n", errorStr.c_str()); 53 | return -1; 54 | } 55 | 56 | fprintf(stdout, "Key is: %s, number is %f, %f, %f\n", 57 | dataStruct.key.c_str(), 58 | dataStruct.vec.data[0], 59 | dataStruct.vec.data[1], 60 | dataStruct.vec.data[2]); 61 | 62 | return 0; 63 | } 64 | 65 | -------------------------------------------------------------------------------- /examples/09_nested_types.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template 5 | struct Vec3 6 | { 7 | T data[3]; 8 | }; 9 | 10 | //Nested types are fully supported and the limitation of the data structures 11 | //that can be expressed is limited by C++ 12 | namespace JS 13 | { 14 | template 15 | struct TypeHandler> 16 | { 17 | static inline Error to(Vec3 &to_type, ParseContext &context) 18 | { 19 | return TypeHandler::to(to_type.data, context); 20 | } 21 | 22 | static inline void from(const Vec3 &from_type, Token &token, Serializer &serializer) 23 | { 24 | return TypeHandler::from(from_type.data, token, serializer); 25 | } 26 | }; 27 | } 28 | 29 | struct InnerJsonData 30 | { 31 | int key; 32 | double value; 33 | JS_OBJ(key, value); 34 | }; 35 | 36 | const char json[] = R"json( 37 | { 38 | "key" : "value", 39 | "vec" : [ 40 | { "key" : 4, "value": 1.0 }, 41 | { "key" : 5, "value": 2.0 }, 42 | { "key" : 6, "value": 3.0 } 43 | ] 44 | } 45 | )json"; 46 | 47 | struct JsonData 48 | { 49 | std::string key; 50 | Vec3 vec; 51 | 52 | JS_OBJECT(JS_MEMBER(key), 53 | JS_MEMBER(vec)); 54 | }; 55 | 56 | int main() 57 | { 58 | JsonData dataStruct; 59 | JS::ParseContext parseContext(json); 60 | if (parseContext.parseTo(dataStruct) != JS::Error::NoError) 61 | { 62 | std::string errorStr = parseContext.makeErrorString(); 63 | fprintf(stderr, "Error parsing struct %s\n", errorStr.c_str()); 64 | return -1; 65 | } 66 | 67 | fprintf(stdout, "Key is: %s, number is %d - %f, %d - %f, %d - %f\n", 68 | dataStruct.key.c_str(), 69 | dataStruct.vec.data[0].key, 70 | dataStruct.vec.data[0].value, 71 | dataStruct.vec.data[1].key, 72 | dataStruct.vec.data[1].value, 73 | dataStruct.vec.data[2].key, 74 | dataStruct.vec.data[2].value); 75 | 76 | return 0; 77 | } 78 | 79 | -------------------------------------------------------------------------------- /examples/10_simple_tokenize.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | const char json[] = R"json( 9 | { 10 | "key" : "value", 11 | "number" : 100, 12 | "boolean" : true 13 | } 14 | )json"; 15 | 16 | int main() 17 | { 18 | std::string key; 19 | int number; 20 | bool boolean; 21 | JS::Error error; 22 | JS::Tokenizer tokenizer; 23 | JS::Token token; 24 | tokenizer.addData(json); 25 | error = tokenizer.nextToken(token); 26 | if (token.value_type == JS::Type::ObjectStart) { 27 | error = tokenizer.nextToken(token); 28 | if (error != JS::Error::NoError) 29 | exit(1); 30 | key = std::string(token.value.data, token.value.size); 31 | error = tokenizer.nextToken(token); 32 | if (error != JS::Error::NoError) 33 | exit(1); 34 | char *outpointer; 35 | number = strtol(token.value.data, 36 | &outpointer, 37 | 10); 38 | error = tokenizer.nextToken(token); 39 | if (error != JS::Error::NoError) 40 | exit(1); 41 | boolean = std::string(token.value.data, token.value.size) == "true"; 42 | error = tokenizer.nextToken(token); 43 | if (error != JS::Error::NoError) 44 | exit(1); 45 | fprintf(stdout, "Parsed data %s - %d - %d\n", key.c_str(), number, boolean); 46 | } 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /examples/11_calling_functions.cpp: -------------------------------------------------------------------------------- 1 | //!!!!! 2 | //THIS IS A VERY ADVANCED SAMPLE 3 | //PLEASE LOOK AT THE OTHER SAMPLES FIRST 4 | #include 5 | #include 6 | 7 | const char json[] = R"json( 8 | { 9 | "function_a" : "Some text", 10 | "function_b" : { 11 | "paramA" : 123.4, 12 | "paramB" : "some string parameter" 13 | }, 14 | "function_c" : { 15 | "this_function" : 3, 16 | "can_fail_at_runtime" : true 17 | }, 18 | "function_d" : 567 19 | } 20 | )json"; 21 | 22 | struct FunctionBArguments 23 | { 24 | float paramA; 25 | std::string paramB; 26 | JS_OBJ(paramA, paramB); 27 | }; 28 | 29 | struct FunctionBReturn 30 | { 31 | float functionBReturnA; 32 | std::string functionBReturnB; 33 | double functionBReturnC[3]; 34 | 35 | JS_OBJ(functionBReturnA, functionBReturnB, functionBReturnC); 36 | }; 37 | 38 | struct FunctionCArguments 39 | { 40 | int this_function; 41 | bool can_fail_at_runtime; 42 | 43 | JS_OBJ(this_function, can_fail_at_runtime); 44 | }; 45 | 46 | struct FunctionCReturn 47 | { 48 | int this_return = 0; 49 | int type_will_not = 0; 50 | int be_serialized = 0; 51 | int on_failure = 0; 52 | JS_OBJ(this_return, type_will_not, be_serialized, on_failure); 53 | }; 54 | 55 | struct JsonFunctions 56 | { 57 | void function_a(const std::string &str) 58 | { 59 | fprintf(stderr, "Function a was called with %s\n", str.c_str()); 60 | } 61 | 62 | FunctionBReturn function_b(const FunctionBArguments &arg) 63 | { 64 | fprintf(stderr, "Function b was called with %f - %s\n", arg.paramA, arg.paramB.c_str()); 65 | FunctionBReturn ret; 66 | ret.functionBReturnA = arg.paramA; 67 | ret.functionBReturnB = "This is the return object"; 68 | ret.functionBReturnC[0] = 3.3; 69 | ret.functionBReturnC[1] = 4.4; 70 | ret.functionBReturnC[2] = 5.5; 71 | return ret; 72 | } 73 | 74 | FunctionCReturn function_c(const FunctionCArguments &arg, JS::CallFunctionErrorContext &context) 75 | { 76 | (void)arg; 77 | fprintf(stderr, "Function c was called and its going to fail miserably\n"); 78 | FunctionCReturn ret; 79 | context.setError(JS::Error::UserDefinedErrors, "Making the error" 80 | " context have failure marked so that it will not" 81 | " serialize the return type"); 82 | return ret; 83 | } 84 | 85 | bool function_d(int arg) 86 | { 87 | fprintf(stderr, "Function d shows that just simple types can be used - %d\n", arg); 88 | return arg; 89 | } 90 | JS_FUNC_OBJ(function_a, function_b, function_c, function_d); 91 | }; 92 | 93 | int main() 94 | { 95 | JsonFunctions functionObject; 96 | std::string output; 97 | JS::DefaultCallFunctionContext callFunctionContext(json, output); 98 | callFunctionContext.stop_execute_on_fail = false; 99 | if (callFunctionContext.callFunctions(functionObject) != JS::Error::NoError) 100 | { 101 | std::string errorStr = callFunctionContext.parse_context.makeErrorString(); 102 | fprintf(stderr, "Error parsing struct %s\n", errorStr.c_str()); 103 | } 104 | 105 | for (auto &executed : callFunctionContext.execution_list) 106 | { 107 | std::string executionStateJson = JS::serializeStruct(executed); 108 | fprintf(stderr, "###\n%s\n", executionStateJson.c_str()); 109 | } 110 | 111 | fprintf(stderr, "This is the result:\n%s\n", output.c_str()); 112 | return 0; 113 | } 114 | 115 | 116 | -------------------------------------------------------------------------------- /examples/12_simple_diff.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | const char jsonBase[] = R"json( 5 | { 6 | "key" : "value", 7 | "number" : 100, 8 | "value" : 1.23456, 9 | "boolean" : true 10 | } 11 | )json"; 12 | 13 | const char jsonDiff[] = R"json( 14 | { 15 | "key" : "val", 16 | "number" : 100, 17 | "value" : 1.23457, 18 | "boolean" : 0 19 | } 20 | )json"; 21 | 22 | int main() 23 | { 24 | fprintf(stdout, "Performing JSON diff between\n%s\nand\n%s\n...\n\n", jsonBase, jsonDiff); 25 | 26 | JS::DiffOptions diffOptions { JS::DiffFlags::FuzzyFloatComparison, 1e-6 }; // 1e-5 would give no floating point diff in this example. 27 | JS::DiffContext diffContext(jsonBase, diffOptions); 28 | diffContext.diff(jsonDiff); 29 | 30 | if (diffContext.error != JS::DiffError::NoError) 31 | { 32 | fprintf(stderr, "Error while diffing JSON: %d\n", static_cast(diffContext.error)); 33 | return 1; 34 | } 35 | 36 | const JS::DiffTokens& baseTokens = diffContext.base; 37 | const JS::DiffTokens& diffTokens = diffContext.diffs[0]; // We only diffed one JSON string, multiple diffs are supported if needed. 38 | fprintf(stdout, "Number of diffs: %zu\n", diffTokens.diff_count); 39 | 40 | if (baseTokens.size() != diffTokens.size()) 41 | { 42 | fprintf(stderr, "The size of the baseTokens and diffTokens must be the same in this example."); 43 | return 2; 44 | } 45 | 46 | // This loop assumes that baseTokens.size() == diffTokens.size() as is the case in this example. 47 | for (size_t i = 0; i < diffTokens.size(); i++) 48 | { 49 | const JS::Token baseToken = baseTokens.tokens.data[i]; 50 | const JS::Token diffToken = diffTokens.tokens.data[i]; 51 | JS::DiffType diffType = diffTokens.diffs[i]; 52 | 53 | std::string baseValue(baseToken.value.data, baseToken.value.size); 54 | std::string diffValue(diffToken.value.data, diffToken.value.size); 55 | 56 | switch (diffType) 57 | { 58 | case JS::DiffType::NoDiff: 59 | { 60 | fprintf(stdout, "No diff: %s\n", baseValue.c_str()); 61 | break; 62 | } 63 | case JS::DiffType::ValueDiff: 64 | { 65 | fprintf(stdout, "Value diff: base = %s, diff = %s\n", baseValue.c_str(), diffValue.c_str()); 66 | break; 67 | } 68 | case JS::DiffType::TypeDiff: 69 | { 70 | fprintf(stdout, "Type diff: base = %s, diff = %s\n", baseValue.c_str(), diffValue.c_str()); 71 | break; 72 | } 73 | case JS::DiffType::NewMember: 74 | case JS::DiffType::NewArrayItem: 75 | case JS::DiffType::MissingMembers: 76 | case JS::DiffType::MissingArrayItems: 77 | case JS::DiffType::RootItemDiff: 78 | case JS::DiffType::ErroneousRootItem: 79 | default: 80 | { 81 | fprintf(stdout, "Other diff type :%d.\n", static_cast(diffType)); // Does not occur in this example. 82 | break; 83 | } 84 | } 85 | } 86 | 87 | return 0; 88 | } 89 | -------------------------------------------------------------------------------- /examples/13_diff_missing_data.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | const char jsonBase[] = R"json( 6 | [ 7 | { 8 | "key" : "val1", 9 | "number" : 1, 10 | "value" : 1.23456, 11 | "boolean" : true 12 | }, 13 | { 14 | "key" : "val2", 15 | "boolean" : false 16 | }, 17 | { 18 | "key" : "val3", 19 | "number" : 3, 20 | "value" : 1.23456, 21 | "boolean" : false 22 | }, 23 | 123 24 | ] 25 | )json"; 26 | 27 | const char jsonDiff[] = R"json( 28 | [ 29 | { 30 | "number" : 0, 31 | "key" : "val1", 32 | "value" : 1.23456001 33 | }, 34 | { 35 | "key" : "val2", 36 | "number" : 2, 37 | "boolean" : false, 38 | "value" : 1.23456 39 | }, 40 | { 41 | "_number" : 3, 42 | "key" : "val3", 43 | "_value" : 1.23456, 44 | "_boolean" : false 45 | }, 46 | 1.23, 47 | "NewArrayItem" 48 | ] 49 | )json"; 50 | 51 | bool isKeyValuePair(const JS::Token& token) 52 | { 53 | return token.name.size != 0; 54 | } 55 | 56 | int main() 57 | { 58 | fprintf(stdout, "Performing JSON diff between\n%s\nand\n%s\n...\n\n", jsonBase, jsonDiff); 59 | 60 | JS::DiffContext diffContext(jsonBase); 61 | size_t diffPos = diffContext.diff(jsonDiff); 62 | 63 | if (diffContext.error != JS::DiffError::NoError) 64 | { 65 | fprintf(stderr, "Error while diffing JSON: %d\n", static_cast(diffContext.error)); 66 | return 1; 67 | } 68 | 69 | const JS::DiffTokens& diffTokens = diffContext.diffs[diffPos]; 70 | fprintf(stdout, "Number of diffs: %zu\n", diffTokens.diff_count); 71 | 72 | for (size_t i = 0; i < diffTokens.size(); i++) 73 | { 74 | const JS::Token& diffToken = diffTokens.tokens.data[i]; 75 | JS::DiffType diffType = diffTokens.diffs[i]; 76 | 77 | // Both of these may be empty. 78 | std::string key(diffToken.name.data, diffToken.name.size); 79 | std::string value(diffToken.value.data, diffToken.value.size); 80 | 81 | switch (diffType) 82 | { 83 | case JS::DiffType::NoDiff: 84 | { 85 | if (isKeyValuePair(diffToken)) 86 | fprintf(stdout, "No diff: %s: %s\n", key.c_str(), value.c_str()); 87 | else 88 | fprintf(stdout, "No diff: %s\n", value.c_str()); 89 | break; 90 | } 91 | case JS::DiffType::ValueDiff: 92 | { 93 | if (isKeyValuePair(diffToken)) 94 | fprintf(stdout, "Value diff: %s: %s\n", key.c_str(), value.c_str()); 95 | else 96 | fprintf(stdout, "Value diff: %s\n", value.c_str()); 97 | break; 98 | } 99 | case JS::DiffType::TypeDiff: 100 | { 101 | fprintf(stdout, "Type diff: %s\n", value.c_str()); 102 | break; 103 | } 104 | case JS::DiffType::NewMember: 105 | { 106 | fprintf(stdout, "New member: %s: %s\n", key.c_str(), value.c_str()); 107 | break; 108 | } 109 | case JS::DiffType::NewArrayItem: 110 | { 111 | // Note: No new objects or arrays in this example. Otherwise we must check for 112 | // diffType == JS::Type::ObjectStart or diffType == JS::Type::ArrayStart and iterate 113 | // through that object or array. 114 | fprintf(stdout, "New array item: %s: %s\n", key.c_str(), value.c_str()); 115 | break; 116 | } 117 | case JS::DiffType::MissingMembers: 118 | { 119 | const auto* missingMembers = diffTokens.getMissingMembers(diffToken); 120 | if (missingMembers) 121 | { 122 | for (const auto &m : *missingMembers) 123 | { 124 | std::string missingStr = "\"" + std::string(m.name.data, m.name.size) + "\""; 125 | fprintf(stdout, "Missing member: %s\n", missingStr.c_str()); 126 | } 127 | } 128 | break; 129 | } 130 | case JS::DiffType::MissingArrayItems: 131 | case JS::DiffType::RootItemDiff: 132 | case JS::DiffType::ErroneousRootItem: 133 | default: 134 | { 135 | fprintf(stdout, "Other diff type :%d.\n", static_cast(diffType)); // Does not occur in this example. 136 | break; 137 | } 138 | } 139 | } 140 | 141 | return 0; 142 | } 143 | -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | function (add_example_executable name) 2 | add_executable(${name} ${ARGN}) 3 | set_compiler_flags_for_target(${name}) 4 | target_include_directories(${name} PRIVATE ${PROJECT_SOURCE_DIR}/include) 5 | endfunction() 6 | 7 | add_example_executable(01_simple_struct 01_simple_struct.cpp) 8 | add_example_executable(02_alias 02_alias.cpp) 9 | add_example_executable(03_optional_types 03_optional_types.cpp) 10 | add_example_executable(04_subclasses 04_subclasses.cpp) 11 | add_example_executable(05_enums 05_enums.cpp) 12 | add_example_executable(06_map 06_map.cpp) 13 | add_example_executable(07_stdtypes 07_stdtypes.cpp) 14 | add_example_executable(08_custom_types 08_custom_types.cpp) 15 | add_example_executable(09_nested_types 09_nested_types.cpp) 16 | add_example_executable(10_simple_tokenize 10_simple_tokenize.cpp) 17 | add_example_executable(11_calling_functions 11_calling_functions.cpp) 18 | add_example_executable(12_simple_diff 12_simple_diff.cpp) 19 | add_example_executable(13_diff_missing_data 13_diff_missing_data.cpp) 20 | add_example_executable(reformat reformat.cpp) 21 | -------------------------------------------------------------------------------- /examples/reformat.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | const char json[] = R"json({"key":"value","number":100,"boolean":true})json"; 5 | 6 | int main() 7 | { 8 | 9 | std::string pretty_json; 10 | JS::reformat(json, pretty_json); 11 | 12 | fprintf(stdout, "Json after reformat:\n%s\n", pretty_json.c_str()); 13 | 14 | return 0; 15 | } 16 | 17 | -------------------------------------------------------------------------------- /package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | json_struct 8 | 0.0.1 9 | 10 | json_struct is a single header only library that parses JSON to C++ structs/classes and serializing structs/classes to JSON. 11 | 12 | 13 | Jørgen Lind 14 | MIT 15 | 16 | cmake 17 | 18 | 19 | cmake 20 | 21 | 22 | -------------------------------------------------------------------------------- /performance/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(benchmark 2 | benchmark.cpp 3 | glaze_benchmark.cpp 4 | include/simdjson/simdjson.cpp 5 | ) 6 | target_compile_definitions(benchmark PRIVATE CATCH_CONFIG_ENABLE_BENCHMARKING) 7 | target_include_directories(benchmark PRIVATE ${PROJECT_SOURCE_DIR}/include) 8 | if (MSVC) 9 | target_compile_options(benchmark PRIVATE /w) 10 | else() 11 | target_compile_options(benchmark PRIVATE -w) 12 | endif() 13 | 14 | add_library(catch_main_benchmark STATIC catch-main.cpp) 15 | target_compile_definitions(catch_main_benchmark PRIVATE CATCH_CONFIG_ENABLE_BENCHMARKING) 16 | target_link_libraries(benchmark catch_main_benchmark) 17 | 18 | -------------------------------------------------------------------------------- /performance/catch-main.cpp: -------------------------------------------------------------------------------- 1 | #define CATCH_CONFIG_MAIN 2 | 3 | #include "catch2/catch.hpp" 4 | -------------------------------------------------------------------------------- /performance/glaze_benchmark.cpp: -------------------------------------------------------------------------------- 1 | #define JS_STL_ARRAY 1 2 | #include 3 | 4 | #include "catch2/catch.hpp" 5 | 6 | //Attribution: 7 | //The json and the parsable structuress are taken from Stephen Berry's json_performance test. Please see here: 8 | //https://github.com/stephenberry/json_performance 9 | 10 | namespace 11 | { 12 | static const char json[] = R"( 13 | { 14 | "fixed_object": { 15 | "int_array": [0, 1, 2, 3, 4, 5, 6], 16 | "float_array": [0.1, 0.2, 0.3, 0.4, 0.5, 0.6], 17 | "double_array": [3288398.238, 233e22, 289e-1, 0.928759872, 0.22222848, 0.1, 0.2, 0.3, 0.4] 18 | }, 19 | "fixed_name_object": { 20 | "name0": "James", 21 | "name1": "Abraham", 22 | "name2": "Susan", 23 | "name3": "Frank", 24 | "name4": "Alicia" 25 | }, 26 | "another_object": { 27 | "string": "here is some text", 28 | "another_string": "Hello World", 29 | "boolean": false, 30 | "nested_object": { 31 | "v3s": [[0.12345, 0.23456, 0.001345], 32 | [0.3894675, 97.39827, 297.92387], 33 | [18.18, 87.289, 2988.298]], 34 | "id": "298728949872" 35 | } 36 | }, 37 | "string_array": ["Cat", "Dog", "Elephant", "Tiger"], 38 | "string": "Hello world", 39 | "number": 3.14, 40 | "boolean": true, 41 | "another_bool": false 42 | } 43 | )"; 44 | 45 | struct fixed_object_t 46 | { 47 | std::vector int_array; 48 | std::vector float_array; 49 | std::vector double_array; 50 | }; 51 | 52 | struct fixed_name_object_t 53 | { 54 | std::string name0{}; 55 | std::string name1{}; 56 | std::string name2{}; 57 | std::string name3{}; 58 | std::string name4{}; 59 | }; 60 | 61 | struct nested_object_t 62 | { 63 | std::vector> v3s{}; 64 | std::string id{}; 65 | }; 66 | 67 | struct another_object_t 68 | { 69 | std::string string{}; 70 | std::string another_string{}; 71 | bool boolean{}; 72 | nested_object_t nested_object{}; 73 | }; 74 | 75 | struct obj_t 76 | { 77 | fixed_object_t fixed_object{}; 78 | fixed_name_object_t fixed_name_object{}; 79 | another_object_t another_object{}; 80 | std::vector string_array{}; 81 | std::string string{}; 82 | double number{}; 83 | bool boolean{}; 84 | bool another_bool{}; 85 | }; 86 | } 87 | 88 | JS_OBJ_EXT(fixed_object_t, int_array, float_array, double_array); 89 | JS_OBJ_EXT(fixed_name_object_t, name0, name1, name2, name3, name4); 90 | JS_OBJ_EXT(nested_object_t, v3s, id); 91 | JS_OBJ_EXT(another_object_t, string, another_string, boolean, nested_object); 92 | JS_OBJ_EXT(obj_t, fixed_object, fixed_name_object, another_object, string_array, string, number, boolean, another_bool); 93 | 94 | TEST_CASE("glaze_json_benchmark", "[performance]") 95 | { 96 | 97 | BENCHMARK("Parse Glaze Json") 98 | { 99 | obj_t obj; 100 | JS::ParseContext context(json); 101 | context.track_member_assignement_state = false; 102 | auto error = context.parseTo(obj); 103 | if (error != JS::Error::NoError) 104 | { 105 | fprintf(stderr, "json_struct error: %s\n", context.makeErrorString().c_str()); 106 | } 107 | return obj; 108 | }; 109 | 110 | BENCHMARK_ADVANCED("Serialize Glaze Json")(Catch::Benchmark::Chronometer meter) 111 | { 112 | obj_t obj; 113 | JS::ParseContext context(json); 114 | context.track_member_assignement_state = false; 115 | auto error = context.parseTo(obj); 116 | if (error != JS::Error::NoError) 117 | { 118 | fprintf(stderr, "json_struct error: %s\n", context.makeErrorString().c_str()); 119 | } 120 | meter.measure([&obj] { return JS::serializeStruct(obj, JS::SerializerOptions(JS::SerializerOptions::Compact));}); 121 | }; 122 | } 123 | -------------------------------------------------------------------------------- /performance/include/rapidjson/cursorstreamwrapper.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_CURSORSTREAMWRAPPER_H_ 16 | #define RAPIDJSON_CURSORSTREAMWRAPPER_H_ 17 | 18 | #include "stream.h" 19 | 20 | #if defined(__GNUC__) 21 | RAPIDJSON_DIAG_PUSH 22 | RAPIDJSON_DIAG_OFF(effc++) 23 | #endif 24 | 25 | #if defined(_MSC_VER) && _MSC_VER <= 1800 26 | RAPIDJSON_DIAG_PUSH 27 | RAPIDJSON_DIAG_OFF(4702) // unreachable code 28 | RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated 29 | #endif 30 | 31 | RAPIDJSON_NAMESPACE_BEGIN 32 | 33 | 34 | //! Cursor stream wrapper for counting line and column number if error exists. 35 | /*! 36 | \tparam InputStream Any stream that implements Stream Concept 37 | */ 38 | template > 39 | class CursorStreamWrapper : public GenericStreamWrapper { 40 | public: 41 | typedef typename Encoding::Ch Ch; 42 | 43 | CursorStreamWrapper(InputStream& is): 44 | GenericStreamWrapper(is), line_(1), col_(0) {} 45 | 46 | // counting line and column number 47 | Ch Take() { 48 | Ch ch = this->is_.Take(); 49 | if(ch == '\n') { 50 | line_ ++; 51 | col_ = 0; 52 | } else { 53 | col_ ++; 54 | } 55 | return ch; 56 | } 57 | 58 | //! Get the error line number, if error exists. 59 | size_t GetLine() const { return line_; } 60 | //! Get the error column number, if error exists. 61 | size_t GetColumn() const { return col_; } 62 | 63 | private: 64 | size_t line_; //!< Current Line 65 | size_t col_; //!< Current Column 66 | }; 67 | 68 | #if defined(_MSC_VER) && _MSC_VER <= 1800 69 | RAPIDJSON_DIAG_POP 70 | #endif 71 | 72 | #if defined(__GNUC__) 73 | RAPIDJSON_DIAG_POP 74 | #endif 75 | 76 | RAPIDJSON_NAMESPACE_END 77 | 78 | #endif // RAPIDJSON_CURSORSTREAMWRAPPER_H_ 79 | -------------------------------------------------------------------------------- /performance/include/rapidjson/error/en.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_ERROR_EN_H_ 16 | #define RAPIDJSON_ERROR_EN_H_ 17 | 18 | #include "error.h" 19 | 20 | #ifdef __clang__ 21 | RAPIDJSON_DIAG_PUSH 22 | RAPIDJSON_DIAG_OFF(switch-enum) 23 | RAPIDJSON_DIAG_OFF(covered-switch-default) 24 | #endif 25 | 26 | RAPIDJSON_NAMESPACE_BEGIN 27 | 28 | //! Maps error code of parsing into error message. 29 | /*! 30 | \ingroup RAPIDJSON_ERRORS 31 | \param parseErrorCode Error code obtained in parsing. 32 | \return the error message. 33 | \note User can make a copy of this function for localization. 34 | Using switch-case is safer for future modification of error codes. 35 | */ 36 | inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) { 37 | switch (parseErrorCode) { 38 | case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error."); 39 | 40 | case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty."); 41 | case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values."); 42 | 43 | case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value."); 44 | 45 | case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member."); 46 | case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member."); 47 | case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member."); 48 | 49 | case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element."); 50 | 51 | case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string."); 52 | case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid."); 53 | case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string."); 54 | case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string."); 55 | case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string."); 56 | 57 | case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double."); 58 | case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number."); 59 | case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number."); 60 | 61 | case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error."); 62 | case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error."); 63 | 64 | default: return RAPIDJSON_ERROR_STRING("Unknown error."); 65 | } 66 | } 67 | 68 | RAPIDJSON_NAMESPACE_END 69 | 70 | #ifdef __clang__ 71 | RAPIDJSON_DIAG_POP 72 | #endif 73 | 74 | #endif // RAPIDJSON_ERROR_EN_H_ 75 | -------------------------------------------------------------------------------- /performance/include/rapidjson/filereadstream.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_FILEREADSTREAM_H_ 16 | #define RAPIDJSON_FILEREADSTREAM_H_ 17 | 18 | #include "stream.h" 19 | #include 20 | 21 | #ifdef __clang__ 22 | RAPIDJSON_DIAG_PUSH 23 | RAPIDJSON_DIAG_OFF(padded) 24 | RAPIDJSON_DIAG_OFF(unreachable-code) 25 | RAPIDJSON_DIAG_OFF(missing-noreturn) 26 | #endif 27 | 28 | RAPIDJSON_NAMESPACE_BEGIN 29 | 30 | //! File byte stream for input using fread(). 31 | /*! 32 | \note implements Stream concept 33 | */ 34 | class FileReadStream { 35 | public: 36 | typedef char Ch; //!< Character type (byte). 37 | 38 | //! Constructor. 39 | /*! 40 | \param fp File pointer opened for read. 41 | \param buffer user-supplied buffer. 42 | \param bufferSize size of buffer in bytes. Must >=4 bytes. 43 | */ 44 | 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) { 45 | RAPIDJSON_ASSERT(fp_ != 0); 46 | RAPIDJSON_ASSERT(bufferSize >= 4); 47 | Read(); 48 | } 49 | 50 | Ch Peek() const { return *current_; } 51 | Ch Take() { Ch c = *current_; Read(); return c; } 52 | size_t Tell() const { return count_ + static_cast(current_ - buffer_); } 53 | 54 | // Not implemented 55 | void Put(Ch) { RAPIDJSON_ASSERT(false); } 56 | void Flush() { RAPIDJSON_ASSERT(false); } 57 | Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 58 | size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } 59 | 60 | // For encoding detection only. 61 | const Ch* Peek4() const { 62 | return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0; 63 | } 64 | 65 | private: 66 | void Read() { 67 | if (current_ < bufferLast_) 68 | ++current_; 69 | else if (!eof_) { 70 | count_ += readCount_; 71 | readCount_ = std::fread(buffer_, 1, bufferSize_, fp_); 72 | bufferLast_ = buffer_ + readCount_ - 1; 73 | current_ = buffer_; 74 | 75 | if (readCount_ < bufferSize_) { 76 | buffer_[readCount_] = '\0'; 77 | ++bufferLast_; 78 | eof_ = true; 79 | } 80 | } 81 | } 82 | 83 | std::FILE* fp_; 84 | Ch *buffer_; 85 | size_t bufferSize_; 86 | Ch *bufferLast_; 87 | Ch *current_; 88 | size_t readCount_; 89 | size_t count_; //!< Number of characters read 90 | bool eof_; 91 | }; 92 | 93 | RAPIDJSON_NAMESPACE_END 94 | 95 | #ifdef __clang__ 96 | RAPIDJSON_DIAG_POP 97 | #endif 98 | 99 | #endif // RAPIDJSON_FILESTREAM_H_ 100 | -------------------------------------------------------------------------------- /performance/include/rapidjson/filewritestream.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_FILEWRITESTREAM_H_ 16 | #define RAPIDJSON_FILEWRITESTREAM_H_ 17 | 18 | #include "stream.h" 19 | #include 20 | 21 | #ifdef __clang__ 22 | RAPIDJSON_DIAG_PUSH 23 | RAPIDJSON_DIAG_OFF(unreachable-code) 24 | #endif 25 | 26 | RAPIDJSON_NAMESPACE_BEGIN 27 | 28 | //! Wrapper of C file stream for output using fwrite(). 29 | /*! 30 | \note implements Stream concept 31 | */ 32 | class FileWriteStream { 33 | public: 34 | typedef char Ch; //!< Character type. Only support char. 35 | 36 | FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) { 37 | RAPIDJSON_ASSERT(fp_ != 0); 38 | } 39 | 40 | void Put(char c) { 41 | if (current_ >= bufferEnd_) 42 | Flush(); 43 | 44 | *current_++ = c; 45 | } 46 | 47 | void PutN(char c, size_t n) { 48 | size_t avail = static_cast(bufferEnd_ - current_); 49 | while (n > avail) { 50 | std::memset(current_, c, avail); 51 | current_ += avail; 52 | Flush(); 53 | n -= avail; 54 | avail = static_cast(bufferEnd_ - current_); 55 | } 56 | 57 | if (n > 0) { 58 | std::memset(current_, c, n); 59 | current_ += n; 60 | } 61 | } 62 | 63 | void Flush() { 64 | if (current_ != buffer_) { 65 | size_t result = std::fwrite(buffer_, 1, static_cast(current_ - buffer_), fp_); 66 | if (result < static_cast(current_ - buffer_)) { 67 | // failure deliberately ignored at this time 68 | // added to avoid warn_unused_result build errors 69 | } 70 | current_ = buffer_; 71 | } 72 | } 73 | 74 | // Not implemented 75 | char Peek() const { RAPIDJSON_ASSERT(false); return 0; } 76 | char Take() { RAPIDJSON_ASSERT(false); return 0; } 77 | size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } 78 | char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 79 | size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } 80 | 81 | private: 82 | // Prohibit copy constructor & assignment operator. 83 | FileWriteStream(const FileWriteStream&); 84 | FileWriteStream& operator=(const FileWriteStream&); 85 | 86 | std::FILE* fp_; 87 | char *buffer_; 88 | char *bufferEnd_; 89 | char *current_; 90 | }; 91 | 92 | //! Implement specialized version of PutN() with memset() for better performance. 93 | template<> 94 | inline void PutN(FileWriteStream& stream, char c, size_t n) { 95 | stream.PutN(c, n); 96 | } 97 | 98 | RAPIDJSON_NAMESPACE_END 99 | 100 | #ifdef __clang__ 101 | RAPIDJSON_DIAG_POP 102 | #endif 103 | 104 | #endif // RAPIDJSON_FILESTREAM_H_ 105 | -------------------------------------------------------------------------------- /performance/include/rapidjson/fwd.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_FWD_H_ 16 | #define RAPIDJSON_FWD_H_ 17 | 18 | #include "rapidjson.h" 19 | 20 | RAPIDJSON_NAMESPACE_BEGIN 21 | 22 | // encodings.h 23 | 24 | template struct UTF8; 25 | template struct UTF16; 26 | template struct UTF16BE; 27 | template struct UTF16LE; 28 | template struct UTF32; 29 | template struct UTF32BE; 30 | template struct UTF32LE; 31 | template struct ASCII; 32 | template struct AutoUTF; 33 | 34 | template 35 | struct Transcoder; 36 | 37 | // allocators.h 38 | 39 | class CrtAllocator; 40 | 41 | template 42 | class MemoryPoolAllocator; 43 | 44 | // stream.h 45 | 46 | template 47 | struct GenericStringStream; 48 | 49 | typedef GenericStringStream > StringStream; 50 | 51 | template 52 | struct GenericInsituStringStream; 53 | 54 | typedef GenericInsituStringStream > InsituStringStream; 55 | 56 | // stringbuffer.h 57 | 58 | template 59 | class GenericStringBuffer; 60 | 61 | typedef GenericStringBuffer, CrtAllocator> StringBuffer; 62 | 63 | // filereadstream.h 64 | 65 | class FileReadStream; 66 | 67 | // filewritestream.h 68 | 69 | class FileWriteStream; 70 | 71 | // memorybuffer.h 72 | 73 | template 74 | struct GenericMemoryBuffer; 75 | 76 | typedef GenericMemoryBuffer MemoryBuffer; 77 | 78 | // memorystream.h 79 | 80 | struct MemoryStream; 81 | 82 | // reader.h 83 | 84 | template 85 | struct BaseReaderHandler; 86 | 87 | template 88 | class GenericReader; 89 | 90 | typedef GenericReader, UTF8, CrtAllocator> Reader; 91 | 92 | // writer.h 93 | 94 | template 95 | class Writer; 96 | 97 | // prettywriter.h 98 | 99 | template 100 | class PrettyWriter; 101 | 102 | // document.h 103 | 104 | template 105 | class GenericMember; 106 | 107 | template 108 | class GenericMemberIterator; 109 | 110 | template 111 | struct GenericStringRef; 112 | 113 | template 114 | class GenericValue; 115 | 116 | typedef GenericValue, MemoryPoolAllocator > Value; 117 | 118 | template 119 | class GenericDocument; 120 | 121 | typedef GenericDocument, MemoryPoolAllocator, CrtAllocator> Document; 122 | 123 | // pointer.h 124 | 125 | template 126 | class GenericPointer; 127 | 128 | typedef GenericPointer Pointer; 129 | 130 | // schema.h 131 | 132 | template 133 | class IGenericRemoteSchemaDocumentProvider; 134 | 135 | template 136 | class GenericSchemaDocument; 137 | 138 | typedef GenericSchemaDocument SchemaDocument; 139 | typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProvider; 140 | 141 | template < 142 | typename SchemaDocumentType, 143 | typename OutputHandler, 144 | typename StateAllocator> 145 | class GenericSchemaValidator; 146 | 147 | typedef GenericSchemaValidator, void>, CrtAllocator> SchemaValidator; 148 | 149 | RAPIDJSON_NAMESPACE_END 150 | 151 | #endif // RAPIDJSON_RAPIDJSONFWD_H_ 152 | -------------------------------------------------------------------------------- /performance/include/rapidjson/internal/clzll.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_CLZLL_H_ 16 | #define RAPIDJSON_CLZLL_H_ 17 | 18 | #include "../rapidjson.h" 19 | 20 | #if defined(_MSC_VER) && !defined(UNDER_CE) 21 | #include 22 | #if defined(_WIN64) 23 | #pragma intrinsic(_BitScanReverse64) 24 | #else 25 | #pragma intrinsic(_BitScanReverse) 26 | #endif 27 | #endif 28 | 29 | RAPIDJSON_NAMESPACE_BEGIN 30 | namespace internal { 31 | 32 | inline uint32_t clzll(uint64_t x) { 33 | // Passing 0 to __builtin_clzll is UB in GCC and results in an 34 | // infinite loop in the software implementation. 35 | RAPIDJSON_ASSERT(x != 0); 36 | 37 | #if defined(_MSC_VER) && !defined(UNDER_CE) 38 | unsigned long r = 0; 39 | #if defined(_WIN64) 40 | _BitScanReverse64(&r, x); 41 | #else 42 | // Scan the high 32 bits. 43 | if (_BitScanReverse(&r, static_cast(x >> 32))) 44 | return 63 - (r + 32); 45 | 46 | // Scan the low 32 bits. 47 | _BitScanReverse(&r, static_cast(x & 0xFFFFFFFF)); 48 | #endif // _WIN64 49 | 50 | return 63 - r; 51 | #elif (defined(__GNUC__) && __GNUC__ >= 4) || RAPIDJSON_HAS_BUILTIN(__builtin_clzll) 52 | // __builtin_clzll wrapper 53 | return static_cast(__builtin_clzll(x)); 54 | #else 55 | // naive version 56 | uint32_t r = 0; 57 | while (!(x & (static_cast(1) << 63))) { 58 | x <<= 1; 59 | ++r; 60 | } 61 | 62 | return r; 63 | #endif // _MSC_VER 64 | } 65 | 66 | #define RAPIDJSON_CLZLL RAPIDJSON_NAMESPACE::internal::clzll 67 | 68 | } // namespace internal 69 | RAPIDJSON_NAMESPACE_END 70 | 71 | #endif // RAPIDJSON_CLZLL_H_ 72 | -------------------------------------------------------------------------------- /performance/include/rapidjson/internal/ieee754.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_IEEE754_ 16 | #define RAPIDJSON_IEEE754_ 17 | 18 | #include "../rapidjson.h" 19 | 20 | RAPIDJSON_NAMESPACE_BEGIN 21 | namespace internal { 22 | 23 | class Double { 24 | public: 25 | Double() {} 26 | Double(double d) : d_(d) {} 27 | Double(uint64_t u) : u_(u) {} 28 | 29 | double Value() const { return d_; } 30 | uint64_t Uint64Value() const { return u_; } 31 | 32 | double NextPositiveDouble() const { 33 | RAPIDJSON_ASSERT(!Sign()); 34 | return Double(u_ + 1).Value(); 35 | } 36 | 37 | bool Sign() const { return (u_ & kSignMask) != 0; } 38 | uint64_t Significand() const { return u_ & kSignificandMask; } 39 | int Exponent() const { return static_cast(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); } 40 | 41 | bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; } 42 | bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; } 43 | bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; } 44 | bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; } 45 | bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; } 46 | 47 | uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); } 48 | int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; } 49 | uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; } 50 | 51 | static int EffectiveSignificandSize(int order) { 52 | if (order >= -1021) 53 | return 53; 54 | else if (order <= -1074) 55 | return 0; 56 | else 57 | return order + 1074; 58 | } 59 | 60 | private: 61 | static const int kSignificandSize = 52; 62 | static const int kExponentBias = 0x3FF; 63 | static const int kDenormalExponent = 1 - kExponentBias; 64 | static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000); 65 | static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); 66 | static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); 67 | static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); 68 | 69 | union { 70 | double d_; 71 | uint64_t u_; 72 | }; 73 | }; 74 | 75 | } // namespace internal 76 | RAPIDJSON_NAMESPACE_END 77 | 78 | #endif // RAPIDJSON_IEEE754_ 79 | -------------------------------------------------------------------------------- /performance/include/rapidjson/internal/pow10.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_POW10_ 16 | #define RAPIDJSON_POW10_ 17 | 18 | #include "../rapidjson.h" 19 | 20 | RAPIDJSON_NAMESPACE_BEGIN 21 | namespace internal { 22 | 23 | //! Computes integer powers of 10 in double (10.0^n). 24 | /*! This function uses lookup table for fast and accurate results. 25 | \param n non-negative exponent. Must <= 308. 26 | \return 10.0^n 27 | */ 28 | inline double Pow10(int n) { 29 | static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes 30 | 1e+0, 31 | 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, 32 | 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, 33 | 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, 34 | 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, 35 | 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, 36 | 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, 37 | 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, 38 | 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, 39 | 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, 40 | 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, 41 | 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, 42 | 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, 43 | 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, 44 | 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, 45 | 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, 46 | 1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308 47 | }; 48 | RAPIDJSON_ASSERT(n >= 0 && n <= 308); 49 | return e[n]; 50 | } 51 | 52 | } // namespace internal 53 | RAPIDJSON_NAMESPACE_END 54 | 55 | #endif // RAPIDJSON_POW10_ 56 | -------------------------------------------------------------------------------- /performance/include/rapidjson/internal/strfunc.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_INTERNAL_STRFUNC_H_ 16 | #define RAPIDJSON_INTERNAL_STRFUNC_H_ 17 | 18 | #include "../stream.h" 19 | #include 20 | 21 | RAPIDJSON_NAMESPACE_BEGIN 22 | namespace internal { 23 | 24 | //! Custom strlen() which works on different character types. 25 | /*! \tparam Ch Character type (e.g. char, wchar_t, short) 26 | \param s Null-terminated input string. 27 | \return Number of characters in the string. 28 | \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints. 29 | */ 30 | template 31 | inline SizeType StrLen(const Ch* s) { 32 | RAPIDJSON_ASSERT(s != 0); 33 | const Ch* p = s; 34 | while (*p) ++p; 35 | return SizeType(p - s); 36 | } 37 | 38 | template <> 39 | inline SizeType StrLen(const char* s) { 40 | return SizeType(std::strlen(s)); 41 | } 42 | 43 | template <> 44 | inline SizeType StrLen(const wchar_t* s) { 45 | return SizeType(std::wcslen(s)); 46 | } 47 | 48 | //! Returns number of code points in a encoded string. 49 | template 50 | bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) { 51 | RAPIDJSON_ASSERT(s != 0); 52 | RAPIDJSON_ASSERT(outCount != 0); 53 | GenericStringStream is(s); 54 | const typename Encoding::Ch* end = s + length; 55 | SizeType count = 0; 56 | while (is.src_ < end) { 57 | unsigned codepoint; 58 | if (!Encoding::Decode(is, &codepoint)) 59 | return false; 60 | count++; 61 | } 62 | *outCount = count; 63 | return true; 64 | } 65 | 66 | } // namespace internal 67 | RAPIDJSON_NAMESPACE_END 68 | 69 | #endif // RAPIDJSON_INTERNAL_STRFUNC_H_ 70 | -------------------------------------------------------------------------------- /performance/include/rapidjson/internal/swap.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_INTERNAL_SWAP_H_ 16 | #define RAPIDJSON_INTERNAL_SWAP_H_ 17 | 18 | #include "../rapidjson.h" 19 | 20 | #if defined(__clang__) 21 | RAPIDJSON_DIAG_PUSH 22 | RAPIDJSON_DIAG_OFF(c++98-compat) 23 | #endif 24 | 25 | RAPIDJSON_NAMESPACE_BEGIN 26 | namespace internal { 27 | 28 | //! Custom swap() to avoid dependency on C++ header 29 | /*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only. 30 | \note This has the same semantics as std::swap(). 31 | */ 32 | template 33 | inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT { 34 | T tmp = a; 35 | a = b; 36 | b = tmp; 37 | } 38 | 39 | } // namespace internal 40 | RAPIDJSON_NAMESPACE_END 41 | 42 | #if defined(__clang__) 43 | RAPIDJSON_DIAG_POP 44 | #endif 45 | 46 | #endif // RAPIDJSON_INTERNAL_SWAP_H_ 47 | -------------------------------------------------------------------------------- /performance/include/rapidjson/istreamwrapper.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_ISTREAMWRAPPER_H_ 16 | #define RAPIDJSON_ISTREAMWRAPPER_H_ 17 | 18 | #include "stream.h" 19 | #include 20 | #include 21 | 22 | #ifdef __clang__ 23 | RAPIDJSON_DIAG_PUSH 24 | RAPIDJSON_DIAG_OFF(padded) 25 | #elif defined(_MSC_VER) 26 | RAPIDJSON_DIAG_PUSH 27 | RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized 28 | #endif 29 | 30 | RAPIDJSON_NAMESPACE_BEGIN 31 | 32 | //! Wrapper of \c std::basic_istream into RapidJSON's Stream concept. 33 | /*! 34 | The classes can be wrapped including but not limited to: 35 | 36 | - \c std::istringstream 37 | - \c std::stringstream 38 | - \c std::wistringstream 39 | - \c std::wstringstream 40 | - \c std::ifstream 41 | - \c std::fstream 42 | - \c std::wifstream 43 | - \c std::wfstream 44 | 45 | \tparam StreamType Class derived from \c std::basic_istream. 46 | */ 47 | 48 | template 49 | class BasicIStreamWrapper { 50 | public: 51 | typedef typename StreamType::char_type Ch; 52 | 53 | //! Constructor. 54 | /*! 55 | \param stream stream opened for read. 56 | */ 57 | BasicIStreamWrapper(StreamType &stream) : stream_(stream), buffer_(peekBuffer_), bufferSize_(4), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { 58 | Read(); 59 | } 60 | 61 | //! Constructor. 62 | /*! 63 | \param stream stream opened for read. 64 | \param buffer user-supplied buffer. 65 | \param bufferSize size of buffer in bytes. Must >=4 bytes. 66 | */ 67 | BasicIStreamWrapper(StreamType &stream, char* buffer, size_t bufferSize) : stream_(stream), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { 68 | RAPIDJSON_ASSERT(bufferSize >= 4); 69 | Read(); 70 | } 71 | 72 | Ch Peek() const { return *current_; } 73 | Ch Take() { Ch c = *current_; Read(); return c; } 74 | size_t Tell() const { return count_ + static_cast(current_ - buffer_); } 75 | 76 | // Not implemented 77 | void Put(Ch) { RAPIDJSON_ASSERT(false); } 78 | void Flush() { RAPIDJSON_ASSERT(false); } 79 | Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 80 | size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } 81 | 82 | // For encoding detection only. 83 | const Ch* Peek4() const { 84 | return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0; 85 | } 86 | 87 | private: 88 | BasicIStreamWrapper(); 89 | BasicIStreamWrapper(const BasicIStreamWrapper&); 90 | BasicIStreamWrapper& operator=(const BasicIStreamWrapper&); 91 | 92 | void Read() { 93 | if (current_ < bufferLast_) 94 | ++current_; 95 | else if (!eof_) { 96 | count_ += readCount_; 97 | readCount_ = bufferSize_; 98 | bufferLast_ = buffer_ + readCount_ - 1; 99 | current_ = buffer_; 100 | 101 | if (!stream_.read(buffer_, static_cast(bufferSize_))) { 102 | readCount_ = static_cast(stream_.gcount()); 103 | *(bufferLast_ = buffer_ + readCount_) = '\0'; 104 | eof_ = true; 105 | } 106 | } 107 | } 108 | 109 | StreamType &stream_; 110 | Ch peekBuffer_[4], *buffer_; 111 | size_t bufferSize_; 112 | Ch *bufferLast_; 113 | Ch *current_; 114 | size_t readCount_; 115 | size_t count_; //!< Number of characters read 116 | bool eof_; 117 | }; 118 | 119 | typedef BasicIStreamWrapper IStreamWrapper; 120 | typedef BasicIStreamWrapper WIStreamWrapper; 121 | 122 | #if defined(__clang__) || defined(_MSC_VER) 123 | RAPIDJSON_DIAG_POP 124 | #endif 125 | 126 | RAPIDJSON_NAMESPACE_END 127 | 128 | #endif // RAPIDJSON_ISTREAMWRAPPER_H_ 129 | -------------------------------------------------------------------------------- /performance/include/rapidjson/memorybuffer.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_MEMORYBUFFER_H_ 16 | #define RAPIDJSON_MEMORYBUFFER_H_ 17 | 18 | #include "stream.h" 19 | #include "internal/stack.h" 20 | 21 | RAPIDJSON_NAMESPACE_BEGIN 22 | 23 | //! Represents an in-memory output byte stream. 24 | /*! 25 | This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream. 26 | 27 | It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file. 28 | 29 | Differences between MemoryBuffer and StringBuffer: 30 | 1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer. 31 | 2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator. 32 | 33 | \tparam Allocator type for allocating memory buffer. 34 | \note implements Stream concept 35 | */ 36 | template 37 | struct GenericMemoryBuffer { 38 | typedef char Ch; // byte 39 | 40 | GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} 41 | 42 | void Put(Ch c) { *stack_.template Push() = c; } 43 | void Flush() {} 44 | 45 | void Clear() { stack_.Clear(); } 46 | void ShrinkToFit() { stack_.ShrinkToFit(); } 47 | Ch* Push(size_t count) { return stack_.template Push(count); } 48 | void Pop(size_t count) { stack_.template Pop(count); } 49 | 50 | const Ch* GetBuffer() const { 51 | return stack_.template Bottom(); 52 | } 53 | 54 | size_t GetSize() const { return stack_.GetSize(); } 55 | 56 | static const size_t kDefaultCapacity = 256; 57 | mutable internal::Stack stack_; 58 | }; 59 | 60 | typedef GenericMemoryBuffer<> MemoryBuffer; 61 | 62 | //! Implement specialized version of PutN() with memset() for better performance. 63 | template<> 64 | inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) { 65 | std::memset(memoryBuffer.stack_.Push(n), c, n * sizeof(c)); 66 | } 67 | 68 | RAPIDJSON_NAMESPACE_END 69 | 70 | #endif // RAPIDJSON_MEMORYBUFFER_H_ 71 | -------------------------------------------------------------------------------- /performance/include/rapidjson/memorystream.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_MEMORYSTREAM_H_ 16 | #define RAPIDJSON_MEMORYSTREAM_H_ 17 | 18 | #include "stream.h" 19 | 20 | #ifdef __clang__ 21 | RAPIDJSON_DIAG_PUSH 22 | RAPIDJSON_DIAG_OFF(unreachable-code) 23 | RAPIDJSON_DIAG_OFF(missing-noreturn) 24 | #endif 25 | 26 | RAPIDJSON_NAMESPACE_BEGIN 27 | 28 | //! Represents an in-memory input byte stream. 29 | /*! 30 | This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream. 31 | 32 | It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file. 33 | 34 | Differences between MemoryStream and StringStream: 35 | 1. StringStream has encoding but MemoryStream is a byte stream. 36 | 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. 37 | 3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4(). 38 | \note implements Stream concept 39 | */ 40 | struct MemoryStream { 41 | typedef char Ch; // byte 42 | 43 | MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {} 44 | 45 | Ch Peek() const { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_; } 46 | Ch Take() { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_++; } 47 | size_t Tell() const { return static_cast(src_ - begin_); } 48 | 49 | Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 50 | void Put(Ch) { RAPIDJSON_ASSERT(false); } 51 | void Flush() { RAPIDJSON_ASSERT(false); } 52 | size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } 53 | 54 | // For encoding detection only. 55 | const Ch* Peek4() const { 56 | return Tell() + 4 <= size_ ? src_ : 0; 57 | } 58 | 59 | const Ch* src_; //!< Current read position. 60 | const Ch* begin_; //!< Original head of the string. 61 | const Ch* end_; //!< End of stream. 62 | size_t size_; //!< Size of the stream. 63 | }; 64 | 65 | RAPIDJSON_NAMESPACE_END 66 | 67 | #ifdef __clang__ 68 | RAPIDJSON_DIAG_POP 69 | #endif 70 | 71 | #endif // RAPIDJSON_MEMORYBUFFER_H_ 72 | -------------------------------------------------------------------------------- /performance/include/rapidjson/ostreamwrapper.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_OSTREAMWRAPPER_H_ 16 | #define RAPIDJSON_OSTREAMWRAPPER_H_ 17 | 18 | #include "stream.h" 19 | #include 20 | 21 | #ifdef __clang__ 22 | RAPIDJSON_DIAG_PUSH 23 | RAPIDJSON_DIAG_OFF(padded) 24 | #endif 25 | 26 | RAPIDJSON_NAMESPACE_BEGIN 27 | 28 | //! Wrapper of \c std::basic_ostream into RapidJSON's Stream concept. 29 | /*! 30 | The classes can be wrapped including but not limited to: 31 | 32 | - \c std::ostringstream 33 | - \c std::stringstream 34 | - \c std::wpstringstream 35 | - \c std::wstringstream 36 | - \c std::ifstream 37 | - \c std::fstream 38 | - \c std::wofstream 39 | - \c std::wfstream 40 | 41 | \tparam StreamType Class derived from \c std::basic_ostream. 42 | */ 43 | 44 | template 45 | class BasicOStreamWrapper { 46 | public: 47 | typedef typename StreamType::char_type Ch; 48 | BasicOStreamWrapper(StreamType& stream) : stream_(stream) {} 49 | 50 | void Put(Ch c) { 51 | stream_.put(c); 52 | } 53 | 54 | void Flush() { 55 | stream_.flush(); 56 | } 57 | 58 | // Not implemented 59 | char Peek() const { RAPIDJSON_ASSERT(false); return 0; } 60 | char Take() { RAPIDJSON_ASSERT(false); return 0; } 61 | size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } 62 | char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 63 | size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } 64 | 65 | private: 66 | BasicOStreamWrapper(const BasicOStreamWrapper&); 67 | BasicOStreamWrapper& operator=(const BasicOStreamWrapper&); 68 | 69 | StreamType& stream_; 70 | }; 71 | 72 | typedef BasicOStreamWrapper OStreamWrapper; 73 | typedef BasicOStreamWrapper WOStreamWrapper; 74 | 75 | #ifdef __clang__ 76 | RAPIDJSON_DIAG_POP 77 | #endif 78 | 79 | RAPIDJSON_NAMESPACE_END 80 | 81 | #endif // RAPIDJSON_OSTREAMWRAPPER_H_ 82 | -------------------------------------------------------------------------------- /performance/include/rapidjson/stringbuffer.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_STRINGBUFFER_H_ 16 | #define RAPIDJSON_STRINGBUFFER_H_ 17 | 18 | #include "stream.h" 19 | #include "internal/stack.h" 20 | 21 | #if RAPIDJSON_HAS_CXX11_RVALUE_REFS 22 | #include // std::move 23 | #endif 24 | 25 | #include "internal/stack.h" 26 | 27 | #if defined(__clang__) 28 | RAPIDJSON_DIAG_PUSH 29 | RAPIDJSON_DIAG_OFF(c++98-compat) 30 | #endif 31 | 32 | RAPIDJSON_NAMESPACE_BEGIN 33 | 34 | //! Represents an in-memory output stream. 35 | /*! 36 | \tparam Encoding Encoding of the stream. 37 | \tparam Allocator type for allocating memory buffer. 38 | \note implements Stream concept 39 | */ 40 | template 41 | class GenericStringBuffer { 42 | public: 43 | typedef typename Encoding::Ch Ch; 44 | 45 | GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} 46 | 47 | #if RAPIDJSON_HAS_CXX11_RVALUE_REFS 48 | GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {} 49 | GenericStringBuffer& operator=(GenericStringBuffer&& rhs) { 50 | if (&rhs != this) 51 | stack_ = std::move(rhs.stack_); 52 | return *this; 53 | } 54 | #endif 55 | 56 | void Put(Ch c) { *stack_.template Push() = c; } 57 | void PutUnsafe(Ch c) { *stack_.template PushUnsafe() = c; } 58 | void Flush() {} 59 | 60 | void Clear() { stack_.Clear(); } 61 | void ShrinkToFit() { 62 | // Push and pop a null terminator. This is safe. 63 | *stack_.template Push() = '\0'; 64 | stack_.ShrinkToFit(); 65 | stack_.template Pop(1); 66 | } 67 | 68 | void Reserve(size_t count) { stack_.template Reserve(count); } 69 | Ch* Push(size_t count) { return stack_.template Push(count); } 70 | Ch* PushUnsafe(size_t count) { return stack_.template PushUnsafe(count); } 71 | void Pop(size_t count) { stack_.template Pop(count); } 72 | 73 | const Ch* GetString() const { 74 | // Push and pop a null terminator. This is safe. 75 | *stack_.template Push() = '\0'; 76 | stack_.template Pop(1); 77 | 78 | return stack_.template Bottom(); 79 | } 80 | 81 | //! Get the size of string in bytes in the string buffer. 82 | size_t GetSize() const { return stack_.GetSize(); } 83 | 84 | //! Get the length of string in Ch in the string buffer. 85 | size_t GetLength() const { return stack_.GetSize() / sizeof(Ch); } 86 | 87 | static const size_t kDefaultCapacity = 256; 88 | mutable internal::Stack stack_; 89 | 90 | private: 91 | // Prohibit copy constructor & assignment operator. 92 | GenericStringBuffer(const GenericStringBuffer&); 93 | GenericStringBuffer& operator=(const GenericStringBuffer&); 94 | }; 95 | 96 | //! String buffer with UTF8 encoding 97 | typedef GenericStringBuffer > StringBuffer; 98 | 99 | template 100 | inline void PutReserve(GenericStringBuffer& stream, size_t count) { 101 | stream.Reserve(count); 102 | } 103 | 104 | template 105 | inline void PutUnsafe(GenericStringBuffer& stream, typename Encoding::Ch c) { 106 | stream.PutUnsafe(c); 107 | } 108 | 109 | //! Implement specialized version of PutN() with memset() for better performance. 110 | template<> 111 | inline void PutN(GenericStringBuffer >& stream, char c, size_t n) { 112 | std::memset(stream.stack_.Push(n), c, n * sizeof(c)); 113 | } 114 | 115 | RAPIDJSON_NAMESPACE_END 116 | 117 | #if defined(__clang__) 118 | RAPIDJSON_DIAG_POP 119 | #endif 120 | 121 | #endif // RAPIDJSON_STRINGBUFFER_H_ 122 | -------------------------------------------------------------------------------- /test_package/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | 3 | project(JsonStructTester 4 | DESCRIPTION "Tester package for json_struct" 5 | LANGUAGES C CXX) 6 | 7 | find_package(json_struct REQUIRED) 8 | 9 | add_executable(${PROJECT_NAME} main.cpp) 10 | 11 | target_link_libraries(${PROJECT_NAME} json_struct::json_struct) 12 | -------------------------------------------------------------------------------- /test_package/conanfile.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from conan import ConanFile 4 | from conan.tools.cmake import CMake, cmake_layout 5 | from conan.tools.build import can_run 6 | 7 | 8 | class JsonStructTest(ConanFile): 9 | settings = "os", "compiler", "build_type", "arch" 10 | generators = "CMakeDeps", "CMakeToolchain" 11 | 12 | def requirements(self): 13 | self.requires(self.tested_reference_str) 14 | 15 | def build(self): 16 | cmake = CMake(self) 17 | cmake.configure() 18 | cmake.build() 19 | 20 | def layout(self): 21 | cmake_layout(self) 22 | 23 | def test(self): 24 | if can_run(self): 25 | self.output.info("Checking compiled tester...") 26 | cmd = os.path.join(self.cpp.build.bindir, "JsonStructTester") 27 | self.run(cmd, env="conanrun") 28 | 29 | -------------------------------------------------------------------------------- /test_package/main.cpp: -------------------------------------------------------------------------------- 1 | #include "json_struct/json_struct.h" 2 | #include 3 | 4 | struct MyTestStruct 5 | { 6 | std::string name; 7 | unsigned age; 8 | JS_OBJ(name, age); 9 | }; 10 | 11 | int main() 12 | { 13 | MyTestStruct person; 14 | person.name="Jonh"; 15 | person.age=23; 16 | 17 | std::string person_json = JS::serializeStruct(person); 18 | std::cout << person_json << std::endl; 19 | 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include_directories(${JSON_STRUCT_INCLUDE_DIR}) 2 | 3 | include(CMakeRC.cmake) 4 | 5 | cmrc_add_resource_library( 6 | external_json_resources 7 | ALIAS external_json::rc 8 | NAMESPACE external_json 9 | generated.json 10 | ) 11 | 12 | add_library(catch_main STATIC catch-main.cpp) 13 | set(unit_test_sources 14 | json-struct-test.cpp 15 | json-struct-test-new.cpp 16 | json-struct-external.cpp 17 | json-struct-big-test.cpp 18 | json-struct-verify.cpp 19 | json-struct-serialize-tuple.cpp 20 | json-struct-aliases-test.cpp 21 | json-struct-serialize-test.cpp 22 | json-struct-diff.cpp 23 | json-struct-fail.cpp 24 | json-struct-float.cpp 25 | json-mias-mat.cpp 26 | json-nullable-test.cpp 27 | json-string-with-nullterminator-test.cpp 28 | json-tokenizer-fail-test.cpp 29 | json-tokenizer-partial-test.cpp 30 | json-tokenizer-test.cpp 31 | json-function-test.cpp 32 | json-function-test-new.cpp 33 | json-function-external-test.cpp 34 | json-function-external-test-new.cpp 35 | json-function-error-test.cpp 36 | json-scope.cpp 37 | members-size-test.cpp 38 | compiler-test.cpp 39 | meta-for-tokens.cpp 40 | json-enum-test.cpp 41 | json-meta-test.cpp 42 | json-copy-test.cpp 43 | multi-compilation-units-1.cpp 44 | multi-compilation-units-2.cpp 45 | multi-compilation-units-main.cpp 46 | json-reformat.cpp 47 | json-unordered-map.cpp 48 | json-struct-utf8.cpp 49 | json-struct-escape.cpp 50 | json-struct-error-string.cpp 51 | json-struct-polymorphic-map.cpp 52 | json-struct-array-varlength.cpp 53 | json-struct-stdint.cpp 54 | json-struct-nested.cpp 55 | json-struct-map-typehandler.cpp 56 | json-tokenizer-invalid-json.cpp 57 | ) 58 | 59 | add_executable(unit-tests ${unit_test_sources}) 60 | set_compiler_flags_for_target(unit-tests) 61 | target_link_libraries(unit-tests PRIVATE catch_main external_json::rc) 62 | if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.16.0" AND NOT JSON_STRUCT_OPT_DISABLE_PCH) 63 | target_precompile_headers(unit-tests PRIVATE ../include/json_struct/json_struct.h catch2/catch.hpp) 64 | endif() 65 | add_test(NAME unit-tests COMMAND unit-tests) 66 | 67 | # Tests for zero value floating points (both negative and positive zeros). 68 | # The tests are run with different compiler options for floating point math. 69 | add_executable(zero-value-test-fp-default zero-value-test.cpp) 70 | set_compiler_flags_for_target(zero-value-test-fp-default) 71 | add_executable(zero-value-test-fp-fast zero-value-test.cpp) 72 | set_compiler_flags_for_target(zero-value-test-fp-fast) 73 | add_test(NAME zero-value-test-fp-default COMMAND zero-value-test-fp-default) 74 | add_test(NAME zero-value-test-fp-fast COMMAND zero-value-test-fp-fast) 75 | 76 | if (MSVC) 77 | target_compile_options(zero-value-test-fp-fast PRIVATE /fp:fast) 78 | else() 79 | target_compile_options(zero-value-test-fp-fast PRIVATE -ffast-math) 80 | endif() 81 | 82 | if ("${CMAKE_CXX_COMPILE_FEATURES}" MATCHES ".*cxx_std_17.*") 83 | add_executable(unit-tests-cxx17 json-optional.cpp ${unit_test_sources}) 84 | if (NOT MSVC OR (MSVC_VERSION GREATER 1900)) 85 | target_sources(unit-tests-cxx17 PRIVATE json-timepoint.cpp) 86 | endif() 87 | set_compiler_flags_for_target(unit-tests-cxx17) 88 | set_property(TARGET unit-tests-cxx17 PROPERTY CXX_STANDARD 17) 89 | target_compile_features(unit-tests-cxx17 PUBLIC cxx_std_17) 90 | target_link_libraries(unit-tests-cxx17 PRIVATE catch_main external_json::rc) 91 | endif() 92 | 93 | #add_executable(unit-tests-experimental json-struct-array-varlength.cpp) 94 | #target_link_libraries(unit-tests-experimental PRIVATE catch_main) 95 | 96 | -------------------------------------------------------------------------------- /tests/catch-main.cpp: -------------------------------------------------------------------------------- 1 | #define CATCH_CONFIG_MAIN 2 | 3 | #include "catch2/catch.hpp" 4 | -------------------------------------------------------------------------------- /tests/compiler-test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2017 Jorgen Lind 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided "as 12 | * is" without express or implied warranty. 13 | * 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | 26 | #include "catch2/catch.hpp" 27 | 28 | #define SUB_ELEM(elem) SubElem(#elem) 29 | #define SUB_LIST(...) std::make_tuple(__VA_ARGS__) 30 | 31 | #define ELEM(elem) makeElem(#elem, &ELEMLIST_T::elem) 32 | //#define ELEM(elem) Elem{#elem, &ELEMLIST_T::elem} 33 | 34 | #define LIST(SUBLIST, ...) \ 35 | template \ 36 | struct FOO \ 37 | { \ 38 | static decltype(SUBLIST) &the_sublist() \ 39 | { \ 40 | static auto list = SUBLIST; \ 41 | return list; \ 42 | } \ 43 | static decltype(std::make_tuple(__VA_ARGS__)) &getList() \ 44 | { \ 45 | static auto list = std::make_tuple(__VA_ARGS__); \ 46 | return list; \ 47 | } \ 48 | } 49 | 50 | namespace 51 | { 52 | template 53 | struct SubElem 54 | { 55 | SubElem(const char *name) 56 | : name(name) 57 | { 58 | } 59 | const char *name; 60 | typedef T type; 61 | }; 62 | 63 | template 64 | struct Elem 65 | { 66 | const char *name; 67 | M T::*member; 68 | typedef T type; 69 | }; 70 | 71 | template 72 | constexpr Elem makeElem(const char (&name)[SIZE], M T::*member) 73 | { 74 | return Elem{name, member}; 75 | } 76 | 77 | struct Cover 78 | { 79 | int bar; 80 | int foo; 81 | // template 82 | // struct FOO 83 | //{ 84 | // static decltype(std::make_tuple(SubElem("int"))) &the_sublist() 85 | // { 86 | // static auto list = std::make_tuple(SubElem("int")); return list; 87 | // } 88 | // static decltype(std::make_tuple(makeElem("bar", &ELEMLIST_T::bar), makeElem("foo", &ELEMLIST_T::foo))) 89 | //&getList() 90 | // { 91 | // static auto list = std::make_tuple(std::make_tuple(makeElem("bar", &ELEMLIST_T::bar), makeElem("foo", 92 | //&ELEMLIST_T::foo))); return list; 93 | // } 94 | //}; 95 | LIST(SUB_LIST(SUB_ELEM(int), SUB_ELEM(int), SUB_ELEM(int), SUB_ELEM(short)), ELEM(bar), ELEM(foo)); 96 | FOO f; 97 | }; 98 | TEST_CASE("compiler_test", "") 99 | { 100 | Cover c; 101 | JS_UNUSED(c); 102 | Cover::FOO::getList(); 103 | // Cover::FOO::the_sublist(); 104 | REQUIRE(true); 105 | } 106 | } // namespace 107 | -------------------------------------------------------------------------------- /tests/json-enum-test.cpp: -------------------------------------------------------------------------------- 1 | #include "catch2/catch.hpp" 2 | #include 3 | #include 4 | 5 | JS_ENUM(Colors, Red, Green, Blue, Yellow4, Purple) 6 | 7 | namespace 8 | { 9 | struct TestEnumParser 10 | { 11 | Colors colors; 12 | 13 | JS_OBJECT(JS_MEMBER(colors)); 14 | }; 15 | } // namespace 16 | 17 | JS_ENUM_DECLARE_STRING_PARSER(Colors) 18 | 19 | namespace 20 | { 21 | const char json[] = R"json({ 22 | "colors": "Green" 23 | })json"; 24 | 25 | TEST_CASE("check_enum_parser", "[json_struct][enum]") 26 | { 27 | JS::ParseContext pc(json); 28 | TestEnumParser ep; 29 | auto error = pc.parseTo(ep); 30 | REQUIRE(error == JS::Error::NoError); 31 | 32 | REQUIRE(ep.colors == Colors::Green); 33 | 34 | std::string jsonout = JS::serializeStruct(ep); 35 | REQUIRE(jsonout == json); 36 | } 37 | 38 | const char json_number[] = R"json({ 39 | "colors": 2 40 | })json"; 41 | 42 | TEST_CASE("check_enum_number_parser", "[json_struct][enum]") 43 | { 44 | JS::ParseContext pc(json_number); 45 | TestEnumParser ep; 46 | auto error = pc.parseTo(ep); 47 | 48 | REQUIRE(error == JS::Error::NoError); 49 | 50 | REQUIRE(ep.colors == Colors::Blue); 51 | } 52 | 53 | namespace FOO 54 | { 55 | namespace BAR 56 | { 57 | JS_ENUM(Cars, Fiat, VW, BMW, Peugeot, Mazda) 58 | } 59 | } // namespace FOO 60 | namespace One 61 | { 62 | namespace Two 63 | { 64 | struct CarContainer 65 | { 66 | FOO::BAR::Cars car; 67 | 68 | JS_OBJECT(JS_MEMBER(car)); 69 | }; 70 | } // namespace Two 71 | } // namespace One 72 | 73 | } // namespace 74 | 75 | JS_ENUM_NAMESPACE_DECLARE_STRING_PARSER(FOO::BAR, Cars) 76 | 77 | namespace 78 | { 79 | const char car_json[] = R"json({ 80 | "car": "BMW" 81 | })json"; 82 | 83 | TEST_CASE("check_enum_parser_namespace", "[json_struct][enum]") 84 | { 85 | JS::ParseContext pc(car_json); 86 | One::Two::CarContainer cc; 87 | auto error = pc.parseTo(cc); 88 | REQUIRE(error == JS::Error::NoError); 89 | 90 | REQUIRE(cc.car == FOO::BAR::Cars::BMW); 91 | 92 | std::string jsonout = JS::serializeStruct(cc); 93 | REQUIRE(jsonout == car_json); 94 | } 95 | 96 | } // namespace 97 | -------------------------------------------------------------------------------- /tests/json-function-error-test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "catch2/catch.hpp" 4 | 5 | const char json_data[] = R"json( 6 | { 7 | "execute_one": { 8 | "prop1": 4, 9 | "prop2": "Property 2" 10 | }, 11 | "execute_two": { 12 | "first_prop": "some string", 13 | "second_prop": 8 14 | } 15 | } 16 | )json"; 17 | 18 | struct ExecuteOneData 19 | { 20 | int prop1; 21 | std::string prop2; 22 | std::string prop3; 23 | JS_OBJECT(JS_MEMBER(prop1), JS_MEMBER(prop2), JS_MEMBER(prop3)); 24 | }; 25 | struct ExecuteTwoData 26 | { 27 | std::string first_prop; 28 | JS_OBJECT(JS_MEMBER(first_prop)); 29 | }; 30 | struct ExecuterTwoReturn 31 | { 32 | std::string string_data; 33 | int value; 34 | std::vector values; 35 | JS_OBJECT(JS_MEMBER(string_data), JS_MEMBER(value), JS_MEMBER(values)); 36 | }; 37 | struct Executor 38 | { 39 | void execute_one(const ExecuteOneData &data) 40 | { 41 | JS_UNUSED(data); 42 | execute_one_called = true; 43 | } 44 | ExecuterTwoReturn execute_two(const ExecuteTwoData &data) 45 | { 46 | JS_UNUSED(data); 47 | execute_two_called = true; 48 | ExecuterTwoReturn ret; 49 | ret.string_data = "Ret data"; 50 | ret.value = 999; 51 | ret.values = {3, 4, 5, 7, 8}; 52 | return ret; 53 | } 54 | bool execute_one_called = false; 55 | bool execute_two_called = false; 56 | 57 | JS_FUNCTION_CONTAINER(JS_FUNCTION(execute_one), JS_FUNCTION(execute_two)); 58 | }; 59 | 60 | TEST_CASE("test_function_error_simple", "[function][error]") 61 | { 62 | Executor executor; 63 | std::string json_out; 64 | JS::DefaultCallFunctionContext context(json_data, json_out); 65 | context.callFunctions(executor); 66 | 67 | REQUIRE(context.execution_list.size() == 2); 68 | REQUIRE(context.execution_list[0].unassigned_required_members.data.size() == 1); 69 | REQUIRE(context.execution_list[0].unassigned_required_members.data[0] == "prop3"); 70 | REQUIRE(context.execution_list[0].missing_members.data.size() == 0); 71 | 72 | REQUIRE(context.execution_list[1].missing_members.data.size() == 1); 73 | REQUIRE(context.execution_list[1].missing_members.data[0] == "second_prop"); 74 | REQUIRE(context.execution_list[1].unassigned_required_members.data.size() == 0); 75 | } 76 | -------------------------------------------------------------------------------- /tests/json-meta-test.cpp: -------------------------------------------------------------------------------- 1 | #include "catch2/catch.hpp" 2 | #include 3 | 4 | namespace 5 | { 6 | const char first_child_with_data_json[] = R"json([ [], [], [ 7 | [], 8 | [], 9 | { 10 | "this has a member": true 11 | }, 12 | [] 13 | ], [], []])json"; 14 | 15 | TEST_CASE("find_first_child_with_data", "[json_struct][meta]") 16 | { 17 | JS::ParseContext pc(first_child_with_data_json); 18 | JS::JsonTokens tokens; 19 | auto error = pc.parseTo(tokens); 20 | REQUIRE(error == JS::Error::NoError); 21 | std::vector meta = JS::metaForTokens(tokens); 22 | size_t first_child = JS::Internal::findFirstChildWithData(meta, 0); 23 | REQUIRE(first_child == 2); 24 | } 25 | const char first_child_with_data_json_last[] = R"json([ [], [], [], [ 26 | [], 27 | [], 28 | { 29 | "this has a member": true 30 | }, 31 | [] 32 | ]])json"; 33 | 34 | TEST_CASE("find_first_child_with_data_last", "[json_struct][meta]") 35 | { 36 | JS::ParseContext pc(first_child_with_data_json_last); 37 | JS::JsonTokens tokens; 38 | auto error = pc.parseTo(tokens); 39 | REQUIRE(error == JS::Error::NoError); 40 | std::vector meta = JS::metaForTokens(tokens); 41 | size_t first_child = JS::Internal::findFirstChildWithData(meta, 0); 42 | REQUIRE(first_child == 3); 43 | } 44 | } // namespace 45 | -------------------------------------------------------------------------------- /tests/json-mias-mat.cpp: -------------------------------------------------------------------------------- 1 | #include "catch2/catch.hpp" 2 | #include 3 | 4 | namespace 5 | { 6 | 7 | const char ingredientJsonError[] = R"json( 8 | { 9 | "id": 666, 10 | "name": "Polser", 11 | "base_unit": "g", 12 | "description": "Fooofooofooo", 13 | "shop_group_id": 4, 14 | "energy_per_unit", 3.14, 15 | "vegetarian": true, 16 | "vegan": false, 17 | "grams_per_deciliter": 0.43, 18 | "grams_per_dimensionless": 0.0, 19 | "unit": "dl", 20 | "quantity": 2.0, 21 | "group_name": "topping", 22 | "recipe_id": 5, 23 | "recipe_name": "gryta", 24 | "use_ingredient_groups": true, 25 | "portions": 2, 26 | "portions_unit": "porsjon", 27 | "shop_group_name": "frukt und grunt", 28 | "allergens": [ 29 | "fisk", 30 | "gluten" 31 | ] 32 | } 33 | )json"; 34 | 35 | const char shoppingListNameSkipJson[] = R"json( 36 | { 37 | "ingredients": [ 38 | { 39 | "id": 123, 40 | "recipe_name_id_list": { 41 | "items": [] 42 | }, 43 | "allergens": [], 44 | "name": "babyleafblader" 45 | } 46 | ], 47 | "userDefinedItems": [ 48 | ], 49 | "notes": "", 50 | "fileVersion": 2, 51 | "sortOrder": 2, 52 | "name": "Handleliste", 53 | "dateExplicit": "9. november 2017", 54 | "timestamp": "2017-11-09 21-52-05", 55 | "isAutomaticSave": false 56 | } 57 | )json"; 58 | 59 | struct RecipeNameIdItem 60 | { 61 | RecipeNameIdItem() 62 | { 63 | } 64 | 65 | RecipeNameIdItem(const std::string &recipe_name, int recipe_id) 66 | : recipe_name(recipe_name) 67 | , recipe_id(recipe_id) 68 | { 69 | } 70 | 71 | std::string recipe_name; 72 | int recipe_id = 0; 73 | 74 | JS_OBJECT(JS_MEMBER(recipe_name), JS_MEMBER(recipe_id)); 75 | }; 76 | 77 | struct RecipeNameIdList 78 | { 79 | std::vector items; 80 | 81 | JS_OBJECT(JS_MEMBER(items)); 82 | }; 83 | 84 | struct ShoppingListItemCPP 85 | { 86 | bool selected; 87 | 88 | JS_OBJECT(JS_MEMBER(selected)); 89 | }; 90 | 91 | struct IngredientCPP : public ShoppingListItemCPP 92 | { 93 | int id; 94 | std::string name; 95 | std::string base_unit; 96 | std::string description; 97 | int shop_group_id; 98 | float energy_per_unit; 99 | bool vegetarian; 100 | bool vegan; 101 | float grams_per_deciliter; 102 | float grams_per_dimensionless; 103 | 104 | std::string unit; 105 | float quantity; 106 | std::string group_name; 107 | 108 | int recipe_id; 109 | std::string recipe_name; 110 | bool use_ingredient_groups; 111 | float portions; 112 | std::string portions_unit; 113 | 114 | std::string shop_group_name; 115 | 116 | std::vector allergens; 117 | 118 | RecipeNameIdList recipe_name_id_list; 119 | 120 | JS_OBJECT_WITH_SUPER(JS_SUPER_CLASSES(JS_SUPER_CLASS(ShoppingListItemCPP)), JS_MEMBER(id), JS_MEMBER(name), 121 | JS_MEMBER(base_unit), JS_MEMBER(description), JS_MEMBER(shop_group_id), 122 | JS_MEMBER(energy_per_unit), JS_MEMBER(vegetarian), JS_MEMBER(vegan), 123 | JS_MEMBER(grams_per_deciliter), JS_MEMBER(grams_per_dimensionless), JS_MEMBER(unit), 124 | JS_MEMBER(quantity), JS_MEMBER(group_name), JS_MEMBER(recipe_id), JS_MEMBER(recipe_name), 125 | JS_MEMBER(use_ingredient_groups), JS_MEMBER(portions), JS_MEMBER(portions_unit), 126 | JS_MEMBER(shop_group_name), JS_MEMBER(allergens), JS_MEMBER(recipe_name_id_list)); 127 | }; 128 | 129 | struct UserDefinedItemCPP : public ShoppingListItemCPP 130 | { 131 | std::string text; 132 | 133 | JS_OBJECT_WITH_SUPER(JS_SUPER_CLASSES(JS_SUPER_CLASS(ShoppingListItemCPP)), JS_MEMBER(text)); 134 | }; 135 | 136 | struct ShoppingListFileBase 137 | { 138 | int fileVersion; 139 | int sortOrder; 140 | std::string name; 141 | std::string dateExplicit; 142 | std::string timestamp; 143 | bool isAutomaticSave; 144 | 145 | JS_OBJECT(JS_MEMBER(fileVersion), JS_MEMBER(sortOrder), JS_MEMBER(name), JS_MEMBER(dateExplicit), 146 | JS_MEMBER(timestamp), JS_MEMBER(isAutomaticSave)); 147 | }; 148 | 149 | struct ShoppingListFileVersion02 : public ShoppingListFileBase 150 | { 151 | std::vector ingredients; 152 | std::vector userDefinedItems; 153 | std::string notes; 154 | 155 | JS_OBJECT_WITH_SUPER(JS_SUPER_CLASSES(JS_SUPER_CLASS(ShoppingListFileBase)), JS_MEMBER(ingredients), 156 | JS_MEMBER(userDefinedItems), JS_MEMBER(notes)); 157 | }; 158 | 159 | TEST_CASE("mias_mat_special_unit_test", "[json_struct]") 160 | { 161 | IngredientCPP ingredient; 162 | JS::ParseContext pc(ingredientJsonError); 163 | auto error = pc.parseTo(ingredient); 164 | REQUIRE(error == JS::Error::ExpectedDelimiter); 165 | 166 | ShoppingListFileBase fileBase; 167 | JS::ParseContext nameContext(shoppingListNameSkipJson); 168 | error = nameContext.parseTo(fileBase); 169 | REQUIRE(error == JS::Error::NoError); 170 | REQUIRE(fileBase.name == "Handleliste"); 171 | } 172 | } // namespace 173 | -------------------------------------------------------------------------------- /tests/json-nullable-test.cpp: -------------------------------------------------------------------------------- 1 | #include "catch2/catch.hpp" 2 | #include 3 | 4 | namespace 5 | { 6 | struct SmallStructWithoutNullable 7 | { 8 | int a; 9 | float b; 10 | 11 | JS_OBJECT(JS_MEMBER(a), JS_MEMBER(b)); 12 | }; 13 | 14 | struct SmallStruct 15 | { 16 | int a = 0; 17 | JS::Nullable b = 2.2f; 18 | 19 | JS_OBJECT(JS_MEMBER(a), JS_MEMBER(b)); 20 | }; 21 | 22 | struct SmallStructNullableChecked 23 | { 24 | int a = 0; 25 | JS::NullableChecked b = 2.2f; 26 | 27 | JS_OBJECT(JS_MEMBER(a), JS_MEMBER(b)); 28 | }; 29 | 30 | const char json[] = R"json( 31 | { 32 | "a": 1, 33 | "b": null 34 | } 35 | )json"; 36 | 37 | TEST_CASE("test_nullable", "[json_struct]") 38 | { 39 | { 40 | JS::ParseContext context(json); 41 | SmallStructWithoutNullable data; 42 | auto error = context.parseTo(data); 43 | REQUIRE(error != JS::Error::NoError); 44 | } 45 | { 46 | JS::ParseContext context(json); 47 | SmallStruct data; 48 | auto error = context.parseTo(data); 49 | REQUIRE(error == JS::Error::NoError); 50 | REQUIRE(data.a == 1); 51 | REQUIRE(data.b() > 2.199); 52 | REQUIRE(data.b() < 2.201); 53 | } 54 | { 55 | JS::ParseContext context(json); 56 | SmallStructNullableChecked data; 57 | auto error = context.parseTo(data); 58 | REQUIRE(error == JS::Error::NoError); 59 | REQUIRE(data.a == 1); 60 | REQUIRE(data.b.null); 61 | REQUIRE(data.b() > 2.199); 62 | REQUIRE(data.b() < 2.201); 63 | } 64 | } 65 | } // namespace 66 | -------------------------------------------------------------------------------- /tests/json-optional.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #ifdef JS_STD_OPTIONAL 3 | #include 4 | #endif 5 | #include "catch2/catch.hpp" 6 | 7 | namespace 8 | { 9 | struct SmallStructWithoutOptional 10 | { 11 | int a = 0; 12 | float b = 2.2f; 13 | std::string d; 14 | 15 | JS_OBJ(a, b, d); 16 | }; 17 | 18 | #ifdef JS_STD_OPTIONAL 19 | struct SmallStructStd 20 | { 21 | int a = 0; 22 | std::optional b = 2.2f; 23 | std::optional c; 24 | std::optional d; 25 | 26 | JS_OBJ(a, b, c, d); 27 | }; 28 | #endif 29 | 30 | const char json[] = R"json( 31 | { 32 | "a": 1, 33 | "b": 2.2, 34 | "c": "hello world" 35 | } 36 | )json"; 37 | 38 | TEST_CASE("test_optional", "[json_struct]") 39 | { 40 | { 41 | JS::ParseContext context(json); 42 | context.allow_unasigned_required_members = false; 43 | SmallStructWithoutOptional data; 44 | auto error = context.parseTo(data); 45 | REQUIRE(error != JS::Error::NoError); 46 | } 47 | #ifdef JS_STD_OPTIONAL 48 | { 49 | JS::ParseContext context(json); 50 | context.allow_unasigned_required_members = false; 51 | SmallStructStd data; 52 | auto error = context.parseTo(data); 53 | REQUIRE(error == JS::Error::NoError); 54 | REQUIRE(context.error == JS::Error::NoError); 55 | REQUIRE(data.a == 1); 56 | REQUIRE(data.b.value() > 2.199); 57 | REQUIRE(data.b.value() < 2.201); 58 | REQUIRE(data.c.value() == "hello world"); 59 | } 60 | #endif 61 | } 62 | } // namespace 63 | -------------------------------------------------------------------------------- /tests/json-reformat.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2019 Jorgen Lind 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided "as 12 | * is" without express or implied warranty. 13 | * 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | 23 | #include 24 | 25 | #include "catch2/catch.hpp" 26 | 27 | #include 28 | 29 | CMRC_DECLARE(external_json); 30 | 31 | TEST_CASE("test_reformat", "[reformat]") 32 | { 33 | auto fs = cmrc::external_json::get_filesystem(); 34 | auto generated = fs.open("generated.json"); 35 | std::string pretty; 36 | JS::Error error = JS::reformat(generated.begin(), generated.size(), pretty); 37 | REQUIRE(error == JS::Error::NoError); 38 | 39 | std::string compact; 40 | error = 41 | JS::reformat(generated.begin(), generated.size(), compact, JS::SerializerOptions(JS::SerializerOptions::Compact)); 42 | REQUIRE(error == JS::Error::NoError); 43 | } 44 | -------------------------------------------------------------------------------- /tests/json-scope.cpp: -------------------------------------------------------------------------------- 1 | #include "catch2/catch.hpp" 2 | #include 3 | #include 4 | 5 | namespace 6 | { 7 | 8 | const char json[] = R"json({ 9 | "func1": { 10 | "arg1": "hello", 11 | "arg2": "world" 12 | }, 13 | "func2": { 14 | "one": [ 1, 2, 3, 4 ], 15 | "two": true 16 | }, 17 | "func3": { 18 | "first": { 19 | "advanced": true 20 | }, 21 | "second": false 22 | } 23 | })json"; 24 | 25 | struct Func1Arg 26 | { 27 | int arg1; 28 | std::string arg2; 29 | JS_OBJECT(JS_MEMBER(arg1), JS_MEMBER(arg2)); 30 | }; 31 | 32 | struct Func2Arg 33 | { 34 | int one[4]; 35 | bool two; 36 | JS_OBJECT(JS_MEMBER(one), JS_MEMBER(two)); 37 | }; 38 | 39 | struct Func3Arg 40 | { 41 | int first; 42 | double second; 43 | JS_OBJECT(JS_MEMBER(first), JS_MEMBER(second)); 44 | }; 45 | 46 | struct FunctionCont 47 | { 48 | void func1(const Func1Arg &) 49 | { 50 | func1_called = true; 51 | } 52 | 53 | void func2(const Func2Arg &arg) 54 | { 55 | JS_UNUSED(arg); 56 | func2_called = true; 57 | } 58 | 59 | void func3(const Func3Arg &arg) 60 | { 61 | JS_UNUSED(arg); 62 | func3_called = true; 63 | } 64 | 65 | bool func1_called = false; 66 | bool func2_called = false; 67 | bool func3_called = false; 68 | JS_FUNCTION_CONTAINER(JS_FUNCTION(func1), JS_FUNCTION(func2), JS_FUNCTION(func3)); 69 | }; 70 | 71 | TEST_CASE("json_function_scope_test", "[function]") 72 | { 73 | FunctionCont cont; 74 | std::string json_out; 75 | JS::DefaultCallFunctionContext context(json, json_out); 76 | context.callFunctions(cont); 77 | REQUIRE(context.error_context.getLatestError() == JS::Error::NoError); 78 | } 79 | } // namespace 80 | -------------------------------------------------------------------------------- /tests/json-string-with-nullterminator-test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2020 Øystein Myrmo 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided "as 12 | * is" without express or implied warranty. 13 | * 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | 23 | #include 24 | 25 | #include "catch2/catch.hpp" 26 | #include 27 | #include 28 | 29 | namespace 30 | { 31 | 32 | struct NullTerminatorStruct 33 | { 34 | std::string data; 35 | 36 | JS_OBJECT(JS_MEMBER(data)); 37 | }; 38 | 39 | std::string create_string_with_nullterminators() 40 | { 41 | std::stringstream content; 42 | content.write("Hello", 5); 43 | int num = 5; 44 | content.write((char *)&num, 4); 45 | content.write(" World!", 7); 46 | return content.str(); 47 | } 48 | 49 | std::string create_json_with_nullterminators() 50 | { 51 | std::stringstream content; 52 | content.write("{\"data\":\"Hello", 14); 53 | int num = 5; 54 | content.write((char *)&num, 4); 55 | content.write(" World!\"}", 9); 56 | return content.str(); 57 | } 58 | 59 | void check_parse_nullterminated_string(const std::string jsonWithNullTerminator) 60 | { 61 | NullTerminatorStruct nullStruct; 62 | 63 | JS::ParseContext pc(jsonWithNullTerminator); 64 | auto error = pc.parseTo(nullStruct); 65 | 66 | REQUIRE(error == JS::Error::NoError); 67 | REQUIRE(nullStruct.data.size() == 16); 68 | } 69 | 70 | TEST_CASE("check_parse_nullterminated_string", "[json_struct]") 71 | { 72 | std::string jsonWithNullTerminator = create_json_with_nullterminators(); 73 | check_parse_nullterminated_string(jsonWithNullTerminator); 74 | } 75 | 76 | TEST_CASE("check_serialize_nullterminated_struct", "[json_struct]") 77 | { 78 | NullTerminatorStruct nullStruct; 79 | nullStruct.data = create_string_with_nullterminators(); 80 | std::string json = JS::serializeStruct(nullStruct); 81 | check_parse_nullterminated_string(json); 82 | } 83 | 84 | } // namespace 85 | -------------------------------------------------------------------------------- /tests/json-struct-aliases-test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2016 Jorgen Lind 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided "as 12 | * is" without express or implied warranty. 13 | * 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | 23 | #include 24 | 25 | #include "catch2/catch.hpp" 26 | 27 | namespace 28 | { 29 | 30 | const char json_data1[] = R"json( 31 | { 32 | "TheAlias": 55, 33 | "SomeOtherValue": 44 34 | } 35 | )json"; 36 | 37 | struct FirstAlias 38 | { 39 | int ThePrimary = 0; 40 | int SomeOtherValue = 0; 41 | 42 | JS_OBJECT(JS_MEMBER_ALIASES(ThePrimary, "TheAlias"), JS_MEMBER(SomeOtherValue)); 43 | }; 44 | 45 | TEST_CASE("struct_aliases_checkPlain", "[json_struct][aliases]") 46 | { 47 | JS::ParseContext context(json_data1); 48 | FirstAlias fa; 49 | auto error = context.parseTo(fa); 50 | REQUIRE(error == JS::Error::NoError); 51 | 52 | REQUIRE(fa.ThePrimary == 55); 53 | REQUIRE(fa.SomeOtherValue == 44); 54 | } 55 | 56 | struct ShadowAlias 57 | { 58 | int TheAlias = 0; 59 | int SomeOtherValue = 0; 60 | 61 | JS_OBJECT(JS_MEMBER_ALIASES(TheAlias, "SomeOtherValue"), JS_MEMBER(SomeOtherValue)); 62 | }; 63 | 64 | TEST_CASE("struct_aliases_checkPlainShadow", "[json_struct][aliases]") 65 | { 66 | JS::ParseContext context(json_data1); 67 | ShadowAlias sa; 68 | auto error = context.parseTo(sa); 69 | REQUIRE(error == JS::Error::NoError); 70 | 71 | REQUIRE(sa.TheAlias == 55); 72 | REQUIRE(sa.SomeOtherValue == 44); 73 | } 74 | 75 | const char json_data2[] = R"json( 76 | { 77 | "SomeOtherValue": 44, 78 | "TheAlias": 55 79 | } 80 | )json"; 81 | 82 | struct TheSuper 83 | { 84 | int TheAlias = 0; 85 | JS_OBJECT(JS_MEMBER(TheAlias)); 86 | }; 87 | 88 | struct TheSub : public TheSuper 89 | { 90 | int SomeOtherValue = 0; 91 | JS_OBJECT_WITH_SUPER(JS_SUPER_CLASSES(JS_SUPER_CLASS(TheSuper)), JS_MEMBER_ALIASES(SomeOtherValue, "TheAlias")); 92 | }; 93 | 94 | TEST_CASE("struct_aliases_checkSuperShadow", "[json_struct][aliases]") 95 | { 96 | JS::ParseContext context(json_data1); 97 | TheSub sa; 98 | auto error = context.parseTo(sa); 99 | REQUIRE(error == JS::Error::NoError); 100 | 101 | REQUIRE(sa.TheAlias == 55); 102 | REQUIRE(sa.SomeOtherValue == 44); 103 | 104 | context = JS::ParseContext(json_data2); 105 | sa = TheSub(); 106 | error = context.parseTo(sa); 107 | REQUIRE(error == JS::Error::NoError); 108 | 109 | REQUIRE(sa.TheAlias == 55); 110 | REQUIRE(sa.SomeOtherValue == 44); 111 | } 112 | 113 | const char recursive_alias[] = R"json( 114 | { 115 | "first": "first", 116 | "second": { 117 | "one": "one", 118 | "two": "two", 119 | "three": "three" 120 | }, 121 | "third": "third" 122 | } 123 | )json"; 124 | 125 | struct Second 126 | { 127 | std::string one; 128 | std::string two_primary; 129 | std::string three; 130 | 131 | JS_OBJECT(JS_MEMBER(one), JS_MEMBER_ALIASES(two_primary, "two"), JS_MEMBER(three)); 132 | }; 133 | struct First 134 | { 135 | std::string first; 136 | Second second; 137 | std::string third; 138 | JS_OBJECT(JS_MEMBER(first), JS_MEMBER(second), JS_MEMBER(third)); 139 | }; 140 | 141 | TEST_CASE("struct_aliases_checkRecursiveShadow", "[json_struct][aliases]") 142 | { 143 | JS::ParseContext context(recursive_alias); 144 | First f; 145 | auto error = context.parseTo(f); 146 | REQUIRE(error == JS::Error::NoError); 147 | 148 | REQUIRE(f.first == "first"); 149 | REQUIRE(f.second.two_primary == "two"); 150 | REQUIRE(f.second.three == "three"); 151 | REQUIRE(f.third == "third"); 152 | } 153 | 154 | } // namespace 155 | -------------------------------------------------------------------------------- /tests/json-struct-array-varlength.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright � 2021 Jorgen Lind 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided "as 12 | * is" without express or implied warranty. 13 | * 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | 23 | #include 24 | 25 | #include "catch2/catch.hpp" 26 | 27 | namespace 28 | { 29 | const char json_data[] = R"json( 30 | { 31 | "vec": [ 32 | 1,2,3,4 33 | ] 34 | } 35 | )json"; 36 | 37 | struct JsonObject1 38 | { 39 | JS::ArrayVariableContent vec; 40 | JS_OBJ(vec); 41 | }; 42 | 43 | struct JsonObject2 44 | { 45 | JS::ArrayVariableContent vec; 46 | JS_OBJ(vec); 47 | }; 48 | 49 | TEST_CASE("array_variable_content", "[json_struct][array]") 50 | { 51 | JS::ParseContext context(json_data); 52 | JsonObject1 object; 53 | REQUIRE(context.parseTo(object) == JS::Error::NoError); 54 | 55 | REQUIRE(object.vec.size == 4); 56 | REQUIRE(object.vec.data[0] == 1); 57 | REQUIRE(object.vec.data[1] == 2); 58 | REQUIRE(object.vec.data[2] == 3); 59 | REQUIRE(object.vec.data[3] == 4); 60 | } 61 | 62 | TEST_CASE("array_variable_content_fail", "[json_struct][array]") 63 | { 64 | JS::ParseContext context(json_data); 65 | JsonObject2 object; 66 | REQUIRE(context.parseTo(object) != JS::Error::NoError); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /tests/json-struct-error-string.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright � 2021 Jorgen Lind 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided "as 12 | * is" without express or implied warranty. 13 | * 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | 23 | #include 24 | 25 | #include "catch2/catch.hpp" 26 | 27 | namespace 28 | { 29 | 30 | static const char json_data1[] = R"json({ 31 | /* Invalid stuff */ 32 | "One": "foo / bar", 33 | "Two": "foo \/ bar" 34 | })json"; 35 | 36 | struct Struct 37 | { 38 | std::string One; 39 | std::string Two; 40 | JS_OBJ(One, Two); 41 | }; 42 | 43 | TEST_CASE("test_make_error_string", "[json_struct][error]") 44 | { 45 | JS::ParseContext context(json_data1); 46 | Struct substruct; 47 | auto error = context.parseTo(substruct); 48 | 49 | REQUIRE(error != JS::Error::NoError); 50 | 51 | std::string errorString = context.makeErrorString(); 52 | REQUIRE(errorString.size() != 0); 53 | } 54 | 55 | TEST_CASE("test_make_error_string_unnasigned_required_member", "[json_struct][error]") 56 | { 57 | static const char json_data[] = R"json({ 58 | "One": "foo / bar" 59 | })json"; 60 | 61 | JS::ParseContext context(json_data); 62 | context.allow_missing_members = false; 63 | context.allow_unasigned_required_members = false; 64 | Struct substruct; 65 | auto error = context.parseTo(substruct); 66 | 67 | REQUIRE(error != JS::Error::NoError); 68 | 69 | std::string errorString = context.makeErrorString(); 70 | REQUIRE(errorString.size() != 0); 71 | } 72 | 73 | TEST_CASE("test_make_error_string_missing_member", "[json_struct][error]") 74 | { 75 | static const char json_data[] = R"json({ 76 | "One": "foo / bar", 77 | "Two": "foo \/ bar", 78 | "Three": "foo \/ bar" 79 | })json"; 80 | 81 | JS::ParseContext context(json_data); 82 | context.allow_missing_members = false; 83 | context.allow_unasigned_required_members = false; 84 | Struct substruct; 85 | auto error = context.parseTo(substruct); 86 | (void) error; 87 | context.error = JS::Error::MissingPropertyMember; 88 | 89 | REQUIRE(context.error != JS::Error::NoError); 90 | 91 | std::string errorString = context.makeErrorString(); 92 | REQUIRE(errorString.size() != 0); 93 | } 94 | 95 | TEST_CASE("test_make_error_string_missing_members", "[json_struct][error]") 96 | { 97 | static const char json_data[] = R"json({ 98 | "One": "foo / bar", 99 | "Two": "foo \/ bar", 100 | "Three": "foo \/ bar", 101 | "Four": 4232 102 | })json"; 103 | 104 | JS::ParseContext context(json_data); 105 | context.allow_missing_members = true; 106 | context.allow_unasigned_required_members = false; 107 | Struct substruct; 108 | auto error = context.parseTo(substruct); 109 | (void)error; 110 | context.error = JS::Error::MissingPropertyMember; 111 | 112 | REQUIRE(context.error != JS::Error::NoError); 113 | 114 | std::string errorString = context.makeErrorString(); 115 | REQUIRE(errorString.size() != 0); 116 | } 117 | 118 | } // namespace 119 | -------------------------------------------------------------------------------- /tests/json-struct-escape.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright � 2021 Jorgen Lind 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided "as 12 | * is" without express or implied warranty. 13 | * 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | 23 | #include 24 | 25 | #include "catch2/catch.hpp" 26 | 27 | namespace 28 | { 29 | 30 | static const char json_data1[] = R"json({ 31 | "One": "foo / bar", 32 | "Two": "foo \/ bar" 33 | })json"; 34 | 35 | struct Struct 36 | { 37 | std::string One; 38 | std::string Two; 39 | JS_OBJ(One, Two); 40 | }; 41 | 42 | TEST_CASE("test_forward_slash", "[json_struct][escape]") 43 | { 44 | JS::ParseContext context(json_data1); 45 | Struct substruct; 46 | auto error = context.parseTo(substruct); 47 | 48 | REQUIRE(error == JS::Error::NoError); 49 | REQUIRE(substruct.One == "foo / bar"); 50 | REQUIRE(substruct.Two == "foo / bar"); 51 | 52 | std::string out = JS::serializeStruct(substruct); 53 | 54 | Struct second_struct; 55 | JS::ParseContext context2(out); 56 | error = context2.parseTo(second_struct); 57 | REQUIRE(error == JS::Error::NoError); 58 | REQUIRE(substruct.One == second_struct.One); 59 | REQUIRE(substruct.Two == second_struct.Two); 60 | 61 | 62 | } 63 | } // namespace 64 | -------------------------------------------------------------------------------- /tests/json-struct-external.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2019 Jorgen Lind 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided "as 12 | * is" without express or implied warranty. 13 | * 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | 23 | #include 24 | 25 | #include "catch2/catch.hpp" 26 | 27 | namespace 28 | { 29 | 30 | const char json_data1[] = R"json( 31 | { 32 | "StringNode": "Some test data", 33 | "NumberNode": 4676.4, 34 | "BooleanTrue": true, 35 | "BooleanFalse": false, 36 | "TestStruct": { 37 | "SubString": "Some other string", 38 | "SubNumber": 500, 39 | "Array": [ 40 | 5, 41 | 6, 42 | 3, 43 | 6 44 | ] 45 | } 46 | } 47 | )json"; 48 | struct TestStructT 49 | { 50 | std::string SubString; 51 | int SubNumber; 52 | }; 53 | } // namespace 54 | JS_OBJECT_EXTERNAL(TestStructT, JS_MEMBER(SubString), JS_MEMBER(SubNumber)) 55 | 56 | namespace 57 | { 58 | struct TestStructSub : public TestStructT 59 | { 60 | std::vector Array; 61 | }; 62 | } // namespace 63 | JS_OBJECT_EXTERNAL_WITH_SUPER(TestStructSub, JS_SUPER_CLASSES(JS_SUPER_CLASS(TestStructT)), JS_MEMBER(Array)) 64 | 65 | namespace 66 | { 67 | struct JsonData1 68 | { 69 | std::string StringNode; 70 | double NumberNode; 71 | bool BooleanTrue; 72 | bool BooleanFalse; 73 | TestStructSub TestStruct; 74 | }; 75 | } // namespace 76 | JS_OBJECT_EXTERNAL(JsonData1, JS_MEMBER(StringNode), JS_MEMBER(NumberNode), JS_MEMBER(BooleanTrue), 77 | JS_MEMBER(BooleanFalse), JS_MEMBER(TestStruct)) 78 | 79 | namespace 80 | { 81 | TEST_CASE("json_struct_external", "[json_struct]") 82 | { 83 | JS::ParseContext context(json_data1); 84 | JsonData1 data; 85 | auto error = context.parseTo(data); 86 | 87 | REQUIRE(error == JS::Error::NoError); 88 | REQUIRE(data.StringNode == "Some test data"); 89 | REQUIRE(data.TestStruct.SubNumber == 500); 90 | REQUIRE(data.TestStruct.Array.size() == 4); 91 | REQUIRE(data.TestStruct.Array[2] == 3); 92 | REQUIRE(context.error == JS::Error::NoError); 93 | 94 | std::string json = JS::serializeStruct(data); 95 | } 96 | 97 | } // namespace 98 | -------------------------------------------------------------------------------- /tests/json-struct-fail.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2019 Jorgen Lind 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided "as 12 | * is" without express or implied warranty. 13 | * 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | 23 | #include 24 | 25 | #include "catch2/catch.hpp" 26 | 27 | namespace 28 | { 29 | 30 | const char json_data[] = R"json( 31 | { 32 | "some_data": 44.50 33 | } 34 | )json"; 35 | 36 | struct JsonMissingMeta 37 | { 38 | float missing_meta; 39 | }; 40 | 41 | struct JsonMissingTypeHandler 42 | { 43 | double vec[3]; 44 | }; 45 | 46 | struct JsonContainingStructMissingTypeHandler 47 | { 48 | JsonMissingTypeHandler data; 49 | 50 | JS_OBJECT(JS_MEMBER(data)); 51 | }; 52 | 53 | TEST_CASE("json_struct_error_check_missing_meta", "[json_struct][error]") 54 | { 55 | JS::ParseContext context(json_data); 56 | JsonMissingMeta missing; 57 | JS_UNUSED(context); 58 | JS_UNUSED(missing); 59 | // context.parseTo(missing); 60 | // std::string out = JS::serializeStruct(missing); 61 | } 62 | 63 | TEST_CASE("json_struct_error_check_missing_typehandler", "[json_struct][error]") 64 | { 65 | JS::ParseContext context(json_data); 66 | JsonContainingStructMissingTypeHandler missing; 67 | JS_UNUSED(context); 68 | JS_UNUSED(missing); 69 | // context.parseTo(missing); 70 | // std::string out = JS::serializeStruct(missing); 71 | } 72 | } // namespace 73 | -------------------------------------------------------------------------------- /tests/json-struct-float.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 Jorgen Lind 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided "as 12 | * is" without express or implied warranty. 13 | * 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | 23 | #include 24 | 25 | #include "catch2/catch.hpp" 26 | 27 | namespace 28 | { 29 | const char json_data[] = R"json( 30 | { 31 | "num1": 32587.403333333333333333, 32 | "num2": 32587.403333333333333333 33 | } 34 | )json"; 35 | 36 | struct Json1 37 | { 38 | float num1; 39 | double num2; 40 | 41 | JS_OBJ(num1, num2); 42 | }; 43 | 44 | TEST_CASE("json_struct_float", "[json_struct][float]") 45 | { 46 | JS::ParseContext context(json_data); 47 | Json1 json; 48 | auto error = context.parseTo(json); 49 | REQUIRE(error == JS::Error::NoError); 50 | REQUIRE(json.num1 == 32587.403333333333333333f); 51 | REQUIRE(json.num2 == 32587.403333333333333333); 52 | // context.parseTo(missing); 53 | // std::string out = JS::serializeStruct(missing); 54 | } 55 | } // namespace 56 | -------------------------------------------------------------------------------- /tests/json-struct-map-typehandler.cpp: -------------------------------------------------------------------------------- 1 | #define JS_STL_UNORDERED_SET 2 | #include 3 | #include "catch2/catch.hpp" 4 | 5 | namespace JS 6 | { 7 | template 8 | struct TypeHandler> 9 | { 10 | static inline Error to(std::unordered_map &to_type, ParseContext &context) 11 | { 12 | if (context.token.value_type != Type::ObjectStart) 13 | { 14 | return JS::Error::ExpectedObjectStart; 15 | } 16 | 17 | Error error = context.nextToken(); 18 | if (error != JS::Error::NoError) 19 | return error; 20 | 21 | const char *pointer = nullptr; 22 | int key = 0; 23 | 24 | while (context.token.value_type != Type::ObjectEnd) 25 | { 26 | auto parse_error = Internal::ft::integer::to_integer(context.token.name.data, context.token.name.size, key, pointer); 27 | if (parse_error != Internal::ft::parse_string_error::ok || context.token.name.data == pointer) 28 | return Error::FailedToParseInt; 29 | 30 | T value; 31 | error = TypeHandler::to(value, context); 32 | to_type[std::move(key)] = std::move(value); 33 | if (error != JS::Error::NoError) 34 | return error; 35 | error = context.nextToken(); 36 | } 37 | 38 | return error; 39 | } 40 | static inline void from(const std::unordered_map &from_type, Token &token, Serializer &serializer) 41 | { 42 | token.value_type = Type::ObjectStart; 43 | token.value = DataRef("{"); 44 | serializer.write(token); 45 | char buf[40]; 46 | int digits_truncated; 47 | for (auto it = from_type.begin(); it != from_type.end(); ++it) 48 | { 49 | int size = Internal::ft::integer::to_buffer(it->first, buf, sizeof(buf), &digits_truncated); 50 | if (size <= 0 || digits_truncated) 51 | return; 52 | token.name = DataRef(buf, size); 53 | token.name_type = Type::String; 54 | TypeHandler::from(it->second, token, serializer); 55 | } 56 | token.name.size = 0; 57 | token.name.data = ""; 58 | token.name_type = Type::String; 59 | token.value_type = Type::ObjectEnd; 60 | token.value = DataRef("}"); 61 | serializer.write(token); 62 | } 63 | }; 64 | } 65 | 66 | namespace 67 | { 68 | const char json[] = R"json( 69 | { 70 | "1": { 71 | "2": { 72 | "Foo": { 73 | "3": { 74 | "4": { 75 | "Bar": { 76 | "1": "1", 77 | "2": "2", 78 | "3": "3" 79 | }, 80 | "Hello": "World", 81 | "World": "Hello", 82 | "Value": 10.0 83 | } 84 | }, 85 | "5": { 86 | "6": { 87 | "Bar": { 88 | "1": "1", 89 | "2": "2", 90 | "3": "3" 91 | }, 92 | "Hello": "World", 93 | "World": "Hello", 94 | "Value": 10.0 95 | } 96 | } 97 | }, 98 | "Baz": "FooBarBaz" 99 | }, 100 | "7": { 101 | "Foo": { 102 | "8": { 103 | "9": { 104 | "Bar": null, 105 | "Hello": "World", 106 | "World": "Hello", 107 | "Value": 11.0 108 | } 109 | } 110 | }, 111 | "Baz": "FooBarBaz" 112 | } 113 | } 114 | } 115 | )json"; 116 | 117 | struct HelloWorldContainer 118 | { 119 | JS::Nullable> Bar; 120 | std::string Hello; 121 | std::string World; 122 | float Value; 123 | JS_OBJ(Bar, Hello, World, Value); 124 | }; 125 | 126 | struct ParentContainer 127 | { 128 | std::unordered_map> Foo; 129 | std::string Baz; 130 | JS_OBJ(Foo, Baz); 131 | }; 132 | 133 | TEST_CASE("map_typehandler", "json_struct") 134 | { 135 | std::unordered_map> obj; 136 | JS::ParseContext pc(json); 137 | auto error = pc.parseTo(obj); 138 | if (error != JS::Error::NoError) 139 | { 140 | auto errorStr = pc.makeErrorString(); 141 | fprintf(stderr, "%s\n", errorStr.c_str()); 142 | } 143 | for (auto &unassigned : pc.unassigned_required_members) 144 | fprintf(stderr, "Unnassigned: %s\n", unassigned.c_str()); 145 | for (auto &missing : pc.missing_members) 146 | fprintf(stderr, "Missing: %s\n", missing.c_str()); 147 | REQUIRE(error == JS::Error::NoError); 148 | REQUIRE(pc.unassigned_required_members.size() == 0); 149 | 150 | REQUIRE(pc.missing_members.size() == 0); 151 | 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /tests/json-struct-nested.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2022 Jonathan Poncelet 3 | 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided "as 12 | * is" without express or implied warranty. 13 | 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | #include 23 | #include 24 | #include 25 | #include "catch2/catch.hpp" 26 | 27 | static constexpr const char* const JSON_ONE_NESTED_OBJECT = R"json( 28 | { 29 | "object1": 30 | { 31 | "value": 1, 32 | "nested_object": 33 | { 34 | "nested_1": 35 | { 36 | "some_value": "foo" 37 | } 38 | } 39 | }, 40 | "object2": 41 | { 42 | "value": 2 43 | } 44 | })json"; 45 | 46 | static constexpr const char* const JSON_TWO_NESTED_OBJECTS = R"json( 47 | { 48 | "object1": 49 | { 50 | "value": 1, 51 | "nested_object": 52 | { 53 | "nested_1": 54 | { 55 | "some_value": "foo" 56 | }, 57 | "nested_2": 58 | { 59 | "some_value": "bar" 60 | } 61 | } 62 | }, 63 | "object2": 64 | { 65 | "value": 2 66 | } 67 | })json"; 68 | 69 | struct NestedObject 70 | { 71 | struct Inner 72 | { 73 | std::string some_value; 74 | 75 | JS_OBJ(some_value); 76 | }; 77 | 78 | Inner nested_1; 79 | Inner nested_2; 80 | 81 | JS_OBJ(nested_1, nested_2); 82 | }; 83 | 84 | struct Object1 85 | { 86 | int32_t value = 0; 87 | NestedObject nested_object; 88 | 89 | JS_OBJ(value, nested_object); 90 | }; 91 | 92 | struct Object1_OmittedVal 93 | { 94 | int32_t value = 0; 95 | // NestedObject is deliberately omitted here. 96 | 97 | JS_OBJ(value); 98 | }; 99 | 100 | struct Object2 101 | { 102 | int32_t value = 0; 103 | 104 | JS_OBJ(value); 105 | }; 106 | 107 | struct Container 108 | { 109 | Object1 object1; 110 | Object2 object2; 111 | 112 | JS_OBJ(object1, object2); 113 | }; 114 | 115 | struct Container_OmittedVal 116 | { 117 | Object1_OmittedVal object1; 118 | Object2 object2; 119 | 120 | JS_OBJ(object1, object2); 121 | }; 122 | 123 | template 124 | static bool TryParse(const std::string& json) 125 | { 126 | static const int32_t EXPECTED_CONTAINER_VALUE = 2; 127 | 128 | JS::ParseContext context(json); 129 | T container; 130 | JS::Error parseError = context.parseTo(container); 131 | 132 | bool parsedSuccessfully = parseError == JS::Error::NoError; 133 | bool containerValueCorrect = container.object2.value == EXPECTED_CONTAINER_VALUE; 134 | return parsedSuccessfully && containerValueCorrect; 135 | } 136 | 137 | TEST_CASE("nested_optional", "json_struct") 138 | { 139 | REQUIRE(TryParse(JSON_ONE_NESTED_OBJECT)); 140 | REQUIRE(TryParse(JSON_TWO_NESTED_OBJECTS)); 141 | REQUIRE(TryParse(JSON_ONE_NESTED_OBJECT)); 142 | REQUIRE(TryParse(JSON_TWO_NESTED_OBJECTS)); 143 | } 144 | 145 | -------------------------------------------------------------------------------- /tests/json-struct-optional.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright � 2020 Jorgen Lind 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided "as 12 | * is" without express or implied warranty. 13 | * 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | 23 | #include 24 | #define JS_STD_OPTIONAL 25 | #include 26 | 27 | #include "catch2/catch.hpp" 28 | #include 29 | 30 | 31 | namespace 32 | { 33 | static const char json[] = R"json({ 34 | "Field1": 4, 35 | "Field2": true, 36 | "Field3": "432" 37 | })json"; 38 | 39 | struct field_struct 40 | { 41 | std::optional Field1; 42 | std::optional Field2; 43 | std::optional Field3; 44 | std::optional Field4; 45 | JS_OBJ(Field1, Field2, Field3, Field4); 46 | }; 47 | TEST_CASE("js_std_optional", "json_struct") 48 | { 49 | JS::ParseContext context(json, sizeof(json)); 50 | context.allow_missing_members = false; 51 | context.allow_unnasigned_required_members = false; 52 | 53 | field_struct to_struct; 54 | context.parseTo(to_struct); 55 | 56 | REQUIRE(Field1 == 4); 57 | REQUIRE(Field2 == true); 58 | REQUIRE(Field3 == "432"); 59 | REQUIRE(context.missing_members.size() == 0); 60 | REQUIRE(context.unassigned_required_members.size() == 0); 61 | } 62 | } 63 | #endif 64 | -------------------------------------------------------------------------------- /tests/json-struct-serialize-test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2017 Jorgen Lind 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided "as 12 | * is" without express or implied warranty. 13 | * 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | 23 | #include 24 | 25 | #include "catch2/catch.hpp" 26 | 27 | #include 28 | 29 | CMRC_DECLARE(external_json); 30 | 31 | namespace 32 | { 33 | 34 | struct Simple 35 | { 36 | std::string A; 37 | bool b; 38 | int some_longer_name; 39 | JS_OBJECT(JS_MEMBER(A), JS_MEMBER(b), JS_MEMBER(some_longer_name)); 40 | }; 41 | 42 | const char expected1[] = R"json({ 43 | "A": "TestString", 44 | "b": false, 45 | "some_longer_name": 456 46 | })json"; 47 | 48 | TEST_CASE("test_serialize_simple", "[json_struct][serialize]") 49 | { 50 | Simple simple; 51 | simple.A = "TestString"; 52 | simple.b = false; 53 | simple.some_longer_name = 456; 54 | 55 | std::string output = JS::serializeStruct(simple); 56 | REQUIRE(output == expected1); 57 | } 58 | 59 | struct A 60 | { 61 | int a; 62 | JS_OBJECT(JS_MEMBER(a)); 63 | }; 64 | 65 | struct B : public A 66 | { 67 | float b; 68 | JS_OBJECT_WITH_SUPER(JS_SUPER_CLASSES(JS_SUPER_CLASS(A)), JS_MEMBER(b)); 69 | }; 70 | 71 | struct D 72 | { 73 | int d; 74 | JS_OBJECT(JS_MEMBER(d)); 75 | }; 76 | 77 | struct E : public D 78 | { 79 | double e; 80 | JS_OBJECT_WITH_SUPER(JS_SUPER_CLASSES(JS_SUPER_CLASS(D)), JS_MEMBER(e)); 81 | }; 82 | 83 | struct F : public E 84 | { 85 | int f; 86 | JS_OBJECT_WITH_SUPER(JS_SUPER_CLASSES(JS_SUPER_CLASS(E)), JS_MEMBER(f)); 87 | }; 88 | struct G 89 | { 90 | std::string g; 91 | JS_OBJECT(JS_MEMBER(g)); 92 | }; 93 | 94 | struct Subclass : public B, public F, public G 95 | { 96 | int h; 97 | JS_OBJECT_WITH_SUPER(JS_SUPER_CLASSES(JS_SUPER_CLASS(B), JS_SUPER_CLASS(F), JS_SUPER_CLASS(G)), JS_MEMBER(h)); 98 | }; 99 | 100 | const char expected2[] = R"json({ 101 | "h": 7, 102 | "g": "OutputString", 103 | "f": 6, 104 | "e": 5.5, 105 | "d": 5, 106 | "b": 4.5, 107 | "a": 4 108 | })json"; 109 | 110 | TEST_CASE("test_serialize_deep", "[json_struct][serialize]") 111 | { 112 | Subclass subclass; 113 | subclass.a = 4; 114 | subclass.b = 4.5; 115 | subclass.d = 5; 116 | subclass.e = 5.5; 117 | subclass.f = 6; 118 | subclass.g = "OutputString"; 119 | subclass.h = 7; 120 | 121 | std::string output = JS::serializeStruct(subclass); 122 | REQUIRE(output == expected2); 123 | } 124 | 125 | struct WithEscapedData 126 | { 127 | std::string data; 128 | JS_OBJECT(JS_MEMBER(data)); 129 | }; 130 | 131 | const char escaped_expected[] = R"json({ 132 | "data": "escaped \n \" \t string" 133 | })json"; 134 | 135 | TEST_CASE("serialze_test_escaped_data", "[json_struct][serialize]") 136 | { 137 | WithEscapedData escaped; 138 | escaped.data = "escaped \n \" \t string"; 139 | std::string output = JS::serializeStruct(escaped); 140 | REQUIRE(output == escaped_expected); 141 | } 142 | 143 | const char expected3[] = R"json({"h":7,"g":"OutputString","f":6,"e":5.5,"d":5,"b":4.5,"a":4})json"; 144 | TEST_CASE("serialize_test_compact", "[json_struct][serialize]") 145 | { 146 | Subclass subclass; 147 | subclass.a = 4; 148 | subclass.b = 4.5; 149 | subclass.d = 5; 150 | subclass.e = 5.5; 151 | subclass.f = 6; 152 | subclass.g = "OutputString"; 153 | subclass.h = 7; 154 | 155 | std::string output = JS::serializeStruct(subclass, JS::SerializerOptions(JS::SerializerOptions::Compact)); 156 | REQUIRE(output == expected3); 157 | } 158 | 159 | TEST_CASE("test_serialize_big", "[json_struct][serialize]") 160 | { 161 | auto fs = cmrc::external_json::get_filesystem(); 162 | auto generated = fs.open("generated.json"); 163 | 164 | JS::JsonObjectOrArrayRef objOrArr; 165 | { 166 | JS::ParseContext pc(generated.begin(), generated.size()); 167 | auto error = pc.parseTo(objOrArr); 168 | REQUIRE(error == JS::Error::NoError); 169 | } 170 | 171 | std::string serialized_json = JS::serializeStruct(objOrArr); 172 | 173 | { 174 | JS::ParseContext pc(serialized_json.data(), serialized_json.size()); 175 | auto error = pc.parseTo(objOrArr); 176 | REQUIRE(error == JS::Error::NoError); 177 | } 178 | } 179 | 180 | const char empty_string_json[] = R"json({ 181 | "key1": "value1", 182 | "key2": "", 183 | "key3": "value3" 184 | })json"; 185 | 186 | struct empty_string_struct 187 | { 188 | std::string key1; 189 | std::string key2; 190 | std::string key3; 191 | 192 | JS_OBJ(key1, key2, key3); 193 | }; 194 | TEST_CASE("test_serialize_empty_string", "[json_struct][serialize]") 195 | { 196 | JS::JsonTokens tokens; 197 | JS::ParseContext context(empty_string_json); 198 | auto error = context.parseTo(tokens); 199 | REQUIRE(error == JS::Error::NoError); 200 | 201 | empty_string_struct empty_struct; 202 | JS::ParseContext context2(empty_string_json); 203 | error = context2.parseTo(empty_struct); 204 | REQUIRE(error == JS::Error::NoError); 205 | 206 | std::string out = JS::serializeStruct(tokens); 207 | 208 | std::string out2 = JS::serializeStruct(empty_struct); 209 | REQUIRE(out == out2); 210 | REQUIRE(out == empty_string_json); 211 | } 212 | 213 | } // namespace 214 | -------------------------------------------------------------------------------- /tests/json-struct-serialize-tuple.cpp: -------------------------------------------------------------------------------- 1 | #include "catch2/catch.hpp" 2 | #include 3 | 4 | #include 5 | 6 | namespace json_struct_serialize_tuple 7 | { 8 | 9 | struct Foo 10 | { 11 | JS::Tuple data; 12 | JS_OBJECT(JS_MEMBER(data)); 13 | }; 14 | 15 | const char json[] = R"json( 16 | { 17 | "data": [ 18 | 9876, 19 | "Tuples are cool", 20 | 3.1415 21 | ] 22 | } 23 | )json"; 24 | 25 | TEST_CASE("serialize_tuple", "[json_struct][tuple]") 26 | { 27 | 28 | Foo out; 29 | out.data.get<0>() = 12345; 30 | out.data.get<1>() = "Hello world"; 31 | out.data.get<2>() = 44.50; 32 | std::string bar = JS::serializeStruct(out); 33 | 34 | Foo in; 35 | JS::ParseContext context(json); 36 | auto error = context.parseTo(in); 37 | REQUIRE(error == JS::Error::NoError); 38 | REQUIRE(in.data.get<0>() == 9876); 39 | REQUIRE(std::string("Tuples are cool") == in.data.get<1>()); 40 | REQUIRE(in.data.get<2>() > 3.14); 41 | REQUIRE(in.data.get<2>() < 3.15); 42 | } 43 | 44 | struct TestInt { 45 | std::tuple member; 46 | JS_OBJ(member); 47 | }; 48 | 49 | struct TestBool { 50 | std::tuple member; 51 | JS_OBJ(member); 52 | }; 53 | 54 | TEST_CASE("bool_tuple", "[json_struct][tuple]") 55 | { 56 | TestInt tiStruct; 57 | JS::ParseContext intContext(R"({ "member": [5] })"); 58 | REQUIRE(intContext.parseTo(tiStruct) == JS::Error::NoError); 59 | 60 | TestBool tbStruct; 61 | JS::ParseContext boolContext(R"({ "member": [true] })"); 62 | REQUIRE(boolContext.parseTo(tbStruct) == JS::Error::NoError); 63 | 64 | std::string serializedTbStruct = JS::serializeStruct(tbStruct); 65 | REQUIRE(serializedTbStruct.size() != 0); 66 | } 67 | 68 | } // namespace json_struct_serialize_tuple 69 | -------------------------------------------------------------------------------- /tests/json-struct-small-test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "assert.h" 3 | 4 | struct SmallStruct 5 | { 6 | int a; 7 | float b; 8 | 9 | JS_OBJECT( 10 | JS_MEMBER(a), 11 | JS_MEMBER(b) 12 | ); 13 | }; 14 | 15 | const char json[] = R"json( 16 | { 17 | "a": 1, 18 | "b": 2.2 19 | } 20 | )json"; 21 | 22 | int main() 23 | { 24 | JS::ParseContext context(json); 25 | SmallStruct data; 26 | context.parseTo(data); 27 | JS_ASSERT(data.a == 1); 28 | JS_ASSERT(data.b > 2.199 && data.b < 2.201); 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /tests/json-struct-stdint.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright � 2022 Jorgen Lind 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided "as 12 | * is" without express or implied warranty. 13 | * 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | 26 | #include "catch2/catch.hpp" 27 | 28 | 29 | namespace 30 | { 31 | static const char json[] = R"json({ 32 | "int8": 4, 33 | "uint8": 5, 34 | "int16": "6", 35 | "uint16": "7", 36 | "int32": "8", 37 | "uint32": "9", 38 | "int64": "10", 39 | "uint64": "11" 40 | })json"; 41 | 42 | struct stdinttypes 43 | { 44 | int8_t int8; 45 | uint8_t uint8; 46 | int16_t int16; 47 | uint16_t uint16; 48 | int32_t int32; 49 | uint32_t uint32; 50 | int64_t int64; 51 | uint64_t uint64; 52 | JS_OBJ(int8, uint8, int16, uint16, int32, uint32, int64, uint64); 53 | }; 54 | TEST_CASE("js_std_int", "json_struct") 55 | { 56 | JS::ParseContext context(json, sizeof(json)); 57 | context.allow_missing_members = false; 58 | context.allow_unasigned_required_members = false; 59 | 60 | stdinttypes to_struct = {}; 61 | auto error = context.parseTo(to_struct); 62 | REQUIRE(error == JS::Error::NoError); 63 | REQUIRE(to_struct.int8 == 4); 64 | REQUIRE(to_struct.uint32 == 9); 65 | } 66 | 67 | TEST_CASE("large_number_roundtrip", "json_struct") 68 | { 69 | stdinttypes to_serialize = {}; 70 | to_serialize.uint64 = 0; 71 | to_serialize.uint64 = ~to_serialize.uint64; 72 | std::string serialized = JS::serializeStruct(to_serialize); 73 | JS::ParseContext context(serialized); 74 | 75 | stdinttypes to_struct; 76 | auto error = context.parseTo(to_struct); 77 | REQUIRE(error == JS::Error::NoError); 78 | 79 | REQUIRE(to_serialize.uint64 == to_struct.uint64); 80 | } 81 | } 82 | 83 | #if defined(__SIZEOF_INT128__) 84 | #define JS_INT_128 85 | #include 86 | namespace 87 | { 88 | struct very_large_int 89 | { 90 | JS::js_int128_t data; 91 | JS_OBJ(data); 92 | }; 93 | 94 | TEST_CASE("test_128_int", "json_struct") 95 | { 96 | very_large_int large_int; 97 | large_int.data = 1; 98 | large_int.data <<= 127; 99 | large_int.data = ~large_int.data; 100 | 101 | std::string large_int_json = JS::serializeStruct(large_int); 102 | 103 | very_large_int large_int_target; 104 | JS::ParseContext pc(large_int_json); 105 | auto error = pc.parseTo(large_int_target); 106 | 107 | REQUIRE(error == JS::Error::NoError); 108 | REQUIRE(large_int_target.data == large_int.data); 109 | } 110 | } 111 | #endif 112 | -------------------------------------------------------------------------------- /tests/json-struct-utf8.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright � 2021 Jorgen Lind 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided "as 12 | * is" without express or implied warranty. 13 | * 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | 23 | #include 24 | 25 | #include "catch2/catch.hpp" 26 | 27 | namespace 28 | { 29 | 30 | static const char json_data1[] = R"json({ 31 | "One": "j\u00f8rgen", 32 | "Two": "j\u00f8rgen\u00f8", 33 | "Three": "j\u00f8rgen\u012", 34 | "Four": "j\u00f8rgen\u01", 35 | "Five": "j\u00f8rgen\u0" 36 | })json"; 37 | 38 | struct Struct 39 | { 40 | std::string One; 41 | std::string Two; 42 | std::string Three; 43 | std::string Four; 44 | std::string Five; 45 | JS_OBJ(One, Two, Three, Four, Five); 46 | }; 47 | 48 | TEST_CASE("test_simple_utf8", "[json_struct][utf-8]") 49 | { 50 | JS::ParseContext context(json_data1); 51 | Struct substruct; 52 | auto error = context.parseTo(substruct); 53 | 54 | REQUIRE(error == JS::Error::NoError); 55 | REQUIRE(substruct.One == u8"j\u00f8rgen"); 56 | REQUIRE(substruct.Two == u8"j\u00f8rgen\u00f8"); 57 | REQUIRE(substruct.Three == u8"j\u00f8rgen\\u012"); 58 | REQUIRE(substruct.Four == u8"j\u00f8rgen\\u01"); 59 | REQUIRE(substruct.Five == u8"j\u00f8rgen\\u0"); 60 | } 61 | } // namespace 62 | -------------------------------------------------------------------------------- /tests/json-test-data.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2012 Jorgen Lind 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided \"as 12 | * is\" without express or implied warranty. 13 | * 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | 23 | #ifndef JSON_TEST_DATA_H 24 | #define JSON_TEST_DATA_H 25 | 26 | #include "assert.h" 27 | 28 | const char json_data1[] = 29 | "{\n" 30 | " \"foo\": \"bar\",\n" 31 | " \"color\": \"red\"\n" 32 | " weather: \"clear\"\n" 33 | " weather1 : \"clear1\"\n" 34 | " ToBeTrue: true,\n" 35 | " HeresANull : null\n" 36 | " ThisIsFalse: false,\n" 37 | "\n" 38 | " EscapedString: \"contains \\\"\",\n" 39 | " \"\\\"EscapedName\\\"\": true,\n" 40 | " \"EscapedProp\": \"\\\"Hello\\\"\",\n" 41 | " ThisIsANumber: 3.14\n" 42 | " ThisIsAnObject: {\n" 43 | " ThisIsASubType: \"red\"\n" 44 | " },\n" 45 | " AnotherProp: \"prop\"\n" 46 | " ThisIsAnotherObject: {\n" 47 | " ThisIsAnotherASubType: \"blue\"\n" 48 | " },\n" 49 | " ThisIsAnArray: [\n" 50 | " 12.4,\n" 51 | " 3,\n" 52 | " 43.2\n" 53 | " ]\n" 54 | " ThisIsAnObjectArray: [\n" 55 | " { Test1: \"Test2\", Test3: \"Test4\" },\n" 56 | " { Test5: true, Test7: false }\n" 57 | " ]\n" 58 | "}\n"; 59 | 60 | const char json_data2[] = 61 | "{\n" 62 | " \"StringNode\": \"Some test data\",\n" 63 | " \"NumberNode\": 4676.4,\n" 64 | " \"NullNode\": null,\n" 65 | " \"BooleanTrue\": true,\n" 66 | " \"BooleanFalse\": false,\n" 67 | " \"Object\": {\n" 68 | " \"SomeSubObjectProp\": \"RED\"\n" 69 | " },\n" 70 | " \"Array\": [\n" 71 | " \"String\",\n" 72 | " null,\n" 73 | " true,\n" 74 | " {\n" 75 | " \"SomeOtherObjectProp\": \"GREEN\"\n" 76 | " }\n" 77 | " ],\n" 78 | " \"LastStringNode\": \"More test data\"\n" 79 | "}\n"; 80 | 81 | #endif //JSON_TEST_DATA_H 82 | -------------------------------------------------------------------------------- /tests/json-timepoint.cpp: -------------------------------------------------------------------------------- 1 | #include "catch2/catch.hpp" 2 | 3 | #include 4 | #define JS_STD_TIMEPOINT 1 5 | #include 6 | 7 | namespace 8 | { 9 | 10 | using sys_tp_t = std::chrono::system_clock::time_point; 11 | using hpc_tp_t = std::chrono::high_resolution_clock::time_point; 12 | using t_s = std::chrono::seconds; 13 | using t_ms = std::chrono::milliseconds; 14 | using t_us = std::chrono::microseconds; 15 | using t_ns = std::chrono::nanoseconds; 16 | 17 | #define TP_0_S 1625409496 18 | #define TP_0_MS 1625409496000 19 | #define TP_0_US 1625409496000000 20 | #define TP_0_NS 1625409496000000000 21 | #define TP_1_S 1625409497 22 | #define TP_2_MS 1625409497002 23 | #define TP_3_US 1625409497002003 24 | #define TP_4_NS 1625409497002003004 25 | 26 | #define _STR_(x) #x 27 | #define _STR(x) _STR_(x) 28 | 29 | const char json[] = "{" 30 | "\"tp_0_s\" : " _STR(TP_0_S) "," 31 | "\"tp_0_ms\": " _STR(TP_0_MS) "," 32 | "\"tp_0_us\": " _STR(TP_0_US) "," 33 | "\"tp_0_ns\": " _STR(TP_0_NS) "," 34 | "\"tp_1_s\" : " _STR(TP_1_S) "," 35 | "\"tp_2_ms\": " _STR(TP_2_MS) "," 36 | "\"tp_3_us\": " _STR(TP_3_US) "," 37 | "\"tp_4_ns\": " _STR(TP_4_NS) 38 | "}"; 39 | 40 | struct JsonData 41 | { 42 | sys_tp_t tp_0_s; 43 | sys_tp_t tp_0_ms; 44 | sys_tp_t tp_0_us; 45 | hpc_tp_t tp_0_ns; 46 | sys_tp_t tp_1_s; 47 | sys_tp_t tp_2_ms; 48 | sys_tp_t tp_3_us; 49 | hpc_tp_t tp_4_ns; 50 | JS_OBJ(tp_0_s, tp_0_ms, tp_0_us, tp_0_ns, tp_1_s, tp_2_ms, tp_3_us, tp_4_ns); 51 | }; 52 | 53 | // Since tp_0_* have trailing zeroes, they should be removed when serializing, 54 | // parse the result of serializeStruct with keys that hold uint64_t values to check that. 55 | struct JsonData2 56 | { 57 | uint64_t tp_0_s; 58 | uint64_t tp_0_ms; 59 | uint64_t tp_0_us; 60 | uint64_t tp_0_ns; 61 | uint64_t tp_1_s; 62 | uint64_t tp_2_ms; 63 | uint64_t tp_3_us; 64 | uint64_t tp_4_ns; 65 | JS_OBJ(tp_0_s, tp_0_ms, tp_0_us, tp_0_ns, tp_1_s, tp_2_ms, tp_3_us, tp_4_ns); 66 | }; 67 | 68 | TEST_CASE("time_point", "json_struct") 69 | { 70 | JsonData dataStruct; 71 | JS::ParseContext parseContext(json); 72 | REQUIRE(parseContext.parseTo(dataStruct) == JS::Error::NoError); 73 | 74 | REQUIRE(dataStruct.tp_0_s == sys_tp_t{t_s {TP_0_S }}); 75 | REQUIRE(dataStruct.tp_0_ms == sys_tp_t{t_ms{TP_0_MS}}); 76 | REQUIRE(dataStruct.tp_0_us == sys_tp_t{t_us{TP_0_US}}); 77 | REQUIRE(dataStruct.tp_0_ns == hpc_tp_t{t_ns{TP_0_NS}}); 78 | REQUIRE(dataStruct.tp_1_s == sys_tp_t{t_s {TP_1_S }}); 79 | REQUIRE(dataStruct.tp_2_ms == sys_tp_t{t_ms{TP_2_MS}}); 80 | REQUIRE(dataStruct.tp_3_us == sys_tp_t{t_us{TP_3_US}}); 81 | REQUIRE(dataStruct.tp_4_ns == hpc_tp_t{t_ns{TP_4_NS}}); 82 | 83 | std::string genjson = JS::serializeStruct(dataStruct); 84 | JsonData dataStruct2; 85 | REQUIRE(memcmp(&dataStruct2, &dataStruct, sizeof(JsonData))); 86 | JS::ParseContext parseContext2(genjson); 87 | REQUIRE(parseContext2.parseTo(dataStruct2) == JS::Error::NoError); 88 | REQUIRE(dataStruct2.tp_0_s == sys_tp_t{t_s {TP_0_S }}); 89 | REQUIRE(dataStruct2.tp_0_ms == sys_tp_t{t_ms{TP_0_MS}}); 90 | REQUIRE(dataStruct2.tp_0_us == sys_tp_t{t_us{TP_0_US}}); 91 | REQUIRE(dataStruct2.tp_0_ns == hpc_tp_t{t_ns{TP_0_NS}}); 92 | REQUIRE(dataStruct2.tp_1_s == sys_tp_t{t_s {TP_1_S }}); 93 | REQUIRE(dataStruct2.tp_2_ms == sys_tp_t{t_ms{TP_2_MS}}); 94 | REQUIRE(dataStruct2.tp_3_us == sys_tp_t{t_us{TP_3_US}}); 95 | REQUIRE(dataStruct2.tp_4_ns == hpc_tp_t{t_ns{TP_4_NS}}); 96 | 97 | JsonData2 dataStruct3; 98 | JS::ParseContext parseContext3(genjson); 99 | REQUIRE(parseContext3.parseTo(dataStruct3) == JS::Error::NoError); 100 | REQUIRE(dataStruct3.tp_0_s == TP_0_S); 101 | REQUIRE(dataStruct3.tp_0_ms == TP_0_S); 102 | REQUIRE(dataStruct3.tp_0_us == TP_0_S); 103 | REQUIRE(dataStruct3.tp_0_ns == TP_0_S); 104 | REQUIRE(dataStruct3.tp_1_s == TP_1_S ); 105 | REQUIRE(dataStruct3.tp_2_ms == TP_2_MS); 106 | REQUIRE(dataStruct3.tp_3_us == TP_3_US); 107 | REQUIRE(dataStruct3.tp_4_ns == TP_4_NS); 108 | } 109 | } // namespace 110 | -------------------------------------------------------------------------------- /tests/json-tokenizer-invalid-json.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "tokenizer-test-util.h" 3 | 4 | #include "catch2/catch.hpp" 5 | 6 | namespace 7 | { 8 | static const char MESSAGE[] = R"html(\r\n 9 | 400 Bad Request\r\n 10 | \r\n 11 |

400 Bad Request

\r\n 12 |
cloudflare
\r\n 13 | \r\n 14 | \r\n)html"; 15 | TEST_CASE("html_to_tokenizer", "[tokenizer]") 16 | { 17 | JS::ParseContext context(MESSAGE); 18 | JS::Map outMap; 19 | JS::Error error = context.parseTo(outMap); 20 | std::string error_str = context.makeErrorString(); 21 | REQUIRE(error == JS::Error::EncounteredIllegalChar); 22 | REQUIRE(error_str.size()); 23 | } 24 | 25 | } -------------------------------------------------------------------------------- /tests/json-unordered-map.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "catch2/catch.hpp" 3 | 4 | #define JS_STL_UNORDERED_SET 5 | #include 6 | 7 | #define JS_STL_MAP 8 | #define JS_STL_SET 9 | #include 10 | namespace 11 | { 12 | 13 | const char json[] = R"json({ 14 | "unordered_map": { 15 | "foo": [ 1.0 ], 16 | "bar": [ 2.0 ] 17 | }, 18 | "map": { 19 | "hello": "world", 20 | "sail": "boat" 21 | }, 22 | "unordered_set": [9, 8, 7, 6], 23 | "set": [1.5, 1.6, 1.7, 1.8] 24 | })json"; 25 | 26 | struct JsonData 27 | { 28 | #ifdef JS_STD_UNORDERED_MAP 29 | std::unordered_map> unordered_map; 30 | std::unordered_set unordered_set; 31 | #else 32 | std::map> unordered_map; 33 | std::set unordered_set; 34 | #endif 35 | std::map map; 36 | std::set set; 37 | JS_OBJ(unordered_map, map, unordered_set, set); 38 | }; 39 | 40 | TEST_CASE("unordered_map_complex_value", "json_struct") 41 | { 42 | JsonData dataStruct; 43 | JS::ParseContext parseContext(json); 44 | REQUIRE(parseContext.parseTo(dataStruct) == JS::Error::NoError); 45 | 46 | REQUIRE(dataStruct.unordered_map["bar"].front() == 2.0);//-V550 47 | REQUIRE(dataStruct.map["sail"] == "boat"); 48 | REQUIRE(dataStruct.unordered_set.find(7) != dataStruct.unordered_set.end()); 49 | REQUIRE(dataStruct.set.find(1.6f) != dataStruct.set.end()); 50 | 51 | 52 | std::vector one; 53 | one.push_back(1.0); 54 | 55 | std::vector two; 56 | two.push_back(2.0); 57 | REQUIRE(dataStruct.unordered_map["foo"] == one); 58 | REQUIRE(dataStruct.unordered_map["bar"] == two); 59 | 60 | std::string genjson = JS::serializeStruct(dataStruct); 61 | 62 | JsonData dataStruct2; 63 | REQUIRE(dataStruct2.unordered_map != dataStruct.unordered_map); 64 | JS::ParseContext parseContext2(genjson); 65 | REQUIRE(parseContext2.parseTo(dataStruct2) == JS::Error::NoError); 66 | 67 | REQUIRE(dataStruct2.unordered_map == dataStruct.unordered_map); 68 | } 69 | } // namespace 70 | -------------------------------------------------------------------------------- /tests/members-size-test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2017 Jorgen Lind 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided "as 12 | * is" without express or implied warranty. 13 | * 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | 23 | #include 24 | 25 | #include "catch2/catch.hpp" 26 | 27 | namespace 28 | { 29 | 30 | struct A 31 | { 32 | int a; 33 | JS_OBJECT(JS_MEMBER(a)); 34 | }; 35 | 36 | struct B : public A 37 | { 38 | float b; 39 | JS_OBJECT_WITH_SUPER(JS_SUPER_CLASSES(JS_SUPER_CLASS(A)), JS_MEMBER(b)); 40 | }; 41 | 42 | struct D 43 | { 44 | unsigned char d; 45 | JS_OBJECT(JS_MEMBER(d)); 46 | }; 47 | 48 | struct E : public D 49 | { 50 | double e; 51 | JS_OBJECT_WITH_SUPER(JS_SUPER_CLASSES(JS_SUPER_CLASS(D)), JS_MEMBER(e)); 52 | }; 53 | 54 | struct F : public E 55 | { 56 | short f; 57 | JS_OBJECT_WITH_SUPER(JS_SUPER_CLASSES(JS_SUPER_CLASS(E)), JS_MEMBER(f)); 58 | }; 59 | struct G 60 | { 61 | char g; 62 | JS_OBJECT(JS_MEMBER(g)); 63 | }; 64 | 65 | struct Subclass : public B, public F, public G 66 | { 67 | unsigned int h; 68 | JS_OBJECT_WITH_SUPER(JS_SUPER_CLASSES(JS_SUPER_CLASS(B), JS_SUPER_CLASS(F), JS_SUPER_CLASS(G)), JS_MEMBER(h)); 69 | }; 70 | 71 | TEST_CASE("members_size", "[json_struct]") 72 | { 73 | size_t member_count = JS::Internal::memberCount(); 74 | REQUIRE(member_count == 7); 75 | int array[JS::Internal::memberCount()]; 76 | for (size_t i = 0; i < JS::Internal::memberCount(); i++) 77 | { 78 | array[i] = static_cast(i); 79 | } 80 | for (int i = 0; i < int(JS::Internal::memberCount()); i++) 81 | { 82 | REQUIRE(array[i] == i); 83 | } 84 | 85 | } 86 | } // namespace 87 | -------------------------------------------------------------------------------- /tests/meta-for-tokens.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "catch2/catch.hpp" 4 | 5 | namespace 6 | { 7 | 8 | const char json_string[] = R"json( 9 | [ 10 | { 11 | "member_one": "hello world", 12 | "member_two": [ 5, 6, 7, 8, 9], 13 | "member_three": { 14 | "member_three_sub_one": 5, 15 | "member_three_sub_two": null, 16 | "member_three_sub_three": [ "hello", "world", "bye"] 17 | }, 18 | "member_four": true 19 | }, 20 | { 21 | "first_member": false, 22 | "second_member": "sky is blue", 23 | "third_member": "grass is green", 24 | "fourth_member": [10, 20, 30, 40, 50] 25 | }, 26 | { 27 | "last_obj": true 28 | } 29 | ] 30 | )json"; 31 | 32 | TEST_CASE("testMetaForTokens", "[meta]") 33 | { 34 | JS::ParseContext context(json_string); 35 | JS::JsonTokens tokens; 36 | auto error = context.parseTo(tokens); 37 | REQUIRE(error == JS::Error::NoError); 38 | 39 | std::vector metaInfo = JS::metaForTokens(tokens); 40 | REQUIRE(metaInfo.size()); 41 | REQUIRE(!metaInfo[3].is_array); 42 | JS::Token token = tokens.data.at(metaInfo.at(3).position); 43 | REQUIRE(std::string("member_three") == std::string(token.name.data, token.name.size)); 44 | token = tokens.data.at(metaInfo.at(3).position + metaInfo.at(3).size); 45 | REQUIRE(std::string("member_four") == std::string(token.name.data, token.name.size)); 46 | token = tokens.data.at(metaInfo.at(6).position); 47 | REQUIRE(std::string("fourth_member") == std::string(token.name.data, token.name.size)); 48 | REQUIRE((1 + metaInfo.at(1).skip + metaInfo.at(1 + metaInfo.at(1).skip).skip) == 7); 49 | } 50 | 51 | } // namespace 52 | -------------------------------------------------------------------------------- /tests/multi-compilation-units-1.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2020 Øystein Myrmo 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided "as 12 | * is" without express or implied warranty. 13 | * 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | 23 | #include "catch2/catch.hpp" 24 | #include 25 | #include 26 | 27 | namespace multiple_compilation_units 28 | { 29 | struct Json1 30 | { 31 | float num1; 32 | double num2; 33 | 34 | JS_OBJECT(JS_MEMBER(num1), JS_MEMBER(num2)); 35 | }; 36 | 37 | std::string serialize_json1(float num1, double num2) 38 | { 39 | Json1 json1{num1, num2}; 40 | return JS::serializeStruct(json1); 41 | } 42 | 43 | bool deserialize_json1(const std::string &json) 44 | { 45 | JS::ParseContext pc(json); 46 | Json1 json1; 47 | auto error = pc.parseTo(json1); 48 | REQUIRE(error == JS::Error::NoError); 49 | return pc.error == JS::Error::NoError; 50 | } 51 | } // namespace multiple_compilation_units 52 | -------------------------------------------------------------------------------- /tests/multi-compilation-units-2.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2020 Øystein Myrmo 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided "as 12 | * is" without express or implied warranty. 13 | * 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | 23 | #include "catch2/catch.hpp" 24 | #include 25 | #include 26 | 27 | namespace multiple_compilation_units 28 | { 29 | struct Json2 30 | { 31 | float num1; 32 | double num2; 33 | 34 | JS_OBJECT(JS_MEMBER(num1), JS_MEMBER(num2)); 35 | }; 36 | 37 | std::string serialize_json2(float num1, double num2) 38 | { 39 | Json2 json2{num1, num2}; 40 | return JS::serializeStruct(json2); 41 | } 42 | 43 | bool deserialize_json2(const std::string &json) 44 | { 45 | JS::ParseContext pc(json); 46 | Json2 json2; 47 | auto error = pc.parseTo(json2); 48 | REQUIRE(error == JS::Error::NoError); 49 | return pc.error == JS::Error::NoError; 50 | } 51 | } // namespace multiple_compilation_units 52 | -------------------------------------------------------------------------------- /tests/multi-compilation-units-main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2020 Øystein Myrmo 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided "as 12 | * is" without express or implied warranty. 13 | * 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | 23 | #include "catch2/catch.hpp" 24 | #include 25 | #include 26 | 27 | namespace multiple_compilation_units 28 | { 29 | const char json_data1[] = R"json( 30 | { 31 | "num1": 1.234, 32 | "num2": 5.678 33 | } 34 | )json"; 35 | 36 | const char json_data2[] = R"json( 37 | { 38 | "num1": 4.321, 39 | "num2": 8.765 40 | } 41 | )json"; 42 | 43 | extern std::string serialize_json1(float num1, double num2); 44 | extern bool deserialize_json1(const std::string &json); 45 | extern std::string serialize_json2(float num1, double num2); 46 | extern bool deserialize_json2(const std::string &json); 47 | 48 | TEST_CASE("test_multiple_compilation_units", "[json_struct]") 49 | { 50 | std::string json1 = serialize_json1(1.111f, 2.222); 51 | std::string json2 = serialize_json2(1.111f, 2.222); 52 | REQUIRE(json1 == json2); 53 | 54 | bool ok1 = deserialize_json1(json_data1); 55 | bool ok2 = deserialize_json2(json_data2); 56 | REQUIRE(ok1); 57 | REQUIRE(ok2); 58 | } 59 | } // namespace multiple_compilation_units 60 | -------------------------------------------------------------------------------- /tests/tokenizer-test-util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2012 Jorgen Lind 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided "as 12 | * is" without express or implied warranty. 13 | * 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include "assert.h" 25 | #include 26 | 27 | inline int assert_token(const JS::Token &token, JS::Type name_type, std::string property, JS::Type value_type, std::string value) 28 | { 29 | if (token.name_type != name_type) { 30 | fprintf(stderr, "token.name_type is: %d, expected %d\n", int(token.name_type), int(name_type)); 31 | return -1; 32 | } 33 | 34 | if (token.name.size != property.size()) { 35 | fprintf(stderr, "token.name_length is: %zu, expected: %zu\n", token.name.size, property.size()); 36 | return -1; 37 | } 38 | std::string token_property(token.name.data, token.name.size); 39 | if (property.compare(token_property) != 0) { 40 | std::string name(token.name.data, token.name.size); 41 | fprintf(stderr, "token.property: %s is unequal to %s\n", name.c_str(), property.c_str()); 42 | return -1; 43 | } 44 | 45 | if (token.value_type != value_type) { 46 | fprintf(stderr, "token.value_type is: %d, expected %d\n", int(token.value_type), int(value_type)); 47 | return -1; 48 | } 49 | 50 | std::string token_value(token.value.data, token.value.size); 51 | if (value.compare(token_value) != 0) { 52 | std::string value_name(token.value.data, token.value.size); 53 | fprintf(stderr, "token.value: %s is unequal to %s\n", value_name.c_str(), value.c_str()); 54 | return -1; 55 | } 56 | 57 | if (token.value.size != value.size()) { 58 | fprintf(stderr, "token.value_length is: %zu, expected: %zu\n", token.value.size, value.size()); 59 | return -1; 60 | } 61 | return 0; 62 | } 63 | -------------------------------------------------------------------------------- /tests/zero-value-test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2020 Øystein Myrmo 3 | * 4 | * Permission to use, copy, modify, distribute, and sell this software and its 5 | * documentation for any purpose is hereby granted without fee, provided that 6 | * the above copyright notice appear in all copies and that both that copyright 7 | * notice and this permission notice appear in supporting documentation, and 8 | * that the name of the copyright holders not be used in advertising or 9 | * publicity pertaining to distribution of the software without specific, 10 | * written prior permission. The copyright holders make no representations 11 | * about the suitability of this software for any purpose. It is provided "as 12 | * is" without express or implied warranty. 13 | * 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 | * OF THIS SOFTWARE. 21 | */ 22 | 23 | #include 24 | 25 | #define CATCH_CONFIG_MAIN 26 | 27 | #include "catch2/catch.hpp" 28 | 29 | namespace 30 | { 31 | 32 | const char json_data[] = R"json( 33 | { 34 | "f_pos_zero": 0, 35 | "f_neg_zero": -0, 36 | "d_pos_zero": 0, 37 | "d_neg_zero": -0 38 | } 39 | )json"; 40 | 41 | const char json_data_decimal[] = R"json( 42 | { 43 | "f_pos_zero": 0.0, 44 | "f_neg_zero": -0.0, 45 | "d_pos_zero": 0.0, 46 | "d_neg_zero": -0.0 47 | } 48 | )json"; 49 | 50 | const char json_data_scientific[] = R"json( 51 | { 52 | "f_pos_zero": 0e0, 53 | "f_neg_zero": -0e0, 54 | "d_pos_zero": 0e0, 55 | "d_neg_zero": -0e0 56 | } 57 | )json"; 58 | 59 | struct ZeroValueStruct 60 | { 61 | float f_pos_zero; 62 | float f_neg_zero; 63 | double d_pos_zero; 64 | double d_neg_zero; 65 | 66 | JS_OBJECT(JS_MEMBER(f_pos_zero), JS_MEMBER(f_neg_zero), JS_MEMBER(d_pos_zero), JS_MEMBER(d_neg_zero)); 67 | }; 68 | 69 | // Notes: 70 | // - This function is not tested on systems where double is 4 bytes. 71 | // - The data is also cast to integer types for asserting since 0.0 normally is equal to -0.0. 72 | void test_zero_value_parse(const char *const json) 73 | { 74 | static float f_pos_zero = 0.0f; 75 | static float f_neg_zero = -0.0; 76 | static double d_pos_zero = 0.0; 77 | static double d_neg_zero = -0.0; 78 | 79 | ZeroValueStruct zero; 80 | JS::ParseContext pc(json); 81 | pc.parseTo(zero); 82 | REQUIRE(pc.error == JS::Error::NoError); 83 | 84 | REQUIRE(zero.f_pos_zero == f_pos_zero);//-V550 85 | REQUIRE(zero.f_neg_zero == f_neg_zero);//-V550 86 | REQUIRE(zero.d_pos_zero == d_pos_zero);//-V550 87 | REQUIRE(zero.d_neg_zero == d_neg_zero);//-V550 88 | 89 | REQUIRE(memcmp(&f_pos_zero, &zero.f_pos_zero, sizeof(float)) == 0); 90 | REQUIRE(memcmp(&f_neg_zero, &zero.f_neg_zero, sizeof(float)) == 0); 91 | REQUIRE(memcmp(&d_pos_zero, &zero.d_pos_zero, sizeof(double)) == 0); 92 | REQUIRE(memcmp(&d_neg_zero, &zero.d_neg_zero, sizeof(double)) == 0); 93 | 94 | // -------------------------- 95 | // Keeping this code to debug on GCC later. foo2 == bar2 fails! 96 | // auto foo1 = 97 | // *reinterpret_cast::uint_alias*>(&zero.f_pos_zero); auto foo2 98 | // = *reinterpret_cast::uint_alias*>(&zero.f_neg_zero); auto 99 | // foo3 = *reinterpret_cast::uint_alias*>(&zero.d_pos_zero); 100 | // auto foo4 = 101 | // *reinterpret_cast::uint_alias*>(&zero.d_neg_zero); 102 | 103 | // auto bar1 = *reinterpret_cast::uint_alias*>(&f_pos_zero); 104 | // auto bar2 = *reinterpret_cast::uint_alias*>(&f_neg_zero); 105 | // auto bar3 = *reinterpret_cast::uint_alias*>(&d_pos_zero); 106 | // auto bar4 = *reinterpret_cast::uint_alias*>(&d_neg_zero); 107 | 108 | // REQUIRE(foo1 == bar1); 109 | // REQUIRE(foo2 == bar2); 110 | // REQUIRE(foo3 == bar3); 111 | // REQUIRE(foo4 == bar4); 112 | // -------------------------- 113 | } 114 | 115 | TEST_CASE("test_zero_value", "[float conversion]") 116 | { 117 | test_zero_value_parse(json_data); 118 | test_zero_value_parse(json_data_decimal); 119 | test_zero_value_parse(json_data_scientific); 120 | } 121 | 122 | } // namespace 123 | --------------------------------------------------------------------------------