From 7fdf322c587580c1b0fd645a6a19edf3b9c0027f Mon Sep 17 00:00:00 2001 From: RealTimeChris <40668522+RealTimeChris@users.noreply.github.com> Date: Fri, 15 Sep 2023 02:34:09 -0400 Subject: [PATCH] Jsonifier Release v0.9.9 - Pre-merge -Modified some concepts. -Modified the DetectArchitecture.cmake script. -Also adding a couple of concepts. -Implemented a bunch of compile-time loops instead of runtime ones. -Implemented a new find function for the string classes. -Also added a couple of concepts. -Removed a bunch of superfluous constructors/destructors/copy/move operators. -Updated some of the integer-postfixes. -Switched to camel-case for types, and concepts. -Modified the DetectArchitecture.cmake script. -Added the check for the lzcnt instruction. -Added a universal fallback tzcnt function. -Modified the string class. -Removed a few unnecessary explicit template parameters. -Implemented the new SelectMenuDefaultValues type. -Improved the ISADetection headers, by splitting it into multiple different headers. -Added an implementation for parsing tuple-array-types. -Moved the concepts out into their own header. --- .github/workflows/CLANG_18-Ubuntu.yml | 8 +- .github/workflows/GCC_13-MacOS.yml | 8 +- .github/workflows/MSVC_2022-Windows.yml | 8 +- BuildTools/Classes/Packager/Vcpkg.php | 2 +- CMake/CollectVersion.cmake | 48 + CMake/DetectArchitecture.cmake | 69 - CMake/JsonifierConfig.cmake.in | 2 +- CMake/JsonifierDetectArchitecture.cmake | 115 ++ CMakeLists.txt | 59 +- CMakePresets.json | 68 +- Documentation/Doxyfile | 4 +- Include/jsonifier/Allocator.hpp | 46 +- Include/jsonifier/Base.hpp | 409 ++--- Include/jsonifier/Compare.hpp | 648 ++----- Include/jsonifier/Concepts.hpp | 291 +++ Include/jsonifier/Derailleur.hpp | 99 +- Include/jsonifier/Error.hpp | 6 +- Include/jsonifier/Expected.hpp | 143 +- Include/jsonifier/HashMap.hpp | 508 +++--- Include/jsonifier/ISADetection.hpp | 1625 +---------------- Include/jsonifier/ISADetection/AVX.hpp | 262 +++ Include/jsonifier/ISADetection/AVX2.hpp | 281 +++ Include/jsonifier/ISADetection/AVX512.hpp | 335 ++++ Include/jsonifier/ISADetection/Bmi.hpp | 85 + Include/jsonifier/ISADetection/Fallback.hpp | 440 +++++ .../ISADetection/ISADetectionBase.hpp | 113 ++ Include/jsonifier/ISADetection/Lzcount.hpp | 64 + .../{Core.hpp => ISADetection/Popcount.hpp} | 38 +- Include/jsonifier/Index.hpp | 11 +- Include/jsonifier/Iterator.hpp | 50 +- Include/jsonifier/JsonifierCore.hpp | 6 +- Include/jsonifier/NumberUtils.hpp | 479 +++-- Include/jsonifier/Pair.hpp | 22 +- Include/jsonifier/Parse_Impl.hpp | 329 ++-- Include/jsonifier/Parser.hpp | 65 +- Include/jsonifier/RawArray.hpp | 54 +- Include/jsonifier/RawJsonData.hpp | 55 +- Include/jsonifier/RawVector.hpp | 32 +- Include/jsonifier/Serialize_Impl.hpp | 366 ++-- Include/jsonifier/Serializer.hpp | 33 +- Include/jsonifier/Simd.hpp | 243 ++- Include/jsonifier/String.hpp | 576 ++---- Include/jsonifier/StringUtils.hpp | 60 +- Include/jsonifier/StringView.hpp | 203 +- Include/jsonifier/StructuralIterator.hpp | 59 +- Include/jsonifier/Tables.hpp | 96 +- Include/jsonifier/Tuple.hpp | 352 ++-- Include/jsonifier/Vector.hpp | 126 +- ReadMe.md | 62 +- Tests/CMakeLists.txt | 29 +- Tests/main.cpp | 448 +++-- Vcpkg/ports/jsonifier/portfile.cmake | 2 +- Vcpkg/ports/jsonifier/vcpkg.json | 4 +- Vcpkg/versions/j-/jsonifier.json | 7 +- 54 files changed, 4691 insertions(+), 4862 deletions(-) create mode 100644 CMake/CollectVersion.cmake delete mode 100644 CMake/DetectArchitecture.cmake create mode 100644 CMake/JsonifierDetectArchitecture.cmake create mode 100644 Include/jsonifier/Concepts.hpp create mode 100644 Include/jsonifier/ISADetection/AVX.hpp create mode 100644 Include/jsonifier/ISADetection/AVX2.hpp create mode 100644 Include/jsonifier/ISADetection/AVX512.hpp create mode 100644 Include/jsonifier/ISADetection/Bmi.hpp create mode 100644 Include/jsonifier/ISADetection/Fallback.hpp create mode 100644 Include/jsonifier/ISADetection/ISADetectionBase.hpp create mode 100644 Include/jsonifier/ISADetection/Lzcount.hpp rename Include/jsonifier/{Core.hpp => ISADetection/Popcount.hpp} (53%) diff --git a/.github/workflows/CLANG_18-Ubuntu.yml b/.github/workflows/CLANG_18-Ubuntu.yml index 46aa8dc3b..15629db19 100644 --- a/.github/workflows/CLANG_18-Ubuntu.yml +++ b/.github/workflows/CLANG_18-Ubuntu.yml @@ -28,17 +28,17 @@ jobs: sudo ./llvm.sh 18 - name: Configure CMake - working-directory: Tests + working-directory: ./ run: | - cmake -S . -B ./Build -DCMAKE_BUILD_TYPE=${{matrix.build_type}} -DCMAKE_CXX_COMPILER=/usr/bin/clang++-18 -DGITHUB_BRANCH_TYPE=${{github.ref}} + cmake -S . -B ./Build -DCMAKE_BUILD_TYPE=${{matrix.build_type}} -DCMAKE_CXX_COMPILER=/usr/bin/clang++-18 -DDEV=true -DJSONIFIER_TEST=true - name: Build the Test - working-directory: Tests/Build + working-directory: ./Build run: | cmake --build . --config=${{matrix.build_type}} - name: Run the Test - working-directory: Tests/Build + working-directory: ./Build/Tests run: | ./Json-Performance continue-on-error: true \ No newline at end of file diff --git a/.github/workflows/GCC_13-MacOS.yml b/.github/workflows/GCC_13-MacOS.yml index 4be90ce9d..f47e57949 100644 --- a/.github/workflows/GCC_13-MacOS.yml +++ b/.github/workflows/GCC_13-MacOS.yml @@ -25,18 +25,18 @@ jobs: brew install gcc - name: Configure CMake - working-directory: Tests + working-directory: ./ run: | - cmake -S . -B ./Build -DCMAKE_BUILD_TYPE=${{matrix.build_type}} -DCMAKE_CXX_COMPILER=/usr/local/opt/gcc@13/bin/g++-13 -DGITHUB_BRANCH_TYPE=${{github.ref}} + cmake -S . -B ./Build -DCMAKE_BUILD_TYPE=${{matrix.build_type}} -DCMAKE_CXX_COMPILER=/usr/local/opt/gcc@13/bin/g++-13 -DDEV=true -DJSONIFIER_TEST=true - name: Build the Test - working-directory: Tests/Build + working-directory: ./Build run: | cmake --build . --config=${{matrix.build_type}} - name: Run the Test - working-directory: Tests/Build + working-directory: ./Build/Tests run: | ./Json-Performance continue-on-error: true diff --git a/.github/workflows/MSVC_2022-Windows.yml b/.github/workflows/MSVC_2022-Windows.yml index 136c1dd4f..b9add8697 100644 --- a/.github/workflows/MSVC_2022-Windows.yml +++ b/.github/workflows/MSVC_2022-Windows.yml @@ -27,17 +27,17 @@ jobs: value: $env:PATH;C:/Program Files/Microsoft Visual Studio/2022/Enterprise/VC/Auxiliary/Build - name: Configure CMake - working-directory: Tests + working-directory: ./ run: | - cmake -S . -B ./Build -DCMAKE_BUILD_TYPE=${{matrix.build_type}} -DGITHUB_BRANCH_TYPE=${{github.ref}} + cmake -S . -B ./Build -DCMAKE_BUILD_TYPE=${{matrix.build_type}} -DDEV=true -DJSONIFIER_TEST=true - name: Build the Test - working-directory: Tests/Build + working-directory: ./Build run: | cmake --build . --config=${{matrix.build_type}} - name: Run the Test - working-directory: Tests/Build/${{matrix.build_type}}/ + working-directory: ./Build/Tests/${{matrix.build_type}} run: | ./Json-Performance.exe continue-on-error: true diff --git a/BuildTools/Classes/Packager/Vcpkg.php b/BuildTools/Classes/Packager/Vcpkg.php index ee8137159..5ad532b5e 100644 --- a/BuildTools/Classes/Packager/Vcpkg.php +++ b/BuildTools/Classes/Packager/Vcpkg.php @@ -159,7 +159,7 @@ function constructPortAndVersionFile(string $sha512 = "0"): string "description": "A few classes for parsing and serializing json - very rapidly.", "homepage": "https://github.com/realtimechris/jsonifier", "license": "MIT", - "supports": "(windows & x64 & !uwp & !xbox) | (linux & x64) | (osx & x64)", + "supports": "(windows & x64 & !xbox) | (linux & x64) | (osx & x64)", "dependencies": [ { "name": "vcpkg-cmake", diff --git a/CMake/CollectVersion.cmake b/CMake/CollectVersion.cmake new file mode 100644 index 000000000..d0b27973b --- /dev/null +++ b/CMake/CollectVersion.cmake @@ -0,0 +1,48 @@ +# +# DiscordCoreAPI, A bot library for Discord, written in C++, and featuring explicit multithreading through the usage of custom, asynchronous C++ CoRoutines. +# +# Copyright 2021, 2022, 2023 Chris M. (RealTimeChris) +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# USA +# +# CollectVersion.cmake - The script for collecting the library's version.. +# May 13, 2021 +# https://discordcoreapi.com + +function(collect_version project_name) + + set(PRODUCT_VERSION "") + file(READ "${CMAKE_CURRENT_SOURCE_DIR}/Vcpkg/ports/${project_name}/vcpkg.json" JSON_STRING) + foreach(IDX RANGE 1) + string(JSON PRODUCT_VERSION GET "${JSON_STRING}" "version") + endforeach() + string(REPLACE "." ";" PRODUCT_VERSION_LIST "${PRODUCT_VERSION}") + list(GET PRODUCT_VERSION_LIST 0 VERSION_MAJOR) + list(APPEND PRODUCT_VERSION_NEW "${VERSION_MAJOR}") + set(VERSION_MAJOR "${VERSION_MAJOR}" PARENT_SCOPE) + list(GET PRODUCT_VERSION_LIST 1 VERSION_MINOR) + list(APPEND PRODUCT_VERSION_NEW "${VERSION_MINOR}") + set(VERSION_MINOR "${VERSION_MINOR}" PARENT_SCOPE) + list(LENGTH PRODUCT_VERSION_LIST LIST_SIZE) + if (LIST_SIZE GREATER 2) + list(GET PRODUCT_VERSION_LIST 2 VERSION_PATCH) + set(VERSION_PATCH "${VERSION_PATCH}" PARENT_SCOPE) + list(APPEND PRODUCT_VERSION_NEW "${VERSION_PATCH}") + endif() + string(REPLACE ";" "." PRODUCT_VERSION_NEW "${PRODUCT_VERSION_NEW}") + set(PRODUCT_VERSION "${PRODUCT_VERSION_NEW}" PARENT_SCOPE) + +endfunction() \ No newline at end of file diff --git a/CMake/DetectArchitecture.cmake b/CMake/DetectArchitecture.cmake deleted file mode 100644 index 5a823325e..000000000 --- a/CMake/DetectArchitecture.cmake +++ /dev/null @@ -1,69 +0,0 @@ -include(CheckCXXSourceRuns) - -function(check_instruction_set INSTRUCTION_SET_NAME INSTRUCTION_SET_FLAG INSTRUCTION_SET_INTRINSIC) - - set(INSTRUCTION_SET_CODE " - #include - #include - int main() - { - ${INSTRUCTION_SET_INTRINSIC}; - return 0; - } - ") - - set(CMAKE_REQUIRED_FLAGS "${INSTRUCTION_SET_FLAG}") - CHECK_CXX_SOURCE_RUNS("${INSTRUCTION_SET_CODE}" "${INSTRUCTION_SET_NAME}") - if(${INSTRUCTION_SET_NAME}) - set(AVX_FLAG "${INSTRUCTION_SET_FLAG}" PARENT_SCOPE) - set(AVX_TYPE "${INSTRUCTION_SET_NAME}" PARENT_SCOPE) - else() - message(STATUS "Instruction set ${INSTRUCTION_SET_NAME} not supported. Falling back to the previous instruction set.") - return() - endif() -endfunction() - -if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") - set(INSTRUCTION_SETS - "T_AVX?/arch:AVX?auto result = _mm_testz_ps(__m128{}, __m128{})" - "T_AVX2?/arch:AVX2?auto result = _mm256_add_epi32(__m256i{}, __m256i{})" - "T_AVX512?/arch:AVX512?auto result = _mm512_add_ps(__m512i{}, __m512i{}).auto result2 = _mm512_cmplt_epu8_mask(__m512i{}, __m512i{})" - ) -elseif(APPLE) - set(INSTRUCTION_SETS - "T_AVX?-mavx.-mpclmul.-mbmi.-mlzcnt?auto result = _mm_testz_ps(__m128{}, __m128{}).auto result2 = _blsr_u64(std::uint64_t{})" - "T_AVX2?-mavx2.-mavx.-mpclmul.-mbmi.-mlzcnt?auto result = _mm256_add_epi32(__m256i{}, __m256i{})" - "T_AVX512?-mavx512bw.-mavx512f.-mavx2.-mavx.-mpclmul.-mbmi.-mlzcnt?auto result = _mm512_add_ps(__m512i{}, __m512i{}).auto result2 = _mm512_cmplt_epu8_mask(__m512i{}, __m512i{})" - ) -else() - set(INSTRUCTION_SETS - "T_AVX?-mavx.-mpclmul.-mbmi.-mlzcnt?auto result = _mm_testz_ps(__m128{}, __m128{})" - "T_AVX2?-mavx2.-mavx.-mpclmul.-mbmi.-mlzcnt?auto result = _mm256_add_epi32(__m256i{}, __m256i{})" - "T_AVX512?-mavx512bw.-mavx512f.-mavx2.-mavx.-mpclmul.-mbmi.-mlzcnt?auto result = _mm512_add_ps(__m512i{}, __m512i{}).auto result2 = _mm512_cmplt_epu8_mask(__m512i{}, __m512i{})" - ) -endif() - -set(CMAKE_REQUIRED_FLAGS_SAVE "${CMAKE_REQUIRED_FLAGS}") - -set(AVX_FLAG "-march=native") -set(AVX_TYPE "T_Fallback") - -if ((${CMAKE_SYSTEM_PROCESSOR} MATCHES "x86_64") OR (${CMAKE_SYSTEM_PROCESSOR} MATCHES "i386") OR (${CMAKE_SYSTEM_PROCESSOR} MATCHES "AMD64")) - - foreach(INSTRUCTION_SET IN LISTS INSTRUCTION_SETS) - string(REPLACE "?" ";" CURRENT_LIST "${INSTRUCTION_SET}") - list(GET CURRENT_LIST 0 INSTRUCTION_SET_NAME) - list(GET CURRENT_LIST 1 INSTRUCTION_SET_FLAG) - string(REPLACE "." ";" INSTRUCTION_SET_FLAG "${INSTRUCTION_SET_FLAG}") - list(GET CURRENT_LIST 2 INSTRUCTION_SET_INTRINSIC) - string(REPLACE "." ";" INSTRUCTION_SET_INTRINSIC "${INSTRUCTION_SET_INTRINSIC}") - check_instruction_set("${INSTRUCTION_SET_NAME}" "${INSTRUCTION_SET_FLAG}" "${INSTRUCTION_SET_INTRINSIC}") - endforeach() - - string(REPLACE "T_" "" AVX_DISPLAY ${AVX_TYPE}) - message(STATUS "Detected CPU Architecture: ${AVX_DISPLAY}") -else() - message(STATUS "SSE not supported by architecture ${CMAKE_SYSTEM_PROCESSOR}") -endif() - -set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS_SAVE}") \ No newline at end of file diff --git a/CMake/JsonifierConfig.cmake.in b/CMake/JsonifierConfig.cmake.in index fb7eae6ad..d7e664637 100644 --- a/CMake/JsonifierConfig.cmake.in +++ b/CMake/JsonifierConfig.cmake.in @@ -1,6 +1,6 @@ @PACKAGE_INIT@ -set_and_check(EXPORT_TARGETS_FILE_NEW "@PACKAGE_EXPORTED_TARGETS_FILE_PATH@") +set_and_check(EXPORT_TARGETS_FILE_NEW "@PACKAGE_EXPORTED_TARGETS_FILE_PATH@") include("${EXPORT_TARGETS_FILE_NEW}") diff --git a/CMake/JsonifierDetectArchitecture.cmake b/CMake/JsonifierDetectArchitecture.cmake new file mode 100644 index 000000000..6290b3f06 --- /dev/null +++ b/CMake/JsonifierDetectArchitecture.cmake @@ -0,0 +1,115 @@ +# MIT License +# +# Copyright (c) 2023 RealTimeChris +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of this +# software and associated documentation files (the "Software"), to deal in the Software +# without restriction, including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, and to permit +# persons to whom the Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all copies or +# substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +# FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# JsonifierDetectArchitecture.cmake - Script for detecting the CPU architecture. +# Sept 18, 2023 +# https://discordcoreapi.com +include(CheckCXXSourceRuns) + +function(jsonifier_check_instruction_set INSTRUCTION_SET_NAME INSTRUCTION_SET_IN_FLAG INSTRUCTION_SET_OUT_FLAG INSTRUCTION_SET_INTRINSIC) + set(INSTRUCTION_SET_CODE " + #include + #include + + int32_t main() + { + ${INSTRUCTION_SET_INTRINSIC}; + return 0; + }") + + set(CMAKE_REQUIRED_FLAGS "${INSTRUCTION_SET_IN_FLAG}") + set(CHECK_RESULT_VAR "${INSTRUCTION_SET_NAME}") + CHECK_CXX_SOURCE_RUNS("${INSTRUCTION_SET_CODE}" "JSONIFIER-${CHECK_RESULT_VAR}") + if(JSONIFIER-${CHECK_RESULT_VAR}) + set(${INSTRUCTION_SET_NAME} "${INSTRUCTION_SET_OUT_FLAG}" PARENT_SCOPE) + list(APPEND JSONIFIER_CPU_INSTRUCTIONS "${INSTRUCTION_SET_NAME}") + string(REPLACE ";" "," JSONIFIER_CPU_INSTRUCTIONS "${JSONIFIER_CPU_INSTRUCTIONS}") + set(JSONIFIER_CPU_INSTRUCTIONS "${JSONIFIER_CPU_INSTRUCTIONS}" PARENT_SCOPE) + else() + message(STATUS "Instruction set ${INSTRUCTION_SET_NAME} not supported.") + return() + endif() +endfunction() + +set(INSTRUCTION_SET_NAMES "POPCNT" "LZCNT" "BMI" "AVX" "AVX2" "AVX512") +set (INSTRUCTION_SET_CODE + "auto result = _mm_popcnt_u64(uint64_t{})" + "auto result = _lzcnt_u64(int64_t{})" + "auto result = _blsr_u64(uint64_t{})" + "auto result = _mm_castsi128_pd(__m128i{}).auto result02 = _mm_setzero_si128()" + "auto result = _mm256_add_epi32(__m256i{}, __m256i{})" + "auto result = _mm512_add_ps(__m512i{}, __m512i{}).auto result2 = _mm512_cmplt_epu8_mask(__m512i{}, __m512i{}).auto result03 = _mm_abs_epi64 (__m128i{})" +) + +set(INDEX_SET "0" "1" "2" "3" "4" "5") + +if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + set(INSTRUCTION_SET_IN_FLAGS "/arch:AVX" "/arch:AVX" "/arch:AVX" "/arch:AVX" "/arch:AVX2" "/arch:AVX512") + set(INSTRUCTION_SET_OUT_FLAGS "/arch:AVX" "/arch:AVX" "/arch:AVX" "/arch:AVX" "/arch:AVX2" "/arch:AVX512") +else() + set(INSTRUCTION_SET_IN_FLAGS "-march=native" "-march=native" "-march=native" "-march=native" "-march=native" "-march=native") + set(INSTRUCTION_SET_OUT_FLAGS "-mpopcnt" "-mlzcnt" "-mbmi" "-mavx.-mpclmul" "-mavx2.-mpclmul" "-mavx512f.-mavx512bw.-mavx512vl.-mpclmul") +endif() + +set(CMAKE_REQUIRED_FLAGS_SAVE "${CMAKE_REQUIRED_FLAGS}") + +if ((${CMAKE_SYSTEM_PROCESSOR} MATCHES "x86_64") OR (${CMAKE_SYSTEM_PROCESSOR} MATCHES "i386") OR (${CMAKE_SYSTEM_PROCESSOR} MATCHES "AMD64")) + + foreach(CURRENT_INDEX IN LISTS INDEX_SET) + list(GET INSTRUCTION_SET_NAMES "${CURRENT_INDEX}" INSTRUCTION_SET_NAME) + list(GET INSTRUCTION_SET_CODE "${CURRENT_INDEX}" INSTRUCTION_SET_INTRINSIC) + list(GET INSTRUCTION_SET_IN_FLAGS "${CURRENT_INDEX}" INSTRUCTION_SET_IN_FLAG) + list(GET INSTRUCTION_SET_OUT_FLAGS "${CURRENT_INDEX}" INSTRUCTION_SET_OUT_FLAG) + string(REPLACE "." ";" INSTRUCTION_SET_OUT_FLAG "${INSTRUCTION_SET_OUT_FLAG}") + string(REPLACE "." ";" INSTRUCTION_SET_INTRINSIC "${INSTRUCTION_SET_INTRINSIC}") + jsonifier_check_instruction_set("${INSTRUCTION_SET_NAME}" "${INSTRUCTION_SET_IN_FLAG}" "${INSTRUCTION_SET_OUT_FLAG}" "${INSTRUCTION_SET_INTRINSIC}") + endforeach() + + message(STATUS "Detected CPU Architecture: ${JSONIFIER_CPU_INSTRUCTIONS}") +else() + message(STATUS "SSE not supported by architecture ${CMAKE_SYSTEM_PROCESSOR}") +endif() + +set(AVX_FLAG) +set(JSONIFIER_CPU_INSTRUCTIONS 0) + +if (NOT "${POPCNT}" STREQUAL "") + list(APPEND AVX_FLAG "${POPCNT}") + math(EXPR JSONIFIER_CPU_INSTRUCTIONS "${JSONIFIER_CPU_INSTRUCTIONS} | 1 << 0" OUTPUT_FORMAT DECIMAL) +endif() +if (NOT "${LZCNT}" STREQUAL "") + list(APPEND AVX_FLAG "${LZCNT}") + math(EXPR JSONIFIER_CPU_INSTRUCTIONS "${JSONIFIER_CPU_INSTRUCTIONS} | 1 << 1" OUTPUT_FORMAT DECIMAL) +endif() +if (NOT "${BMI}" STREQUAL "") + list(APPEND AVX_FLAG "${BMI}") + math(EXPR JSONIFIER_CPU_INSTRUCTIONS "${JSONIFIER_CPU_INSTRUCTIONS} | 1 << 2" OUTPUT_FORMAT DECIMAL) +endif() +if (NOT "${AVX512}" STREQUAL "") + list(APPEND AVX_FLAG "${AVX512}") + math(EXPR JSONIFIER_CPU_INSTRUCTIONS "${JSONIFIER_CPU_INSTRUCTIONS} | 1 << 5" OUTPUT_FORMAT DECIMAL) +elseif (NOT "${AVX2}" STREQUAL "") + list(APPEND AVX_FLAG "${AVX2}") + math(EXPR JSONIFIER_CPU_INSTRUCTIONS "${JSONIFIER_CPU_INSTRUCTIONS} | 1 << 4" OUTPUT_FORMAT DECIMAL) +elseif (NOT "${AVX}" STREQUAL "") + list(APPEND AVX_FLAG "${AVX}") + math(EXPR JSONIFIER_CPU_INSTRUCTIONS "${JSONIFIER_CPU_INSTRUCTIONS} | 1 << 3" OUTPUT_FORMAT DECIMAL) +endif() + +set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS_SAVE}") \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 916e0d1e0..56c62bf9b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,8 +24,13 @@ cmake_minimum_required(VERSION 3.18) +set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${CMAKE_CURRENT_SOURCE_DIR}/CMake;") + +include("CollectVersion") +collect_version("jsonifier") + set(PROJECT_NAME "Jsonifier") -set(PRODUCT_VERSION 0.9.4) +set(PRODUCT_VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}") project( "${PROJECT_NAME}" @@ -41,13 +46,19 @@ add_library("${PROJECT_NAME}::${PROJECT_NAME}" ALIAS "${PROJECT_NAME}") file(GLOB_RECURSE HEADERS CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/Include/jsonifier/*.hpp") -if(NOT DEFINED AVX_TYPE) - include("${CMAKE_CURRENT_SOURCE_DIR}/CMake/DetectArchitecture.cmake") +set(JSONIFIER-POPCNT_EXITCODE 0 CACHE INTERNAL "For cross-compiling.") +set(JSONIFIER-LZCNT_EXITCODE 0 CACHE INTERNAL "For cross-compiling.") +set(JSONIFIER-BMI_EXITCODE 0 CACHE INTERNAL "For cross-compiling.") +set(JSONIFIER-AVX_EXITCODE 0 CACHE INTERNAL "For cross-compiling.") +set(JSONIFIER-AVX2_EXITCODE 0 CACHE INTERNAL "For cross-compiling.") +set(JSONIFIER-AVX512_EXITCODE 0 CACHE INTERNAL "For cross-compiling.") + +if(NOT DEFINED JSONIFIER_CPU_INSTRUCTIONS) + include("JsonifierDetectArchitecture") endif() set_target_properties( "${PROJECT_NAME}" PROPERTIES - PUBLIC_HEADER "${HEADERS}" OUTPUT_NAME "jsonifier" CXX_STANDARD_REQUIRED ON CXX_EXTENSIONS OFF @@ -55,45 +66,38 @@ set_target_properties( target_include_directories( "${PROJECT_NAME}" INTERFACE - "$/include>" "$" ) target_compile_definitions( "${PROJECT_NAME}" INTERFACE - "${AVX_TYPE}" + "JSONIFIER_CPU_INSTRUCTIONS=${JSONIFIER_CPU_INSTRUCTIONS}" ) +set(JSONIFIER_CPU_INSTRUCTIONS "${JSONIFIER_CPU_INSTRUCTIONS}" CACHE INTERNAL "For the CPU architecture selection.") +set(AVX_FLAG "${AVX_FLAG}" CACHE INTERNAL "For the CPU flag selection.") + target_compile_options( "${PROJECT_NAME}" INTERFACE "$<$:$<$:/fsanitize=address>>" "$<$:$<$:/EHsc>>" - "$<$:/Zc:preprocessor>" + "$<$:/Zc:preprocessor>" "$<$:/permissive->" + "$<$:-pedantic>" "$<$:/Zc:lambda>" + "$<$:-pedantic>" "$<$:-Wextra>" "$<$:-Wall>" - "$<$:-Wextra>" - "$<$:/W4>" + "$<$:-Wextra>" "$<$:-Wall>" "$<$:/GL>" - "$<$:-pedantic>" - "$<$:-pedantic>" - "$<$:-I/usr/local/opt/llvm/include/c++/v1/>" - "$<$:-I/usr/local/opt/llvm/include>" + "$<$:/W4>" "${AVX_FLAG}" ) target_link_options( "${PROJECT_NAME}" INTERFACE "$<$:$<$:-fsanitize=address>>" - "$<$:-Wl,-rpath,/usr/local/opt/llvm/lib>" - "$<$:-L/usr/local/opt/llvm/lib>" -) - -target_link_libraries( - "${PROJECT_NAME}" INTERFACE - "$<$:-lc++>" ) set(CONFIG_FILE_NAME "${PROJECT_NAME}Config.cmake") @@ -125,12 +129,15 @@ install( DESTINATION "share/jsonifier" ) +install( + DIRECTORY + "${CMAKE_CURRENT_SOURCE_DIR}/Include/" + DESTINATION "include" +) + install( TARGETS "${PROJECT_NAME}" EXPORT "${EXPORTED_TARGETS_NAME}" - RUNTIME DESTINATION "$<$>:$,${DEBUG_PREFIX}bin,bin>>" - ARCHIVE DESTINATION "$,${DEBUG_PREFIX}lib,lib>" - PUBLIC_HEADER DESTINATION "include/jsonifier" ) install( @@ -138,4 +145,8 @@ install( FILE "${EXPORTED_TARGETS_FILE_NAME}" NAMESPACE "${PROJECT_NAME}::" DESTINATION "share/jsonifier" -) \ No newline at end of file +) + +if (JSONIFIER_TEST) + add_subdirectory("./Tests") +endif() \ No newline at end of file diff --git a/CMakePresets.json b/CMakePresets.json index 4c48eee40..3871b5481 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -8,7 +8,6 @@ "rhs": "Windows", "type": "equals" }, - "description": "Target Windows with the Visual Studio development environment.", "generator": "Visual Studio 17 2022", "hidden": true, "installDir": "${sourceDir}/Install/${presetName}", @@ -20,7 +19,6 @@ "strategy": "external" }, "cacheVariables": { "CMAKE_BUILD_TYPE": "Release" }, - "description": "Target Windows (64-bit) with the Visual Studio development environment. (Release)", "inherits": "Windows-Base", "name": "Windows-Release" }, @@ -31,9 +29,8 @@ }, "cacheVariables": { "CMAKE_BUILD_TYPE": "Release", - "DEV": true + "JSONIFIER_TEST": true }, - "description": "Target Windows (64-bit) with the Visual Studio development environment. (Release)", "inherits": "Windows-Base", "name": "Windows-Release-Dev" }, @@ -43,7 +40,6 @@ "value": "x64" }, "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug" }, - "description": "Target Windows (64-bit) with the Visual Studio development environment. (Debug)", "inherits": "Windows-Base", "name": "Windows-Debug" }, @@ -54,9 +50,8 @@ }, "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug", - "DEV": true + "JSONIFIER_TEST": true }, - "description": "Target Windows (64-bit) with the Visual Studio development environment. (Debug)", "inherits": "Windows-Base", "name": "Windows-Debug-Dev" }, @@ -68,9 +63,8 @@ "cacheVariables": { "ASAN_ENABLED": "TRUE", "CMAKE_BUILD_TYPE": "Release", - "DEV": true + "JSONIFIER_TEST": true }, - "description": "Target Windows (64-bit) with the Visual Studio development environment. (Release)", "inherits": "Windows-Base", "name": "Windows-Release-Asan" }, @@ -82,9 +76,8 @@ "cacheVariables": { "ASAN_ENABLED": "TRUE", "CMAKE_BUILD_TYPE": "Debug", - "DEV": true + "JSONIFIER_TEST": true }, - "description": "Target Windows (64-bit) with the Visual Studio development environment. (Debug)", "inherits": "Windows-Base", "name": "Windows-Debug-Asan" }, @@ -95,7 +88,6 @@ "rhs": "Linux", "type": "equals" }, - "description": "Target Linux with the Visual Studio development environment.", "generator": "Unix Makefiles", "hidden": true, "name": "Linux-Base" @@ -106,20 +98,42 @@ "strategy": "external" }, "cacheVariables": { "CMAKE_BUILD_TYPE": "Release" }, - "description": "Target Linux (64-bit) with the Visual Studio development environment. (Release)", "inherits": "Linux-Base", "name": "Linux-Release" }, + { + "architecture": { + "strategy": "external", + "value": "x64" + }, + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release", + "JSONIFIER_TEST": true + }, + "inherits": "Linux-Base", + "name": "Linux-Release-Dev" + }, { "architecture": { "strategy": "external", "value": "x64" }, "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug" }, - "description": "Target Linux (64-bit) with the Visual Studio development environment. (Debug)", "inherits": "Linux-Base", "name": "Linux-Debug" }, + { + "architecture": { + "strategy": "external", + "value": "x64" + }, + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug", + "JSONIFIER_TEST": true + }, + "inherits": "Linux-Base", + "name": "Linux-Debug-Dev" + }, { "architecture": { "strategy": "external", @@ -127,9 +141,9 @@ }, "cacheVariables": { "ASAN_ENABLED": "TRUE", - "CMAKE_BUILD_TYPE": "Release" + "CMAKE_BUILD_TYPE": "Release", + "JSONIFIER_TEST": true }, - "description": "Target Linux (64-bit) with the Visual Studio development environment. (Release)", "inherits": "Linux-Base", "name": "Linux-Release-Asan" }, @@ -140,9 +154,9 @@ }, "cacheVariables": { "ASAN_ENABLED": "TRUE", - "CMAKE_BUILD_TYPE": "Debug" + "CMAKE_BUILD_TYPE": "Debug", + "JSONIFIER_TEST": true }, - "description": "Target Linux (64-bit) with the Visual Studio development environment. (Debug)", "inherits": "Linux-Base", "name": "Linux-Debug-Asan" } @@ -192,15 +206,15 @@ }, { "configurePreset": "Linux-Release", - "inheritConfigureEnvironment": true, "configuration": "Release", + "inheritConfigureEnvironment": true, "name": "Linux-Release", "verbose": true }, { "configurePreset": "Linux-Debug", - "inheritConfigureEnvironment": true, "configuration": "Debug", + "inheritConfigureEnvironment": true, "name": "Linux-Debug", "verbose": true }, @@ -217,6 +231,20 @@ "configuration": "Debug", "name": "Linux-Debug-Asan", "verbose": true + }, + { + "configurePreset": "Linux-Release-Dev", + "inheritConfigureEnvironment": true, + "configuration": "Release", + "name": "Linux-Release-Dev", + "verbose": true + }, + { + "configurePreset": "Linux-Debug-Dev", + "inheritConfigureEnvironment": true, + "configuration": "Debug", + "name": "Linux-Debug-Dev", + "verbose": true } ] } \ No newline at end of file diff --git a/Documentation/Doxyfile b/Documentation/Doxyfile index 625c1ed65..3a8fae60b 100644 --- a/Documentation/Doxyfile +++ b/Documentation/Doxyfile @@ -451,8 +451,8 @@ INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or # enum is documented as struct, union, or enum with the name of the typedef. So -# typedef struct TypeS {} TypeT, will appear in the documentation as a struct -# with name TypeT. When disabled the typedef will appear as a member of a file, +# typedef struct TypeS {} type_t, will appear in the documentation as a struct +# with name type_t. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically be # useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. diff --git a/Include/jsonifier/Allocator.hpp b/Include/jsonifier/Allocator.hpp index 1ba20eca6..fc2bd77e0 100644 --- a/Include/jsonifier/Allocator.hpp +++ b/Include/jsonifier/Allocator.hpp @@ -19,58 +19,46 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/// https://github.com/RealTimeChris/Jsonifier +/// https://github.com/RealTimeChris/jsonifier /// Feb 3, 2023 #pragma once -#include -#include +#include #include -#include - -#if defined T_AVX512 - #define ALIGNMENT 64 -#elif defined T_AVX2 - #define ALIGNMENT 32 -#elif defined T_AVX - #define ALIGNMENT 16 -#else - #define ALIGNMENT 16 -#endif inline uint64_t findNextClosestMultiple(uint64_t number) { - if constexpr (ALIGNMENT == 0) { + if constexpr (JSONIFIER_ALIGNMENT == 0) { return 0; } - uint64_t remainder = number % ALIGNMENT; + uint64_t remainder = number % JSONIFIER_ALIGNMENT; if (remainder == 0) { return number; } - uint64_t nextMultiple = number + (ALIGNMENT - remainder); + uint64_t nextMultiple = number + (JSONIFIER_ALIGNMENT - remainder); return nextMultiple; } -namespace JsonifierInternal { +namespace jsonifier_internal { - template class AlignedAllocator : public std::pmr::polymorphic_allocator { + template class aligned_allocator : public std::pmr::polymorphic_allocator { public: - using value_type = ValueType; + using value_type = value_type_new; using pointer = value_type*; using size_type = uint64_t; - using allocator = std::pmr::polymorphic_allocator; + using allocator = std::pmr::polymorphic_allocator; inline pointer allocate(size_type n) { if (n == 0) { return nullptr; } - return static_cast(allocator::allocate_bytes(findNextClosestMultiple(n * sizeof(value_type)), ALIGNMENT)); + return static_cast(allocator::allocate_bytes(findNextClosestMultiple(n * sizeof(value_type)), JSONIFIER_ALIGNMENT)); } inline void deallocate(pointer ptr, size_type n) { if (ptr) { - allocator::deallocate_bytes(ptr, findNextClosestMultiple(n * sizeof(value_type)), ALIGNMENT); + allocator::deallocate_bytes(ptr, findNextClosestMultiple(n * sizeof(value_type)), JSONIFIER_ALIGNMENT); } } @@ -83,16 +71,14 @@ namespace JsonifierInternal { } }; - template class AllocWrapper : public AlignedAllocator { + template class alloc_wrapper : public aligned_allocator { public: - using value_type = ValueType; + using value_type = value_type_new; using pointer = value_type*; using size_type = uint64_t; - using allocator = AlignedAllocator; + using allocator = aligned_allocator; using allocator_traits = std::allocator_traits; - inline AllocWrapper(){}; - inline pointer allocate(size_type count) { return allocator_traits::allocate(*this, count); } @@ -108,8 +94,6 @@ namespace JsonifierInternal { inline void destroy(pointer ptr) { allocator_traits::destroy(*this, ptr); } - - inline ~AllocWrapper(){}; }; -}// namespace JsonifierInternal +}// namespace jsonifier_internal diff --git a/Include/jsonifier/Base.hpp b/Include/jsonifier/Base.hpp index 79a1a23c0..5fe69ea0a 100644 --- a/Include/jsonifier/Base.hpp +++ b/Include/jsonifier/Base.hpp @@ -19,434 +19,269 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/// https://github.com/RealTimeChris/Jsonifier +/// https://github.com/RealTimeChris/jsonifier /// Feb 3, 2023 #pragma once -#if !defined __GNUC__ - #pragma warning(push) - #pragma warning(disable : 4244) -#endif - -#include +#include #include #include #include #include #include -#include -#include -#include +#include #include -#include +#include #include -#include -#include -#include -#include -#include #include #include +#include +#include +#include +#include #include +#include -namespace JsonifierInternal { - - class Serializer; +namespace jsonifier_internal { - template struct always_false : std::false_type {}; + class serializer; - template constexpr bool always_false_v = always_false::value; + template struct hash { + static_assert(std::is_integral::value || std::is_enum::value, "hash only supports integral types, specialize for other types."); - template void printTypeInCompilationError(ValueType&&) noexcept { - static_assert(always_false_v, "Compilation failed because you failed to specialize the Core<> template for the following class:"); - } - - template struct Hash { - static_assert(std::is_integral::value || std::is_enum::value, "Hash only supports integral types, specialize for other types."); - - constexpr std::size_t operator()(ValueType const& value, std::size_t seed) const { - std::size_t key = seed ^ static_cast(value); - key = (~key) + (key << 21); - key = key ^ (key >> 24); - key = (key + (key << 3)) + (key << 8); - key = key ^ (key >> 14); - key = (key + (key << 2)) + (key << 4); - key = key ^ (key >> 28); - key = key + (key << 31); + constexpr size_t operator()(value_type const& value, size_t seed) const { + size_t key = seed ^ static_cast(value); + key = (~key) + (key << 21); + key = key ^ (key >> 24); + key = (key + (key << 3)) + (key << 8); + key = key ^ (key >> 14); + key = (key + (key << 2)) + (key << 4); + key = key ^ (key >> 28); + key = key + (key << 31); return key; } }; - // From: - // https://stackoverflow.com/questions/16337610/how-to-know-if-a-type-is-a-specialization-of-stdvector - template class Ref> struct IsSpecializationV : std::false_type {}; - - template class Ref, typename... Args> struct IsSpecializationV, Ref> : std::true_type {}; - - template - concept Range = requires(ValueType& value) { - typename ValueType::value_type; - requires !std::same_as; - requires !std::same_as; - }; - - template - concept ComplexT = JsonifierT>; - - template - concept TupleT = requires(ValueType value) { - std::tuple_size::value; - Tuplet::get<0>(value); - } && !ComplexT && !Range; - - template - concept MapSubscriptable = requires(ValueType value, typename ValueType::key_type keyNew) { - { value[keyNew] } -> std::same_as; - }; - - template - concept VectorSubscriptable = requires(ValueType value, uint64_t index) { - { value[index] } -> std::same_as::reference>; - } || requires(ValueType value, uint64_t index) { - { value[index] } -> std::same_as::const_reference>; - }; - - template - concept PairT = requires(ValueType value) { - { value.first } -> std::same_as; - { value.second } -> std::same_as; - }; - - template - concept BoolT = std::same_as, bool>; - - template - concept IntegerT = std::integral; - - template - concept FloatT = std::floating_point> && !BoolT>; - - template - concept SignedT = std::signed_integral> && !BoolT>; - - template - concept UnsignedT = std::unsigned_integral> && !BoolT> && !SignedT; - - template - concept NumT = FloatT || UnsignedT || SignedT; - - template - concept MapT = requires(ValueType data) { - typename ValueType::mapped_type; - typename ValueType::key_type; - } && Range && MapSubscriptable && !StringT && !ComplexT; - - template - concept HasEmplaceBack = requires(ValueType data, typename ValueType::value_type&& valueNew) { - { data.emplace_back(valueNew) } -> std::same_as; - }; - - template - concept UniquePtrT = requires(ValueType other) { - typename ValueType::element_type; - typename ValueType::deleter_type; - { other.release() } -> std::same_as; - }; - - template - concept HasFind = requires(Container c, const typename Container::key_type& val) { - { c.find(val) }; - }; - - template - concept HasExcludedKeys = requires(ValueType value) { - { value.excludedKeys }; - }; - - template - concept NullT = std::same_as; - - template struct FalseT : std::false_type {}; + template struct false_t : std::false_type {}; - struct RandomCoreType; + struct random_core_type; - template<> struct FalseT : std::true_type {}; + template<> struct false_t : std::true_type {}; - template constexpr bool FalseV = FalseT::value; + template constexpr bool falseV = false_t::value; - template class StringLiteral { + template class string_literal { public: - static constexpr std::size_t sizeVal = (strLength > 0) ? (strLength - 1) : 0; + static constexpr size_t sizeVal = (strLength > 0) ? (strLength - 1) : 0; - constexpr StringLiteral() noexcept = default; + constexpr string_literal() = default; - constexpr StringLiteral(const ValueType (&str)[strLength]) { + constexpr string_literal(const value_type (&str)[strLength]) { std::copy(str, str + strLength, string); } - constexpr const ValueType* data() const { + constexpr const value_type* data() const { return string; } - constexpr const ValueType* begin() const { + constexpr const value_type* begin() const { return string; } - constexpr const ValueType* end() const { + constexpr const value_type* end() const { return string + sizeVal; } - constexpr std::size_t size() const { + constexpr size_t size() const { return sizeVal; } - constexpr const Jsonifier::StringView stringView() const { + constexpr const jsonifier::string_view stringView() const { return { string, sizeVal }; } - ValueType string[strLength]; + value_type string[strLength]; }; - template constexpr auto stringLiteralFromView(const Jsonifier::StringViewBase& str) { - constexpr StringLiteral string{}; + template constexpr auto stringLiteralFromView(const jsonifier::string_view_base& str) { + constexpr string_literal string{}; std::copy_n(str.data(), str.size(), string.string); *(string.string + Count) = '\0'; return string; } - template struct CharsImpl { - static constexpr Jsonifier::StringView value{ str.string, JsonifierInternal::CharTraits::length(str.string) }; + template struct chars_impl { + static constexpr jsonifier::string_view value{ str.string, jsonifier_internal::char_traits::length(str.string) }; }; - template constexpr Jsonifier::StringView Chars = CharsImpl::value; - - template - concept StdTupleT = IsSpecializationV::value || IsSpecializationV::value; + template constexpr jsonifier::string_view Chars = chars_impl::value; - template constexpr auto indexer(std::index_sequence) { - return [](auto&& f) noexcept -> decltype(auto) { - return decltype(f)(f)(std::integral_constant{}...); + template constexpr auto indexer(std::index_sequence) { + return [](auto&& f) -> decltype(auto) { + return decltype(f)(f)(std::integral_constant{}...); }; } - template struct Sequence {}; - template struct GenSeq : GenSeq {}; - template struct GenSeq<0, Is...> : Sequence {}; - - template - constexpr std::array concat(const char (&a1)[N1], const char (&a2)[N2], Sequence, Sequence) { - return { { a1[I1]..., a2[I2]... } }; - } + template struct sequence {}; + template struct gen_sequence : gen_sequence {}; + template struct gen_sequence<0, Is...> : sequence {}; - template& string01, typename ValueType02, std::size_t size02> - constexpr auto concatArrays(const ValueType02 (&string02)[size02]) { - std::array returnArray{}; + template& string01, typename value_type02, size_t size02> + constexpr auto concatArrays(const value_type02 (&string02)[size02]) { + jsonifier_internal::raw_array returnArray{}; std::copy(string01.data(), string01.data() + string01.size(), returnArray.data()); std::copy(string02, string02 + size02, returnArray.data() + string01.size()); return returnArray; } - template& string01, typename ValueType02, std::size_t size> - constexpr auto concatArrays(const ValueType02 (&string02)[size]) { - std::array returnArray{}; + template& string01, typename value_type02, size_t size> + constexpr auto concatArrays(const value_type02 (&string02)[size]) { + jsonifier_internal::raw_array returnArray{}; std::copy(string01.data(), string01.data() + string01.size(), returnArray.data()); std::copy(string02, string02 + size, returnArray.data() + string01.size()); return returnArray; } - template& string01, typename ValueType02, const Jsonifier::StringViewBase& string02> + template& string01, typename value_type02, const jsonifier::string_view_base& string02> constexpr auto concatArrays() { - std::array returnArray{}; + jsonifier_internal::raw_array returnArray{}; std::copy(string01.data(), string01.data() + string01.size(), returnArray.data()); std::copy(string02.data(), string02.data() + string02.size(), returnArray.data() + string01.size()); return returnArray; } - template constexpr auto indexer() { + template constexpr auto indexer() { return indexer(std::make_index_sequence{}); } - template constexpr auto forEach(Func&& f) { + template constexpr auto forEach(Func&& f) { return indexer()([&](auto&&... i) { - (std::forward>(f)(i), ...); + (std::forward>(f)(i), ...); }); } - template struct MakeStatic { + template struct make_static { static constexpr auto value = newArr; }; - template constexpr Jsonifier::StringView join() { + template constexpr jsonifier::string_view join() { constexpr auto joinedArr = []() { - constexpr std::size_t len = (Strings.size() + ... + 0); - RawArray arr{}; + constexpr size_t len = (strings.size() + ... + 0); + raw_array arr{}; auto append = [i = 0, &arr](const auto& s) mutable { for (auto c: s) - arr[i++] = c; + arr[static_cast(i++)] = c; }; - (append(Strings), ...); + (append(strings), ...); arr[len] = 0; return arr; }(); - auto& staticArr = MakeStatic::value; + auto& staticArr = make_static::value; return { staticArr.data(), staticArr.size() - 1 }; } - template constexpr auto JoinV = join(); + template constexpr auto JoinV = join(); inline decltype(auto) getMember(auto&& value, auto& member_ptr) { - using ValueType = std::decay_t; - if constexpr (std::is_member_object_pointer_v) { + using value_type = std::decay_t; + if constexpr (std::is_member_object_pointer_v) { return value.*member_ptr; - } else if constexpr (std::is_member_function_pointer_v) { + } else if constexpr (std::is_member_function_pointer_v) { return member_ptr; - } else if constexpr (std::invocable) { + } else if constexpr (std::invocable) { return std::invoke(member_ptr, value); - } else if constexpr (std::is_pointer_v) { + } else if constexpr (std::is_pointer_v) { return *member_ptr; } else { return member_ptr; } } - template using MemberT = decltype(getMember(std::declval(), std::declval&>())); - - template - concept HasResize = requires(ValueType value) { value.resize(0); }; -}// namespace JsonifierInternal - -namespace Jsonifier { - - template struct Array { - ValueType parseValue; - }; - - template Array(ValueType) -> Array; + template using member_t = decltype(getMember(std::declval(), std::declval&>())); +}// namespace jsonifier_internal - template struct Object { - ValueType parseValue; - }; - - template Object(ValueType) -> Object; +namespace jsonifier { - constexpr auto array(auto&&... args) { - return Array{ JsonifierInternal::Tuplet::copyTuple(args...) }; + constexpr auto createArray(auto&&... args) { + return array{ jsonifier_internal::tuplet::copyTuple(args...) }; } - constexpr auto object(auto&&... args) { + constexpr auto createObject(auto&&... args) { if constexpr (sizeof...(args) == 0) { - return Object{ JsonifierInternal::Tuplet::Tuple{} }; - } else { - return Object{ JsonifierInternal::GroupBuilder>::op( - JsonifierInternal::Tuplet::copyTuple(args...)) }; - } - } - -}// namespace Jsonifier - -namespace JsonifierInternal { - - template - concept RawJsonT = std::same_as && !StringT; - - template - concept JsonifierArrayT = JsonifierT && IsSpecializationV, Jsonifier::Array>::value; - - template - concept JsonifierObjectT = JsonifierT && IsSpecializationV, Jsonifier::Object>::value; - - template - concept ArrayTupleT = JsonifierArrayT || TupleT>; - - template - concept ObjectT = MapT || JsonifierObjectT; - - template - concept TimeT = std::same_as || std::same_as || std::same_as || - std::same_as || std::same_as || std::same_as; - - template - concept EnumT = std::is_enum::value; - - template inline auto dataPtr(ValueType& buffer) { - if constexpr (HasResize) { - return buffer.data(); + return object{ jsonifier_internal::tuplet::tuple{} }; } else { - return buffer; + return object{ jsonifier_internal::GroupBuilder>::op( + jsonifier_internal::tuplet::copyTuple(args...)) }; } } - template - concept ArrayT = - ( !ComplexT && !MapT && VectorSubscriptable && HasData && HasEmplaceBack )&&!JsonifierArrayT && - !TupleT && !HasSubstr && requires(ValueType data) { typename ValueType::value_type; } || - IsSpecializationV::value; +}// namespace jsonifier - template - concept RawArrayT = - ( ( !ComplexT && !MapT && VectorSubscriptable && HasData && !HasEmplaceBack )&&!JsonifierArrayT && - !TupleT && !HasSubstr && !HasResize ) || - std::is_array_v; +namespace jsonifier_internal { - template - concept VectorLike = HasResize && VectorSubscriptable && HasData; - - template - concept CoreType = IsSpecializationV, Jsonifier::Core>::value; - - template class StopWatch { + template class stop_watch { public: - inline StopWatch() = default; - - using HRClock = std::chrono::high_resolution_clock; + using hr_clock = std::chrono::high_resolution_clock; - inline StopWatch& operator=(StopWatch&& other) noexcept { - maxNumberOfTimeUnits.store(other.maxNumberOfTimeUnits.load(std::memory_order_acquire), std::memory_order_release); - startTime.store(other.startTime.load(std::memory_order_acquire), std::memory_order_release); - return *this; + inline stop_watch(uint64_t newTime) { + totalNumberOfTimeUnits.store(value_type{ newTime }, std::memory_order_release); } - inline StopWatch(StopWatch&& other) noexcept { - *this = std::move(other); + inline stop_watch(value_type newTime) { + totalNumberOfTimeUnits.store(newTime, std::memory_order_release); } - StopWatch& operator=(const StopWatch& data) = delete; - StopWatch(const StopWatch& other) = delete; - - inline StopWatch(uint64_t maxNumberOfTimeUnitsNew) { - maxNumberOfTimeUnits.store(TimeType{ maxNumberOfTimeUnitsNew }, std::memory_order_release); + inline stop_watch& operator=(stop_watch&& other) { + this->totalNumberOfTimeUnits.store(other.totalNumberOfTimeUnits.load(std::memory_order_acquire), std::memory_order_release); + this->startTimeInTimeUnits.store(other.startTimeInTimeUnits.load(std::memory_order_acquire), std::memory_order_release); + return *this; } - inline StopWatch(TimeType maxNumberOfTimeUnitsNew) { - maxNumberOfTimeUnits.store(maxNumberOfTimeUnitsNew, std::memory_order_release); + inline stop_watch(stop_watch&& other) { + *this = std::move(other); } - inline TimeType totalTimePassed() const { - return std::chrono::duration_cast(HRClock::now().time_since_epoch()) - startTime.load(std::memory_order_acquire); + inline stop_watch& operator=(const stop_watch& other) { + this->totalNumberOfTimeUnits.store(other.totalNumberOfTimeUnits.load(std::memory_order_acquire), std::memory_order_release); + this->startTimeInTimeUnits.store(other.startTimeInTimeUnits.load(std::memory_order_acquire), std::memory_order_release); + return *this; } - inline TimeType getTotalWaitTime() const { - return maxNumberOfTimeUnits.load(std::memory_order_acquire); + inline stop_watch(const stop_watch& other) { + *this = other; } - inline bool hasTimePassed() const { - if (std::chrono::duration_cast(HRClock::now().time_since_epoch()) - startTime.load(std::memory_order_acquire) >= - maxNumberOfTimeUnits.load(std::memory_order_acquire)) { + inline bool hasTimeElapsed() { + if (std::chrono::duration_cast(hr_clock::now().time_since_epoch()) - startTimeInTimeUnits.load(std::memory_order_acquire) >= + totalNumberOfTimeUnits.load(std::memory_order_acquire)) { return true; } else { return false; } } - inline void resetTimer() { - startTime.store(std::chrono::duration_cast(HRClock::now().time_since_epoch()), std::memory_order_release); + inline void reset(value_type newTimeValue = value_type{}) { + if (newTimeValue != value_type{}) { + totalNumberOfTimeUnits.store(newTimeValue, std::memory_order_release); + startTimeInTimeUnits.store(std::chrono::duration_cast(hr_clock::now().time_since_epoch()), std::memory_order_release); + } else { + startTimeInTimeUnits.store(std::chrono::duration_cast(hr_clock::now().time_since_epoch()), std::memory_order_release); + } + } + + inline value_type getTotalWaitTime() const { + return totalNumberOfTimeUnits.load(std::memory_order_acquire); + } + + inline value_type totalTimeElapsed() { + return std::chrono::duration_cast(hr_clock::now().time_since_epoch()) - startTimeInTimeUnits.load(std::memory_order_acquire); } protected: - std::atomic maxNumberOfTimeUnits{ TimeType{ 0 } }; - std::atomic startTime{ TimeType{ 0 } }; + std::atomic totalNumberOfTimeUnits{}; + std::atomic startTimeInTimeUnits{}; }; - template StopWatch(TimeType) -> StopWatch; -}// namespace JsonifierInternal \ No newline at end of file + template stop_watch(value_type) -> stop_watch; +}// namespace jsonifier_internal \ No newline at end of file diff --git a/Include/jsonifier/Compare.hpp b/Include/jsonifier/Compare.hpp index b35092a9d..4bd75699f 100644 --- a/Include/jsonifier/Compare.hpp +++ b/Include/jsonifier/Compare.hpp @@ -19,167 +19,81 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/// https://github.com/RealTimeChris/Jsonifier +/// https://github.com/RealTimeChris/jsonifier /// Feb 3, 2023 #pragma once -#include -#include +#include -#if defined max - #undef max -#endif - -#if defined min - #undef min -#endif - -namespace JsonifierInternal { - - template - concept FloatingT = std::floating_point; +namespace jsonifier_internal { -#if defined T_AVX512 - - template inline __m128i gatherValues128(const ValueType* str) { - alignas(ALIGNMENT) float newArray[sizeof(__m128i) / sizeof(float)]{}; - std::memcpy(newArray, str, sizeof(__m128i)); - return _mm_castps_si128(_mm_load_ps(newArray)); - } - - template inline __m256i gatherValues256(const ValueType* str) { - alignas(ALIGNMENT) float newArray[sizeof(__m256i) / sizeof(float)]{}; - std::memcpy(newArray, str, sizeof(__m256i)); - return _mm256_castps_si256(_mm256_load_ps(newArray)); - } - - template inline __m512i gatherValues512(const ValueType* str) { - return _mm512_loadu_epi64(str); - } - - template inline __m128 gatherValues128(const ValueType* str) { - return _mm_load_ps(str); - } - - template inline __m256 gatherValues256(const ValueType* str) { - return _mm256_load_ps(str); - } - - template inline __m512 gatherValues512(const ValueType* str) { - return _mm512_loadu_ps(str); - } +#if JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX512) - template inline uint64_t findFirstCharacterNotEqual(const ValueType01* str, uint64_t length, ValueType02 target) { - static constexpr uint64_t vecSize = sizeof(__m512); - const __m512i targetVec = _mm512_set1_epi8(target); - uint64_t remainingBytes = length; - __m512i currentVec{}; + template inline uint64_t find(const value_type01* str, uint64_t length, const value_type02* sub, uint64_t subLength = 1) { + static constexpr uint64_t vecSize = sizeof(avx_int_512); + uint64_t remainingBytes{ length }; uint64_t index{}; - uint64_t mask{}; - - while (remainingBytes >= vecSize) { - currentVec = gatherValues512(str); - mask = _mm512_cmpeq_epi8_mask(targetVec, currentVec); - - if (mask != 0xffffffff) { - uint64_t firstNonMatchMask = ~mask; - return index + _tzcnt_u64(firstNonMatchMask); - } - - str += vecSize; - index += vecSize; - remainingBytes -= vecSize; - } - for (uint64_t i = 0; i < remainingBytes; i++) { - if (str[i] != target) { - return index + i; - } + if (subLength == 0) { + return 0; } + auto strNew = str; - return std::numeric_limits::max(); - } - - template inline uint64_t findSingleCharacter(const ValueType01* str, uint64_t length, ValueType02 target) { - static constexpr uint64_t vecSize = sizeof(__m512); - const __m512i targetVec = _mm512_set1_epi8(target); - uint64_t remainingBytes{ length }; - __m512i currentVec{}; - uint64_t index{}; - uint64_t mask{}; while (remainingBytes >= vecSize) { - currentVec = gatherValues512(str); - mask = _mm512_cmpeq_epi8_mask(targetVec, currentVec); - - if (mask != 0) { - return index + _tzcnt_u64(mask); - } - - str += vecSize; + avx_int_512 currentVec = gatherValues512(strNew); + + const avx_int_512 subVec = _mm512_set1_epi8(static_cast(sub[0])); + uint64_t mask = static_cast(_mm512_cmpeq_epi8_mask(subVec, currentVec)); + do { + if (mask != 0) { + uint64_t pos = tzCount(mask); + if (memcmp(strNew + pos, sub, subLength) == 0) { + return pos + index; + } + mask = blsr(mask); + } + } while (mask != 0); + + strNew += vecSize; index += vecSize; remainingBytes -= vecSize; } - for (uint64_t i = 0; i < remainingBytes; i++) { - if (str[i] == target) { - return index + i; - } - } - - return std::numeric_limits::max(); - } - - template inline uint64_t findLastSingleCharacter(const ValueType01* str, uint64_t length, ValueType02 target) { - static constexpr uint64_t vecSize = sizeof(__m512); - const __m512i targetVec = _mm512_set1_epi8(target); - uint64_t remainingBytes{}; - __m512i currentVec{}; - uint64_t index{ length }; - uint64_t mask{}; - str += length - vecSize; - while (remainingBytes >= 0) { - currentVec = gatherValues512(str); - mask = _mm512_cmpeq_epi8_mask(targetVec, currentVec); - - if (mask != 0) { - return index - _lzcnt_u64(mask); + if (remainingBytes >= subLength) { + for (int64_t i = 0; i < static_cast(remainingBytes); ++i) { + if (str[index + i] == sub[0]) { + if (memcmp(str + index + i, sub, subLength) == 0) { + return index + i; + } + } } - - str -= vecSize; - index -= vecSize; - remainingBytes -= vecSize; } - for (uint64_t i = remainingBytes; i > 0; --i) { - if (str[i] == target) { - return index + i; - } - } return std::numeric_limits::max(); } - template inline bool compareValues(const ValueType01* string1, const ValueType02* string2, uint64_t length); + template inline bool compareValues(const value_type01* string1, const value_type02* string2, uint64_t length); - template inline uint64_t getIntervalCount(uint64_t originalLength) { - return originalLength * sizeof(ValueType) / sizeof(IndexType); + template constexpr uint64_t getIntervalCount(uint64_t originalLength) { + return originalLength * sizeof(value_type) / sizeof(IndexType); } - template inline bool compareValues16(const ValueType01* string1, const ValueType02* string2, uint64_t length) { - static constexpr uint64_t vectorSize = sizeof(__m128i) / sizeof(ValueType01); - const uint64_t intervalCount = getIntervalCount(length); + template inline bool compareValues16(const value_type01* string1, const value_type02* string2, uint64_t length) { + static constexpr uint64_t vectorSize = sizeof(avx_int_128) / sizeof(value_type01); + const uint64_t intervalCount = getIntervalCount(length); const uint64_t remainder = length % vectorSize; static constexpr uint16_t maskValue{ 0xffff }; - auto destVector = gatherValues128(string1); - auto sourceVector = gatherValues128(string2); - if (_mm_movemask_ps(_mm_cmpeq_ps(destVector, sourceVector)) != maskValue) { + auto destvector = gatherValues128(string1); + auto sourcevector = gatherValues128(string2); + if (_mm_movemask_ps(_mm_cmpeq_ps(destvector, sourcevector)) != maskValue) { return false; } for (uint64_t x = 1; x < intervalCount; ++x) { - destVector = gatherValues128(string1 + x * vectorSize); - sourceVector = gatherValues128(string2 + x * vectorSize); - if (_mm_movemask_ps(_mm_cmpeq_ps(destVector, sourceVector)) != maskValue) { + destvector = gatherValues128(string1 + x * vectorSize); + sourcevector = gatherValues128(string2 + x * vectorSize); + if (_mm_movemask_ps(_mm_cmpeq_ps(destvector, sourcevector)) != maskValue) { return false; } } @@ -191,20 +105,20 @@ namespace JsonifierInternal { return true; } - template inline bool compareValues16(const ValueType01* string1, const ValueType02* string2, uint64_t length) { - static constexpr uint64_t vectorSize = sizeof(__m128i) / sizeof(ValueType01); - const uint64_t intervalCount = getIntervalCount(length); + template inline bool compareValues16(const value_type01* string1, const value_type02* string2, uint64_t length) { + static constexpr uint64_t vectorSize = sizeof(avx_int_128) / sizeof(value_type01); + const uint64_t intervalCount = getIntervalCount(length); const uint64_t remainder = length % vectorSize; static constexpr uint16_t maskValue{ 0xffff }; - auto destVector = gatherValues128(string1); - auto sourceVector = gatherValues128(string2); - if (_mm_movemask_epi8(_mm_cmpeq_epi8(destVector, sourceVector)) != maskValue) { + auto destvector = gatherValues128(string1); + auto sourcevector = gatherValues128(string2); + if (_mm_movemask_epi8(_mm_cmpeq_epi8(destvector, sourcevector)) != maskValue) { return false; } for (uint64_t x = 1; x < intervalCount; ++x) { - destVector = gatherValues128(string1 + x * vectorSize); - sourceVector = gatherValues128(string2 + x * vectorSize); - if (_mm_movemask_epi8(_mm_cmpeq_epi8(destVector, sourceVector)) != maskValue) { + destvector = gatherValues128(string1 + x * vectorSize); + sourcevector = gatherValues128(string2 + x * vectorSize); + if (_mm_movemask_epi8(_mm_cmpeq_epi8(destvector, sourcevector)) != maskValue) { return false; } } @@ -214,20 +128,20 @@ namespace JsonifierInternal { return true; } - template inline bool compareValues32(const ValueType01* string1, const ValueType02* string2, uint64_t length) { - static constexpr uint64_t vectorSize = sizeof(__m256i) / sizeof(ValueType01); - const uint64_t intervalCount = getIntervalCount(length); + template inline bool compareValues32(const value_type01* string1, const value_type02* string2, uint64_t length) { + static constexpr uint64_t vectorSize = sizeof(avx_int_256) / sizeof(value_type01); + const uint64_t intervalCount = getIntervalCount(length); const uint64_t remainder = length % vectorSize; static constexpr uint32_t maskValue{ 0xffffffff }; - auto destVector = gatherValues256(string1); - auto sourceVector = gatherValues256(string2); - if (_mm256_movemask_ps(_mm256_cmp_ps(destVector, sourceVector, _CMP_EQ_OQ)) != maskValue) { + auto destvector = gatherValues256(string1); + auto sourcevector = gatherValues256(string2); + if (_mm256_movemask_ps(_mm256_cmp_ps(destvector, sourcevector, _CMP_EQ_OQ)) != maskValue) { return false; } for (uint64_t x = 1; x < intervalCount; ++x) { - destVector = gatherValues256(string1 + x * vectorSize); - sourceVector = gatherValues256(string2 + x * vectorSize); - if (_mm256_movemask_ps(_mm256_cmp_ps(destVector, sourceVector, _CMP_EQ_OQ)) != maskValue) { + destvector = gatherValues256(string1 + x * vectorSize); + sourcevector = gatherValues256(string2 + x * vectorSize); + if (_mm256_movemask_ps(_mm256_cmp_ps(destvector, sourcevector, _CMP_EQ_OQ)) != maskValue) { return false; } } @@ -237,20 +151,20 @@ namespace JsonifierInternal { return true; } - template inline bool compareValues32(const ValueType01* string1, const ValueType02* string2, uint64_t length) { - static constexpr uint64_t vectorSize = sizeof(__m256i) / sizeof(ValueType01); - const uint64_t intervalCount = getIntervalCount(length); + template inline bool compareValues32(const value_type01* string1, const value_type02* string2, uint64_t length) { + static constexpr uint64_t vectorSize = sizeof(avx_int_256) / sizeof(value_type01); + const uint64_t intervalCount = getIntervalCount(length); const uint64_t remainder = length % vectorSize; static constexpr uint32_t maskValue{ 0xffffffff }; - auto destVector = gatherValues256(string1); - auto sourceVector = gatherValues256(string2); - if (_mm256_movemask_epi8(_mm256_cmpeq_epi8(destVector, sourceVector)) != maskValue) { + auto destvector = gatherValues256(string1); + auto sourcevector = gatherValues256(string2); + if (_mm256_movemask_epi8(_mm256_cmpeq_epi8(destvector, sourcevector)) != maskValue) { return false; } for (uint64_t x = 1; x < intervalCount; ++x) { - destVector = gatherValues256(string1 + x * vectorSize); - sourceVector = gatherValues256(string2 + x * vectorSize); - if (_mm256_movemask_epi8(_mm256_cmpeq_epi8(destVector, sourceVector)) != maskValue) { + destvector = gatherValues256(string1 + x * vectorSize); + sourcevector = gatherValues256(string2 + x * vectorSize); + if (_mm256_movemask_epi8(_mm256_cmpeq_epi8(destvector, sourcevector)) != maskValue) { return false; } } @@ -260,20 +174,20 @@ namespace JsonifierInternal { return true; } - template inline bool compareValues64(const ValueType01* string1, const ValueType02* string2, uint64_t length) { - static constexpr uint64_t vectorSize = sizeof(__m512i) / sizeof(ValueType01); - const uint64_t intervalCount = getIntervalCount(length); + template inline bool compareValues64(const value_type01* string1, const value_type02* string2, uint64_t length) { + static constexpr uint64_t vectorSize = sizeof(avx_int_512) / sizeof(value_type01); + const uint64_t intervalCount = getIntervalCount(length); const uint64_t remainder = length % vectorSize; static constexpr uint64_t maskValue{ 0xffffffffffffffff }; - auto destVector = gatherValues512(string1); - auto sourceVector = gatherValues512(string2); - if (_mm512_cmpeq_epi8_mask(destVector, sourceVector) != maskValue) { + auto destvector = gatherValues512(string1); + auto sourcevector = gatherValues512(string2); + if (_mm512_cmpeq_epi8_mask(destvector, sourcevector) != maskValue) { return false; } for (uint64_t x = 1; x < intervalCount; ++x) { - destVector = gatherValues512(string1 + x * vectorSize); - sourceVector = gatherValues512(string2 + x * vectorSize); - if (_mm512_cmpeq_epi8_mask(destVector, sourceVector) != maskValue) { + destvector = gatherValues512(string1 + x * vectorSize); + sourcevector = gatherValues512(string2 + x * vectorSize); + if (_mm512_cmpeq_epi8_mask(destvector, sourcevector) != maskValue) { return false; } } @@ -283,20 +197,20 @@ namespace JsonifierInternal { return true; } - template inline bool compareValues64(const ValueType01* string1, const ValueType02* string2, uint64_t length) { - static constexpr uint64_t vectorSize = sizeof(__m512i) / sizeof(ValueType01); - const uint64_t intervalCount = getIntervalCount(length); + template inline bool compareValues64(const value_type01* string1, const value_type02* string2, uint64_t length) { + static constexpr uint64_t vectorSize = sizeof(avx_int_512) / sizeof(value_type01); + const uint64_t intervalCount = getIntervalCount(length); const uint64_t remainder = length % vectorSize; static constexpr uint64_t maskValue{ 0xffffffffffffffff }; - auto destVector = gatherValues512(string1); - auto sourceVector = gatherValues512(string2); - if (_mm512_cmpeq_epi8_mask(destVector, sourceVector) != maskValue) { + auto destvector = gatherValues512(string1); + auto sourcevector = gatherValues512(string2); + if (_mm512_cmpeq_epi8_mask(destvector, sourcevector) != maskValue) { return false; } for (uint64_t x = 1; x < intervalCount; ++x) { - destVector = gatherValues512(string1 + x * vectorSize); - sourceVector = gatherValues512(string2 + x * vectorSize); - if (_mm512_cmpeq_epi8_mask(destVector, sourceVector) != maskValue) { + destvector = gatherValues512(string1 + x * vectorSize); + sourcevector = gatherValues512(string2 + x * vectorSize); + if (_mm512_cmpeq_epi8_mask(destvector, sourcevector) != maskValue) { return false; } } @@ -306,7 +220,7 @@ namespace JsonifierInternal { return true; } - template inline bool compareValues(const ValueType01* string1, const ValueType02* string2, uint64_t length) { + template inline bool compareValues(const value_type01* string1, const value_type02* string2, uint64_t length) { if (length >= 64) { return compareValues64(string1, string2, length); } else if (length >= 32) { @@ -314,144 +228,77 @@ namespace JsonifierInternal { } else if (length >= 16) { return compareValues16(string1, string2, length); } else { - return (std::memcmp(string1, string2, length * sizeof(ValueType01)) == 0); + return (std::memcmp(string1, string2, length * sizeof(value_type01)) == 0); } } -#elif defined T_AVX2 - - template inline __m128i gatherValues128(const ValueType* str) { - alignas(ALIGNMENT) float newArray[sizeof(__m128i) / sizeof(float)]{}; - std::memcpy(newArray, str, sizeof(__m128i)); - return _mm_castps_si128(_mm_load_ps(newArray)); - } - - template inline __m256i gatherValues256(const ValueType* str) { - alignas(ALIGNMENT) float newArray[sizeof(__m256i) / sizeof(float)]{}; - std::memcpy(newArray, str, sizeof(__m256i)); - return _mm256_castps_si256(_mm256_load_ps(newArray)); - } - - template inline __m128 gatherValues128(const ValueType* str) { - return _mm_load_ps(str); - } - - template inline __m256 gatherValues256(const ValueType* str) { - return _mm256_load_ps(str); - } +#elif JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX2) - template inline uint64_t findFirstCharacterNotEqual(const ValueType01* str, uint64_t length, ValueType02 target) { - static constexpr uint32_t vecSize = sizeof(__m256); - const __m256i targetVec = _mm256_set1_epi8(target); - uint64_t remainingBytes = length; - __m256i currentVec{}; + template inline uint64_t find(const value_type01* str, uint64_t length, const value_type02* sub, uint64_t subLength = 1) { + static constexpr uint64_t vecSize = sizeof(avx_int_256); + uint64_t remainingBytes{ length }; uint64_t index{}; - uint32_t mask{}; - - while (remainingBytes >= vecSize) { - currentVec = gatherValues256(str); - mask = _mm256_movemask_epi8(_mm256_cmpeq_epi8(targetVec, currentVec)); - - if (mask != 0xffffffff) { - uint32_t firstNonMatchMask = ~mask; - return index + _tzcnt_u32(firstNonMatchMask); - } - - str += vecSize; - index += vecSize; - remainingBytes -= vecSize; - } - for (uint64_t i = 0; i < remainingBytes; i++) { - if (str[i] != target) { - return index + i; - } + if (subLength == 0) { + return 0; } + auto strNew = str; - return std::numeric_limits::max(); - } - - - template inline uint64_t findSingleCharacter(const ValueType01* str, uint64_t length, ValueType02 target) { - static constexpr uint32_t vecSize = sizeof(__m256); - const __m256i targetVec = _mm256_set1_epi8(target); - uint64_t remainingBytes{ length }; - __m256i currentVec{}; - uint64_t index{}; - uint32_t mask{}; while (remainingBytes >= vecSize) { - currentVec = gatherValues256(str); - mask = _mm256_movemask_epi8(_mm256_cmpeq_epi8(targetVec, currentVec)); - - if (mask != 0) { - return index + _tzcnt_u32(mask); - } - - str += vecSize; + avx_int_256 currentVec = gatherValues256(strNew); + + const avx_int_256 subVec = _mm256_set1_epi8(static_cast(sub[0])); + uint64_t mask = static_cast(_mm256_movemask_epi8(_mm256_cmpeq_epi8(subVec, currentVec))); + do { + if (mask != 0) { + uint64_t pos = tzCount(mask); + if (memcmp(strNew + pos, sub, subLength) == 0) { + return pos + index; + } + mask = blsr(mask); + } + } while (mask != 0); + + strNew += vecSize; index += vecSize; remainingBytes -= vecSize; } - for (uint64_t i = 0; i < remainingBytes; i++) { - if (str[i] == target) { - return index + i; - } - } - - return std::numeric_limits::max(); - } - - template inline uint64_t findLastSingleCharacter(const ValueType01* str, uint64_t length, ValueType02 target) { - static constexpr uint32_t vecSize = sizeof(__m256); - const __m256i targetVec = _mm256_set1_epi8(target); - uint64_t remainingBytes{}; - __m256i currentVec{}; - uint64_t index{ length }; - uint32_t mask{}; - str += length - vecSize; - while (remainingBytes >= 0) { - currentVec = gatherValues256(str); - mask = _mm256_movemask_epi8(_mm256_cmpeq_epi8(targetVec, currentVec)); - - if (mask != 0) { - return index - _lzcnt_u32(mask); + if (remainingBytes >= subLength) { + for (int64_t i = 0; i < static_cast(remainingBytes); ++i) { + if (str[index + i] == sub[0]) { + if (memcmp(str + index + i, sub, subLength) == 0) { + return index + i; + } + } } - - str -= vecSize; - index -= vecSize; - remainingBytes -= vecSize; } - for (uint64_t i = remainingBytes; i > 0; --i) { - if (str[i] == target) { - return index + i; - } - } return std::numeric_limits::max(); } - template inline bool compareValues(const ValueType01* string1, const ValueType02* string2, uint64_t length); + template inline bool compareValues(const value_type01* string1, const value_type02* string2, uint64_t length); - template inline uint64_t getIntervalCount(uint64_t originalLength) { - return originalLength * sizeof(ValueType) / sizeof(IndexType); + template constexpr uint64_t getIntervalCount(uint64_t originalLength) { + return originalLength * sizeof(value_type) / sizeof(IndexType); } - template inline bool compareValues16(const ValueType01* string1, const ValueType02* string2, uint64_t length) { - static constexpr uint64_t vectorSize = sizeof(__m128i) / sizeof(ValueType01); - const uint64_t intervalCount = getIntervalCount(length); + template inline bool compareValues16(const value_type01* string1, const value_type02* string2, uint64_t length) { + static constexpr uint64_t vectorSize = sizeof(avx_int_128) / sizeof(value_type01); + const uint64_t intervalCount = getIntervalCount(length); const uint64_t remainder = length % vectorSize; static constexpr uint16_t maskValue{ 0xffff }; - auto destVector = gatherValues128(string1); - auto sourceVector = gatherValues128(string2); - if (_mm_movemask_ps(_mm_cmpeq_ps(destVector, sourceVector)) != maskValue) { + auto destvector = gatherValues128(string1); + auto sourcevector = gatherValues128(string2); + if (_mm_movemask_ps(_mm_cmpeq_ps(destvector, sourcevector)) != maskValue) { return false; } for (uint64_t x = 1; x < intervalCount; ++x) { - destVector = gatherValues128(string1 + x * vectorSize); - sourceVector = gatherValues128(string2 + x * vectorSize); - if (_mm_movemask_ps(_mm_cmpeq_ps(destVector, sourceVector)) != maskValue) { + destvector = gatherValues128(string1 + x * vectorSize); + sourcevector = gatherValues128(string2 + x * vectorSize); + if (_mm_movemask_ps(_mm_cmpeq_ps(destvector, sourcevector)) != maskValue) { return false; } } @@ -463,20 +310,20 @@ namespace JsonifierInternal { return true; } - template inline bool compareValues16(const ValueType01* string1, const ValueType02* string2, uint64_t length) { - static constexpr uint64_t vectorSize = sizeof(__m128i) / sizeof(ValueType01); - const uint64_t intervalCount = getIntervalCount(length); + template inline bool compareValues16(const value_type01* string1, const value_type02* string2, uint64_t length) { + static constexpr uint64_t vectorSize = sizeof(avx_int_128) / sizeof(value_type01); + const uint64_t intervalCount = getIntervalCount(length); const uint64_t remainder = length % vectorSize; static constexpr uint16_t maskValue{ 0xffff }; - auto destVector = gatherValues128(string1); - auto sourceVector = gatherValues128(string2); - if (_mm_movemask_epi8(_mm_cmpeq_epi8(destVector, sourceVector)) != maskValue) { + auto destvector = gatherValues128(string1); + auto sourcevector = gatherValues128(string2); + if (_mm_movemask_epi8(_mm_cmpeq_epi8(destvector, sourcevector)) != maskValue) { return false; } for (uint64_t x = 1; x < intervalCount; ++x) { - destVector = gatherValues128(string1 + x * vectorSize); - sourceVector = gatherValues128(string2 + x * vectorSize); - if (_mm_movemask_epi8(_mm_cmpeq_epi8(destVector, sourceVector)) != maskValue) { + destvector = gatherValues128(string1 + x * vectorSize); + sourcevector = gatherValues128(string2 + x * vectorSize); + if (_mm_movemask_epi8(_mm_cmpeq_epi8(destvector, sourcevector)) != maskValue) { return false; } } @@ -486,20 +333,20 @@ namespace JsonifierInternal { return true; } - template inline bool compareValues32(const ValueType01* string1, const ValueType02* string2, uint64_t length) { - static constexpr uint64_t vectorSize = sizeof(__m256i) / sizeof(ValueType01); - const uint64_t intervalCount = getIntervalCount(length); + template inline bool compareValues32(const value_type01* string1, const value_type02* string2, uint64_t length) { + static constexpr uint64_t vectorSize = sizeof(avx_int_256) / sizeof(value_type01); + const uint64_t intervalCount = getIntervalCount(length); const uint64_t remainder = length % vectorSize; static constexpr uint32_t maskValue{ 0xffffffff }; - auto destVector = gatherValues256(string1); - auto sourceVector = gatherValues256(string2); - if (_mm256_movemask_ps(_mm256_cmp_ps(destVector, sourceVector, _CMP_EQ_OQ)) != maskValue) { + auto destvector = gatherValues256(string1); + auto sourcevector = gatherValues256(string2); + if (_mm256_movemask_ps(_mm256_cmp_ps(destvector, sourcevector, _CMP_EQ_OQ)) != maskValue) { return false; } for (uint64_t x = 1; x < intervalCount; ++x) { - destVector = gatherValues256(string1 + x * vectorSize); - sourceVector = gatherValues256(string2 + x * vectorSize); - if (_mm256_movemask_ps(_mm256_cmp_ps(destVector, sourceVector, _CMP_EQ_OQ)) != maskValue) { + destvector = gatherValues256(string1 + x * vectorSize); + sourcevector = gatherValues256(string2 + x * vectorSize); + if (_mm256_movemask_ps(_mm256_cmp_ps(destvector, sourcevector, _CMP_EQ_OQ)) != maskValue) { return false; } } @@ -509,20 +356,20 @@ namespace JsonifierInternal { return true; } - template inline bool compareValues32(const ValueType01* string1, const ValueType02* string2, uint64_t length) { - static constexpr uint64_t vectorSize = sizeof(__m256i) / sizeof(ValueType01); - const uint64_t intervalCount = getIntervalCount(length); + template inline bool compareValues32(const value_type01* string1, const value_type02* string2, uint64_t length) { + static constexpr uint64_t vectorSize = sizeof(avx_int_256) / sizeof(value_type01); + const uint64_t intervalCount = getIntervalCount(length); const uint64_t remainder = length % vectorSize; static constexpr uint32_t maskValue{ 0xffffffff }; - auto destVector = gatherValues256(string1); - auto sourceVector = gatherValues256(string2); - if (_mm256_movemask_epi8(_mm256_cmpeq_epi8(destVector, sourceVector)) != static_cast(maskValue)) { + auto destvector = gatherValues256(string1); + auto sourcevector = gatherValues256(string2); + if (_mm256_movemask_epi8(_mm256_cmpeq_epi8(destvector, sourcevector)) != static_cast(maskValue)) { return false; } for (uint64_t x = 1; x < intervalCount; ++x) { - destVector = gatherValues256(string1 + x * vectorSize); - sourceVector = gatherValues256(string2 + x * vectorSize); - if (_mm256_movemask_epi8(_mm256_cmpeq_epi8(destVector, sourceVector)) != static_cast(maskValue)) { + destvector = gatherValues256(string1 + x * vectorSize); + sourcevector = gatherValues256(string2 + x * vectorSize); + if (_mm256_movemask_epi8(_mm256_cmpeq_epi8(destvector, sourcevector)) != static_cast(maskValue)) { return false; } } @@ -532,175 +379,84 @@ namespace JsonifierInternal { return true; } - template inline bool compareValues(const ValueType01* string1, const ValueType02* string2, uint64_t length) { + template inline bool compareValues(const value_type01* string1, const value_type02* string2, uint64_t length) { if (length >= 32) { return compareValues32(string1, string2, length); } else if (length >= 16) { return compareValues16(string1, string2, length); } else { - return (std::memcmp(string1, string2, length * sizeof(ValueType01)) == 0); + return (std::memcmp(string1, string2, length * sizeof(value_type01)) == 0); } } -#elif defined T_AVX - - template inline __m128i gatherValues128(const ValueType* str) { - alignas(ALIGNMENT) float newArray[sizeof(__m128i) / sizeof(float)]{}; - std::memcpy(newArray, str, sizeof(__m128i)); - return _mm_castps_si128(_mm_load_ps(newArray)); - } +#elif JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX) - template inline uint64_t findFirstCharacterNotEqual(const ValueType01* str, uint64_t length, ValueType02 target) { - static constexpr uint32_t vecSize = sizeof(__m128); - const __m128i targetVec = _mm_set1_epi8(target); - uint64_t remainingBytes = length; - __m128i currentVec{}; + template inline uint64_t find(const value_type01* str, uint64_t length, const value_type02* sub, uint64_t subLength = 1) { + static constexpr uint64_t vecSize = sizeof(avx_int_128); + uint64_t remainingBytes{ length }; uint64_t index{}; - uint32_t mask{}; - - while (remainingBytes >= vecSize) { - currentVec = gatherValues128(str); - mask = _mm_movemask_epi8(_mm_cmpeq_epi8(targetVec, currentVec)); - - if (mask != 0xffff) { - uint32_t firstNonMatchMask = ~mask; - return index + _tzcnt_u16(firstNonMatchMask); - } - str += vecSize; - index += vecSize; - remainingBytes -= vecSize; - } - - for (uint64_t i = 0; i < remainingBytes; i++) { - if (str[i] != target) { - return index + i; - } + if (subLength == 0) { + return 0; } + auto strNew = str; - return std::numeric_limits::max(); - } - - - template inline uint64_t findSingleCharacter(const ValueType01* str, uint64_t length, ValueType02 target) { - static constexpr uint32_t vecSize = sizeof(__m128); - const __m128i targetVec = _mm_set1_epi8(target); - uint64_t remainingBytes{ length }; - __m128i currentVec{}; - uint64_t index{}; - uint32_t mask{}; while (remainingBytes >= vecSize) { - currentVec = gatherValues128(str); - mask = _mm_movemask_epi8(_mm_cmpeq_epi8(targetVec, currentVec)); - - if (mask != 0) { - return index + _tzcnt_u16(mask); - } - - str += vecSize; + avx_int_128 currentVec = gatherValues128(strNew); + + const avx_int_128 subVec = _mm_set1_epi8(static_cast(sub[0])); + uint64_t mask = static_cast(_mm_movemask_epi8(_mm_cmpeq_epi8(subVec, currentVec))); + do { + if (mask != 0) { + uint64_t pos = tzCount(mask); + if (memcmp(strNew + pos, sub, subLength) == 0) { + return pos + index; + } + mask = blsr(mask); + } + } while (mask != 0); + + strNew += vecSize; index += vecSize; remainingBytes -= vecSize; } - for (uint64_t i = 0; i < remainingBytes; i++) { - if (str[i] == target) { - return index + i; - } - } - - return std::numeric_limits::max(); - } - - template inline uint64_t findLastSingleCharacter(const ValueType01* str, uint64_t length, ValueType02 target) { - static constexpr uint32_t vecSize = sizeof(__m128); - const __m128i targetVec = _mm_set1_epi8(target); - uint64_t remainingBytes{}; - __m128i currentVec{}; - uint64_t index{ length }; - uint32_t mask{}; - str += length - vecSize; - while (remainingBytes >= 0) { - currentVec = gatherValues128(str); - mask = _mm_movemask_epi8(_mm_cmpeq_epi8(targetVec, currentVec)); - - if (mask != 0) { - return index - _lzcnt_u32(mask); + if (remainingBytes >= subLength) { + for (int64_t i = 0; i < static_cast(remainingBytes); ++i) { + if (str[index + i] == sub[0]) { + if (memcmp(str + index + i, sub, subLength) == 0) { + return index + i; + } + } } - - str -= vecSize; - index -= vecSize; - remainingBytes -= vecSize; } - for (uint64_t i = remainingBytes; i > 0; --i) { - if (str[i] == target) { - return index + i; - } - } return std::numeric_limits::max(); } - template inline bool compareValues(const ValueType01* string1, const ValueType02* string2, uint64_t length) { - return (std::memcmp(string1, string2, length * sizeof(ValueType01)) == 0); + template inline bool compareValues(const value_type01* string1, const value_type02* string2, uint64_t length) { + return (std::memcmp(string1, string2, length * sizeof(value_type01)) == 0); } #else - struct __m128I { - inline __m128I() noexcept = default; - inline __m128I(__m128I&& valueNew) { - *this = std::move(valueNew); - } - - inline __m128I& operator=(__m128I&& valueNew) { - values[0] = valueNew.values[0]; - values[1] = valueNew.values[1]; - return *this; - } - - inline __m128I(const __m128I& valueNew) { - *this = std::move(valueNew); - } - - inline __m128I& operator=(const __m128I& valueNew) { - values[0] = valueNew.values[0]; - values[1] = valueNew.values[1]; - return *this; - } - - uint64_t values[2]{}; - }; - - template inline __m128I gatherValues128(const ValueType* str) { - alignas(ALIGNMENT) __m128I newArray{}; - std::memcpy(&newArray, str, sizeof(__m128I)); - return newArray; - } - - template inline uint64_t findFirstCharacterNotEqual(const ValueType01* str, uint64_t length, ValueType02 target) { - return std::basic_string_view{ static_cast(str), length }.find_first_not_of(static_cast(target)); - } - - template inline uint64_t findSingleCharacter(const ValueType01* str, uint64_t length, ValueType02 target) { - return std::basic_string_view{ static_cast(str), length }.find(static_cast(target)); - } - - template inline uint64_t findLastSingleCharacter(const ValueType01* str, uint64_t length, ValueType02 target) { - return std::basic_string_view{ static_cast(str), length }.find_last_of(static_cast(target)); + template inline uint64_t find(const value_type01* str, uint64_t length, value_type02* target, uint64_t subLength = 0) { + std::basic_string_view> newString{ target, subLength }; + return std::basic_string_view{ static_cast(str), length }.find(newString); } - template inline bool compareValues(const void* destVector, const void* sourceVector, uint64_t length) { - return std::basic_string_view>{ static_cast(destVector), length } == - std::basic_string_view>{ static_cast(sourceVector), length }; + template inline bool compareValues(const void* destvector, const void* sourcevector, uint64_t length) { + return std::basic_string_view>{ static_cast(destvector), length } == + std::basic_string_view>{ static_cast(sourcevector), length }; } #endif - class JsonifierCoreInternal { + class jsonifier_core_internal { public: - template static inline bool compare(const ValueType01* destVector, const ValueType02* sourceVector, uint64_t length) { - return compareValues(destVector, sourceVector, length); + template inline static bool compare(const value_type01* destvector, const value_type02* sourcevector, uint64_t length) { + return compareValues(destvector, sourcevector, length); } }; -}// namespace JsonifierInternal \ No newline at end of file +}// namespace jsonifier_internal diff --git a/Include/jsonifier/Concepts.hpp b/Include/jsonifier/Concepts.hpp new file mode 100644 index 000000000..5b17ff380 --- /dev/null +++ b/Include/jsonifier/Concepts.hpp @@ -0,0 +1,291 @@ +/* + MIT License + + Copyright (c) 2023 RealTimeChris + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, and to permit + persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE + FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ +/// https://github.com/RealTimeChris/jsonifier +/// Feb 3, 2023 +#pragma once + +#include +#include +#include +#include + +namespace jsonifier { + + class raw_json_data; + + template class vector; + + template struct core {}; + + template struct array { + value_type parseValue; + }; + + template array(value_type) -> array; + + template struct object { + value_type parseValue; + }; + + template object(value_type) -> object; +} + +namespace jsonifier_internal { + + // From: + // https://stackoverflow.com/questions/16337610/how-to-know-if-a-type-is-a-specialization-of-stdvector + template typename Ref> struct is_specialization_v : std::false_type {}; + + template typename Ref, typename... Args> struct is_specialization_v, Ref> : std::true_type {}; + + template using ref_unwrap = std::decay_t; + + template using Tag = std::integral_constant; + + template constexpr Tag TagV{}; + + template + concept range = requires(value_type& value) { + typename value_type::value_type; + requires !std::same_as; + requires !std::same_as; + }; + + template + concept stateless = std::is_empty_v>; + + template + concept map_subscriptable = requires(value_type value) { + { value[std::declval()] } -> std::same_as; + } || requires(value_type value) { + { value[std::declval()] } -> std::same_as; + }; + + template + concept vector_subscriptable = requires(value_type value) { + { value[std::declval()] } -> std::same_as>::reference>; + } || requires(value_type value) { + { value[std::declval()] } -> std::same_as>::const_reference>; + }; + + template + concept pair_t = requires(value_type value) { + { value.first } -> std::same_as; + { value.second } -> std::same_as; + }; + + template + concept has_size = requires(value_type value) { + { value.size() }; + }; + + template + concept has_data = requires(value_type data) { + { data.data() }; + }; + + template + concept void_t = std::is_void_v; + + template + concept indexable = stateless || requires(value_type value) { value[Tag<0>()]; }; + + template + concept same_as = std::same_as && std::same_as; + + template + concept other_than = !std::same_as, u>; + + template + concept base_list_tuple = requires() { typename ref_unwrap::base_list; }; + + template + concept ordered = requires(value_type const& object) { + { object <=> object }; + }; + + template + concept equality_comparable = requires(value_type const& object) { + { object == object } -> same_as; + }; + + template + concept bool_t = std::same_as, bool>; + + template + concept char_array_t = std::is_array_v && std::is_same_v>, char>; + + template + concept pointer_t = std::is_pointer_v && !char_array_t; + + template + concept signed_t = std::signed_integral> && !bool_t>; + + template + concept unsigned_t = std::unsigned_integral> && !bool_t> && !signed_t; + + template + concept float_t = std::floating_point; + + template + concept char_t = std::same_as || std::same_as || std::same_as || std::same_as || + std::same_as; + + template + concept num_t = ( float_t || unsigned_t || signed_t )&&!std::same_as; + template + concept searchable_string_value = char_t || indexable; + + template + concept has_data_and_size = has_data && has_size; + + template + concept has_substr = requires(value_type value) { + { value.substr(std::declval(), std::declval()) }; + }; + + template + concept string_t = has_substr> && has_data_and_size> && !std::same_as> && + vector_subscriptable> && !char_array_t && !pointer_t; + + template + concept map_t = requires(value_type data) { + typename value_type::mapped_type; + typename value_type::key_type; + } && range && map_subscriptable && !string_t; + + template + concept has_emplace_back = requires(value_type data) { + { data.emplace_back(std::declval()) } -> std::same_as; + }; + + template + concept has_release = requires(value_type value) { + { value.release() } -> std::same_as; + }; + + template + concept unique_ptr_t = requires(value_type other) { + typename value_type::element_type; + typename value_type::deleter_type; + { other.release() } -> std::same_as; + } && has_release && !std::is_copy_assignable_v; + + template + concept shared_ptr_t = (requires(value_type other) { + typename value_type::element_type; + typename value_type::deleter_type; + { other.release() } -> std::same_as; + }) && has_release; + + template + concept has_find = requires(Container c) { + { c.find(std::declval()) }; + }; + + template + concept has_excluded_keys = requires(value_type value) { + { value.excludedKeys }; + }; + + template + concept null_t = std::same_as; + + template + concept has_resize = requires(value_type value) { value.resize(0); }; + + template inline auto dataPtr(value_type& buffer) { + if constexpr (has_resize) { + return buffer.data(); + } else { + return buffer; + } + } + + template + concept raw_json_t = std::same_as && !string_t; + + template + concept jsonifier_t = requires { jsonifier::core>::parseValue; }; + + struct empty_val { + static constexpr std::tuple<> parseValue{}; + }; + + template constexpr auto coreWrapperV = [] { + if constexpr (jsonifier_t) { + return jsonifier::core::parseValue; + } else { + return empty_val{}; + } + }(); + + template constexpr auto coreV = coreWrapperV>.parseValue; + + template using core_t = ref_unwrap)>; + + template using core_wrapper_t = ref_unwrap>)>; + + template + concept jsonifier_array_t = jsonifier_t && is_specialization_v, jsonifier::array>::value; + + template + concept jsonifier_object_t = jsonifier_t && is_specialization_v, jsonifier::object>::value; + + template + concept object_t = map_t || jsonifier_object_t; + + template + concept enum_t = std::is_enum::value; + + template + concept tuple_t = requires(value_type value) { std::tuple_size::value; } && !range; + + template + concept array_tuple_t = jsonifier_array_t || tuple_t>; + + template + concept vector_t = ( !map_t && vector_subscriptable && has_data && has_emplace_back )&&!jsonifier_array_t && + !tuple_t && !has_substr && requires(value_type data) { typename value_type::value_type; } || + is_specialization_v::value; + + template + concept raw_array_t = ( ( !map_t && vector_subscriptable && has_data && !has_emplace_back )&&!jsonifier_array_t && + !tuple_t && !has_substr && !has_resize ) || + std::is_array_v; + + template + concept vector_like = has_resize && vector_subscriptable && has_data; + + template + concept core_type = is_specialization_v, jsonifier::core>::value; + + template + concept time_type = is_specialization_v, std::chrono::duration>::value; + + template + concept char_type = requires(value_type) { sizeof(value_type) == 1; }; + + template + concept integer_t = std::integral && !bool_t>; + +}// namespace jsonifier_internal diff --git a/Include/jsonifier/Derailleur.hpp b/Include/jsonifier/Derailleur.hpp index 085d43850..fcee7ca71 100644 --- a/Include/jsonifier/Derailleur.hpp +++ b/Include/jsonifier/Derailleur.hpp @@ -19,7 +19,7 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/// https://github.com/RealTimeChris/Jsonifier +/// https://github.com/RealTimeChris/jsonifier /// Feb 20, 2023 #pragma once @@ -27,24 +27,26 @@ #include #include -namespace JsonifierInternal { +namespace jsonifier_internal { - enum class TypeOfMisread { Wrong_Type = 0, Damaged_Input = 1 }; + enum class type_of_misread { Wrong_Type = 0, Damaged_Input = 1 }; - template class Derailleur { + template class derailleur { public: - template static inline bool checkForMatchClosed(StructuralIterator& iter, std::source_location location = std::source_location::current()) { + using size_type = uint64_t; + + template inline static bool checkForMatchClosed(structural_iterator& iter, std::source_location location = std::source_location::current()) { if (iter == c) { ++iter; return true; } else { reportError(iter, location); - skipToNextValue(iter); + skipToNextValue(iter); return false; } } - template static inline bool checkForMatchOpen(StructuralIterator& iter) { + template inline static bool checkForMatchOpen(structural_iterator& iter) { if (iter == c) { ++iter; return true; @@ -53,7 +55,28 @@ namespace JsonifierInternal { } } - static inline void skipValue(StructuralIterator& iter) noexcept { + inline static void skipToNextValue(structural_iterator& iter) { + while (iter != ',' && iter != iter) { + switch (**iter) { + case '{': { + skipObject(iter); + break; + } + case '[': { + skipArray(iter); + break; + } + case '\0': { + break; + } + default: { + ++iter; + } + } + } + } + + inline static void skipValue(structural_iterator& iter) { switch (**iter) { case '{': { skipObject(iter); @@ -72,9 +95,9 @@ namespace JsonifierInternal { } } - static inline size_t countArrayElements(StructuralIterator iter) noexcept { - size_t currentDepth{ 1 }; - size_t currentCount{ 1 }; + inline static size_type countArrayElements(structural_iterator iter) { + size_type currentDepth{ 1 }; + size_type currentCount{ 1 }; if (iter == ']') { ++iter; return {}; @@ -108,9 +131,9 @@ namespace JsonifierInternal { } protected: - static inline void skipObject(StructuralIterator& iter) noexcept { + inline static void skipObject(structural_iterator& iter) { ++iter; - uint64_t currentDepth{ 1 }; + size_type currentDepth{ 1 }; if (iter == '}') { ++iter; return; @@ -135,9 +158,9 @@ namespace JsonifierInternal { } } - static inline void skipArray(StructuralIterator& iter) noexcept { + inline static void skipArray(structural_iterator& iter) { ++iter; - uint64_t currentDepth{ 1 }; + size_type currentDepth{ 1 }; if (iter == ']') { ++iter; return; @@ -162,33 +185,23 @@ namespace JsonifierInternal { } } - static inline bool isTypeType(uint8_t c) { - const uint8_t array01[]{ "0123456789-ftn\"{[" }; - return findSingleCharacter(array01, std::size(array01), c) != Jsonifier::String::npos; + inline static bool isTypeType(uint8_t c) { + static constexpr uint8_t array01[]{ "0123456789-ftn\"{[" }; + return find(array01, std::size(array01), &c) != jsonifier::string::npos; } - static inline bool isDigitType(uint8_t c) { - const uint8_t array01[]{ "0123456789-" }; - return findSingleCharacter(array01, std::size(array01), c) != Jsonifier::String::npos; - } - - template static inline void skipToNextValue(StructuralIterator& iter) { - while (iter != iter) { - if (iter == ',') { - return; - } - ++iter; - } - return; + inline static bool isDigitType(uint8_t c) { + static constexpr uint8_t array01[]{ "0123456789-" }; + return find(array01, std::size(array01), &c) != jsonifier::string::npos; } - static inline Jsonifier::StringView getValueType(uint8_t charToCheck) { - static constexpr Jsonifier::StringView array{ "Array" }; - static constexpr Jsonifier::StringView object{ "Object" }; - static constexpr Jsonifier::StringView boolean{ "Bool" }; - static constexpr Jsonifier::StringView number{ "Number" }; - static constexpr Jsonifier::StringView str{ "String" }; - static constexpr Jsonifier::StringView null{ "Null" }; + inline static jsonifier::string_view getValueType(uint8_t charToCheck) { + static constexpr jsonifier::string_view array{ "array" }; + static constexpr jsonifier::string_view object{ "object" }; + static constexpr jsonifier::string_view boolean{ "Bool" }; + static constexpr jsonifier::string_view number{ "Number" }; + static constexpr jsonifier::string_view str{ "string" }; + static constexpr jsonifier::string_view null{ "Null" }; if (isDigitType(charToCheck)) { return number; } else if (charToCheck == 't' || charToCheck == 'f') { @@ -206,9 +219,9 @@ namespace JsonifierInternal { } } - template static inline void reportError(StructuralIterator& iter, std::source_location location) { + template inline static void reportError(structural_iterator& iter, std::source_location location) { if (printErrors) { - if (collectMisReadType(iter) == TypeOfMisread::Wrong_Type) { + if (collectMisReadType(iter) == type_of_misread::Wrong_Type) { std::cout << "It seems you mismatched a value for a value of type: " << getValueType(c) << ", the found value was actually: " << getValueType(**iter) << ", at index: " << iter.getCurrentIndex() << ", in file: " << location.file_name() << ", at: " << location.line() << ":" << location.column() << ", in function: " << location.function_name() << "()." << std::endl; @@ -220,11 +233,11 @@ namespace JsonifierInternal { } } - template static inline TypeOfMisread collectMisReadType(StructuralIterator& iter) { + template inline static type_of_misread collectMisReadType(structural_iterator& iter) { if (isTypeType(**iter) && isTypeType(c)) { - return TypeOfMisread::Wrong_Type; + return type_of_misread::Wrong_Type; } else { - return TypeOfMisread::Damaged_Input; + return type_of_misread::Damaged_Input; } } }; diff --git a/Include/jsonifier/Error.hpp b/Include/jsonifier/Error.hpp index 016fad1ef..5c1a4477b 100644 --- a/Include/jsonifier/Error.hpp +++ b/Include/jsonifier/Error.hpp @@ -19,7 +19,7 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/// https://github.com/RealTimeChris/Jsonifier +/// https://github.com/RealTimeChris/jsonifier /// Feb 3, 2023 #pragma once @@ -28,8 +28,8 @@ #include #include -namespace JsonifierInternal { +namespace jsonifier_internal { - enum class ErrorCode { Success = 0, Parse_Error = 1, Number_Error = 2, Unknown_Key = 3, Incorrect_Type = 4, Setup_Error = 5 }; + enum class error_code { Success = 0, Parse_Error = 1, Number_Error = 2, Unknown_Key = 3, Incorrect_Type = 4, Setup_Error = 5 }; } diff --git a/Include/jsonifier/Expected.hpp b/Include/jsonifier/Expected.hpp index ab8a5d0fc..2422ed86b 100644 --- a/Include/jsonifier/Expected.hpp +++ b/Include/jsonifier/Expected.hpp @@ -19,72 +19,63 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/// https://github.com/RealTimeChris/Jsonifier +/// https://github.com/RealTimeChris/jsonifier /// Feb 20, 2023 #pragma once #include -namespace JsonifierInternal { +namespace jsonifier_internal { - template class Unexpected; + template class unexpected; - struct UnexpectT { - explicit constexpr UnexpectT() noexcept = default; - }; - - template class Expected; + template class expected; - template - requires std::is_void_v - class Expected; + template + requires std::is_void_v + class expected; - template class Unexpected { + template class unexpected { public: - constexpr Unexpected& operator=(Unexpected&&) noexcept = default; - constexpr Unexpected(Unexpected&& other) noexcept = default; - constexpr Unexpected& operator=(const Unexpected&) noexcept = default; - constexpr Unexpected(const Unexpected& other) noexcept = default; - - constexpr Unexpected& operator=(ETy&& other) { + constexpr unexpected& operator=(ETy&& other) { unex = std::move(other); return *this; } - constexpr Unexpected(ETy&& other) { + constexpr unexpected(ETy&& other) { *this = std::move(other); } - constexpr Unexpected& operator=(const ETy& other) { + constexpr unexpected& operator=(const ETy& other) { unex = other; return *this; } - constexpr Unexpected(const ETy& other) { + constexpr unexpected(const ETy& other) { *this = other; } - constexpr const ETy&& error() const&& noexcept { + constexpr const ETy&& error() const&& { return std::move(unex); } - constexpr ETy&& error() && noexcept { + constexpr ETy&& error() && { return std::move(unex); } - constexpr const ETy& error() const& noexcept { + constexpr const ETy& error() const& { return unex; } - constexpr ETy& error() & noexcept { + constexpr ETy& error() & { return unex; } - constexpr void swap(Unexpected& other) noexcept { + constexpr void swap(unexpected& other) { std::swap(unex, other.unex); } - friend constexpr bool operator==(const Unexpected& lhs, const Unexpected& rhs) { + friend constexpr bool operator==(const unexpected& lhs, const unexpected& rhs) { return lhs.unex == rhs.unex; } @@ -92,51 +83,46 @@ namespace JsonifierInternal { ETy unex{}; }; - template Unexpected(ETy) -> Unexpected; + template unexpected(ETy) -> unexpected; - template class Expected { + template class expected { public: - using value_type = ValueType; + using value_type = value_type_new; using error_type = ETy; - using unexpected_type = Unexpected; - template using rebind = Expected; + using unexpected_type = unexpected; + template using rebind = expected; - constexpr Expected() noexcept = default; + constexpr expected() = default; - constexpr Expected& operator=(Expected&&) noexcept = default; - constexpr explicit Expected(Expected&&) noexcept = default; - constexpr Expected& operator=(const Expected&) noexcept = default; - constexpr Expected(const Expected&) noexcept = default; - - template constexpr Expected& operator=(Unexpected&& other) { + template constexpr expected& operator=(unexpected&& other) { hasValue = false; return *this; } - template constexpr Expected(Unexpected&& other) { + template constexpr expected(unexpected&& other) { *this = std::move(other); } - template constexpr Expected& operator=(const Unexpected& other) { + template constexpr expected& operator=(const unexpected& other) { hasValue = false; return *this; } - template constexpr Expected(const Unexpected& other) { + template constexpr expected(const unexpected& other) { *this = other; } - constexpr Expected& operator=(ValueType&& other) { + constexpr expected& operator=(value_type&& other) { val = std::move(other); hasValue = true; return *this; } - constexpr Expected(ValueType&& v) { + constexpr expected(value_type&& v) { *this = std::move(v); } - constexpr void swap(Expected& other) noexcept { + constexpr void swap(expected& other) { if (hasValue) { std::swap(val, other.val); } else { @@ -145,51 +131,51 @@ namespace JsonifierInternal { std::swap(hasValue, other.hasValue); } - constexpr const ValueType* operator->() const noexcept { + constexpr const value_type* operator->() const { return &val; } - constexpr ValueType* operator->() noexcept { + constexpr value_type* operator->() { return &val; } - constexpr const ValueType&& operator*() const&& noexcept { + constexpr const value_type&& operator*() const&& { return std::move(val); } - constexpr ValueType&& operator*() && noexcept { + constexpr value_type&& operator*() && { return std::move(val); } - constexpr const ValueType& operator*() const& noexcept { + constexpr const value_type& operator*() const& { return val; } - constexpr ValueType& operator*() & noexcept { + constexpr value_type& operator*() & { return val; } - constexpr explicit operator bool() const noexcept { + constexpr explicit operator bool() const { return hasValue; } - constexpr bool has_value() const noexcept { + constexpr bool has_value() const { return hasValue; } - constexpr const ValueType&& value() const&& { + constexpr const value_type&& value() const&& { return std::move(val); } - constexpr ValueType&& value() && { + constexpr value_type&& value() && { return std::move(val); } - constexpr const ValueType& value() const& { + constexpr const value_type& value() const& { return val; } - constexpr ValueType& value() & { + constexpr value_type& value() & { return val; } @@ -209,62 +195,57 @@ namespace JsonifierInternal { return unex; } - friend constexpr bool operator==(const Expected& x, const Expected& y) { + friend constexpr bool operator==(const expected& x, const expected& y) { return x.hasValue == y.hasValue && x.unex == y.unex && x.val == y.val; } - constexpr ~Expected() noexcept {}; + constexpr ~expected(){}; protected: bool hasValue{}; union { - ValueType val{}; + value_type val{}; ETy unex; }; }; - template - requires std::is_void_v - class Expected { + template + requires std::is_void_v + class expected { public: - using value_type = ValueType; + using value_type = value_type_new; using error_type = ETy; - using unexpected_type = Unexpected; - - template using rebind = Expected; + using unexpected_type = unexpected; - constexpr Expected() noexcept = default; + template using rebind = expected; - constexpr Expected& operator=(Expected&&) noexcept = default; - constexpr explicit Expected(Expected&&) noexcept = default; - constexpr Expected& operator=(const Expected&) noexcept = default; - constexpr explicit Expected(const Expected&) noexcept = default; + constexpr expected() = default; - template constexpr Expected& operator=(Unexpected&& other) { + template constexpr expected& operator=(unexpected&& other) { return *this; } - template constexpr Expected(Unexpected&& other) { + template constexpr expected(unexpected&& other) { *this = std::move(other); } - template constexpr Expected& operator=(const Unexpected& other) { + template constexpr expected& operator=(const unexpected& other) { return *this; } - template constexpr Expected(const Unexpected& other) { + template constexpr expected(const unexpected& other) { *this = other; } - constexpr void swap(Expected& other) noexcept { + constexpr void swap(expected& other) { std::swap(unex, other.unex); } - constexpr explicit operator bool() const noexcept { + constexpr explicit operator bool() const { return false; } - constexpr bool has_value() const noexcept { + constexpr bool has_value() const { return false; } @@ -284,11 +265,11 @@ namespace JsonifierInternal { return unex; } - template friend constexpr bool operator==(const Expected& x, const Expected& y) { + template friend constexpr bool operator==(const expected& x, const expected& y) { return x.unex == y.unex; } - constexpr ~Expected() noexcept {}; + constexpr ~expected(){}; protected: union { diff --git a/Include/jsonifier/HashMap.hpp b/Include/jsonifier/HashMap.hpp index d3ddcefae..03d1ed9d3 100644 --- a/Include/jsonifier/HashMap.hpp +++ b/Include/jsonifier/HashMap.hpp @@ -19,7 +19,7 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/// https://github.com/RealTimeChris/Jsonifier +/// https://github.com/RealTimeChris/jsonifier /// Feb 20, 2023 #pragma once @@ -30,13 +30,11 @@ #include #include #include -#include -#include #include -namespace JsonifierInternal { +namespace jsonifier_internal { - template constexpr uint64_t toUint64(const ValueType* bytes, const uint64_t n) noexcept { + template constexpr uint64_t toUint64(const value_type* bytes, const uint64_t n) { if (std::is_constant_evaluated()) { uint64_t res{}; for (uint64_t x = 0; x < n; ++x) { @@ -50,7 +48,7 @@ namespace JsonifierInternal { } } - template constexpr uint64_t toUint64N(const ValueType* bytes) noexcept { + template constexpr uint64_t toUint64N(const value_type* bytes) { static_assert(n <= 8); if (std::is_constant_evaluated()) { uint64_t res{}; @@ -65,17 +63,17 @@ namespace JsonifierInternal { } } - struct StringCompareHelper { - template constexpr bool operator()(T0&& lhs, T1&& rhs) const noexcept { + struct string_compare_helper { + template constexpr bool operator()(T0&& lhs, T1&& rhs) const { if (std::is_constant_evaluated()) { return stringConstCompare(std::forward(lhs), std::forward(rhs)); } else { - return JsonifierCoreInternal::compare(lhs.data(), rhs.data(), rhs.size()); + return jsonifier_core_internal::compare(lhs.data(), rhs.data(), rhs.size()); } } }; - template constexpr uint64_t fnv1aHash(const StringT& value) { + template constexpr uint64_t fnv1aHash(const string_t& value) { uint64_t d = 5381; for (const auto& c: value) d = d * 33 + static_cast(c); @@ -84,27 +82,45 @@ namespace JsonifierInternal { // https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function // With the lowest bits removed, based on experimental setup. - template constexpr uint64_t fnv1aHash(const StringT& value, uint64_t seed) { + template constexpr uint64_t fnv1aHash(const string_t& value, uint64_t seed) { uint64_t d = (0x811c9dc5 ^ seed) * static_cast(0x01000193); for (const auto& c: value) d = (d ^ static_cast(c)) * static_cast(0x01000193); return d >> 8; } - template struct Hash> { - constexpr uint64_t operator()(Jsonifier::StringViewBase value) const noexcept { + template struct hash> { + constexpr uint64_t operator()(jsonifier::string_view_base value) const { return fnv1aHash(value); } - constexpr uint64_t operator()(Jsonifier::StringViewBase value, uint64_t seed) const noexcept { + constexpr uint64_t operator()(jsonifier::string_view_base value, uint64_t seed) const { return fnv1aHash(value, seed); } - constexpr uint64_t operator()(Jsonifier::StringViewBase value) const noexcept { + constexpr uint64_t operator()(jsonifier::string_view_base value) const { return fnv1aHash(value); } - constexpr uint64_t operator()(Jsonifier::StringViewBase value, uint64_t seed) const noexcept { + constexpr uint64_t operator()(jsonifier::string_view_base value, uint64_t seed) const { + return fnv1aHash(value, seed); + } + }; + + template struct hash> { + constexpr uint64_t operator()(std::basic_string value) const { + return fnv1aHash(value); + } + + constexpr uint64_t operator()(std::basic_string value, uint64_t seed) const { + return fnv1aHash(value, seed); + } + + constexpr uint64_t operator()(std::basic_string value) const { + return fnv1aHash(value); + } + + constexpr uint64_t operator()(std::basic_string value, uint64_t seed) const { return fnv1aHash(value, seed); } }; @@ -119,7 +135,7 @@ namespace JsonifierInternal { return v; } - template constexpr auto log(ValueType v) { + template constexpr auto log(value_type v) { uint64_t n = 0; while (v > 1) { n += 1; @@ -129,8 +145,8 @@ namespace JsonifierInternal { } constexpr uint64_t bitWeight(uint64_t n) { - return static_cast(n <= 8ull) * sizeof(uint32_t) + (static_cast(n <= 8ull) * sizeof(uint32_t)) + - (static_cast(n <= 8ull) * sizeof(unsigned long long)) + (n <= 128ull); + return static_cast(n <= 8ULL) * sizeof(uint32_t) + (static_cast(n <= 8ULL) * sizeof(uint32_t)) + + (static_cast(n <= 8ULL) * sizeof(unsigned long long)) + (n <= 128ULL); } template inline unsigned long long selectUintLeast(std::integral_constant) { @@ -140,32 +156,32 @@ namespace JsonifierInternal { template using SelectUintLeastT = decltype(selectUintLeast(std::integral_constant())); - template constexpr void primitiveSwap(ValueType&& a, ValueType&& b) { + template constexpr void primitiveSwap(value_type&& a, value_type&& b) { auto tmp = std::move(a); a = std::move(b); b = std::move(tmp); } - template constexpr void primitiveSwap(Pair&& a, Pair&& b) { - primitiveSwap(std::forward>(a.first), std::forward>(b.first)); - primitiveSwap(std::forward>(a.second), std::forward>(b.second)); + template constexpr void primitiveSwap(pair&& a, pair&& b) { + primitiveSwap(std::forward>(a.first), std::forward>(b.first)); + primitiveSwap(std::forward>(a.second), std::forward>(b.second)); } - template constexpr void primitiveSwap(Tuplet::Tuple&& a, Tuplet::Tuple&& b, std::index_sequence) { + template constexpr void primitiveSwap(tuplet::tuple&& a, tuplet::tuple&& b, std::index_sequence) { using swallow = int32_t[]; - ( void )swallow{ (primitiveSwap(std::forward(Tuplet::get(a)), std::forward(Tuplet::get(b))), 0)... }; + ( void )swallow{ (primitiveSwap(std::forward(tuplet::get(a)), std::forward(tuplet::get(b))), 0)... }; } - template constexpr void primitiveSwap(Tuplet::Tuple& a, Tuplet::Tuple& b) { + template constexpr void primitiveSwap(tuplet::tuple& a, tuplet::tuple& b) { primitiveSwap(a, b, std::make_index_sequence()); } - template constexpr Iterator partition(Iterator left, Iterator right, const Compare& compare) { + template constexpr iterator partition(iterator left, iterator right, const compare& compareNew) { auto pivot = left + (right - left) / 2; auto value = *pivot; primitiveSwap(*right, *pivot); for (auto it = left; 0 < right - it; ++it) { - if (compare(*it, value)) { + if (compareNew(*it, value)) { primitiveSwap(*it, *left); ++left; } @@ -174,21 +190,21 @@ namespace JsonifierInternal { return left; } - template constexpr void quicksort(Iterator left, Iterator right, const Compare& compare) { + template constexpr void quicksort(iterator left, iterator right, const compare& compareNew) { while (0 < right - left) { - auto new_pivot = partition(left, right, compare); - quicksort(left, new_pivot, compare); + auto new_pivot = partition(left, right, compareNew); + quicksort(left, new_pivot, compareNew); left = new_pivot + 1; } } - template constexpr RawArray quicksort(RawArray const& array, const Compare& compare) { - RawArray res = array; - quicksort(res.begin(), res.end() - 1, compare); + template constexpr raw_array quicksort(raw_array const& array, const compare& compareNew) { + raw_array res = array; + quicksort(res.begin(), res.end() - 1, compareNew); return res; } - template constexpr bool equal(InputIt1 first1, InputIt1 last1, InputIt2 first2) { + template constexpr bool equal(input_iter_1 first1, input_iter_1 last1, input_iter_2 first2) { for (; first1 != last1; ++first1, ++first2) { if (!(*first1 == *first2)) { return false; @@ -197,38 +213,38 @@ namespace JsonifierInternal { return true; } - template class LinearCongruentialEngine { - static_assert(std::is_unsigned::value, "UintType must be an unsigned integral type."); + template class linear_congruential_engine { + static_assert(std::is_unsigned::value, "uint_type must be an unsigned integral type."); - template static constexpr UintType modulo(ValueType val, std::integral_constant) { - return static_cast(val); + template static constexpr uint_type modulo(value_type val, std::integral_constant) { + return static_cast(val); } - template static constexpr UintType modulo(ValueType val, std::integral_constant) { - return static_cast(val % m2); + template static constexpr uint_type modulo(value_type val, std::integral_constant) { + return static_cast(val % m2); } public: - using ResultType = UintType; - static constexpr ResultType multiplier = a; - static constexpr ResultType increment = c; - static constexpr ResultType modulus = m; - static constexpr ResultType default_seed = 1u; - - inline LinearCongruentialEngine() noexcept = default; - constexpr LinearCongruentialEngine(ResultType S) { + using result_type = uint_type; + static constexpr result_type multiplier = a; + static constexpr result_type increment = c; + static constexpr result_type modulus = m; + static constexpr result_type default_seed = 1u; + + inline linear_congruential_engine() = default; + constexpr linear_congruential_engine(result_type S) { seed(S); } - inline void seed(ResultType S = default_seed) { + inline void seed(result_type S = default_seed) { state_ = S; } - constexpr ResultType operator()() { + constexpr result_type operator()() { using uint_least_t = SelectUintLeastT; uint_least_t tmp = static_cast(multiplier) * state_ + increment; - state_ = modulo(tmp, std::integral_constant()); + state_ = modulo(tmp, std::integral_constant()); return state_; } @@ -237,15 +253,15 @@ namespace JsonifierInternal { operator()(); } - constexpr bool operator==(LinearCongruentialEngine const& other) const { + constexpr bool operator==(linear_congruential_engine const& other) const { return state_ == other.state_; } protected: - ResultType state_ = default_seed; + result_type state_ = default_seed; }; - using MinStdRand = LinearCongruentialEngine; + using MinStdRand = linear_congruential_engine; using DefaultPrgT = MinStdRand; @@ -254,10 +270,10 @@ namespace JsonifierInternal { static constexpr uint64_t fnv64Prime = 1099511628211; static constexpr uint64_t fnv64OffsetBasis = 0xcbf29ce484222325; - template struct Xsm1 {}; + template struct xsm1 {}; - template<> struct Xsm1 { - template constexpr uint64_t operator()(ValueType&& value, const uint64_t seed) noexcept { + template<> struct xsm1 { + template constexpr uint64_t operator()(value_type&& value, const uint64_t seed) { uint64_t h = (fnv64OffsetBasis ^ seed) * fnv64Prime; const auto n = value.size(); @@ -268,9 +284,9 @@ namespace JsonifierInternal { h *= fnv64Prime; return h; } - using StringType = RefUnwrap; - const typename StringType::value_type* d0 = value.data(); - const typename StringType::value_type* end7 = value.data() + n - 7; + using string_type = ref_unwrap; + const typename string_type::value_type* d0 = value.data(); + const typename string_type::value_type* end7 = value.data() + n - 7; for (; d0 < end7; d0 += 8) { h ^= toUint64N<8>(d0); h ^= h >> 33; @@ -285,14 +301,14 @@ namespace JsonifierInternal { } }; - template<> struct Xsm1 { - constexpr uint32_t operator()(auto&& value, const uint32_t seed) noexcept { - uint64_t hash = Xsm1{}(value, seed); + template<> struct xsm1 { + constexpr uint32_t operator()(auto&& value, const uint32_t seed) { + uint64_t hash = xsm1{}(value, seed); return hash >> 32; } }; - constexpr bool contains(auto&& data, auto&& val) noexcept { + constexpr bool contains(auto&& data, auto&& val) { const auto n = data.size(); for (uint64_t x = 0; x < n; ++x) { if (data[x] == val) { @@ -302,15 +318,15 @@ namespace JsonifierInternal { return false; } - template constexpr auto naiveBucketSize() noexcept { + template constexpr auto naiveBucketSize() { return n < 8 ? 2 * n : 4 * n; } - template constexpr uint32_t naivePerfectHash(auto&& keys) noexcept { + template constexpr uint32_t naivePerfectHash(auto&& keys) { static_assert(n <= 20); constexpr uint64_t m = naiveBucketSize(); - RawArray hashes{}; - RawArray buckets{}; + raw_array hashes{}; + raw_array buckets{}; DefaultPrgT gen{}; @@ -318,7 +334,7 @@ namespace JsonifierInternal { uint32_t seed = gen(); uint64_t index = 0; for (const auto& key: keys) { - const auto hash = Xsm1{}(key, seed); + const auto hash = xsm1{}(key, seed); if (contains(std::span{ hashes.data(), index }, hash)) break; hashes[index] = hash; @@ -335,37 +351,37 @@ namespace JsonifierInternal { return seed; } - return (std::numeric_limits::max)(); + return std::numeric_limits::max(); } - template struct NaiveMap { + template struct naive_map { static_assert(n <= 20); static constexpr uint64_t m = naiveBucketSize(); uint32_t seed{}; - RawArray, n> items{}; - RawArray hashes{}; - RawArray table{}; + raw_array, n> items{}; + raw_array hashes{}; + raw_array table{}; - constexpr decltype(auto) begin() const noexcept { + constexpr decltype(auto) begin() const { return items.begin(); } - constexpr decltype(auto) end() const noexcept { + constexpr decltype(auto) end() const { return items.end(); } - constexpr Expected, ErrorCode> at(auto&& key) const noexcept { - const auto hash = Xsm1{}(key, seed); + constexpr expected, error_code> at(auto&& key) const { + const auto hash = xsm1{}(key, seed); const auto index = table[hash % m]; const auto& item = items[index]; if (hashes[index] != hash) [[unlikely]] { - return Unexpected(ErrorCode::Unknown_Key); + return unexpected(error_code::Unknown_Key); } return item.second; } - constexpr decltype(auto) find(auto&& key) const noexcept { - const auto hash = Xsm1{}(key, seed); + constexpr decltype(auto) find(auto&& key) const { + const auto hash = xsm1{}(key, seed); const auto index = table[hash % m]; if (hashes[index] != hash) [[unlikely]] return items.end(); @@ -373,15 +389,15 @@ namespace JsonifierInternal { } }; - template constexpr auto makeNaiveMap(std::initializer_list> pairs) { + template constexpr auto makeNaiveMap(std::initializer_list> pairs) { static_assert(n <= 20); if (pairs.size() != n) { throw std::runtime_error{ "pairs.size() != n" }; } - NaiveMap ht{}; + naive_map ht{}; constexpr uint64_t m = naiveBucketSize(); - RawArray keys{}; + raw_array keys{}; uint64_t x = 0; for (const auto& pair: pairs) { ht.items[x] = pair; @@ -394,97 +410,98 @@ namespace JsonifierInternal { } for (x = 0; x < n; ++x) { - const auto hash = Xsm1{}(keys[x], ht.seed); + const auto hash = xsm1{}(keys[x], ht.seed); ht.hashes[x] = hash; - ht.table[hash % m] = x; + ht.table[hash % m] = static_cast(x); } return ht; } - struct SingleCharHashDesc { + struct single_char_hash_desc { uint64_t n{}; bool valid{}; uint8_t min_diff{}; uint8_t front{}; uint8_t back{}; bool is_front_hash = true; + uint8_t padding[3]{}; }; - template constexpr SingleCharHashDesc singleCharHash(const RawArray& v) noexcept { + template constexpr single_char_hash_desc singleCharHash(const raw_array& v) { if constexpr (n > 255) { return {}; } - RawArray hashes; + raw_array hashes; for (uint64_t x = 0; x < n; ++x) { if (v[x].size() == 0) { return {}; } if constexpr (IsFrontHash) { - hashes[x] = v[x][0]; + hashes[x] = static_cast(v[x][0]); } else { - hashes[x] = v[x].back(); + hashes[x] = static_cast(v[x].back()); } } std::sort(hashes.begin(), hashes.end()); - uint8_t min_diff = (std::numeric_limits::max)(); + uint8_t min_diff = std::numeric_limits::max(); for (uint64_t x = 0; x < n - 1; ++x) { if ((hashes[x + 1] - hashes[x]) < min_diff) { - min_diff = hashes[x + 1] - hashes[x]; + min_diff = static_cast(hashes[x + 1] - hashes[x]); } } - return SingleCharHashDesc{ n, min_diff > 0, min_diff, hashes.front(), hashes.back(), IsFrontHash }; + return single_char_hash_desc{ n, min_diff > 0, min_diff, hashes.front(), hashes.back(), IsFrontHash }; } - template struct SingleCharMap { + template struct single_char_map { static constexpr auto n = D.n; static_assert(n < 256); - RawArray, n> items{}; - static constexpr uint64_t N_table = D.back - D.front + 1; - RawArray table{}; + raw_array, n> items{}; + static constexpr uint64_t N_table = static_cast(D.back) - D.front + 1; + raw_array table{}; - constexpr decltype(auto) begin() const noexcept { + constexpr decltype(auto) begin() const { return items.begin(); } - constexpr decltype(auto) end() const noexcept { + constexpr decltype(auto) end() const { return items.end(); } - constexpr Expected, ErrorCode> at(auto&& key) const noexcept { + constexpr expected, error_code> at(auto&& key) const { if (key.size() == 0) [[unlikely]] { - return Unexpected(ErrorCode::Unknown_Key); + return unexpected(error_code::Unknown_Key); } if constexpr (D.is_front_hash) { const auto k = static_cast(key[0] - D.front); if (k >= N_table) [[unlikely]] { - return Unexpected(ErrorCode::Unknown_Key); + return unexpected(error_code::Unknown_Key); } const auto index = table[k]; const auto& item = items[index]; if (!stringConstCompare(item.first, key)) [[unlikely]] { - return Unexpected(ErrorCode::Unknown_Key); + return unexpected(error_code::Unknown_Key); } return item.second; } else { const auto k = static_cast(key.back() - D.front); if (k >= N_table) [[unlikely]] { - return Unexpected(ErrorCode::Unknown_Key); + return unexpected(error_code::Unknown_Key); } const auto index = table[k]; const auto& item = items[index]; if (!stringConstCompare(item.first, key)) [[unlikely]] { - return Unexpected(ErrorCode::Unknown_Key); + return unexpected(error_code::Unknown_Key); } return item.second; } } - constexpr decltype(auto) find(auto&& key) const noexcept { + constexpr decltype(auto) find(auto&& key) const { if (key.size() == 0) [[unlikely]] { return items.end(); } @@ -513,17 +530,17 @@ namespace JsonifierInternal { } }; - template constexpr auto makeSingleCharMap(std::initializer_list> pairs) { + template constexpr auto makeSingleCharMap(std::initializer_list> pairs) { static_assert(D.n < 256); - SingleCharMap ht{}; + single_char_map ht{}; uint8_t x = 0; for (const auto& pair: pairs) { ht.items[x] = pair; if constexpr (D.is_front_hash) { - ht.table[pair.first[0] - D.front] = x; + ht.table[static_cast(pair.first[0] - D.front)] = x; } else { - ht.table[pair.first.back() - D.front] = x; + ht.table[static_cast(pair.first.back() - D.front)] = x; } ++x; } @@ -531,14 +548,14 @@ namespace JsonifierInternal { return ht; } - template struct SingleItem { - RawArray, 1> items{}; + template struct single_item { + raw_array, 1> items{}; - constexpr decltype(auto) end() const noexcept { + constexpr decltype(auto) end() const { return items.end(); } - constexpr decltype(auto) find(auto&& key) const noexcept { + constexpr decltype(auto) find(auto&& key) const { if (stringConstCompare(S, key)) [[likely]] { return items.begin(); } else [[unlikely]] { @@ -547,19 +564,19 @@ namespace JsonifierInternal { } }; - template struct DoubleItem { - RawArray, 2> items{}; + template struct double_item { + raw_array, 2> items{}; static constexpr auto s0 = string01; static constexpr auto s1 = string02; - constexpr decltype(auto) end() const noexcept { + constexpr decltype(auto) end() const { return items.end(); } static constexpr bool sameSize = s0.size() == s1.size(); - constexpr decltype(auto) find(auto&& key) const noexcept { + constexpr decltype(auto) find(auto&& key) const { if constexpr (sameSize) { constexpr auto n = s0.size(); if (key.size() != n) { @@ -577,85 +594,84 @@ namespace JsonifierInternal { }; // from - // https://stackoverflow.com/questions/55941964/how-to-filter-duplicate-types-from-Tuple-c - template struct Unique { - using type = ValueType; + // https://stackoverflow.com/questions/55941964/how-to-filter-duplicate-types-from-tuple-c + template struct unique { + using type = value_type; }; - template class ValueType, typename... ValueTypes, typename U, typename... Us> struct Unique, U, Us...> - : std::conditional_t<(std::same_as || ...), Unique, Us...>, Unique, Us...>> {}; + template class value_type, typename... value_types, typename u, typename... Us> struct unique, u, Us...> + : std::conditional_t<(std::same_as || ...), unique, Us...>, unique, Us...>> {}; - template struct TupleVariant; + template struct tuple_variant; - template struct TupleVariant> : Unique, ValueTypes...> {}; + template struct tuple_variant> : unique, value_types...> {}; - template struct TuplePtrVariant; + template struct tuple_ptr_variant; - template struct TuplePtrVariant> : Unique, std::add_pointer_t...> {}; + template struct tuple_ptr_variant> : unique, std::add_pointer_t...> {}; - template struct TuplePtrVariant> : Unique, std::add_pointer_t...> {}; + template struct tuple_ptr_variant> : unique, std::add_pointer_t...> {}; - template struct TuplePtrVariant> : Unique, std::add_pointer_t...> {}; + template struct tuple_ptr_variant> : unique, std::add_pointer_t...> {}; - template::value>> struct ValueTupleVariant; + template::value>> struct value_tuple_variant; - template struct ValueTupleVariant> { - using type = typename TupleVariant>>>()...))>::type; + template struct value_tuple_variant> { + using type = typename tuple_variant>>>()...))>::type; }; - template using ValueTupleVariantT = typename ValueTupleVariant::type; + template using value_tuple_variant_t = typename value_tuple_variant::type; - struct BucketSizeCompare { - template bool constexpr operator()(B const& b0, B const& b1) const noexcept { + struct bucket_size_compare { + template bool constexpr operator()(b const& b0, b const& b1) const { return b0.size() > b1.size(); } }; - template struct PmhBuckets { + template struct pmh_buckets { static constexpr auto bucket_max = 2 * (1u << (log(m) / 2)); - using bucket_t = RawVector; - RawArray buckets; + using bucket_t = raw_vector; + raw_array buckets; uint64_t seed; - struct BucketRef { + struct bucket_ref { unsigned hash; const bucket_t* values; using value_type = typename bucket_t::value_type; using const_iterator = typename bucket_t::const_iterator; - constexpr auto size() const noexcept { + constexpr auto size() const { return values->size(); } - constexpr const auto& operator[](uint64_t idx) const noexcept { + constexpr const auto& operator[](uint64_t idx) const { return (*values)[idx]; } - constexpr auto begin() const noexcept { + constexpr auto begin() const { return values->begin(); } - constexpr auto end() const noexcept { + constexpr auto end() const { return values->end(); } }; - template RawArray constexpr makeBucketRefs(std::index_sequence) const noexcept { - return { { BucketRef{ Is, &buckets[Is] }... } }; + template raw_array constexpr makeBucketRefs(std::index_sequence) const { + return { { bucket_ref{ Is, &buckets[Is] }... } }; } - RawArray constexpr getSortedBuckets() const noexcept { - RawArray result{ makeBucketRefs(std::make_index_sequence()) }; - quicksort(result.begin(), result.end() - 1, BucketSizeCompare{}); + raw_array constexpr getSortedBuckets() const { + raw_array result{ makeBucketRefs(std::make_index_sequence()) }; + quicksort(result.begin(), result.end() - 1, bucket_size_compare{}); return result; } }; - template - PmhBuckets constexpr makePmhBuckets(const RawArray& items, Key const& key, DefaultPrgT& prg) { - using result_t = PmhBuckets; - using hasher = Hash; + template pmh_buckets constexpr makePmhBuckets(const raw_array& items, key const& keyNew, DefaultPrgT& prg) { + using result_t = pmh_buckets; + using hasher = hash; result_t result{}; bool rejected = false; while (true) { @@ -665,7 +681,7 @@ namespace JsonifierInternal { result.seed = prg(); rejected = false; for (uint64_t x = 0; x < n; ++x) { - auto& bucket = result.buckets[hasher{}(key(items[x]), static_cast(result.seed)) % m]; + auto& bucket = result.buckets[hasher{}(keyNew(items[x]), static_cast(result.seed)) % m]; if (bucket.size() >= result_t::bucket_max) [[unlikely]] { rejected = true; break; @@ -678,7 +694,7 @@ namespace JsonifierInternal { } } - template constexpr bool allDifferentFrom(RawVector& data, ValueType& a) { + template constexpr bool allDifferentFrom(raw_vector& data, value_type& a) { for (uint64_t x = 0; x < data.size(); ++x) if (data[x] == a) [[unlikely]] { return false; @@ -686,68 +702,66 @@ namespace JsonifierInternal { return true; } - struct SeedOrIndex { + struct seed_or_index { using value_type = uint64_t; protected: - static constexpr value_type MinusOne = (std::numeric_limits::max)(); + static constexpr value_type MinusOne = std::numeric_limits::max(); static constexpr value_type HighBit = ~(MinusOne >> 1); value_type val = 0; public: - constexpr value_type value() const noexcept { + constexpr value_type value() const { return val; } - constexpr bool isSeed() const noexcept { + constexpr bool isSeed() const { return val & HighBit; } - constexpr SeedOrIndex(bool isSeed, value_type value) : val(isSeed ? (value | HighBit) : (value & ~HighBit)) { + constexpr seed_or_index(bool isSeed, value_type value) : val(isSeed ? (value | HighBit) : (value & ~HighBit)) { } - constexpr SeedOrIndex() noexcept = default; - constexpr SeedOrIndex(const SeedOrIndex&) noexcept = default; - constexpr SeedOrIndex& operator=(const SeedOrIndex&) noexcept = default; + constexpr seed_or_index() = default; }; - template struct PmhTables : protected Hash> { - constexpr PmhTables() noexcept = default; - constexpr PmhTables(uint64_t firstSeedNew, RawArray firstTableNew, RawArray secondTableNew) { - firstSeed = firstSeedNew; + template struct pmh_tables { + constexpr pmh_tables() = default; + constexpr pmh_tables(uint64_t firstSeedNew, raw_array firstTableNew, raw_array secondTableNew) { + firstSeed = firstSeedNew; firstTable = firstTableNew; secondTable = secondTableNew; } uint64_t firstSeed; - RawArray firstTable; - RawArray secondTable; - using hasher = Hash>; + raw_array firstTable; + raw_array secondTable; - constexpr const hasher& getHasher() const { - return *this; + template using hasher = hash; + + template constexpr const hasher getHasher() const { + return hasher{}; } - template constexpr uint64_t lookup(const KeyType& key) const noexcept { - auto const d = firstTable[getHasher()(key, static_cast(firstSeed)) % m]; + template constexpr uint64_t lookup(const KeyType& key) const { + auto const d = firstTable[getHasher()(key, static_cast(firstSeed)) % m]; if (!d.isSeed()) [[unlikely]] { return static_cast(d.value()); } else [[likely]] { - return secondTable[getHasher()(key, static_cast(d.value())) % m]; + return secondTable[getHasher()(key, static_cast(d.value())) % m]; } } }; - template - PmhTables constexpr makePmhTables(const RawArray& items, Key const& key, DefaultPrgT prg) { - auto step_one = makePmhBuckets(items, key, prg); + template pmh_tables constexpr makePmhTables(const raw_array& items, key const& keyNew, DefaultPrgT prg) { + auto step_one = makePmhBuckets(items, keyNew, prg); auto buckets = step_one.getSortedBuckets(); - RawArray G; - using hasher = Hash>; + raw_array G; + using hasher = hash>; - constexpr uint64_t UNUSED = (std::numeric_limits::max)(); - RawArray H; + constexpr uint64_t UNUSED = std::numeric_limits::max(); + raw_array H; H.fill(UNUSED); for (const auto& bucket: buckets) { @@ -756,11 +770,11 @@ namespace JsonifierInternal { if (bsize == 1) { G[bucket.hash] = { false, static_cast(bucket[0]) }; } else if (bsize > 1) { - SeedOrIndex d{ true, prg() }; - RawVector bucket_slots; + seed_or_index d{ true, prg() }; + raw_vector bucket_slots; while (bucket_slots.size() < bsize) { - auto slot = hasher{}(key(items[bucket[bucket_slots.size()]]), d.value()) % m; + auto slot = hasher{}(keyNew(items[bucket[bucket_slots.size()]]), d.value()) % m; if (H[slot] != UNUSED || !allDifferentFrom(bucket_slots, slot)) { bucket_slots.clear(); @@ -784,28 +798,25 @@ namespace JsonifierInternal { return { step_one.seed, G, H }; } - struct GetKey { - template constexpr auto const& operator()(KV const& kv) const noexcept { + struct get_key { + template constexpr auto const& operator()(KV const& kv) const { return kv.first; } }; - template class UnorderedMap : protected StringCompareHelper, - protected RawArray, n>, - protected PmhTables { + template + class unordered_map : protected string_compare_helper, protected raw_array, n>, protected pmh_tables { public: static constexpr auto storageSize = nextHighestPowerOfTwo(n) * (n < 32 ? 2 : 1); - using container_type = RawArray, n>; - using tables_type = PmhTables; + using container_type = raw_array, n>; + using tables_type = pmh_tables; - using Self = UnorderedMap; - using key_type = Key; + using key_type = key; using mapped_type = Value; using value_type = typename container_type::value_type; using size_type = typename container_type::size_type; using difference_type = typename container_type::difference_type; - using hasher = Hash; - using key_equal = StringCompareHelper; + using key_equal = string_compare_helper; using reference = typename container_type::reference; using const_reference = typename container_type::const_reference; using pointer = typename container_type::pointer; @@ -813,50 +824,26 @@ namespace JsonifierInternal { using iterator = typename container_type::iterator; using const_iterator = typename container_type::const_iterator; - constexpr UnorderedMap() noexcept = default; - constexpr UnorderedMap& operator=(UnorderedMap&&) noexcept = default; - constexpr UnorderedMap(UnorderedMap&&) noexcept = default; - constexpr UnorderedMap& operator=(const UnorderedMap&) noexcept = default; - constexpr UnorderedMap(const UnorderedMap&) noexcept = default; - - constexpr UnorderedMap(container_type items) : container_type{ items }, tables_type{ makePmhTables(items, GetKey{}, DefaultPrgT{}) } {} + constexpr unordered_map() = default; - constexpr UnorderedMap(std::initializer_list items) : UnorderedMap{ container_type{ items } } { - constexpr_assert(items.size() == n, "Inconsistent initializer_list size and type size argument."); - } - - constexpr iterator begin() { - return container_type::begin(); + constexpr unordered_map(container_type items) : container_type{ items }, tables_type{ makePmhTables(items, get_key{}, DefaultPrgT{}) } { } - constexpr iterator end() { - return container_type::end(); + constexpr unordered_map(std::initializer_list items) : unordered_map{ container_type{ items } } { + constexpr_assert(items.size() == n, "Inconsistent initializer_list size and type size argument."); } - constexpr const_iterator begin() const noexcept { + constexpr const_iterator begin() const { return container_type::begin(); } - constexpr const_iterator end() const noexcept { + constexpr const_iterator end() const { return container_type::end(); } - constexpr size_type size() const noexcept { - return n; - } - - template constexpr const_iterator find(const key_type_new& key) const noexcept { - auto& kv = lookup(key); - if (keyEq()(kv.first, key)) { - return &kv; - } else { - return end(); - } - } - - template constexpr iterator find(const key_type_new& key) { - auto& kv = lookup(key); - if (keyEq()(kv.first, key)) { + template constexpr const_iterator find(const key_type_new& keyNew) const { + auto& kv = lookup(keyNew); + if (keyEq()(kv.first, keyNew)) { return &kv; } else { return end(); @@ -864,65 +851,60 @@ namespace JsonifierInternal { } protected: - template constexpr const auto& lookup(const key_type_new& key) const noexcept { - return container_type::operator[](tables_type::lookup(key)); - } - - template constexpr auto& lookup(const key_type_new& key) { - return container_type::operator[](tables_type::lookup(key)); + template constexpr const auto& lookup(const key_type_new& keyNew) const { + return container_type::operator[](tables_type::lookup(keyNew)); } - constexpr const key_equal& keyEq() const noexcept { + constexpr const key_equal& keyEq() const { return *this; } }; - template - constexpr auto makeUnorderedMap(Pair const (&items)[n]) { - return UnorderedMap{ items }; + template constexpr auto makeUnorderedMap(pair const (&items)[n]) { + return unordered_map{ items }; } - template struct CoreSV { - static constexpr Jsonifier::StringView value = Tuplet::get<0>(Tuplet::get(CoreV)); + template struct core_sv { + static constexpr jsonifier::string_view value = tuplet::get<0>(tuplet::get(coreV)); }; - template constexpr auto makeMapImpl(std::index_sequence) { - using value_t = ValueTupleVariantT>; - constexpr auto n = std::tuple_size_v>; + template constexpr auto makeMapImpl(std::index_sequence) { + using value_t = value_tuple_variant_t>; + constexpr auto n = std::tuple_size_v>; constexpr auto size = sizeof...(I); static_assert(size == n); auto naiveOrNormalHash = [&] { if constexpr (size <= 20) { - return makeNaiveMap({ Pair(Jsonifier::StringView(Tuplet::get<0>(Tuplet::get(CoreV))), - Tuplet::get<1>(Tuplet::get(CoreV)))... }); + return makeNaiveMap({ pair(jsonifier::string_view(tuplet::get<0>(tuplet::get(coreV))), + tuplet::get<1>(tuplet::get(coreV)))... }); } else { - return makeUnorderedMap({ Pair( - Jsonifier::StringView(Tuplet::get<0>(Tuplet::get(CoreV))), Tuplet::get<1>(Tuplet::get(CoreV)))... }); + return makeUnorderedMap({ pair( + jsonifier::string_view(tuplet::get<0>(tuplet::get(coreV))), tuplet::get<1>(tuplet::get(coreV)))... }); } }; constexpr bool n128 = n < 128; if constexpr (n == 0) { - static_assert(FalseV, "Empty object in Jsonifier::Core."); + static_assert(falseV, "Empty object in jsonifier::core."); } else if constexpr (n == 1) { - return SingleItem::value...>{ RawArray, n>{ Pair( - Jsonifier::StringView(Tuplet::get<0>(Tuplet::get(CoreV))), Tuplet::get<1>(Tuplet::get(CoreV)))... } }; + return single_item::value...>{ raw_array, n>{ pair( + jsonifier::string_view(tuplet::get<0>(tuplet::get(coreV))), tuplet::get<1>(tuplet::get(coreV)))... } }; } else if constexpr (n == 2) { - return DoubleItem::value...>{ RawArray, n>{ Pair( - Jsonifier::StringView(Tuplet::get<0>(Tuplet::get(CoreV))), Tuplet::get<1>(Tuplet::get(CoreV)))... } }; + return double_item::value...>{ raw_array, n>{ pair( + jsonifier::string_view(tuplet::get<0>(tuplet::get(coreV))), tuplet::get<1>(tuplet::get(coreV)))... } }; } else if constexpr (n128) { - constexpr auto frontDesc = singleCharHash(RawArray{ Jsonifier::StringView{ Tuplet::get<0>(Tuplet::get(CoreV)) }... }); + constexpr auto frontDesc = singleCharHash(raw_array{ jsonifier::string_view{ tuplet::get<0>(tuplet::get(coreV)) }... }); if constexpr (frontDesc.valid) { - return makeSingleCharMap({ Pair(Jsonifier::StringView(Tuplet::get<0>(Tuplet::get(CoreV))), - Tuplet::get<1>(Tuplet::get(CoreV)))... }); + return makeSingleCharMap({ pair(jsonifier::string_view(tuplet::get<0>(tuplet::get(coreV))), + tuplet::get<1>(tuplet::get(coreV)))... }); } else { constexpr auto backDesc = - singleCharHash(RawArray{ Jsonifier::StringView{ Tuplet::get<0>(Tuplet::get(CoreV)) }... }); + singleCharHash(raw_array{ jsonifier::string_view{ tuplet::get<0>(tuplet::get(coreV)) }... }); if constexpr (backDesc.valid) { - return makeSingleCharMap({ Pair(Jsonifier::StringView(Tuplet::get<0>(Tuplet::get(CoreV))), - Tuplet::get<1>(Tuplet::get(CoreV)))... }); + return makeSingleCharMap({ pair(jsonifier::string_view(tuplet::get<0>(tuplet::get(coreV))), + tuplet::get<1>(tuplet::get(coreV)))... }); } else { return naiveOrNormalHash(); } @@ -932,8 +914,8 @@ namespace JsonifierInternal { } } - template constexpr auto makeMap() { - constexpr auto indices = std::make_index_sequence>>{}; - return makeMapImpl>(indices); + template constexpr auto makeMap() { + constexpr auto indices = std::make_index_sequence>>{}; + return makeMapImpl>(indices); } } \ No newline at end of file diff --git a/Include/jsonifier/ISADetection.hpp b/Include/jsonifier/ISADetection.hpp index 37b690714..9c3072cde 100644 --- a/Include/jsonifier/ISADetection.hpp +++ b/Include/jsonifier/ISADetection.hpp @@ -19,1623 +19,14 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/// https://github.com/RealTimeChris/Jsonifier +/// https://github.com/RealTimeChris/jsonifier /// Feb 3, 2023 #pragma once -#include -#include -#include - -namespace JsonifierInternal { - - using StringViewPtr = const uint8_t*; - using StructuralIndex = const uint8_t*; - using StringBufferPtr = uint8_t*; - - template struct SimdBase {}; - -#if defined T_AVX512 - - template - concept CharType = requires(CharacterType) { sizeof(CharacterType) == 1; }; - - template - concept Avx256T = std::same_as<__m256i, ValueType> || std::same_as<__m256, ValueType>; - - template - concept Avx512T = std::same_as<__m512i, ValueType> || std::same_as<__m512, ValueType>; - - template<> struct SimdBase<256> { - public: - inline SimdBase() noexcept = default; - - inline SimdBase& operator=(SimdBase&& other) noexcept = default; - inline SimdBase(SimdBase&& other) noexcept = default; - inline SimdBase& operator=(const SimdBase& other) noexcept = default; - inline SimdBase(const SimdBase& other) noexcept = default; - - template inline SimdBase& operator=(ValueType&& data) { - value = std::forward(data); - return *this; - } - - template inline SimdBase(ValueType&& data) { - value = std::forward(data); - } - - inline operator const __m256i&&() const { - return std::forward(value); - } - - inline uint64_t getUint64(uint64_t index) { - switch (index) { - case 0: { - return static_cast(_mm256_extract_epi64(value, 0)); - } - case 1: { - return static_cast(_mm256_extract_epi64(value, 1)); - } - case 2: { - return static_cast(_mm256_extract_epi64(value, 2)); - } - case 3: { - return static_cast(_mm256_extract_epi64(value, 3)); - } - default: { - return static_cast(_mm256_extract_epi64(value, 0)); - } - } - } - - inline void insertInt64(int64_t valueNew, uint64_t index) { - switch (index) { - case 0: { - value = _mm256_insert_epi64(value, valueNew, 0); - break; - } - case 1: { - value = _mm256_insert_epi64(value, valueNew, 1); - break; - } - case 2: { - value = _mm256_insert_epi64(value, valueNew, 2); - break; - } - case 3: { - value = _mm256_insert_epi64(value, valueNew, 3); - break; - } - default: { - value = _mm256_insert_epi64(value, valueNew, 0); - break; - } - } - } - - inline SimdBase carrylessMultiplication(uint64_t& prevInString) const { - __m128i allOnes{ _mm_set1_epi8('\xFF') }; - SimdBase valuesNew{}; - __m128i valueLow{ _mm256_extracti128_si256(value, 0) }; - __m128i valueHigh{ _mm256_extracti128_si256(value, 1) }; - valuesNew.insertInt64(_mm_cvtsi128_si64(_mm_clmulepi64_si128(valueLow, allOnes, 0)) ^ prevInString, 0); - prevInString = uint64_t(static_cast(valuesNew.getUint64(0)) >> 63); - valuesNew.insertInt64(_mm_cvtsi128_si64(_mm_clmulepi64_si128(valueLow, allOnes, 1)) ^ prevInString, 1); - prevInString = uint64_t(static_cast(valuesNew.getUint64(1)) >> 63); - valuesNew.insertInt64(_mm_cvtsi128_si64(_mm_clmulepi64_si128(valueHigh, allOnes, 0)) ^ prevInString, 2); - prevInString = uint64_t(static_cast(valuesNew.getUint64(2)) >> 63); - valuesNew.insertInt64(_mm_cvtsi128_si64(_mm_clmulepi64_si128(valueHigh, allOnes, 1)) ^ prevInString, 3); - prevInString = uint64_t(static_cast(valuesNew.getUint64(3)) >> 63); - return valuesNew; - } - - protected: - __m256i value{}; - }; - - constexpr uint64_t StepSize{ 512 }; - constexpr uint64_t BytesPerStep{ StepSize / 8 }; - constexpr uint64_t SixtyFourPer{ StepSize / 64 }; - using SimdBaseReal = SimdBase<512>; - using StringParsingType = uint64_t; - using AvxType = __m512i; - - template<> struct SimdBase<512> { - public: - inline SimdBase() noexcept = default; - - inline SimdBase& operator=(SimdBase&& other) noexcept = default; - inline SimdBase(SimdBase&& other) noexcept = default; - inline SimdBase& operator=(const SimdBase& other) noexcept = default; - inline SimdBase(const SimdBase& other) noexcept = default; - - template inline SimdBase& operator=(ValueType&& data) { - value = std::forward(data); - return *this; - } - - template inline SimdBase(ValueType&& data) { - value = std::forward(data); - } - - inline SimdBase& operator=(uint8_t other) { - value = _mm512_set1_epi8(other); - return *this; - } - - inline explicit SimdBase(uint8_t other) { - *this = other; - } - - template inline SimdBase(ValueType values[64]) { - value = _mm512_loadu_epi64(values); - } - - inline operator __m512i&() { - return value; - } - - inline operator const __m512i&&() const { - return std::forward(value); - } - - inline explicit operator bool() const { - return _mm512_test_epi64_mask(value, value) != 0; - } - - inline explicit operator uint64_t() const { - return toBitMask(); - } - - inline SimdBase operator|(SimdBase&& other) noexcept { - return _mm512_or_si512(value, std::forward<__m512i>(other)); - } - - inline SimdBase operator|(const SimdBase& other) const { - return _mm512_or_si512(value, other); - } - - inline SimdBase operator&(const SimdBase& other) const { - return _mm512_and_si512(value, other); - } - - inline SimdBase operator-(const SimdBase& other) const { - return _mm512_sub_epi8(value, other); - } - - inline SimdBase operator^(const SimdBase& other) const { - return _mm512_xor_si512(value, other); - } - - inline uint64_t operator==(const SimdBase& other) const { - return _mm512_cmpeq_epi8_mask(value, other); - } - - inline uint64_t operator==(const uint8_t& other) const { - return _mm512_cmpeq_epi8_mask(value, _mm512_set1_epi8(other)); - } - - inline SimdBase operator~() const { - return _mm512_xor_si512(*this, _mm512_set1_epi64(-1ll)); - } - - inline void convertWhitespaceToSimdBase(const SimdBase* valuesNew) { - alignas(ALIGNMENT) uint8_t arrayNew[64]{ ' ', 100, 100, 100, 17, 100, 113, 2, 100, '\t', '\n', 112, 100, '\r', 100, 100, ' ', 100, 100, 100, 17, 100, 113, 2, 100, '\t', - '\n', 112, 100, '\r', 100, 100, ' ', 100, 100, 100, 17, 100, 113, 2, 100, '\t', '\n', 112, 100, '\r', 100, 100, ' ', 100, 100, 100, 17, 100, 113, 2, 100, '\t', - '\n', 112, 100, '\r', 100, 100 }; - SimdBase whitespaceTable{ arrayNew }; - - for (uint64_t x = 0; x < 8; ++x) { - addValues(valuesNew[x].shuffle(whitespaceTable) == valuesNew[x], x); - } - } - - inline void convertBackslashesToSimdBase(const SimdBase* valuesNew) { - for (uint64_t x = 0; x < 8; ++x) { - addValues(valuesNew[x] == '\\', x); - } - } - - inline void convertStructuralsToSimdBase(const SimdBase* valuesNew) { - alignas(ALIGNMENT) uint8_t arrayNew[64]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ':', '{', ',', '}', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ':', '{', ',', '}', 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, ':', '{', ',', '}', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ':', '{', ',', '}', 0, 0 }; - SimdBase opTable{ arrayNew }; - SimdBase chars{ uint8_t{ 0x20 } }; - - for (uint64_t x = 0; x < 8; ++x) { - addValues(valuesNew[x].shuffle(opTable) == (valuesNew[x] | chars), x); - } - } - - inline void convertQuotesToSimdBase(const SimdBase* valuesNew) { - for (uint64_t x = 0; x < 8; ++x) { - addValues(valuesNew[x] == '"', x); - } - } - - inline SimdBase bitAndNot(const SimdBase& other) const { - return _mm512_andnot_si512(other, value); - } - - inline SimdBase shuffle(SimdBase& other) const { - return _mm512_shuffle_epi8(other, value); - } - - inline void insertInt64(int64_t valueNew, uint64_t index) { - switch (index) { - case 0: { - auto lower = _mm512_extracti64x4_epi64(value, 0); - lower = _mm256_insert_epi64(lower, valueNew, 0); - value = _mm512_inserti64x4(value, lower, 0); - break; - } - case 1: { - auto lower = _mm512_extracti64x4_epi64(value, 0); - lower = _mm256_insert_epi64(lower, valueNew, 1); - value = _mm512_inserti64x4(value, lower, 0); - break; - } - case 2: { - auto lower = _mm512_extracti64x4_epi64(value, 0); - lower = _mm256_insert_epi64(lower, valueNew, 2); - value = _mm512_inserti64x4(value, lower, 0); - break; - } - case 3: { - auto lower = _mm512_extracti64x4_epi64(value, 0); - lower = _mm256_insert_epi64(lower, valueNew, 3); - value = _mm512_inserti64x4(value, lower, 0); - break; - } - case 4: { - auto lower = _mm512_extracti64x4_epi64(value, 1); - lower = _mm256_insert_epi64(lower, valueNew, 0); - value = _mm512_inserti64x4(value, lower, 1); - break; - } - case 5: { - auto lower = _mm512_extracti64x4_epi64(value, 1); - lower = _mm256_insert_epi64(lower, valueNew, 1); - value = _mm512_inserti64x4(value, lower, 1); - break; - } - case 6: { - auto lower = _mm512_extracti64x4_epi64(value, 1); - lower = _mm256_insert_epi64(lower, valueNew, 2); - value = _mm512_inserti64x4(value, lower, 1); - break; - } - case 7: { - auto lower = _mm512_extracti64x4_epi64(value, 1); - lower = _mm256_insert_epi64(lower, valueNew, 3); - value = _mm512_inserti64x4(value, lower, 1); - break; - } - default: { - auto lower = _mm512_extracti64x4_epi64(value, 0); - lower = _mm256_insert_epi64(lower, valueNew, 0); - value = _mm512_inserti64x4(value, lower, 0); - break; - } - } - } - - inline void addValues(uint64_t&& values, uint64_t index) { - insertInt64(values, index); - } - - template inline SimdBase shl() const { - SimdBase newValue{ _mm512_slli_epi64(*this, (amount % 64)) }; - SimdBase newerValue{ _mm512_srli_epi64(_mm512_permutexvar_epi64(_mm512_set_epi64(6, 5, 4, 3, 2, 1, 0, 7), *this), 64 - (amount % 64)) }; - uint64_t maxValue{ std::numeric_limits::max() }; - SimdBase newestValue{ _mm512_set_epi64(maxValue, maxValue, maxValue, maxValue, maxValue, maxValue, maxValue, 0) }; - return SimdBase{ newValue | (newerValue & newestValue) }; - } - - inline int64_t toBitMask() const { - return _mm512_movepi8_mask(*this); - } - - inline void reset() { - value = _mm512_setzero_si512(); - } - - template inline void store(ValueType* destVector) const { - _mm512_store_si512(destVector, value); - } - - inline SimdBase& setLSB(bool valueNew) { - if (valueNew) { - *this = _mm512_or_si512(*this, _mm512_set_epi64(0, 0, 0, 0, 0, 0, 0, 0x1)); - } else { - *this = _mm512_andnot_si512(_mm512_set_epi64(0, 0, 0, 0, 0, 0, 0, 0x1), *this); - } - return *this; - } - - inline bool checkMSB() const { - __m512i result = _mm512_and_si512(*this, _mm512_set_epi64(0x8000000000000000, 0, 0, 0, 0, 0, 0, 0)); - return _mm512_test_epi64_mask(result, result); - } - - inline SimdBase carrylessMultiplication(uint64_t& prevInString) const { - SimdBase<256> lowValues{ _mm512_extracti64x4_epi64(value, 0) }; - SimdBase<256> highValues{ _mm512_extracti64x4_epi64(value, 1) }; - lowValues = lowValues.carrylessMultiplication(prevInString); - highValues = highValues.carrylessMultiplication(prevInString); - SimdBase returnValue{}; - returnValue = _mm512_inserti64x4(returnValue, lowValues, 0); - returnValue = _mm512_inserti64x4(returnValue, highValues, 1); - return returnValue; - } - - inline bool collectCarries(const SimdBase& other1, SimdBase& result) const { - __m512i carry = _mm512_set1_epi64(0); - __m512i sum = _mm512_add_epi64(*this, other1); - sum = _mm512_add_epi64(sum, carry); - result = std::move(sum); - return _mm512_test_epi64_mask(carry, sum) == 0; - } - - inline SimdBase follows(bool& overflow) { - SimdBase result = shl<1>(); - result.setLSB(overflow); - overflow = checkMSB(); - return result; - } - - inline void printBits(uint64_t values, const std::string& valuesTitle) const { - std::cout << valuesTitle; - std::cout << std::bitset<64>{ values }; - std::cout << std::endl; - } - - inline SimdBase printBits(const std::string& valuesTitle) const { - std::cout << valuesTitle; - for (uint64_t x = 0; x < 8; ++x) { - std::cout << std::bitset<64>{ *(reinterpret_cast(&value) + x) }; - } - std::cout << std::endl; - return *this; - } - - protected: - __m512i value{}; - }; - - inline SimdBaseReal makeSimdBase(uint64_t value) { - return _mm512_set1_epi64(value); - } - - #define popcnt(x) _mm_popcnt_u64(x) - #define blsr(x) _blsr_u64(x) - #define load(x) _mm512_loadu_si512(x) - #define tzCount(x) _tzcnt_u64(x) - #define tzCount64(x) _tzcnt_u64(x) - -#elif defined T_AVX2 - - template - concept CharType = requires(CharacterType) { sizeof(CharacterType) == 1; }; - - template - concept Avx256T = std::same_as<__m256i, ValueType> || std::same_as<__m256, ValueType>; - - constexpr uint64_t StepSize{ 256 }; - constexpr uint64_t BytesPerStep{ StepSize / 8 }; - constexpr uint64_t SixtyFourPer{ StepSize / 64 }; - using StringParsingType = uint32_t; - using SimdBaseReal = SimdBase<256>; - using AvxType = __m256i; - - template<> struct SimdBase<256> { - public: - inline SimdBase() noexcept = default; - - inline SimdBase& operator=(SimdBase&& other) noexcept = default; - inline SimdBase(SimdBase&& other) noexcept = default; - inline SimdBase& operator=(const SimdBase& other) noexcept = delete; - inline SimdBase(const SimdBase& other) noexcept = delete; - - template inline SimdBase& operator=(ValueType&& data) { - value = std::forward(data); - return *this; - } - - template inline SimdBase(ValueType&& data) { - value = std::forward(data); - } - - inline SimdBase& operator=(uint8_t other) { - value = _mm256_set1_epi8(other); - return *this; - } - - inline explicit SimdBase(uint8_t other) { - *this = other; - } - - template inline SimdBase& operator=(ValueType values[32]) { - value = gatherValues256(values); - return *this; - } - - template inline SimdBase(ValueType values[32]) { - *this = values; - } - - inline operator __m256i&() { - return value; - } - - inline operator const __m256i&&() const { - return std::forward(value); - } - - inline explicit operator bool() const { - return !_mm256_testz_si256(value, value); - } - - inline operator uint32_t() const { - return toBitMask(); - } - - inline SimdBase operator|(SimdBase&& other) noexcept { - return _mm256_or_si256(value, std::forward<__m256i>(other)); - } - - inline SimdBase operator|(const SimdBase& other) const { - return _mm256_or_si256(value, other); - } - - inline SimdBase operator-(const SimdBase& other) const { - return _mm256_sub_epi8(value, other); - } - - inline SimdBase operator&(const SimdBase& other) const { - return _mm256_and_si256(value, other); - } - - inline SimdBase operator^(const SimdBase& other) const { - return _mm256_xor_si256(value, other); - } - - inline StringParsingType operator==(const SimdBase& other) const { - SimdBase newValue = _mm256_cmpeq_epi8(value, other); - return newValue.toBitMask(); - } - - inline StringParsingType operator==(const uint8_t& other) const { - SimdBase newValue = _mm256_cmpeq_epi8(value, _mm256_set1_epi8(other)); - return newValue.toBitMask(); - } - - inline SimdBase operator~() const { - return _mm256_xor_si256(*this, _mm256_set1_epi64x(std::numeric_limits::max())); - } - - inline void convertWhitespaceToSimdBase(const SimdBase* valuesNew) { - alignas(ALIGNMENT) uint8_t arrayNew[32]{ ' ', 100, 100, 100, 17, 100, 113, 2, 100, '\t', '\n', 112, 100, '\r', 100, 100, ' ', 100, 100, 100, 17, 100, 113, 2, 100, '\t', - '\n', 112, 100, '\r', 100, 100 }; - SimdBase whitespaceTable{ arrayNew }; - for (uint64_t x = 0; x < 8; ++x) { - addValues(valuesNew[x].shuffle(whitespaceTable) == valuesNew[x], x); - } - }; - - inline void convertBackslashesToSimdBase(const SimdBase* valuesNew) { - SimdBase backslashes{ _mm256_set1_epi8('\\') }; - for (uint64_t x = 0; x < 8; ++x) { - addValues(valuesNew[x] == backslashes, x); - } - }; - - inline void convertStructuralsToSimdBase(const SimdBase* valuesNew) { - alignas(ALIGNMENT) uint8_t arrayNew[32]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ':', '{', ',', '}', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ':', '{', ',', '}', 0, 0 }; - SimdBase opTable{ arrayNew }; - SimdBase chars{ uint8_t{ 0x20 } }; - for (uint64_t x = 0; x < 8; ++x) { - addValues(valuesNew[x].shuffle(opTable) == (valuesNew[x] | chars), x); - } - }; - - inline void convertQuotesToSimdBase(const SimdBase* valuesNew) { - SimdBase quotes = _mm256_set1_epi8('"'); - for (uint64_t x = 0; x < 8; ++x) { - addValues(valuesNew[x] == quotes, x); - } - } - - inline uint64_t getUint64(uint64_t index) { - switch (index) { - case 0: { - return static_cast(_mm256_extract_epi64(value, 0)); - } - case 1: { - return static_cast(_mm256_extract_epi64(value, 1)); - } - case 2: { - return static_cast(_mm256_extract_epi64(value, 2)); - } - case 3: { - return static_cast(_mm256_extract_epi64(value, 3)); - } - default: { - return static_cast(_mm256_extract_epi64(value, 0)); - } - } - } - - inline int64_t getInt64(uint64_t index) { - switch (index) { - case 0: { - return _mm256_extract_epi64(value, 0); - } - case 1: { - return _mm256_extract_epi64(value, 1); - } - case 2: { - return _mm256_extract_epi64(value, 2); - } - case 3: { - return _mm256_extract_epi64(value, 3); - } - default: { - return _mm256_extract_epi64(value, 0); - } - } - } - - inline void insertInt64(int64_t valueNew, uint64_t index) { - switch (index) { - case 0: { - value = _mm256_insert_epi64(value, valueNew, 0); - break; - } - case 1: { - value = _mm256_insert_epi64(value, valueNew, 1); - break; - } - case 2: { - value = _mm256_insert_epi64(value, valueNew, 2); - break; - } - case 3: { - value = _mm256_insert_epi64(value, valueNew, 3); - break; - } - default: { - value = _mm256_insert_epi64(value, valueNew, 0); - break; - } - } - } - - inline void insertInt32(uint32_t valueNew, uint64_t index) { - switch (index) { - case 0: { - value = _mm256_insert_epi32(value, valueNew, 0); - break; - } - case 1: { - value = _mm256_insert_epi32(value, valueNew, 1); - break; - } - case 2: { - value = _mm256_insert_epi32(value, valueNew, 2); - break; - } - case 3: { - value = _mm256_insert_epi32(value, valueNew, 3); - break; - } - case 4: { - value = _mm256_insert_epi32(value, valueNew, 4); - break; - } - case 5: { - value = _mm256_insert_epi32(value, valueNew, 5); - break; - } - case 6: { - value = _mm256_insert_epi32(value, valueNew, 6); - break; - } - case 7: { - value = _mm256_insert_epi32(value, valueNew, 7); - break; - } - default: { - value = _mm256_insert_epi32(value, valueNew, 0); - break; - } - } - } - - inline SimdBase bitAndNot(const SimdBase& other) const { - return _mm256_andnot_si256(other, value); - } - - inline SimdBase shuffle(const SimdBase& other) const { - return _mm256_shuffle_epi8(other, value); - } - - inline void addValues(uint32_t values, uint64_t index) { - insertInt32(values, index); - } - - template inline SimdBase shl() const { - return SimdBase{ _mm256_slli_epi64(*this, (amount % 64)) } | _mm256_srli_epi64(_mm256_permute4x64_epi64(*this, 0b10010011), 64 - (amount % 64)); - } - - inline uint32_t toBitMask() const { - return _mm256_movemask_epi8(*this); - } - - inline void reset() { - value = _mm256_setzero_si256(); - } - - template inline void store(ValueType* storageLocation) { - alignas(ALIGNMENT) double newArray[SixtyFourPer]{}; - _mm256_store_pd(newArray, _mm256_castsi256_pd(value)); - std::memcpy(storageLocation, newArray, sizeof(value)); - } - - inline SimdBase& setLSB(bool valueNew) { - if (valueNew) { - *this = _mm256_or_si256(*this, _mm256_set_epi64x(0, 0, 0, 0x1)); - } else { - *this = _mm256_andnot_si256(_mm256_set_epi64x(0, 0, 0, 0x1), *this); - } - return *this; - } - - inline bool checkMSB() const { - __m256i result = _mm256_and_si256(*this, _mm256_set_epi64x(0x8000000000000000, 0, 0, 0)); - return !_mm256_testz_si256(result, result); - } - - inline SimdBase carrylessMultiplication(uint64_t& prevInString) const { - __m128i allOnes{ _mm_set1_epi8('\xFF') }; - SimdBase valuesNew{}; - __m128i valueLow{ _mm256_extracti128_si256(value, 0) }; - __m128i valueHigh{ _mm256_extracti128_si256(value, 1) }; - valuesNew.insertInt64(_mm_cvtsi128_si64(_mm_clmulepi64_si128(valueLow, allOnes, 0)) ^ prevInString, 0); - prevInString = uint64_t(static_cast(valuesNew.getUint64(0)) >> 63); - valuesNew.insertInt64(_mm_cvtsi128_si64(_mm_clmulepi64_si128(valueLow, allOnes, 1)) ^ prevInString, 1); - prevInString = uint64_t(static_cast(valuesNew.getUint64(1)) >> 63); - valuesNew.insertInt64(_mm_cvtsi128_si64(_mm_clmulepi64_si128(valueHigh, allOnes, 0)) ^ prevInString, 2); - prevInString = uint64_t(static_cast(valuesNew.getUint64(2)) >> 63); - valuesNew.insertInt64(_mm_cvtsi128_si64(_mm_clmulepi64_si128(valueHigh, allOnes, 1)) ^ prevInString, 3); - prevInString = uint64_t(static_cast(valuesNew.getUint64(3)) >> 63); - return valuesNew; - } - - inline bool collectCarries(SimdBase<256>& other1, SimdBase<256>& result) { - bool returnValue{}; - long long unsigned returnValue64{}; - for (uint64_t x = 0; x < 4; ++x) { - if (_addcarry_u64(0, getInt64(x), other1.getInt64(x), &returnValue64)) { - returnValue = true; - } else { - returnValue = false; - } - result.insertInt64(returnValue64, x); - } - return returnValue; - } - - inline SimdBase follows(bool& overflow) const { - SimdBase result = shl<1>(); - result.setLSB(overflow); - overflow = checkMSB(); - return result; - } - - inline void printBits(uint64_t values, const std::string& valuesTitle) const { - std::cout << valuesTitle; - std::cout << std::bitset<64>{ values }; - std::cout << std::endl; - } - - inline SimdBase<256>& printBits(const std::string& valuesTitle) { - std::cout << valuesTitle; - for (uint64_t x = 0; x < 32; ++x) { - for (uint64_t y = 0; y < 8; ++y) { - std::cout << std::bitset<1>{ static_cast(*(reinterpret_cast(&value) + x)) >> y }; - } - } - std::cout << std::endl; - return *this; - } - - protected: - __m256i value{}; - }; - - inline SimdBaseReal makeSimdBase(uint64_t value) { - return _mm256_set1_epi64x(value); - } - - #define popcnt(x) _mm_popcnt_u64(x) - #define blsr(x) _blsr_u64(x) - #define load(x) gatherValues256>(x) - #define tzCount(x) _tzcnt_u32(x) - #define tzCount64(x) _tzcnt_u64(x) - -#elif defined T_AVX - - template - concept CharType = requires(CharacterType) { sizeof(CharacterType) == 1; }; - - template - concept Avx128T = std::same_as<__m128i, ValueType> || std::same_as<__m128, ValueType>; - - constexpr uint64_t StepSize{ 128 }; - constexpr uint64_t BytesPerStep{ StepSize / 8 }; - constexpr uint64_t SixtyFourPer{ StepSize / 64 }; - using StringParsingType = uint16_t; - using SimdBaseReal = SimdBase<128>; - using AvxType = __m128i; - - template<> struct SimdBase<128> { - public: - inline SimdBase() noexcept = default; - - inline SimdBase& operator=(SimdBase&& other) noexcept = default; - inline SimdBase(SimdBase&& other) noexcept = default; - inline SimdBase& operator=(const SimdBase& other) noexcept = delete; - inline SimdBase(const SimdBase& other) noexcept = delete; - - template inline SimdBase& operator=(ValueType&& data) { - value = std::forward(data); - return *this; - } - - template inline SimdBase(ValueType&& data) { - value = std::forward(data); - } - - inline SimdBase& operator=(uint8_t other) { - value = _mm_set1_epi8(other); - return *this; - } - - inline explicit SimdBase(uint8_t other) { - *this = other; - } - - inline SimdBase& operator=(const uint8_t values[16]) { - value = gatherValues128(values); - return *this; - } - - inline SimdBase(StringViewPtr values) { - *this = values; - } - - inline operator __m128i&() { - return value; - } - - inline operator const __m128i&&() const { - return std::forward(value); - } - - inline explicit operator bool() const { - return !_mm_testz_si128(value, value); - } - - inline operator uint16_t() const { - return toBitMask(); - } - - inline SimdBase operator|(SimdBase&& other) noexcept { - return _mm_or_si128(value, std::forward<__m128i>(other)); - } - - inline SimdBase operator-(SimdBase&& other) noexcept { - return _mm_sub_epi8(value, std::forward<__m128i>(other)); - } - - inline SimdBase operator|(const SimdBase& other) const { - return _mm_or_si128(value, other); - } - - inline SimdBase operator&(const SimdBase& other) const { - return _mm_and_si128(value, other); - } - - inline SimdBase operator-(const SimdBase& other) const { - return _mm_sub_epi8(value, other); - } - - inline SimdBase operator^(const SimdBase& other) const { - return _mm_xor_si128(value, other); - } - - inline StringParsingType operator==(const SimdBase& other) const { - SimdBase newValue = _mm_cmpeq_epi8(value, other); - return newValue.toBitMask(); - } - - inline StringParsingType operator==(const uint8_t& other) const { - SimdBase newValue = _mm_cmpeq_epi8(value, _mm_set1_epi8(other)); - return newValue.toBitMask(); - } - - inline SimdBase operator~() const { - return _mm_xor_si128(*this, _mm_set1_epi64x(std::numeric_limits::max())); - } - - inline void convertWhitespaceToSimdBase(const SimdBase* valuesNew) { - alignas(ALIGNMENT) uint8_t arrayNew[16]{ ' ', 100, 100, 100, 17, 100, 113, 2, 100, '\t', '\n', 112, 100, '\r', 100, 100 }; - SimdBase whitespaceTable{ arrayNew }; - for (uint64_t x = 0; x < 8; ++x) { - addValues(valuesNew[x].shuffle(whitespaceTable) == valuesNew[x], x); - } - }; - - inline void convertBackslashesToSimdBase(const SimdBase* valuesNew) { - SimdBase backslashes{ _mm_set1_epi8('\\') }; - for (uint64_t x = 0; x < 8; ++x) { - addValues(valuesNew[x] == backslashes, x); - } - }; - - inline void convertStructuralsToSimdBase(const SimdBase* valuesNew) { - alignas(ALIGNMENT) uint8_t arrayNew[16]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ':', '{', ',', '}', 0, 0 }; - SimdBase opTable{ arrayNew }; - SimdBase chars{ uint8_t{ 0x20 } }; - for (uint64_t x = 0; x < 8; ++x) { - addValues(valuesNew[x].shuffle(opTable) == (valuesNew[x] | chars), x); - } - }; - - inline void convertQuotesToSimdBase(const SimdBase* valuesNew) { - SimdBase quotes = _mm_set1_epi8('"'); - for (uint64_t x = 0; x < 8; ++x) { - addValues(valuesNew[x] == quotes, x); - } - } - - inline uint64_t getUint64(uint64_t index) const { - switch (index) { - case 0: { - return static_cast(_mm_extract_epi64(value, 0)); - } - case 1: { - return static_cast(_mm_extract_epi64(value, 1)); - } - default: { - return static_cast(_mm_extract_epi64(value, 0)); - } - } - } - - inline int64_t getInt64(uint64_t index) const { - switch (index) { - case 0: { - return _mm_extract_epi64(value, 0); - } - case 1: { - return _mm_extract_epi64(value, 1); - } - default: { - return _mm_extract_epi64(value, 0); - } - } - } - - inline void insertInt64(int64_t valueNew, uint64_t index) { - switch (index) { - case 0: { - value = _mm_insert_epi64(value, valueNew, 0); - break; - } - case 1: { - value = _mm_insert_epi64(value, valueNew, 1); - break; - } - default: { - value = _mm_insert_epi64(value, valueNew, 0); - break; - } - } - } - - inline void insertInt32(uint32_t valueNew, uint64_t index) { - switch (index) { - case 0: { - value = _mm_insert_epi32(value, valueNew, 0); - break; - } - case 1: { - value = _mm_insert_epi32(value, valueNew, 1); - break; - } - case 2: { - value = _mm_insert_epi32(value, valueNew, 2); - break; - } - case 3: { - value = _mm_insert_epi32(value, valueNew, 3); - break; - } - default: { - value = _mm_insert_epi32(value, valueNew, 0); - break; - } - } - } - - inline void insertInt16(int16_t valueNew, uint64_t index) { - switch (index) { - case 0: { - value = _mm_insert_epi16(value, valueNew, 0); - break; - } - case 1: { - value = _mm_insert_epi16(value, valueNew, 1); - break; - } - case 2: { - value = _mm_insert_epi16(value, valueNew, 2); - break; - } - case 3: { - value = _mm_insert_epi16(value, valueNew, 3); - break; - } - case 4: { - value = _mm_insert_epi16(value, valueNew, 4); - break; - } - case 5: { - value = _mm_insert_epi16(value, valueNew, 5); - break; - } - case 6: { - value = _mm_insert_epi16(value, valueNew, 6); - break; - } - case 7: { - value = _mm_insert_epi16(value, valueNew, 7); - break; - } - default: { - value = _mm_insert_epi16(value, valueNew, 0); - break; - } - } - } - - inline SimdBase bitAndNot(const SimdBase& other) const { - return _mm_andnot_si128(other, value); - } - - inline SimdBase shuffle(const SimdBase& other) const { - return _mm_shuffle_epi8(other, value); - } - - inline void addValues(uint16_t values, uint64_t index) { - insertInt16(values, index); - } - - template inline SimdBase shl() const { - SimdBase currentValues{}; - currentValues.insertInt64(getUint64(0) << amount, 0); - size_t shiftBetween = amount % 64; - currentValues.insertInt64((getUint64(1) << amount) | (getUint64(0) >> (64 - shiftBetween)), 1); - return currentValues; - } - - inline int16_t toBitMask() const { - return static_cast(_mm_movemask_epi8(*this)); - } - - inline void reset() { - value = _mm_setzero_si128(); - } - - template inline void store(ValueType* storageLocation) { - alignas(ALIGNMENT) double newArray[SixtyFourPer]{}; - _mm_store_pd(newArray, _mm_castsi128_pd(value)); - std::memcpy(storageLocation, newArray, sizeof(value)); - } - - inline SimdBase& setLSB(bool valueNew) { - if (valueNew) { - *this = _mm_or_si128(*this, _mm_set_epi64x(0, 0x1)); - } else { - *this = _mm_andnot_si128(_mm_set_epi64x(0, 0x1), *this); - } - return *this; - } - - inline bool checkMSB() const { - __m128i result = _mm_and_si128(*this, _mm_set_epi64x(0x8000000000000000, 0)); - return !_mm_testz_si128(result, result); - } - - inline SimdBase carrylessMultiplication(uint64_t& prevInString) const { - __m128i allOnes{ _mm_set1_epi8('\xFF') }; - SimdBase valuesNew{}; - __m128i valueLow{ value }; - valuesNew.insertInt64(_mm_cvtsi128_si64(_mm_clmulepi64_si128(valueLow, allOnes, 0)) ^ prevInString, 0); - prevInString = uint64_t(static_cast(valuesNew.getUint64(0)) >> 63); - valuesNew.insertInt64(_mm_cvtsi128_si64(_mm_clmulepi64_si128(valueLow, allOnes, 1)) ^ prevInString, 1); - prevInString = uint64_t(static_cast(valuesNew.getUint64(1)) >> 63); - return valuesNew; - } - - inline bool collectCarries(SimdBase<128>& other1, SimdBase<128>& result) { - bool returnValue{}; - long long unsigned returnValue64{}; - for (uint64_t x = 0; x < 2; ++x) { - if (_addcarry_u64(0, getInt64(x), other1.getInt64(x), &returnValue64)) { - returnValue = true; - } else { - returnValue = false; - } - result.insertInt64(returnValue64, x); - } - return returnValue; - } - - inline SimdBase follows(bool& overflow) const { - SimdBase result = shl<1>(); - result.setLSB(overflow); - overflow = checkMSB(); - return result; - } - - inline void printBits(uint64_t values, const std::string& valuesTitle) const { - std::cout << valuesTitle; - std::cout << std::bitset<64>{ values }; - std::cout << std::endl; - } - - inline const SimdBase<128>& printBits(const std::string& valuesTitle) const { - std::cout << valuesTitle; - for (uint64_t x = 0; x < 16; ++x) { - for (uint64_t y = 0; y < 8; ++y) { - std::cout << std::bitset<1>{ static_cast(*(reinterpret_cast(&value) + x)) >> y }; - } - } - std::cout << std::endl; - return *this; - } - - protected: - __m128i value{}; - }; - - inline SimdBaseReal makeSimdBase(uint64_t value) { - return _mm_set1_epi64x(value); - } - - #define popcnt(x) _mm_popcnt_u64(x) - #define blsr(x) _blsr_u64(x) - #define load(x) gatherValues128>(x) - #define tzCount(x) _tzcnt_u16(x) - #define tzCount64(x) _tzcnt_u64(x) - -#else - - template - concept CharType = requires(CharacterType) { sizeof(CharacterType) == 1; }; - - template - concept Avx128T = std::same_as<__m128I, ValueType>; - - constexpr uint64_t StepSize{ 128 }; - constexpr uint64_t BytesPerStep{ StepSize / 8 }; - constexpr uint64_t SixtyFourPer{ StepSize / 64 }; - using StringParsingType = uint16_t; - using SimdBaseReal = SimdBase<128>; - using AvxType = __m128I; - - inline int16_t movemaskEpi8(const __m128I& a) { - int16_t result{}; - for (int16_t i = 0; i < 2; ++i) { - for (int16_t j = 0; j < 8; ++j) { - uint8_t value = (a.values[i] >> (j * 8)) & 0xff; - int16_t mask = (value >> 7) & 1; - result |= mask << (i * 8 + j); - } - } - return result; - } - - inline __m128I orSi128(const __m128I& valOne, const __m128I& valTwo) { - __m128I value{}; - value.values[0] = valOne.values[0] | valTwo.values[0]; - value.values[1] = valOne.values[1] | valTwo.values[1]; - return value; - } - - inline __m128I andSi128(const __m128I& valOne, const __m128I& valTwo) { - __m128I value{}; - value.values[0] = valOne.values[0] & valTwo.values[0]; - value.values[1] = valOne.values[1] & valTwo.values[1]; - return value; - } - - inline __m128I andNotSi128(const __m128I& valOne, const __m128I& valTwo) { - __m128I result{}; - - for (int i = 0; i < 2; ++i) { - result.values[i] = valTwo.values[i] & (~valOne.values[i]); - } - - return result; - } - - inline __m128I xorSi128(const __m128I& valOne, const __m128I& valTwo) { - __m128I value{}; - value.values[0] = valOne.values[0] ^ valTwo.values[0]; - value.values[1] = valOne.values[1] ^ valTwo.values[1]; - return value; - } - - inline __m128I subEpi8(const __m128I& valOne, const __m128I& valTwo) { - __m128I result{}; - result.values[0] = valOne.values[0] - valTwo.values[0]; - result.values[1] = valOne.values[1] - valTwo.values[1]; - return result; - } - - inline __m128I notSi128(const __m128I& valOne) { - __m128I result{}; - - for (int64_t i = 0; i < 2; ++i) { - result.values[i] = ~valOne.values[i]; - } - - return result; - } - - inline __m128I cmpeqEpi8(const __m128I& a, const __m128I& b) { - __m128I result{}; - for (int i = 0; i < 2; ++i) { - for (int j = 0; j < 8; ++j) { - uint8_t a8 = (a.values[i] >> (j * 8)) & 0xff; - uint8_t b8 = (b.values[i] >> (j * 8)) & 0xff; - result.values[i] |= (a8 == b8 ? 0xFFULL : 0) << (j * 8); - } - } - return result; - } - - inline bool testzSi128(const __m128I& valOne, const __m128I& valTwo) { - __m128I result{}; - for (int i = 0; i < 2; ++i) { - result.values[i] = valOne.values[i] & valTwo.values[i]; - } - - return result.values[0] == 0 && result.values[1] == 0; - } - - inline __m128I setEpi64x(uint64_t argOne, uint64_t argTwo) { - __m128I returnValue{}; - returnValue.values[0] = argTwo; - returnValue.values[1] = argOne; - return returnValue; - } - - inline __m128I set1Epi64x(uint64_t argOne) { - __m128I returnValue{}; - returnValue.values[0] = argOne; - returnValue.values[1] = argOne; - return returnValue; - } - - inline __m128I insertUint16(__m128I value, int64_t position, uint16_t newValue) { - if (position < 0 || position >= 8) { - return value; - } - int arrayIndex = (position < 4) ? 0 : 1; - int shiftAmount = (position % 4) * 16; - value.values[arrayIndex] &= ~(static_cast(0xffff) << shiftAmount); - value.values[arrayIndex] |= (static_cast(newValue) << shiftAmount); - return value; - } - - inline __m128I insertUint32(const __m128I& value, int64_t position, uint32_t newValue) { - __m128I result = value; - - if (position == 0) { - result.values[0] = (result.values[0] & 0xFFFFFFFF00000000ull) | static_cast(newValue); - } else if (position == 1) { - result.values[0] = (result.values[0] & 0xFFFFFFFFull) | (static_cast(newValue) << 32); - } - - return result; - } - - inline __m128I insertUint64(const __m128I& value, int64_t position, uint64_t newValue) { - __m128I result = value; - - if (position == 0) { - result.values[0] = newValue; - } else if (position == 1) { - result.values[1] = newValue; - } - - return result; - } - - inline uint32_t extractUint32(__m128I value, int64_t index) { - if (index >= 0 && index < 4) { - int64_t valueIndex = index / 2; - - int64_t offset = (index % 2) * 32; - - uint32_t extractedValue = static_cast((value.values[valueIndex] >> offset) & 0xFFFFFFFFULL); - return extractedValue; - } - - return 0; - } - - inline uint64_t extractUint64(__m128I value, int64_t index) { - if (index >= 0 && index < 2) { - return value.values[index]; - } - - return 0; - } - - inline __m128I shuffleEpi8(const __m128I& a, const __m128I& b) { - __m128I dst{}; - for (int j = 0; j < 16; j++) { - int i = j * 8; - int bitIndex = i + 7; - - if ((b.values[bitIndex >> 6] & (1ULL << (bitIndex & 0x3F))) == (1ULL << (bitIndex & 0x3F))) { - dst.values[bitIndex >> 6] &= ~(1ULL << (bitIndex & 0x3F)); - } else { - int index = 0; - for (int m = i + 3; m >= i; m--) { - index = (index << 1) | ((b.values[m >> 6] >> (m & 0x3F)) & 1); - } - - int aIndex = index * 8; - for (int n = i; n <= i + 7; n++) { - dst.values[n >> 6] |= ((a.values[aIndex >> 6] >> (aIndex & 0x3F)) & 1ULL) << (n & 0x3F); - aIndex++; - } - } - } - - return dst; - } - - inline __m128I set1Epi8(int8_t newValue) { - __m128I returnValue{}; - std::memset(&returnValue, newValue, sizeof(__m128I)); - return returnValue; - } - - inline SimdBaseReal makeSimdBase(uint64_t value); - - template<> struct SimdBase<128> { - public: - inline SimdBase() noexcept = default; - - inline SimdBase& operator=(SimdBase&& other) noexcept = default; - inline SimdBase(SimdBase&& other) noexcept = default; - inline SimdBase& operator=(const SimdBase& other) noexcept = delete; - inline SimdBase(const SimdBase& other) noexcept = delete; - - template inline SimdBase& operator=(ValueType&& data) { - valueNew = std::forward<__m128I>(data); - return *this; - } - - template inline SimdBase(ValueType&& data) { - *this = std::forward<__m128I>(data); - } - - inline SimdBase& operator=(__m128I&& data) { - valueNew = std::forward<__m128I>(data); - return *this; - } - - inline SimdBase(__m128I&& data) { - *this = std::forward<__m128I>(data); - } - - inline SimdBase& operator=(uint8_t other) { - valueNew = set1Epi8(other); - return *this; - } - - inline explicit SimdBase(uint8_t other) { - *this = other; - } - - inline SimdBase& operator=(const uint8_t values[16]) { - valueNew = gatherValues128(values); - return *this; - } - - inline explicit SimdBase(StringViewPtr values) { - *this = values; - } - - inline explicit operator bool() { - return !testzSi128(valueNew, valueNew); - } - - inline operator __m128I&() { - return valueNew; - } - - inline SimdBase operator|(SimdBase&& other) noexcept { - return orSi128(valueNew, std::forward<__m128I>(other.valueNew)); - } - - inline SimdBase operator-(SimdBase&& other) noexcept { - return subEpi8(valueNew, std::forward<__m128I>(other.valueNew)); - } - - inline SimdBase operator|(const SimdBase& other) { - auto valueNewer = other.valueNew; - return orSi128(valueNew, valueNewer); - } - - inline SimdBase operator&(const SimdBase& other) { - auto valueNewer = other.valueNew; - return andSi128(valueNew, valueNewer); - } - - inline SimdBase operator-(const SimdBase& other) { - auto valueNewer = other.valueNew; - return subEpi8(valueNew, valueNewer); - } - - inline SimdBase operator^(const SimdBase& other) { - auto valueNewer = other.valueNew; - return xorSi128(valueNew, valueNewer); - } - - inline StringParsingType operator==(const uint8_t other) const { - SimdBase newValue = cmpeqEpi8(valueNew, set1Epi8(other)); - return newValue.toBitMask(); - } - - inline StringParsingType operator==(const SimdBase& other) const { - SimdBase newValue = cmpeqEpi8(valueNew, other.valueNew); - return newValue.toBitMask(); - } - - inline SimdBase operator~() { - return xorSi128(this->valueNew, set1Epi64x(std::numeric_limits::max())); - } - - inline void convertWhitespaceToSimdBase(SimdBase* valuesNew) { - alignas(ALIGNMENT) uint8_t arrayNew[16]{ ' ', 100, 100, 100, 17, 100, 113, 2, 100, '\t', '\n', 112, 100, '\r', 100, 100 }; - SimdBase whitespaceTable{ arrayNew }; - for (uint64_t x = 0; x < 8; ++x) { - addValues(valuesNew[x].shuffle(whitespaceTable) == valuesNew[x], x); - } - }; - - inline void convertBackslashesToSimdBase(SimdBase* valuesNew) { - SimdBase backslashes{ set1Epi8('\\') }; - for (uint64_t x = 0; x < 8; ++x) { - addValues(valuesNew[x] == backslashes, x); - } - }; - - inline void convertStructuralsToSimdBase(SimdBase* valuesNew) { - alignas(ALIGNMENT) uint8_t arrayNew[16]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ':', '{', ',', '}', 0, 0 }; - SimdBase opTable{ arrayNew }; - SimdBase chars{ uint8_t{ 0x20 } }; - for (uint64_t x = 0; x < 8; ++x) { - addValues(valuesNew[x].shuffle(opTable) == (valuesNew[x] | chars), x); - } - }; - - inline void convertQuotesToSimdBase(SimdBase* valuesNew) { - SimdBase quotes{ set1Epi8('"') }; - for (uint64_t x = 0; x < 8; ++x) { - addValues(valuesNew[x] == quotes, x); - } - } - - inline uint64_t getUint64(uint64_t index) const { - return extractUint64(valueNew, index); - } - - inline int64_t getInt64(uint64_t index) const { - return extractUint64(valueNew, index); - } - - inline void insertInt64(int64_t valueNewer, uint64_t index) { - valueNew = insertUint64(valueNew, index, valueNewer); - } - - inline void insertInt32(uint32_t valueNewer, uint64_t index) { - valueNew = insertUint32(valueNew, index, valueNewer); - } - - inline void insertInt16(int16_t valueNewer, uint64_t index) { - valueNew = insertUint16(valueNew, index, valueNewer); - } - - inline SimdBase bitAndNot(const SimdBase& other) { - return andNotSi128(other.valueNew, valueNew); - } - - inline SimdBase shuffle(const SimdBase& other) { - return shuffleEpi8(other.valueNew, valueNew); - } - - inline void addValues(uint16_t values, uint64_t index) { - insertInt16(values, index); - } - - template inline SimdBase shl() const { - SimdBase currentValues{}; - currentValues.insertInt64(getUint64(0) << amount, 0); - size_t shiftBetween = amount % 64; - currentValues.insertInt64((getUint64(1) << amount) | (getUint64(0) >> (64 - shiftBetween)), 1); - return currentValues; - } - - inline int16_t toBitMask() { - return static_cast(movemaskEpi8(this->valueNew)); - } - - inline void reset() { - valueNew.values[0] = 0; - valueNew.values[1] = 0; - } - - template inline void store(ValueType* storageLocation) { - std::memcpy(storageLocation, &valueNew, sizeof(valueNew)); - } - - inline SimdBase& setLSB(bool valueNew) { - if (valueNew) { - *this = orSi128(*this, setEpi64x(0, 0x1)); - } else { - *this = andNotSi128(setEpi64x(0, 0x1), *this); - } - return *this; - } - - inline bool checkMSB() const { - __m128I result = andSi128(this->valueNew, setEpi64x(0x8000000000000000, 0)); - return !testzSi128(result, result); - } - - inline uint64_t prefixXor(uint64_t prevInString) const { - prevInString ^= prevInString << 1; - prevInString ^= prevInString << 2; - prevInString ^= prevInString << 4; - prevInString ^= prevInString << 8; - prevInString ^= prevInString << 16; - prevInString ^= prevInString << 32; - return prevInString; - } - - inline SimdBase carrylessMultiplication(uint64_t& prevInString) const { - SimdBase valuesNew{}; - __m128I valueLow{ valueNew }; - valuesNew.insertInt64(prefixXor(valueLow.values[0]) ^ prevInString, 0); - prevInString = uint64_t(static_cast(valuesNew.getUint64(0)) >> 63); - valuesNew.insertInt64(prefixXor(valueLow.values[1]) ^ prevInString, 1); - prevInString = uint64_t(static_cast(valuesNew.getUint64(1)) >> 63); - return valuesNew; - } - - inline bool collectCarries(SimdBase<128>& other1, SimdBase<128>& result) { - bool returnValue{}; - long long unsigned returnValue64{}; - for (uint64_t x = 0; x < 2; ++x) { - if (_addcarry_u64(0, getInt64(x), other1.getInt64(x), &returnValue64)) { - returnValue = true; - } else { - returnValue = false; - } - result.insertInt64(returnValue64, x); - } - return returnValue; - } - - inline SimdBase follows(bool& overflow) const { - SimdBase result = shl<1>(); - result.setLSB(overflow); - overflow = checkMSB(); - return result; - } - - inline void printBits(uint64_t values, const std::string& valuesTitle) const { - std::cout << valuesTitle; - std::cout << std::bitset<64>{ values }; - std::cout << std::endl; - } - - inline const SimdBase<128>& printBits(const std::string& valuesTitle) const { - std::cout << valuesTitle; - for (uint64_t x = 0; x < 16; ++x) { - for (uint64_t y = 0; y < 8; ++y) { - std::cout << std::bitset<1>{ static_cast(*(reinterpret_cast(&valueNew) + x)) >> y }; - } - } - std::cout << std::endl; - return *this; - } - - protected: - __m128I valueNew{}; - }; - - inline SimdBaseReal makeSimdBase(uint64_t value) { - return set1Epi64x(value); - } - - inline uint32_t tzcnt_u16(uint16_t value) { - if (value == 0) { - return 16; - } - - uint32_t count = 0; - while ((value & 1) == 0) { - value >>= 1; - ++count; - } - - return count; - } - - inline uint64_t popcnt_u64(uint64_t value) { - uint64_t count = 0; - - while (value > 0) { - count += value & 1; - value >>= 1; - } - - return count; - } - - inline uint64_t blsr_u64(uint64_t value) { - if (value == 0) { - return 0; - } - - uint64_t result = value & (value - 1); - - return result; - } - - inline uint64_t tzcnt_u64(uint64_t value) { - uint64_t count = 0; - - if (value == 0) { - return 64; - } - - while ((value & 1) == 0) { - value >>= 1; - count++; - } - - return count; - } - - #define popcnt(x) popcnt_u64(x) - #define blsr(x) blsr_u64(x) - #define load(x) gatherValues128>(x) - #define tzCount(x) tzcnt_u16(x) - #define tzCount64(x) tzcnt_u64(x) - -#endif - -} \ No newline at end of file +#include +#include +#include +#include +#include +#include +#include \ No newline at end of file diff --git a/Include/jsonifier/ISADetection/AVX.hpp b/Include/jsonifier/ISADetection/AVX.hpp new file mode 100644 index 000000000..f4af03e93 --- /dev/null +++ b/Include/jsonifier/ISADetection/AVX.hpp @@ -0,0 +1,262 @@ +/* + MIT License + + Copyright (c) 2023 RealTimeChris + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, and to permit + persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE + FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ +/// https://github.com/RealTimeChris/jsonifier +/// Feb 3, 2023 +#pragma once + +#include + +namespace jsonifier_internal { + +#if JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX) && !JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX2) && !JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX512) + + constexpr uint64_t StepSize{ 128 }; + constexpr uint64_t BytesPerStep{ StepSize / 8 }; + constexpr uint64_t SixtyFourBytesPerStep{ StepSize / 64 }; + constexpr uint64_t StridesPerStep{ StepSize / BytesPerStep }; + using string_parsing_type = uint16_t; + + template + concept avx_t = std::same_as, avx_int_128>; + + template inline avx_int_128 gatherValues128(const value_type* str) { + alignas(JSONIFIER_ALIGNMENT) double newArray[sizeof(avx_int_128) / sizeof(double)]{}; + std::memcpy(newArray, str, sizeof(avx_int_128)); + return _mm_castpd_si128(_mm_load_pd(newArray)); + } + + template inline avx_float_128 gatherValues128(const value_type* str) { + return _mm_load_ps(str); + } + + template<> class simd_base_internal<128> { + public: + inline simd_base_internal() = default; + + template inline simd_base_internal& operator=(avx_type_new&& data) { + value = std::forward(data); + return *this; + } + + template inline simd_base_internal(avx_type_new&& data) { + *this = std::forward(data); + } + + inline simd_base_internal& operator=(uint8_t other) { + value = _mm_set1_epi8(other); + return *this; + } + + inline explicit simd_base_internal(uint8_t other) { + *this = other; + } + + inline simd_base_internal(const uint8_t values[BytesPerStep]) { + value = gatherValues128(values); + } + + inline operator const avx_int_128&() const { + return value; + } + + inline explicit operator bool() const { + return !_mm_testz_si128(value, value); + } + + template inline simd_base_internal operator|(simd_base_type&& other) const { + return _mm_or_si128(value, std::forward(other)); + } + + template inline simd_base_internal operator-(simd_base_type&& other) const { + return _mm_sub_epi8(value, std::forward(other)); + } + + template inline simd_base_internal operator&(simd_base_type&& other) const { + return _mm_and_si128(value, std::forward(other)); + } + + template inline simd_base_internal operator^(simd_base_type&& other) const { + return _mm_xor_si128(value, std::forward(other)); + } + + inline string_parsing_type operator==(const simd_base_internal& other) const { + simd_base_internal newValue{ _mm_cmpeq_epi8(value, other) }; + return newValue.toBitMask(); + } + + inline string_parsing_type operator==(const uint8_t& other) const { + simd_base_internal newValue = _mm_cmpeq_epi8(value, _mm_set1_epi8(other)); + return newValue.toBitMask(); + } + + inline simd_base_internal operator~() const { + return _mm_xor_si128(*this, _mm_set1_epi64x(std::numeric_limits::max())); + } + + template inline void convertWhitespaceToSimdBase(const simd_base_internal* valuesNew) { + if constexpr (index < StridesPerStep) { + alignas(JSONIFIER_ALIGNMENT) static constexpr uint8_t arrayNew[]{ ' ', 100, 100, 100, 17, 100, 113, 2, 100, '\t', '\n', 112, 100, '\r', 100, 100 }; + static const simd_base_internal whitespaceTable{ arrayNew }; + addValues(valuesNew[index].shuffle(whitespaceTable) == valuesNew[index]); + convertWhitespaceToSimdBase(valuesNew); + } + } + + template inline void convertBackslashesToSimdBase(const simd_base_internal* valuesNew) { + if constexpr (index < StridesPerStep) { + static const simd_base_internal backslashes{ _mm_set1_epi8('\\') }; + addValues(valuesNew[index] == backslashes); + convertBackslashesToSimdBase(valuesNew); + } + } + + template inline void convertStructuralsToSimdBase(const simd_base_internal* valuesNew) { + if constexpr (index < StridesPerStep) { + alignas(JSONIFIER_ALIGNMENT) static constexpr uint8_t arrayNew[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ':', '{', ',', '}', 0, 0 }; + static const simd_base_internal opTable{ arrayNew }; + static const simd_base_internal chars{ uint8_t{ 0x20 } }; + addValues(valuesNew[index].shuffle(opTable) == (valuesNew[index] | chars)); + convertStructuralsToSimdBase(valuesNew); + } + } + + template inline void convertQuotesToSimdBase(const simd_base_internal* valuesNew) { + if constexpr (index < StridesPerStep) { + static const simd_base_internal quotes{ _mm_set1_epi8('"') }; + addValues(valuesNew[index] == quotes); + convertQuotesToSimdBase(valuesNew); + } + } + + template inline uint64_t getUint64() const { + static_assert(index < SixtyFourBytesPerStep, "Sorry, but that index value is incorrect."); + return static_cast(_mm_extract_epi64(value, index)); + } + + template inline void insertUint64(uint64_t valueNew) { + static_assert(index < SixtyFourBytesPerStep, "Sorry, but that index value is incorrect."); + value = _mm_insert_epi64(value, static_cast(valueNew), index); + } + + template inline void insertUint16(string_parsing_type valueNew) { + static_assert(index < StridesPerStep, "Sorry, but that index value is incorrect."); + value = _mm_insert_epi16(value, static_cast(valueNew), index); + } + + inline simd_base_internal bitAndNot(const simd_base_internal& other) const { + return _mm_andnot_si128(other, value); + } + + inline simd_base_internal shuffle(const simd_base_internal& other) const { + return _mm_shuffle_epi8(other, value); + } + + template inline void addValues(string_parsing_type valuesToAdd) { + insertUint16(valuesToAdd); + } + + template inline simd_base_internal shl() const { + simd_base_internal currentValues{}; + currentValues.insertUint64(getUint64() << amount); + uint64_t shiftBetween = amount % 64; + currentValues.insertUint64<1>((getUint64<1>() << amount) | (getUint64() >> (64 - shiftBetween))); + return currentValues; + } + + inline string_parsing_type toBitMask() const { + return static_cast(_mm_movemask_epi8(*this)); + } + + inline void reset() { + value = _mm_setzero_si128(); + } + + template inline void store(value_type* storageLocation) { + alignas(JSONIFIER_ALIGNMENT) double newArray[SixtyFourBytesPerStep]{}; + _mm_store_pd(newArray, _mm_castsi128_pd(value)); + std::memcpy(storageLocation, newArray, sizeof(value)); + } + + inline simd_base_internal& setLSB(bool valueNew) { + if (valueNew) { + *this = _mm_or_si128(*this, _mm_set_epi64x(0, 0x1)); + } else { + *this = _mm_andnot_si128(_mm_set_epi64x(0, 0x1), *this); + } + return *this; + } + + inline bool checkMSB() const { + avx_int_128 result = _mm_and_si128(*this, _mm_set_epi64x(0x8000000000000000, 0)); + return !_mm_testz_si128(result, result); + } + + inline simd_base_internal carrylessMultiplication(uint64_t& prevInString) const { + avx_int_128 allOnes{ _mm_set1_epi8('\xFF') }; + simd_base_internal valuesNew{}; + avx_int_128 valueNew{ value }; + valuesNew.insertUint64(static_cast(_mm_cvtsi128_si64(_mm_clmulepi64_si128(valueNew, allOnes, 0)) ^ prevInString)); + prevInString = uint64_t(static_cast(valuesNew.getUint64()) >> 63); + valuesNew.insertUint64<1>(static_cast(_mm_cvtsi128_si64(_mm_clmulepi64_si128(valueNew, allOnes, 1)) ^ prevInString)); + prevInString = uint64_t(static_cast(valuesNew.getUint64<1>()) >> 63); + return valuesNew; + } + + inline simd_base_internal follows(bool& overflow) const { + simd_base_internal result = shl<1>(); + result.setLSB(overflow); + overflow = checkMSB(); + return result; + } + + inline void printBits(uint64_t values, const std::string& valuesTitle) const { + std::cout << valuesTitle; + std::cout << std::bitset<64>{ values }; + std::cout << std::endl; + } + + inline simd_base_internal& printBits(const std::string& valuesTitle) noexcept { + uint8_t values[BytesPerStep]{}; + store(values); + std::cout << valuesTitle; + for (uint64_t x = 0; x < BytesPerStep; ++x) { + for (uint64_t y = 0; y < 8; ++y) { + std::cout << std::bitset<1>{ static_cast(*(values + x)) >> y }; + } + } + std::cout << std::endl; + return *this; + } + + protected: + avx_int_128 value{}; + }; + + inline simd_base makeSimdBase(uint64_t value) { + return _mm_set1_epi64x(value); + } + + #define load(value) gatherValues128(value) + +#endif + +} \ No newline at end of file diff --git a/Include/jsonifier/ISADetection/AVX2.hpp b/Include/jsonifier/ISADetection/AVX2.hpp new file mode 100644 index 000000000..502cbdd49 --- /dev/null +++ b/Include/jsonifier/ISADetection/AVX2.hpp @@ -0,0 +1,281 @@ +/* + MIT License + + Copyright (c) 2023 RealTimeChris + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, and to permit + persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE + FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ +/// https://github.com/RealTimeChris/jsonifier +/// Feb 3, 2023 +#pragma once + +#include + +namespace jsonifier_internal { + +#if JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX2) && !JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX) && !JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX512) + + constexpr uint64_t StepSize{ 256 }; + constexpr uint64_t BytesPerStep{ StepSize / 8 }; + constexpr uint64_t SixtyFourBytesPerStep{ StepSize / 64 }; + constexpr uint64_t StridesPerStep{ StepSize / BytesPerStep }; + + using string_parsing_type = uint32_t; + + template + concept avx_t = std::same_as, avx_int_256>; + + template inline avx_int_128 gatherValues128(const value_type* str) { + alignas(JSONIFIER_ALIGNMENT) double newArray[sizeof(avx_int_128) / sizeof(double)]{}; + std::memcpy(newArray, str, sizeof(avx_int_128)); + return _mm_castpd_si128(_mm_load_pd(newArray)); + } + + template inline avx_int_256 gatherValues256(const value_type* str) { + alignas(JSONIFIER_ALIGNMENT) double newArray[sizeof(avx_int_256) / sizeof(double)]{}; + std::memcpy(newArray, str, sizeof(avx_int_256)); + return _mm256_castpd_si256(_mm256_load_pd(newArray)); + } + + template inline avx_float_128 gatherValues128(const value_type* str) { + return _mm_load_ps(str); + } + + template inline avx_float_256 gatherValues256(const value_type* str) { + return _mm256_load_ps(str); + } + + template<> class simd_base_internal<256> { + public: + inline simd_base_internal() = default; + + template inline simd_base_internal& operator=(avx_type_new&& data) { + value = std::forward(data); + return *this; + } + + template inline simd_base_internal(avx_type_new&& data) { + *this = std::forward(data); + } + + inline simd_base_internal& operator=(uint8_t other) { + value = _mm256_set1_epi8(static_cast(other)); + return *this; + } + + inline explicit simd_base_internal(uint8_t other) { + *this = other; + } + + inline simd_base_internal(const uint8_t values[BytesPerStep]) { + value = gatherValues256(values); + } + + inline simd_base_internal(const uint64_t values[SixtyFourBytesPerStep]) { + value = _mm256_setr_epi64x(static_cast(values[0]), static_cast(values[1]), static_cast(values[2]), static_cast(values[3])); + } + + inline operator const avx_int_256&() const { + return value; + } + + inline explicit operator bool() const { + return !_mm256_testz_si256(value, value); + } + + template inline simd_base_internal operator|(simd_base_type&& other) const { + return _mm256_or_si256(value, std::forward(other)); + } + + template inline simd_base_internal operator-(simd_base_type&& other) const { + return _mm256_sub_epi8(value, std::forward(other)); + } + + template inline simd_base_internal operator&(simd_base_type&& other) const { + return _mm256_and_si256(value, std::forward(other)); + } + + template inline simd_base_internal operator^(simd_base_type&& other) const { + return _mm256_xor_si256(value, std::forward(other)); + } + + inline string_parsing_type operator==(const simd_base_internal& other) const { + simd_base_internal newValue{ _mm256_cmpeq_epi8(value, other) }; + return newValue.toBitMask(); + } + + inline string_parsing_type operator==(const uint8_t& other) const { + simd_base_internal newValue = _mm256_cmpeq_epi8(value, _mm256_set1_epi8(static_cast(other))); + return newValue.toBitMask(); + } + + inline simd_base_internal operator~() const { + return _mm256_xor_si256(*this, _mm256_set1_epi64x(static_cast(std::numeric_limits::max()))); + } + + template inline void convertWhitespaceToSimdBase(const simd_base_internal* valuesNew) { + if constexpr (index < StridesPerStep) { + alignas(JSONIFIER_ALIGNMENT) static constexpr uint8_t arrayNew[]{ ' ', 100, 100, 100, 17, 100, 113, 2, 100, '\t', '\n', 112, 100, '\r', 100, 100, ' ', 100, 100, + 100, 17, 100, 113, 2, 100, '\t', '\n', 112, 100, '\r', 100, 100 }; + static const simd_base_internal whitespaceTable{ arrayNew }; + addValues(valuesNew[index].shuffle(whitespaceTable) == valuesNew[index]); + convertWhitespaceToSimdBase(valuesNew); + } + } + + template inline void convertBackslashesToSimdBase(const simd_base_internal* valuesNew) { + if constexpr (index < StridesPerStep) { + static const simd_base_internal backslashes{ _mm256_set1_epi8('\\') }; + addValues(valuesNew[index] == backslashes); + convertBackslashesToSimdBase(valuesNew); + } + } + + template inline void convertStructuralsToSimdBase(const simd_base_internal* valuesNew) { + if constexpr (index < StridesPerStep) { + alignas(JSONIFIER_ALIGNMENT) static constexpr uint8_t arrayNew[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ':', '{', ',', '}', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ':', '{', + ',', '}', 0, 0 }; + static const simd_base_internal opTable{ arrayNew }; + static const simd_base_internal chars{ uint8_t{ 0x20 } }; + addValues(valuesNew[index].shuffle(opTable) == (valuesNew[index] | chars)); + convertStructuralsToSimdBase(valuesNew); + } + } + + template inline void convertQuotesToSimdBase(const simd_base_internal* valuesNew) { + if constexpr (index < StridesPerStep) { + static const simd_base_internal quotes{ _mm256_set1_epi8('"') }; + addValues(valuesNew[index] == quotes); + convertQuotesToSimdBase(valuesNew); + } + } + + template inline uint64_t getUint64() const { + static_assert(index < SixtyFourBytesPerStep, "Sorry, but that index value is incorrect."); + return static_cast(_mm256_extract_epi64(value, index)); + } + + template inline void insertUint64(uint64_t valueNew) { + static_assert(index < SixtyFourBytesPerStep, "Sorry, but that index value is incorrect."); + value = _mm256_insert_epi64(value, static_cast(valueNew), index); + } + + template inline void insertUint32(string_parsing_type valueNew) { + static_assert(index < StridesPerStep, "Sorry, but that index value is incorrect."); + value = _mm256_insert_epi32(value, static_cast(valueNew), index); + } + + inline simd_base_internal bitAndNot(const simd_base_internal& other) const { + return _mm256_andnot_si256(other, value); + } + + inline simd_base_internal shuffle(const simd_base_internal& other) const { + return _mm256_shuffle_epi8(other, value); + } + + template inline void addValues(string_parsing_type valuesToAdd) { + insertUint32(valuesToAdd); + } + + template inline simd_base_internal shl() const { + return simd_base_internal{ _mm256_slli_epi64(*this, (amount % 64)) } | _mm256_srli_epi64(_mm256_permute4x64_epi64(*this, 0b10010011), 64 - (amount % 64)); + } + + inline string_parsing_type toBitMask() const { + return static_cast(_mm256_movemask_epi8(*this)); + } + + inline void reset() { + value = _mm256_setzero_si256(); + } + + template inline void store(value_type* storageLocation) { + alignas(JSONIFIER_ALIGNMENT) double newArray[SixtyFourBytesPerStep]{}; + _mm256_store_pd(newArray, _mm256_castsi256_pd(value)); + std::memcpy(storageLocation, newArray, sizeof(value)); + } + + inline simd_base_internal& setLSB(bool valueNew) { + if (valueNew) { + *this = _mm256_or_si256(*this, _mm256_set_epi64x(0, 0, 0, 0x1)); + } else { + *this = _mm256_andnot_si256(_mm256_set_epi64x(0, 0, 0, 0x1), *this); + } + return *this; + } + + inline bool checkMSB() const { + avx_int_256 result = _mm256_and_si256(*this, _mm256_set_epi64x(0x8000000000000000, 0, 0, 0)); + return !_mm256_testz_si256(result, result); + } + + template inline void processValue(avx_int_128& val, uint64_t* valuesNewer, uint64_t& prevInstring) const { + static const avx_int_128 allOnes{ _mm_set1_epi8('\xFF') }; + valuesNewer[index] = static_cast(_mm_cvtsi128_si64(_mm_clmulepi64_si128(val, allOnes, index % 2)) ^ prevInstring); + prevInstring = static_cast(static_cast(valuesNewer[index]) >> 63); + } + + inline simd_base_internal carrylessMultiplication(uint64_t& prevInstring) const { + avx_int_128 valueLow{ _mm256_extracti128_si256(value, 0) }; + avx_int_128 valueHigh{ _mm256_extracti128_si256(value, 1) }; + alignas(JSONIFIER_ALIGNMENT) uint64_t valuesNewer[SixtyFourBytesPerStep]{}; + processValue<0>(valueLow, valuesNewer, prevInstring); + processValue<1>(valueLow, valuesNewer, prevInstring); + processValue<2>(valueHigh, valuesNewer, prevInstring); + processValue<3>(valueHigh, valuesNewer, prevInstring); + return valuesNewer; + } + + inline simd_base_internal follows(bool& overflow) const { + simd_base_internal result = shl<1>(); + result.setLSB(overflow); + overflow = checkMSB(); + return result; + } + + inline void printBits(uint64_t values, const std::string& valuesTitle) const { + std::cout << valuesTitle; + std::cout << std::bitset<64>{ values }; + std::cout << std::endl; + } + + inline simd_base_internal& printBits(const std::string& valuesTitle) noexcept { + uint8_t values[BytesPerStep]{}; + store(values); + std::cout << valuesTitle; + for (uint64_t x = 0; x < BytesPerStep; ++x) { + for (uint64_t y = 0; y < 8; ++y) { + std::cout << std::bitset<1>{ static_cast(*(values + x)) >> y }; + } + } + std::cout << std::endl; + return *this; + } + + protected: + avx_int_256 value{}; + }; + + inline simd_base makeSimdBase(uint64_t value) { + return _mm256_set1_epi64x(static_cast(value)); + } + + #define load(value) gatherValues256(value) + +#endif + +} \ No newline at end of file diff --git a/Include/jsonifier/ISADetection/AVX512.hpp b/Include/jsonifier/ISADetection/AVX512.hpp new file mode 100644 index 000000000..71c6e87fb --- /dev/null +++ b/Include/jsonifier/ISADetection/AVX512.hpp @@ -0,0 +1,335 @@ +/* + MIT License + + Copyright (c) 2023 RealTimeChris + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, and to permit + persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE + FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ +/// https://github.com/RealTimeChris/jsonifier +/// Feb 3, 2023 +#pragma once + +#include + +namespace jsonifier_internal { + +#if JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX512) && !JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX) && !JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX2) + + constexpr uint64_t StepSize{ 512 }; + constexpr uint64_t BytesPerStep{ StepSize / 8 }; + constexpr uint64_t SixtyFourBytesPerStep{ StepSize / 64 }; + constexpr uint64_t StridesPerStep{ StepSize / BytesPerStep };\ + using string_parsing_type = uint64_t; + + template + concept avx_t = std::same_as, avx_int_512>; + + template inline avx_int_128 gatherValues128(const value_type* str) { + if constexpr (alignof(value_type) == 1) { + return _mm_loadu_epi8(str); + } else { + alignas(JSONIFIER_ALIGNMENT) double newArray[sizeof(avx_int_256) / sizeof(double)]{}; + std::memcpy(newArray, str, sizeof(avx_int_256)); + return _mm_castpd_si128(_mm_load_pd(newArray)); + } + } + + template inline avx_int_256 gatherValues256(const value_type* str) { + if constexpr (alignof(value_type) == 1) { + return _mm256_loadu_epi8(str); + } else { + alignas(JSONIFIER_ALIGNMENT) double newArray[sizeof(avx_int_512) / sizeof(double)]{}; + std::memcpy(newArray, str, sizeof(avx_int_256)); + return _mm256_castpd_si256(_mm256_load_pd(newArray)); + } + } + + template inline avx_int_512 gatherValues512(const value_type* str) { + if constexpr (alignof(value_type) == 1) { + return _mm512_loadu_si512(str); + } else { + return _mm512_load_si512(str); + } + } + + template inline avx_float_128 gatherValues128(const value_type* str) { + return _mm_load_ps(str); + } + + template inline avx_float_256 gatherValues256(const value_type* str) { + return _mm256_load_ps(str); + } + + template inline avx_float_512 gatherValues512(const value_type* str) { + return _mm512_load_ps(str); + } + + template<> class simd_base_internal<256> { + public: + inline simd_base_internal() = default; + + inline simd_base_internal& operator=(avx_int_256&& data) { + value = std::forward(data); + return *this; + } + + inline simd_base_internal(avx_int_256&& data) { + value = std::forward(data); + } + + inline operator const avx_int_256&&() const { + return std::forward(value); + } + + inline simd_base_internal(const uint64_t values[SixtyFourBytesPerStep]) { + value = _mm256_setr_epi64x(values[0], values[1], values[2], values[3]); + } + + template inline uint64_t getUint64() const { + static_assert(index < SixtyFourBytesPerStep, "Sorry, but that index value is incorrect."); + return static_cast(_mm256_extract_epi64(value, index)); + } + + template inline void insertUint64(uint64_t valueNew) { + static_assert(index < SixtyFourBytesPerStep, "Sorry, but that index value is incorrect."); + value = _mm256_insert_epi64(value, static_cast(valueNew), index); + } + + template inline void processValue(avx_int_128& val, uint64_t* valuesNewer, uint64_t& prevInstring) const { + static const avx_int_128 allOnes{ _mm_set1_epi8('\xFF') }; + valuesNewer[index] = static_cast(_mm_cvtsi128_si64(_mm_clmulepi64_si128(val, allOnes, index % 2)) ^ prevInstring); + prevInstring = static_cast(valuesNewer[index]) >> 63; + } + + inline simd_base_internal carrylessMultiplication(uint64_t& prevInstring) const { + avx_int_128 valueLow{ _mm256_extracti128_si256(value, 0) }; + avx_int_128 valueHigh{ _mm256_extracti128_si256(value, 1) }; + alignas(JSONIFIER_ALIGNMENT) uint64_t valuesNewer[SixtyFourBytesPerStep]{}; + processValue<0>(valueLow, valuesNewer, prevInstring); + processValue<1>(valueLow, valuesNewer, prevInstring); + processValue<2>(valueHigh, valuesNewer, prevInstring); + processValue<3>(valueHigh, valuesNewer, prevInstring); + return valuesNewer; + } + + protected: + avx_int_256 value{}; + }; + + template<> class simd_base_internal<512> { + public: + inline simd_base_internal() = default; + + template inline simd_base_internal& operator=(avx_type_new&& data) { + value = std::forward(data); + return *this; + } + + template inline simd_base_internal(avx_type_new&& data) { + *this = std::forward(data); + } + + inline simd_base_internal& operator=(uint8_t other) { + value = _mm512_set1_epi8(other); + return *this; + } + + inline explicit simd_base_internal(uint8_t other) { + *this = other; + } + + inline simd_base_internal(const uint8_t values[BytesPerStep]) { + value = gatherValues512(values); + } + + inline operator const avx_int_512&() const { + return value; + } + + inline explicit operator bool() const { + return _mm512_test_epi64_mask(value, value) != 0; + } + + template inline simd_base_internal operator|(simd_base_type&& other) const { + return _mm512_or_si512(value, std::forward(other)); + } + + template inline simd_base_internal operator-(simd_base_type&& other) const { + return _mm512_sub_epi8(value, std::forward(other)); + } + + template inline simd_base_internal operator&(simd_base_type&& other) const { + return _mm512_and_si512(value, std::forward(other)); + } + + template inline simd_base_internal operator^(simd_base_type&& other) const { + return _mm512_xor_si512(value, std::forward(other)); + } + + inline string_parsing_type operator==(const simd_base_internal& other) const { + return _mm512_cmpeq_epi8_mask(value, other); + } + + inline string_parsing_type operator==(const uint8_t& other) const { + return _mm512_cmpeq_epi8_mask(value, _mm512_set1_epi8(other)); + } + + inline simd_base_internal operator~() const { + return _mm512_xor_si512(*this, _mm512_set1_epi64(std::numeric_limits::max())); + } + + template inline void convertWhitespaceToSimdBase(const simd_base_internal* valuesNew) { + if constexpr (index < StridesPerStep) { + alignas(JSONIFIER_ALIGNMENT) static constexpr uint8_t arrayNew[]{ ' ', 100, 100, 100, 17, 100, 113, 2, 100, '\t', '\n', 112, 100, '\r', 100, 100, ' ', 100, 100, + 100, 17, 100, 113, 2, 100, '\t', '\n', 112, 100, '\r', 100, 100, ' ', 100, 100, 100, 17, 100, 113, 2, 100, '\t', '\n', 112, 100, '\r', 100, 100, ' ', 100, 100, + 100, 17, 100, 113, 2, 100, '\t', '\n', 112, 100, '\r', 100, 100 }; + static const simd_base_internal whitespaceTable{ arrayNew }; + addValues(valuesNew[index].shuffle(whitespaceTable) == valuesNew[index]); + convertWhitespaceToSimdBase(valuesNew); + } + } + + template inline void convertBackslashesToSimdBase(const simd_base_internal* valuesNew) { + if constexpr (index < StridesPerStep) { + static const simd_base_internal backslashes{ _mm512_set1_epi8('\\') }; + addValues(valuesNew[index] == backslashes); + convertBackslashesToSimdBase(valuesNew); + } + } + + template inline void convertStructuralsToSimdBase(const simd_base_internal* valuesNew) { + if constexpr (index < StridesPerStep) { + alignas(JSONIFIER_ALIGNMENT) static constexpr uint8_t arrayNew[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ':', '{', ',', '}', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ':', '{', + ',', '}', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ':', '{', ',', '}', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ':', '{', ',', '}', 0, 0 }; + static const simd_base_internal opTable{ arrayNew }; + static const simd_base_internal chars{ uint8_t{ 0x20 } }; + addValues(valuesNew[index].shuffle(opTable) == (valuesNew[index] | chars)); + convertStructuralsToSimdBase(valuesNew); + } + } + + template inline void convertQuotesToSimdBase(const simd_base_internal* valuesNew) { + if constexpr (index < StridesPerStep) { + static const simd_base_internal quotes{ _mm512_set1_epi8('"') }; + addValues(valuesNew[index] == quotes); + convertQuotesToSimdBase(valuesNew); + } + } + + template inline void insertUint64(uint64_t valueNew) { + static_assert(index < SixtyFourBytesPerStep, "Sorry, but that index value is incorrect."); + auto lower = _mm512_extracti64x4_epi64(value, index / 4); + lower = _mm256_insert_epi64(lower, static_cast(valueNew), index % 4); + value = _mm512_inserti64x4(value, lower, index / 4); + } + + inline simd_base_internal bitAndNot(const simd_base_internal& other) const { + return _mm512_andnot_si512(other, value); + } + + inline simd_base_internal shuffle(const simd_base_internal& other) const { + return _mm512_shuffle_epi8(other, value); + } + + template inline void addValues(string_parsing_type valuesToAdd) { + insertUint64(valuesToAdd); + } + + template inline simd_base_internal shl() const { + simd_base_internal newValue{ _mm512_slli_epi64(*this, (amount % 64)) }; + simd_base_internal newerValue{ _mm512_srli_epi64(_mm512_permutexvar_epi64(_mm512_set_epi64(6, 5, 4, 3, 2, 1, 0, 7), *this), 64 - (amount % 64)) }; + static constexpr int64_t maxValue{ static_cast(std::numeric_limits::max()) }; + simd_base_internal newestValue{ _mm512_set_epi64(maxValue, maxValue, maxValue, maxValue, maxValue, maxValue, maxValue, 0) }; + return simd_base_internal{ newValue | (newerValue & newestValue) }; + } + + inline string_parsing_type toBitMask() const { + return static_cast(_mm512_movepi8_mask(*this)); + } + + inline void reset() { + value = _mm512_setzero_si512(); + } + + template inline void store(value_type* storageLocation) const { + _mm512_store_si512(storageLocation, value); + } + + inline simd_base_internal& setLSB(bool valueNew) { + if (valueNew) { + *this = _mm512_or_si512(*this, _mm512_set_epi64(0, 0, 0, 0, 0, 0, 0, 0x1)); + } else { + *this = _mm512_andnot_si512(_mm512_set_epi64(0, 0, 0, 0, 0, 0, 0, 0x1), *this); + } + return *this; + } + + inline bool checkMSB() const { + avx_int_512 result = _mm512_and_si512(*this, _mm512_set_epi64(0x8000000000000000, 0, 0, 0, 0, 0, 0, 0)); + return static_cast(_mm512_test_epi64_mask(result, result)); + } + + inline simd_base carrylessMultiplication(string_parsing_type& prevInstring) const { + simd_base_small lowValues{ _mm512_extracti64x4_epi64(value, 0) }; + simd_base_small highValues{ _mm512_extracti64x4_epi64(value, 1) }; + lowValues = lowValues.carrylessMultiplication(prevInstring); + highValues = highValues.carrylessMultiplication(prevInstring); + simd_base returnValue{}; + returnValue = _mm512_inserti64x4(returnValue, lowValues, 0); + returnValue = _mm512_inserti64x4(returnValue, highValues, 1); + return returnValue; + } + + inline simd_base_internal follows(bool& overflow) { + simd_base_internal result = shl<1>(); + result.setLSB(overflow); + overflow = checkMSB(); + return result; + } + + inline void printBits(string_parsing_type values, const std::string& valuesTitle) const { + std::cout << valuesTitle; + std::cout << std::bitset<64>{ values }; + std::cout << std::endl; + } + + inline simd_base_internal& printBits(const std::string& valuesTitle) noexcept { + uint8_t values[BytesPerStep]{}; + store(values); + std::cout << valuesTitle; + for (string_parsing_type x = 0; x < BytesPerStep; ++x) { + for (string_parsing_type y = 0; y < 8; ++y) { + std::cout << std::bitset<1>{ static_cast(*(values + x)) >> y }; + } + } + std::cout << std::endl; + return *this; + } + + protected: + avx_int_512 value{}; + }; + + inline simd_base makeSimdBase(int64_t value) { + return _mm512_set1_epi64(value); + } + + #define load(value) gatherValues512(value) + +#endif + +} \ No newline at end of file diff --git a/Include/jsonifier/ISADetection/Bmi.hpp b/Include/jsonifier/ISADetection/Bmi.hpp new file mode 100644 index 000000000..3ef057e92 --- /dev/null +++ b/Include/jsonifier/ISADetection/Bmi.hpp @@ -0,0 +1,85 @@ +/* + MIT License + + Copyright (c) 2023 RealTimeChris + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, and to permit + persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE + FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ +/// https://github.com/RealTimeChris/jsonifier +/// Feb 3, 2023 +#pragma once + +#include + +namespace jsonifier_internal { + +#if JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_BMI) + + template constexpr value_type blsr(value_type value) { + static_assert(std::is_integral_v, "Input must be an integer type"); + if constexpr (sizeof(value_type) == 4) { + return _blsr_u32(value); + } else if constexpr (sizeof(value_type) == 8) { + return _blsr_u64(value); + } else { + static_assert(sizeof(value_type) == 4 || sizeof(value_type) == 8, "Unsupported size for blsr()"); + return value; + } + } + + template constexpr value_type tzCount(value_type value) { + static_assert(std::is_integral_v, "Input must be an integer type"); + if constexpr (sizeof(value_type) == 2) { + return _tzcnt_u16(value); + } else if constexpr (sizeof(value_type) == 4) { + return _tzcnt_u32(value); + } else if constexpr (sizeof(value_type) == 8) { + return _tzcnt_u64(value); + } else { + static_assert(sizeof(value_type) == 2 || sizeof(value_type) == 4 || sizeof(value_type) == 8, "Unsupported size for tzCount()"); + return value; + } + } + + +#else + + inline uint64_t blsr(uint64_t value) { + if (value == 0) { + return 0; + } + + return value & (value - 1); + } + + template inline value_type tzCount(value_type value) { + if (value == 0) { + return sizeof(value_type) * 8; + } + + value_type count{}; + while ((value & 1) == 0) { + value >>= 1; + ++count; + } + + return count; + } + +#endif + +} diff --git a/Include/jsonifier/ISADetection/Fallback.hpp b/Include/jsonifier/ISADetection/Fallback.hpp new file mode 100644 index 000000000..2a15d445c --- /dev/null +++ b/Include/jsonifier/ISADetection/Fallback.hpp @@ -0,0 +1,440 @@ +/* + MIT License + + Copyright (c) 2023 RealTimeChris + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, and to permit + persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE + FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ +/// https://github.com/RealTimeChris/jsonifier +/// Feb 3, 2023 +#pragma once + +#include + +namespace jsonifier_internal { + +#if !JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX) && !JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX2) && !JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX512) + + constexpr uint64_t StepSize{ 128 }; + constexpr uint64_t BytesPerStep{ StepSize / 8 }; + constexpr uint64_t SixtyFourBytesPerStep{ StepSize / 64 }; + constexpr uint64_t StridesPerStep{ StepSize / BytesPerStep }; + using string_parsing_type = uint16_t; + + template + concept avx_t = std::same_as, avx_int_128>; + + inline uint64_t packUint64(uint8_t* arr) { + return (static_cast(arr[7]) << 56) | (static_cast(arr[6]) << 48) | (static_cast(arr[5]) << 40) | (static_cast(arr[4]) << 32) | + (static_cast(arr[3]) << 24) | (static_cast(arr[2]) << 16) | (static_cast(arr[1]) << 8) | static_cast(arr[0]); + } + + inline void packUint64Array(string_view_ptr input, avx_int_128& output) { + output.values[0] = packUint64(const_cast(input)); + output.values[1] = packUint64(const_cast(input + 8)); + } + + template inline avx_int_128 gatherValues128(const value_type* str) { + alignas(JSONIFIER_ALIGNMENT) avx_int_128 newArray{}; + packUint64Array(str, newArray); + return newArray; + } + + template inline void movemaskEpi8Helper02(int16_t& result, const avx_int_128& a) { + if constexpr (index < 8) { + uint8_t value = (a.values[index02] >> (index * 8)) & 0xff; + int16_t mask = (value >> 7) & 1; + result |= mask << (index02 * 8 + index); + movemaskEpi8Helper02(result, a); + } + } + + template inline int16_t movemaskEpi8(const avx_int_128& a) { + int16_t result{}; + if constexpr (index < 2) { + movemaskEpi8Helper02<0, index>(result, a); + result |= movemaskEpi8(a); + } + return result; + } + + inline avx_int_128 orSi128(const avx_int_128& valOne, const avx_int_128& valTwo) { + avx_int_128 value{}; + value.values[0] = valOne.values[0] | valTwo.values[0]; + value.values[1] = valOne.values[1] | valTwo.values[1]; + return value; + } + + inline avx_int_128 andSi128(const avx_int_128& valOne, const avx_int_128& valTwo) { + avx_int_128 value{}; + value.values[0] = valOne.values[0] & valTwo.values[0]; + value.values[1] = valOne.values[1] & valTwo.values[1]; + return value; + } + + inline avx_int_128 andNotSi128(const avx_int_128& valOne, const avx_int_128& valTwo) { + avx_int_128 result{}; + result.values[0] = valTwo.values[0] & (~valOne.values[0]); + result.values[1] = valTwo.values[1] & (~valOne.values[1]); + return result; + } + + inline avx_int_128 xorSi128(const avx_int_128& valOne, const avx_int_128& valTwo) { + avx_int_128 value{}; + value.values[0] = valOne.values[0] ^ valTwo.values[0]; + value.values[1] = valOne.values[1] ^ valTwo.values[1]; + return value; + } + + inline avx_int_128 subEpi8(const avx_int_128& valOne, const avx_int_128& valTwo) { + avx_int_128 result{}; + result.values[0] = valOne.values[0] - valTwo.values[0]; + result.values[1] = valOne.values[1] - valTwo.values[1]; + return result; + } + + inline avx_int_128 notSi128(const avx_int_128& valOne) { + avx_int_128 result{}; + result.values[0] = ~valOne.values[0]; + result.values[1] = ~valOne.values[1]; + return result; + } + + template inline avx_int_128 cmpeqEpi8(const avx_int_128& a, const avx_int_128& b) { + avx_int_128 result{}; + if constexpr (index < 2) { + cmpeqEpi8Helper<0, index>(result, a, b); + result = orSi128(result, cmpeqEpi8(a, b)); + } + return result; + } + + template inline void cmpeqEpi8Helper(avx_int_128& result, const avx_int_128& a, const avx_int_128& b) { + if constexpr (index < 8) { + uint8_t a8 = (a.values[index02] >> (index * 8)) & 0xff; + uint8_t b8 = (b.values[index02] >> (index * 8)) & 0xff; + result.values[index02] |= (a8 == b8 ? 0xFFULL : 0) << (index * 8); + cmpeqEpi8Helper(result, a, b); + } + } + + inline bool testzSi128(const avx_int_128& valOne, const avx_int_128& valTwo) { + avx_int_128 result{}; + result.values[0] = valOne.values[0] & valTwo.values[0]; + result.values[1] = valOne.values[1] & valTwo.values[1]; + return result.values[0] == 0 && result.values[1] == 0; + } + + inline avx_int_128 setEpi64x(uint64_t argOne, uint64_t argTwo) { + avx_int_128 returnValue{}; + returnValue.values[0] = argTwo; + returnValue.values[1] = argOne; + return returnValue; + } + + inline avx_int_128 set1Epi64x(uint64_t argOne) { + avx_int_128 returnValue{}; + returnValue.values[0] = argOne; + returnValue.values[1] = argOne; + return returnValue; + } + + inline avx_int_128& insertUint16(avx_int_128& value, uint64_t position, uint16_t newValue) { + if (position < 0 || position >= 8) { + return value; + } + int32_t arrayIndex = (position < 4) ? 0 : 1; + int32_t shiftAmount = (position % 4) * 16; + value.values[arrayIndex] &= ~(static_cast(0xffff) << shiftAmount); + value.values[arrayIndex] |= (static_cast(newValue) << shiftAmount); + return value; + } + + inline avx_int_128& insertUint64(avx_int_128& value, uint64_t position, uint64_t newValue) { + if (position == 0) { + value.values[0] = static_cast(newValue); + } else if (position == 1) { + value.values[1] = static_cast(newValue); + } + return value; + } + + inline uint64_t extractUint64(avx_int_128 value, uint64_t index) { + if (index >= 0 && index < 2) { + return static_cast(value.values[index]); + } + return 0; + } + + template inline avx_int_128 shuffleEpi8(const avx_int_128& a, const avx_int_128& b) { + avx_int_128 result{}; + if constexpr (index < 16) { + static constexpr int32_t i = index * 8; + static constexpr int32_t bitIndex = i + 7; + + if ((b.values[bitIndex >> 6] & (1ULL << (bitIndex & 0x3F))) == (1ULL << (bitIndex & 0x3F))) { + result.values[bitIndex >> 6] &= ~(1ULL << (bitIndex & 0x3F)); + } else { + int32_t indexNew = 0; + shuffleEpi8Helper02(indexNew, b); + + int32_t aIndex = indexNew * 8; + shuffleEpi8Helper03(result, aIndex, a); + } + result = orSi128(result, shuffleEpi8(a, b)); + } + return result; + } + + template inline void shuffleEpi8Helper02(int32_t& result, const avx_int_128& b) { + if constexpr (index >= index02) { + result = (result << 1) | ((b.values[index >> 6] >> (index & 0x3F)) & 1); + shuffleEpi8Helper02(result, b); + } + } + + template inline void shuffleEpi8Helper03(avx_int_128& result, int32_t& result02, const avx_int_128& a) { + if constexpr (index < index02) { + result.values[index >> 6] |= ((a.values[result02 >> 6] >> (result02 & 0x3F)) & 1ULL) << (index & 0x3F); + result02++; + shuffleEpi8Helper03(result, result02, a); + } + } + + inline avx_int_128 set1Epi8(int8_t newValue) { + avx_int_128 returnValue{}; + std::memset(&returnValue, newValue, sizeof(avx_int_128)); + return returnValue; + } + + template<> class simd_base_internal<128> { + public: + inline simd_base_internal() noexcept = default; + + template inline simd_base_internal& operator=(avx_type_new&& data) { + value = std::forward(data); + return *this; + } + + template inline simd_base_internal(avx_type_new&& data) { + *this = std::forward(data); + } + + inline simd_base_internal& operator=(uint8_t other) { + value = set1Epi8(other); + return *this; + } + + inline simd_base_internal(uint8_t other) { + *this = other; + } + + inline simd_base_internal(const uint8_t values[BytesPerStep]) { + value = gatherValues128(values); + } + + inline explicit operator bool() { + return !testzSi128(value, value); + } + + inline operator avx_int_128&() { + return value; + } + + template inline simd_base_internal operator|(simd_base_type&& other) const { + return orSi128(value, other.value); + } + + template inline simd_base_internal operator-(simd_base_type&& other) const { + return subEpi8(value, other.value); + } + + template inline simd_base_internal operator&(simd_base_type&& other) const { + return andSi128(value, other.value); + } + + template inline simd_base_internal operator^(simd_base_type&& other) const { + return xorSi128(value, other.value); + } + + inline string_parsing_type operator==(const uint8_t other) const { + simd_base_internal newValue = cmpeqEpi8(value, set1Epi8(other)); + return newValue.toBitMask(); + } + + inline string_parsing_type operator==(const simd_base_internal& other) const { + simd_base_internal newValue = cmpeqEpi8(value, other.value); + return newValue.toBitMask(); + } + + inline simd_base_internal operator~() { + return notSi128(this->value); + } + + template inline void convertWhitespaceToSimdBase(const simd_base_internal* valuesNew) { + if constexpr (index < StridesPerStep) { + alignas(JSONIFIER_ALIGNMENT) static constexpr uint8_t arrayNew[]{ ' ', 100, 100, 100, 17, 100, 113, 2, 100, '\t', '\n', 112, 100, '\r', 100, 100 }; + static const simd_base_internal whitespaceTable{ arrayNew }; + addValues(valuesNew[index].shuffle(whitespaceTable) == valuesNew[index]); + convertWhitespaceToSimdBase(valuesNew); + } + } + + template inline void convertBackslashesToSimdBase(const simd_base_internal* valuesNew) { + if constexpr (index < StridesPerStep) { + static const simd_base_internal backslashes{ set1Epi8('\\') }; + addValues(valuesNew[index] == backslashes); + convertBackslashesToSimdBase(valuesNew); + } + } + + template inline void convertStructuralsToSimdBase(const simd_base_internal* valuesNew) { + if constexpr (index < StridesPerStep) { + alignas(JSONIFIER_ALIGNMENT) static constexpr uint8_t arrayNew[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ':', '{', ',', '}', 0, 0 }; + static const simd_base_internal opTable{ arrayNew }; + static const simd_base_internal chars{ uint8_t{ 0x20 } }; + addValues(valuesNew[index].shuffle(opTable) == (valuesNew[index] | chars)); + convertStructuralsToSimdBase(valuesNew); + } + } + + template inline void convertQuotesToSimdBase(const simd_base_internal* valuesNew) { + if constexpr (index < StridesPerStep) { + static const simd_base_internal quotes{ set1Epi8('"') }; + addValues(valuesNew[index] == quotes); + convertQuotesToSimdBase(valuesNew); + } + } + + inline uint64_t getUint64(uint64_t index) const { + return extractUint64(value, index); + } + + inline void insertUint64(uint64_t valueNew, uint64_t index) { + value = jsonifier_internal::insertUint64(value, index, valueNew); + } + + inline void insertUint16(uint16_t valueNew, uint64_t index) { + value = jsonifier_internal::insertUint16(value, index, valueNew); + } + + inline simd_base_internal bitAndNot(const simd_base_internal& other) { + return andNotSi128(other.value, value); + } + + inline simd_base_internal shuffle(const simd_base_internal& other) const { + return shuffleEpi8(other.value, value); + } + + template inline void addValues(string_parsing_type valuesToAdd) { + insertUint16(valuesToAdd, index); + } + + template inline simd_base_internal shl() const { + simd_base_internal currentValues{}; + currentValues.insertUint64(getUint64(0) << amount, 0); + uint64_t shiftBetween = amount % 64; + currentValues.insertUint64((getUint64(1) << amount) | (getUint64(0) >> (64 - shiftBetween)), 1); + return currentValues; + } + + inline int16_t toBitMask() { + return static_cast(movemaskEpi8(this->value)); + } + + inline void reset() { + value.values[0] = 0; + value.values[1] = 0; + } + + template inline void store(ValueType* storageLocation) { + std::memcpy(storageLocation, &value, sizeof(value)); + } + + inline simd_base_internal& setLSB(bool valueNew) { + if (valueNew) { + *this = orSi128(*this, setEpi64x(0, 0x1)); + } else { + *this = andNotSi128(setEpi64x(0, 0x1), *this); + } + return *this; + } + + inline bool checkMSB() const { + avx_int_128 result = andSi128(this->value, setEpi64x(0x8000000000000000, 0)); + return !testzSi128(result, result); + } + + inline uint64_t prefixXor(uint64_t prevInString) const { + prevInString ^= prevInString << 1; + prevInString ^= prevInString << 2; + prevInString ^= prevInString << 4; + prevInString ^= prevInString << 8; + prevInString ^= prevInString << 16; + prevInString ^= prevInString << 32; + return prevInString; + } + + inline simd_base_internal carrylessMultiplication(uint64_t& prevInString) const { + simd_base_internal valuesNew{}; + avx_int_128 valueLow{ value }; + valuesNew.insertUint64(prefixXor(valueLow.values[0]) ^ prevInString, 0); + prevInString = uint64_t(static_cast(valuesNew.getUint64(0)) >> 63); + valuesNew.insertUint64(prefixXor(valueLow.values[1]) ^ prevInString, 1); + prevInString = uint64_t(static_cast(valuesNew.getUint64(1)) >> 63); + return valuesNew; + } + + inline simd_base_internal follows(bool& overflow) const { + simd_base_internal result = shl<1>(); + result.setLSB(overflow); + overflow = checkMSB(); + return result; + } + + inline void printBits(uint64_t values, const std::string& valuesTitle) const { + std::cout << valuesTitle; + std::cout << std::bitset<64>{ values }; + std::cout << std::endl; + } + + inline simd_base_internal& printBits(const std::string& valuesTitle) noexcept { + uint8_t values[BytesPerStep]{}; + store(values); + std::cout << valuesTitle; + for (uint64_t x = 0; x < BytesPerStep; ++x) { + for (uint64_t y = 0; y < 8; ++y) { + std::cout << std::bitset<1>{ static_cast(*(values + x)) >> y }; + } + } + std::cout << std::endl; + return *this; + } + + protected: + avx_int_128 value{}; + }; + + inline simd_base makeSimdBase(uint64_t value) { + return set1Epi64x(value); + } + + #define load(value) gatherValues128(value) + +#endif + +} \ No newline at end of file diff --git a/Include/jsonifier/ISADetection/ISADetectionBase.hpp b/Include/jsonifier/ISADetection/ISADetectionBase.hpp new file mode 100644 index 000000000..c7301e6ed --- /dev/null +++ b/Include/jsonifier/ISADetection/ISADetectionBase.hpp @@ -0,0 +1,113 @@ +/* + MIT License + + Copyright (c) 2023 RealTimeChris + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, and to permit + persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE + FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ +/// https://github.com/RealTimeChris/jsonifier +/// Feb 3, 2023 +#pragma once + +#if !defined(__GNUC__) + #pragma warning(disable : 4251) + #pragma warning(disable : 4371) + #pragma warning(disable : 4514) + #pragma warning(disable : 4623) + #pragma warning(disable : 4625) + #pragma warning(disable : 4626) + #pragma warning(disable : 4820) + #pragma warning(disable : 5027) + #pragma warning(disable : 5246) +#endif + +#ifndef JSONIFIER_CPU_INSTRUCTIONS + #define JSONIFIER_CPU_INSTRUCTIONS 0 +#endif + +#ifndef JSONIFIER_CHECK_FOR_INSTRUCTION + #define JSONIFIER_CHECK_FOR_INSTRUCTION(x) (JSONIFIER_CPU_INSTRUCTIONS & x) +#endif + +#ifndef JSONIFIER_POPCNT + #define JSONIFIER_POPCNT (1 << 0) +#endif +#ifndef JSONIFIER_LZCNT + #define JSONIFIER_LZCNT (1 << 1) +#endif +#ifndef JSONIFIER_BMI + #define JSONIFIER_BMI (1 << 2) +#endif +#ifndef JSONIFIER_AVX + #define JSONIFIER_AVX (1 << 3) +#endif +#ifndef JSONIFIER_AVX2 + #define JSONIFIER_AVX2 (1 << 4) +#endif +#ifndef JSONIFIER_AVX512 + #define JSONIFIER_AVX512 (1 << 5) +#endif + +#if JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_POPCNT) || JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_LZCNT) || JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_BMI) || \ + JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX) || JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX2) || JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX512) + #include + +using avx_int_512 = __m512i; +using avx_int_256 = __m256i; +using avx_int_128 = __m128i; +using avx_float_512 = __m512; +using avx_float_256 = __m256; +using avx_float_128 = __m128; + +#else + +struct __m128x { + uint64_t values[2]{}; +}; + +using avx_int_128 = __m128x; + +#endif + +#include +#include +#include +#include +#include +#include + +#if JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX512) +constexpr uint64_t JSONIFIER_ALIGNMENT{ 64 }; +#elif JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX2) +constexpr uint64_t JSONIFIER_ALIGNMENT{ 32 }; +#elif JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX) +constexpr uint64_t JSONIFIER_ALIGNMENT{ 16 }; +#else +constexpr uint64_t JSONIFIER_ALIGNMENT{ 16 }; +#endif + +namespace jsonifier_internal { + + template struct simd_base_internal {}; + + template using simd_base = simd_base_internal; + template using simd_base_small = simd_base_internal; + using string_view_ptr = const uint8_t*; + using structural_index = string_view_ptr; + using string_buffer_ptr = uint8_t*; + +}; \ No newline at end of file diff --git a/Include/jsonifier/ISADetection/Lzcount.hpp b/Include/jsonifier/ISADetection/Lzcount.hpp new file mode 100644 index 000000000..9d4633d59 --- /dev/null +++ b/Include/jsonifier/ISADetection/Lzcount.hpp @@ -0,0 +1,64 @@ +/* + MIT License + + Copyright (c) 2023 RealTimeChris + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, and to permit + persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE + FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ +/// https://github.com/RealTimeChris/jsonifier +/// Feb 3, 2023 +#pragma once + +#include + +namespace jsonifier_internal { + +#if JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_LZCNT) + + template constexpr value_type lzCount(value_type value) { + static_assert(std::is_integral_v, "Input must be an integer type"); + if constexpr (sizeof(value_type) == 4) { + return static_cast(_lzcnt_u32(static_cast(value))); + } else if constexpr (sizeof(value_type) == 8) { + return static_cast(_lzcnt_u64(static_cast(value))); + } else { + static_assert(sizeof(value_type) == 4 || sizeof(value_type) == 8, "Unsupported integer size"); + return static_cast(_lzcnt_u64(static_cast(value))); + } + } + +#else + + template inline value_type lzCount(value_type value) { + if (value == 0) { + return sizeof(value_type) * 8; + } + + value_type count{}; + value_type mask{ static_cast(1) << (std::numeric_limits::digits - 1) }; + + while ((value & mask) == 0) { + count++; + mask >>= 1; + } + + return count; + } + +#endif + +} \ No newline at end of file diff --git a/Include/jsonifier/Core.hpp b/Include/jsonifier/ISADetection/Popcount.hpp similarity index 53% rename from Include/jsonifier/Core.hpp rename to Include/jsonifier/ISADetection/Popcount.hpp index a1bd1f8d3..b7f3f730c 100644 --- a/Include/jsonifier/Core.hpp +++ b/Include/jsonifier/ISADetection/Popcount.hpp @@ -19,38 +19,30 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/// https://github.com/RealTimeChris/Jsonifier +/// https://github.com/RealTimeChris/jsonifier /// Feb 3, 2023 -#pragma once -#include -#include +#include -namespace Jsonifier { - /// A class to aid in registering a class/struct to be parsed/serialized. - template struct Core {}; -} +namespace jsonifier_internal { + +#if JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_POPCNT) -namespace JsonifierInternal { + #define popcnt(value) _mm_popcnt_u64(value) - template - concept JsonifierT = requires { Jsonifier::Core>::parseValue; }; +#else - struct EmptyVal { - static constexpr Tuplet::Tuple<> parseValue{}; - }; + inline uint64_t popcnt(uint64_t value) { + uint64_t count{}; - template constexpr auto CoreWrapperV = [] { - if constexpr (JsonifierT) { - return Jsonifier::Core::parseValue; - } else { - return EmptyVal{}; + while (value > 0) { + count += value & 1; + value >>= 1; } - }(); - template constexpr auto CoreV = CoreWrapperV>.parseValue; + return count; + } - template using CoreT = std::decay_t)>; +#endif - template using CoreWrapperT = std::decay_t>)>; } diff --git a/Include/jsonifier/Index.hpp b/Include/jsonifier/Index.hpp index 65f09c0c5..28dc4bd1a 100644 --- a/Include/jsonifier/Index.hpp +++ b/Include/jsonifier/Index.hpp @@ -19,10 +19,18 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/// https://github.com/RealTimeChris/Jsonifier +/// https://github.com/RealTimeChris/jsonifier /// Feb 3, 2023 #pragma once +#if defined(min) + #undef min +#endif + +#if defined(max) + #undef max +#endif + #include #include #include @@ -34,4 +42,3 @@ #include #include #include -#include diff --git a/Include/jsonifier/Iterator.hpp b/Include/jsonifier/Iterator.hpp index 2fac96ca8..56da46449 100644 --- a/Include/jsonifier/Iterator.hpp +++ b/Include/jsonifier/Iterator.hpp @@ -19,24 +19,24 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/// https://github.com/RealTimeChris/Jsonifier +/// https://github.com/RealTimeChris/jsonifier /// Feb 3, 2023 #pragma once #include -namespace JsonifierInternal { +namespace jsonifier_internal { - template class Iterator { + template class iterator { public: using iterator_concept = std::contiguous_iterator_tag; using iterator_category = std::random_access_iterator_tag; - using value_type = ValueType; - using difference_type = ptrdiff_t; + using value_type = value_type_new; using reference = value_type&; using pointer = value_type*; + using difference_type = ptrdiff_t; - constexpr Iterator(pointer pointerNew) noexcept : value{ pointerNew } {}; + constexpr iterator(pointer pointerNew) : value{ pointerNew } {}; constexpr reference operator*() const { return *value; @@ -46,45 +46,45 @@ namespace JsonifierInternal { return value; } - constexpr Iterator& operator++() { + constexpr iterator& operator++() { ++value; return *this; } - constexpr Iterator operator++(int32_t) { - Iterator temp = *this; + constexpr iterator operator++(int32_t) { + iterator temp{ *this }; ++*this; return temp; } - constexpr Iterator& operator--() { + constexpr iterator& operator--() { --value; return *this; } - constexpr Iterator operator--(int32_t) { - Iterator temp = *this; + constexpr iterator operator--(int32_t) { + iterator temp{ *this }; --*this; return temp; } - constexpr Iterator& operator+=(const difference_type iter) { + constexpr iterator& operator+=(const difference_type iter) { value += iter; return *this; } - constexpr Iterator operator+(const difference_type iter) const { - Iterator temp = *this; + constexpr iterator operator+(const difference_type iter) const { + iterator temp{ *this }; temp += iter; return temp; } - constexpr Iterator& operator-=(const difference_type iter) { + constexpr iterator& operator-=(const difference_type iter) { return *this += -iter; } - constexpr Iterator operator-(const difference_type iter) const { - Iterator temp = *this; + constexpr iterator operator-(const difference_type iter) const { + iterator temp{ *this }; temp -= iter; return temp; } @@ -93,31 +93,31 @@ namespace JsonifierInternal { return *(*this + iter); } - constexpr difference_type operator-(const Iterator& iter) const { + constexpr difference_type operator-(const iterator& iter) const { return value - iter.value; } - constexpr bool operator==(const Iterator& iter) const { + constexpr bool operator==(const iterator& iter) const { return value == iter.value; } - constexpr bool operator>=(const Iterator& iter) const { + constexpr bool operator>=(const iterator& iter) const { return value >= iter.value; } - constexpr bool operator<=(const Iterator& iter) const { + constexpr bool operator<=(const iterator& iter) const { return value <= iter.value; } - constexpr bool operator>(const Iterator& iter) const { + constexpr bool operator>(const iterator& iter) const { return value > iter.value; } - constexpr bool operator<(const Iterator& iter) const { + constexpr bool operator<(const iterator& iter) const { return value < iter.value; } pointer value; }; -}// namespace JsonifierInternal +}// namespace jsonifier_internal diff --git a/Include/jsonifier/JsonifierCore.hpp b/Include/jsonifier/JsonifierCore.hpp index 80a3f92be..19284ca13 100644 --- a/Include/jsonifier/JsonifierCore.hpp +++ b/Include/jsonifier/JsonifierCore.hpp @@ -19,15 +19,15 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/// https://github.com/RealTimeChris/Jsonifier +/// https://github.com/RealTimeChris/jsonifier /// Feb 20, 2023 #pragma once #include #include -namespace Jsonifier { +namespace jsonifier { - class JsonifierCore : public JsonifierInternal::Parser, public JsonifierInternal::Serializer {}; + class jsonifier_core : public jsonifier_internal::parser, public jsonifier_internal::serializer {}; } diff --git a/Include/jsonifier/NumberUtils.hpp b/Include/jsonifier/NumberUtils.hpp index 37f6fb523..fdc582d71 100644 --- a/Include/jsonifier/NumberUtils.hpp +++ b/Include/jsonifier/NumberUtils.hpp @@ -19,7 +19,7 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/// https://github.com/RealTimeChris/Jsonifier +/// https://github.com/RealTimeChris/jsonifier /// Feb 3, 2023 /// Most of the code in this header was sampled from Glaze library - https://github.com/stephenberry/glaze #pragma once @@ -31,23 +31,23 @@ #include #include -#if defined _M_X64 || _M_ARM64 - #if !defined __linux__ +#if defined(_M_X64) || defined(_M_ARM64) + #if !defined(__linux__) #include #else #include #endif #endif -namespace JsonifierInternal { +namespace jsonifier_internal { // Based on yyjson: https://github.com/ibireme/yyjson/blob/master/src/yyjson.c with some changes to rounding and // dirrect for floats // https://stackoverflow.com/questions/28868367/getting-the-high-part-of-64-bit-integer-multiplication -#if defined __SIZEOF_INT128__ - static inline uint64_t mulhi64(uint64_t a, uint64_t b) { - #if defined __GNUC__ || __GNUG__ +#if defined(__SIZEOF_INT128__) + inline static uint64_t mulhi64(uint64_t a, uint64_t b) { + #if defined(__GNUC__) || defined(__GNUG__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpedantic" unsigned __int128 prod = a * static_cast(b); @@ -55,10 +55,10 @@ namespace JsonifierInternal { #endif return prod >> 64; } -#elif defined _M_X64 || _M_ARM64 +#elif defined(_M_X64) || defined(_M_ARM64) #define mulhi64 __umulh #else - static inline uint64_t mulhi64(uint64_t a, uint64_t b) { + inline static uint64_t mulhi64(uint64_t a, uint64_t b) { uint64_t aLo = ( uint32_t )a; uint64_t aHi = a >> 32; uint64_t bLo = ( uint32_t )b; @@ -79,17 +79,17 @@ namespace JsonifierInternal { static constexpr auto pow10SigTable128MinExactExp = 0; static constexpr auto pow10SigTable128MaxExactExp = 55; - static inline void pow10TableGetSig128(int32_t exp10, uint64_t* hi, uint64_t* lo) { + inline static void pow10TableGetSig128(int32_t exp10, uint64_t* hi, uint64_t* lo) { int32_t idx = exp10 - (pow10SigTable128MinExp); - *hi = pow10SigTable128[idx * 2ull]; - *lo = pow10SigTable128[idx * 2ull + 1ull]; + *hi = pow10SigTable128[idx * 2ULL]; + *lo = pow10SigTable128[idx * 2ULL + 1ULL]; } - static inline uint64_t sig2FromExp10(int32_t exp10) { + inline static uint64_t sig2FromExp10(int32_t exp10) { return pow10SigTable128[static_cast(exp10) - pow10SigTable128MinExp]; } - static inline int32_t exp2FromExp10(int32_t exp10) { + inline static int32_t exp2FromExp10(int32_t exp10) { return (((exp10 * 217706 - 4128768) >> 16) + 126); } @@ -100,15 +100,15 @@ namespace JsonifierInternal { static constexpr uint8_t digiTypeDot = 1 << 4; static constexpr uint8_t digiTypeExp = 1 << 5; - static inline bool digiIsType(uint8_t d, uint8_t type) { + inline static bool digiIsType(uint8_t d, uint8_t type) { return (digiTable[d] & type) != 0; } - static inline bool digiIsFp(uint8_t d) { + inline static bool digiIsFp(uint8_t d) { return digiIsType(d, uint8_t(digiTypeDot | digiTypeExp)); } - static inline bool digiIsDigitOrFp(uint8_t d) { + inline static bool digiIsDigitOrFp(uint8_t d) { return digiIsType(d, uint8_t(digiTypeZero | digiTypeNonZero | digiTypeDot | digiTypeExp)); } @@ -119,14 +119,14 @@ namespace JsonifierInternal { static constexpr auto f64MaxDecExp = 308; static constexpr auto f64MinDecExp = (-324); - static inline consteval uint32_t ceillog2(uint32_t x) { + inline static consteval uint32_t ceillog2(uint32_t x) { return x < 2 ? x : 1 + ceillog2(x >> 1); } - struct BigIntT { - Jsonifier::Vector data = {}; + struct big_int_t { + jsonifier::vector data = {}; - inline BigIntT(uint64_t num) { + inline big_int_t(uint64_t num) { uint32_t lowerWord = uint32_t(num); uint32_t upperWord = uint32_t(num >> 32); if (upperWord > 0) { @@ -166,7 +166,7 @@ namespace JsonifierInternal { if (shft == 0) { data.resize(data.size() + move); for (; idx > 0; idx--) { - data[static_cast(idx) + static_cast(move) - 1ull] = data[static_cast(idx) - 1ull]; + data[static_cast(idx) + static_cast(move) - 1ULL] = data[static_cast(idx) - 1ULL]; } while (move) data[--move] = 0; @@ -175,7 +175,7 @@ namespace JsonifierInternal { ++idx; for (; idx > 0; idx--) { uint32_t num = data[idx] << shft; - num |= data[idx - 1ull] >> (32 - shft); + num |= data[idx - 1ULL] >> (32 - shft); data[static_cast(idx) + static_cast(move)] = num; } data[move] = data[0] << shft; @@ -186,7 +186,7 @@ namespace JsonifierInternal { } } - inline auto operator<=>(const BigIntT& rhs) const { + inline auto operator<=>(const big_int_t& rhs) const { if (data.size() < rhs.data.size()) return -1; if (data.size() > rhs.data.size()) @@ -204,14 +204,14 @@ namespace JsonifierInternal { // Source: https://github.com/ibireme/yyjson/blob/master/src/yyjson.c - static inline void u128Mul(uint64_t a, uint64_t b, uint64_t* hi, uint64_t* lo) { -#if defined __SIZEOF_INT128__ - #if defined __GNUC__ || __GNUG__ + inline static void u128Mul(uint64_t a, uint64_t b, uint64_t* hi, uint64_t* lo) { +#if defined(__SIZEOF_INT128__) + #if defined(__GNUC__) || defined(__GNUG__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpedantic" #endif unsigned __int128 m = static_cast(a) * b; - #if defined __GNUC__ || __GNUG__ + #if defined(__GNUC__) || defined(__GNUG__) #pragma GCC diagnostic pop #endif *hi = uint64_t(m >> 64); @@ -235,14 +235,14 @@ namespace JsonifierInternal { #endif } - static inline void u128MulAdd(uint64_t a, uint64_t b, uint64_t c, uint64_t* hi, uint64_t* lo) { -#if defined __SIZEOF_INT128__ - #if defined __GNUC__ || __GNUG__ + inline static void u128MulAdd(uint64_t a, uint64_t b, uint64_t c, uint64_t* hi, uint64_t* lo) { +#if defined(__SIZEOF_INT128__) + #if defined(__GNUC__) || defined(__GNUG__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpedantic" #endif unsigned __int128 m = static_cast(a) * b + c; - #if defined __GNUC__ || __GNUG__ + #if defined(__GNUC__) || defined(__GNUG__) #pragma GCC diagnostic pop #endif *hi = uint64_t(m >> 64); @@ -257,47 +257,47 @@ namespace JsonifierInternal { #endif } - static inline uint64_t roundToOdd(uint64_t hi, uint64_t lo, uint64_t codePoint) { - uint64_t xHi, xLo, yHi, yLo; + inline static uint64_t roundToOdd(uint64_t hi, uint64_t lo, uint64_t codePoint) { + uint64_t xHi{}, xLo{}, yHi{}, yLo{}; u128Mul(codePoint, lo, &xHi, &xLo); u128MulAdd(codePoint, hi, xHi, &yHi, &yLo); return yHi | (yLo > 1); } - template static inline bool parseNumber(ValueType& val, auto* cur) { - StringViewPtr sigCut = nullptr; - [[maybe_unused]] StringViewPtr sigEnd = nullptr; - StringViewPtr dotPos = nullptr; - uint32_t fracZeroes = 0; - uint64_t sig = 0; - int32_t exp = 0; - bool expSign; - int32_t expSig = 0; - int32_t expLit = 0; - uint64_t numTmp; - StringViewPtr tmp; - StringViewPtr hdr = cur; - bool sign; + template inline static bool parseNumber(value_type& val, auto* cur) { + [[maybe_unused]] string_view_ptr sigEnd{}; + string_view_ptr sigCut{}; + string_view_ptr dotPos{}; + uint32_t fracZeroes{}; + uint64_t sig{}; + int32_t exp{}; + bool expSign{}; + int32_t expSig{}; + int32_t expLit{}; + uint64_t numTmp{}; + string_view_ptr tmp{}; + string_view_ptr hdr = cur; + bool sign{}; sign = (*hdr == '-'); cur += sign; - auto applySign = [&](auto&& val) -> ValueType { - if constexpr (std::is_unsigned_v) { - return static_cast(val); + auto applySign = [&](auto&& val) -> value_type { + if constexpr (std::is_unsigned_v) { + return static_cast(val); } else { - return sign ? -static_cast(val) : static_cast(val); + return sign ? -static_cast(val) : static_cast(val); } }; sig = uint64_t(*cur - '0'); if (sig > 9) { - if constexpr (std::integral) { + if constexpr (std::integral) { return false; } else if (*cur == 'n' && cur[1] == 'u' && cur[2] == 'l' && cur[3] == 'l') { cur += 4; - val = std::numeric_limits::quiet_NaN(); + val = static_cast(std::numeric_limits::quiet_NaN()); return true; } else if ((*cur | eBit) == 'n' && (cur[1] | eBit) == 'a' && (cur[2] | eBit) == 'n') { cur += 3; - val = sign ? -std::numeric_limits::quiet_NaN() : std::numeric_limits::quiet_NaN(); + val = static_cast(sign ? -std::numeric_limits::quiet_NaN() : std::numeric_limits::quiet_NaN()); return true; } else { return false; @@ -305,8 +305,8 @@ namespace JsonifierInternal { } static constexpr auto zero = static_cast('0'); #define expr_intg(x) \ - if ((numTmp = cur[x] - zero) <= 9) [[likely]] \ - sig = numTmp + sig * 10; \ + if ((numTmp = static_cast(cur[x] - zero)) <= 9) [[likely]] \ + sig = static_cast(numTmp) + sig * 10ULL; \ else { \ goto digi_sepr_##x; \ } @@ -314,8 +314,8 @@ namespace JsonifierInternal { #undef expr_intg cur += 19; if (!digiIsDigitOrFp(*cur)) { - val = static_cast(sig); - if constexpr (!std::is_unsigned_v) { + val = static_cast(sig); + if constexpr (!std::is_unsigned_v) { val *= sign ? -1 : 1; } return true; @@ -324,7 +324,7 @@ namespace JsonifierInternal { #define expr_sepr(x) \ digi_sepr_##x : if ((!digiIsFp(cur[x]))) [[likely]] { \ cur += x; \ - val = applySign(sig); \ + val = static_cast(applySign(sig)); \ return true; \ } \ dotPos = cur + x; \ @@ -346,23 +346,23 @@ namespace JsonifierInternal { } repeatIIn_1_18(expr_frac) #undef expr_frac - cur += 20ull + fracZeroes; + cur += 20ULL + fracZeroes; if (uint8_t(*cur - zero) > 9) goto digi_frac_end; goto digi_frac_more; #define expr_stop(x) \ - digi_stop_##x : cur += x##ull + 1ull + fracZeroes; \ + digi_stop_##x : cur += x##ULL + 1ULL + fracZeroes; \ goto digi_frac_end; repeatIIn_1_18(expr_stop) #undef expr_stop - digi_intg_more : static constexpr uint64_t u64Max = (std::numeric_limits::max)(); - if ((numTmp = *cur - zero) < 10) { + digi_intg_more : static constexpr uint64_t u64Max = std::numeric_limits::max(); + if ((numTmp = static_cast(*cur - zero)) < 10) { if (!digiIsDigitOrFp(cur[1])) { if ((sig < (u64Max / 10)) || (sig == (u64Max / 10) && numTmp <= (u64Max % 10))) { sig = numTmp + sig * 10; ++cur; - val = static_cast(sig); - if constexpr (!std::is_unsigned_v) { + val = static_cast(sig); + if constexpr (!std::is_unsigned_v) { val *= sign ? -1 : 1; } return true; @@ -401,18 +401,15 @@ namespace JsonifierInternal { tmp--; if (tmp < sigCut) { sigCut = nullptr; - } else { - sigEnd = cur; } if ((eBit | *cur) == 'e') goto digi_exp_more; goto digi_exp_finish; digi_frac_end: - sigEnd = cur; expSig = -int32_t((cur - dotPos) - 1); if ((eBit | *cur) != 'e') [[likely]] { if ((expSig < f64MinDecExp - 19)) [[unlikely]] { - val = applySign(0); + val = static_cast(applySign(0)); return true; } exp = expSig; @@ -430,133 +427,133 @@ namespace JsonifierInternal { ++cur; tmp = cur; uint8_t c; - while (uint8_t(c = *cur - zero) < 10) { + while (uint8_t(c = static_cast(*cur - zero)) < 10) { ++cur; - expLit = c + uint32_t(expLit) * 10; + expLit = c + int32_t(expLit) * 10; } if ((cur - tmp >= 6)) [[unlikely]] { if (sig == 0 || expSign) { - val = applySign(0); - val = static_cast(sig); + val = static_cast(applySign(0)); + val = static_cast(sig); return true; } else { - val = applySign(std::numeric_limits::infinity()); + val = static_cast(applySign(std::numeric_limits::infinity())); return true; } } expSig += expSign ? -expLit : expLit; digi_exp_finish: - if constexpr (std::integral) { + if constexpr (std::integral) { if (sig == 0) { - val = ((sign && !std::is_unsigned_v) ? -0 : 0); + val = static_cast((sign && !std::is_unsigned_v) ? -0 : 0); return true; } if (expSig < -20) { - val = applySign(0); + val = static_cast(applySign(0)); return true; } else if (expSig > 20) { - val = applySign(std::numeric_limits::infinity()); + val = static_cast(applySign(std::numeric_limits::infinity())); return true; } exp = expSig; } else { if (sig == 0) { - val = (sign ? -ValueType{ 0 } : ValueType{ 0 }); + val = static_cast(sign ? -value_type{ 0 } : value_type{ 0 }); return true; } if ((expSig < f64MinDecExp - 19)) [[unlikely]] { - val = (sign ? -ValueType{ 0 } : ValueType{ 0 }); + val = static_cast(sign ? -value_type{ 0 } : value_type{ 0 }); return true; } else if ((expSig > f64MaxDecExp)) [[unlikely]] { - val = sign ? -std::numeric_limits::infinity() : std::numeric_limits::infinity(); + val = static_cast(sign ? -std::numeric_limits::infinity() : std::numeric_limits::infinity()); return true; } exp = expSig; } digi_finish: - if constexpr (std::integral) { - val = static_cast(sig); - if constexpr (!std::is_unsigned_v) { + if constexpr (std::integral) { + val = static_cast(sig); + if constexpr (!std::is_unsigned_v) { val *= sign ? -1 : 1; } - if (exp >= 0) { - val *= ValueType(powersOfTenInt[exp]); - } else { - val /= ValueType(powersOfTenInt[-exp]); + if (exp >= 0 && exp < 20) { + val *= static_cast(powersOfTenInt[exp]); + } else if (exp > -20 && exp < 0) { + val /= static_cast(powersOfTenInt[-exp]); } return true; } else { - if constexpr (std::same_as) { + if constexpr (std::floating_point) { if (sig < (uint64_t(1) << 53) && std::abs(exp) <= 22) { - val = static_cast(sig); - if constexpr (!std::is_unsigned_v) { + val = static_cast(sig); + if constexpr (!std::is_unsigned_v) { val *= sign ? -1 : 1; } - if (exp >= 0) { - val *= powersOfTenFloat[exp]; - } else { - val /= powersOfTenFloat[-exp]; + if (exp >= 0 && exp < 23) { + val *= static_cast(powersOfTenFloat[exp]); + } else if (exp > -23 && exp < 0) { + val /= static_cast(powersOfTenFloat[-exp]); } return true; } } else { if (sig < (uint64_t(1) << 24) && std::abs(exp) <= 8) { - val = static_cast(sig); - if constexpr (!std::is_unsigned_v) { + val = static_cast(sig); + if constexpr (!std::is_unsigned_v) { val *= sign ? -1 : 1; } - if (exp >= 0) { - val *= static_cast(powersOfTenFloat[exp]); - } else { - val /= static_cast(powersOfTenFloat[-exp]); + if (exp >= 0 && exp < 23) { + val *= static_cast(powersOfTenFloat[exp]); + } else if (exp > -23 && exp < 0) { + val /= static_cast(powersOfTenFloat[-exp]); } return true; } } - static_assert(std::numeric_limits::is_iec559); - static_assert(std::numeric_limits::radix == 2); - static_assert(std::same_as> || std::same_as>); + static_assert(std::numeric_limits::is_iec559); + static_assert(std::numeric_limits::radix == 2); + static_assert(std::same_as> || std::same_as>); static_assert(sizeof(float) == 4 && sizeof(double) == 8); - using raw_t = std::conditional_t>, uint32_t, uint64_t>; + using raw_t = std::conditional_t>, uint32_t, uint64_t>; const auto sigLeadingZeroes = std::countl_zero(sig); const auto sigNorm = sig << sigLeadingZeroes; const auto sig2Norm = sig2FromExp10(exp); const auto sigProduct = mulhi64(sigNorm, sig2Norm) + 1; const auto sigProductStartsWith1 = sigProduct >> 63; auto mantisa = sigProduct << (2 - sigProductStartsWith1); - static constexpr uint64_t roundMask = uint64_t(1) << 63 >> (std::numeric_limits::digits - 1); - static constexpr uint32_t exponentBits = ceillog2(std::numeric_limits::max_exponent - std::numeric_limits::min_exponent + 1); + static constexpr uint64_t roundMask = uint64_t(1) << 63 >> (std::numeric_limits::digits - 1); + static constexpr uint32_t exponentBits = ceillog2(std::numeric_limits::max_exponent - std::numeric_limits::min_exponent + 1); static constexpr uint32_t mantissaShift = exponentBits + 1 + 64 - 8 * sizeof(raw_t); - int32_t exp2 = exp2FromExp10(exp) + static_cast(-sigLeadingZeroes + sigProductStartsWith1); + int32_t exp2 = static_cast(exp2FromExp10(exp) + static_cast(-sigLeadingZeroes + sigProductStartsWith1)); - if (exp2 < std::numeric_limits::min_exponent - 1) [[unlikely]] { - val = sign ? -ValueType(0) : ValueType(0); + if (exp2 < std::numeric_limits::min_exponent - 1) [[unlikely]] { + val = static_cast(sign ? -value_type(0) : value_type(0)); return true; - } else if (exp2 > std::numeric_limits::max_exponent - 1) [[unlikely]] { - val = sign ? -std::numeric_limits::infinity() : std::numeric_limits::infinity(); + } else if (exp2 > std::numeric_limits::max_exponent - 1) [[unlikely]] { + val = static_cast(sign ? -std::numeric_limits::infinity() : std::numeric_limits::infinity()); return true; } uint64_t round = 0; if (roundMask & mantisa) { - if (mantisa << (std::numeric_limits::digits) == 0) { + if (mantisa << (std::numeric_limits::digits) == 0) { auto sigUpper = (mantisa >> (mantissaShift - 1)) | (uint64_t(1) << 63 >> (mantissaShift - 2)) | 1; - int32_t exp2Upper = exp2 - std::numeric_limits::digits; + int32_t exp2Upper = exp2 - std::numeric_limits::digits; - BigIntT bigComp{ sigUpper }; - BigIntT bigFull{ sig }; + big_int_t bigComp{ sigUpper }; + big_int_t bigFull{ sig }; if (exp >= 0) { - bigFull.mulPow10(exp); + bigFull.mulPow10(static_cast(exp)); } else { - bigComp.mulPow10(-exp); + bigComp.mulPow10(static_cast(-exp)); } if (exp2Upper >= 0) { - bigComp.mulPow2(exp2Upper); + bigComp.mulPow2(static_cast(exp2Upper)); } else { - bigFull.mulPow2(-exp2Upper); + bigFull.mulPow2(static_cast(-exp2Upper)); } auto cmp = bigFull <=> bigComp; if (cmp != 0) [[likely]] { @@ -566,48 +563,48 @@ namespace JsonifierInternal { } } else if ((exp < pow10SigTable128MinExactExp || exp > pow10SigTable128MaxExactExp) || (mantisa & (roundMask << 1)) || (static_cast(std::countr_zero(sigNorm)) + static_cast(std::countr_zero(sig2Norm)) < - 128ull - std::numeric_limits::digits - (2ull - sigProductStartsWith1))) { + 128ULL - std::numeric_limits::digits - (2ULL - sigProductStartsWith1))) { round = 1; } } - auto num = raw_t(sign) << (sizeof(raw_t) * 8ull - 1ull) | raw_t(mantisa >> mantissaShift) | - (raw_t(static_cast(exp2) + std::numeric_limits::max_exponent - 1ull) << (std::numeric_limits::digits - 1ull)); + auto num = raw_t(sign) << (sizeof(raw_t) * 8ULL - 1ULL) | raw_t(mantisa >> mantissaShift) | + (raw_t(static_cast(exp2) + std::numeric_limits::max_exponent - 1ULL) << (std::numeric_limits::digits - 1ULL)); num += raw_t(round); - std::memcpy(&val, &num, sizeof(ValueType)); + std::memcpy(&val, &num, sizeof(value_type)); return true; } } - template static inline auto* toChars(auto* buf, ValueType val) { + template inline static auto* toChars(auto* buf, value_type val) { uint32_t aa, bb, cc, dd, ee, aabb, bbcc, ccdd, ddee, aabbcc; uint32_t lz; if (val < 100) { lz = val < 10; - std::memcpy(&buf[0], &charTable[val * 2ull + lz], 2); + std::memcpy(&buf[0], &charTable[val * 2ULL + lz], 2); buf -= lz; - return buf + 2ull; + return buf + 2ULL; } else if (val < 10000) { aa = (val * 5243) >> 19; bb = val - aa * 100; lz = aa < 10; - std::memcpy(&buf[0], &charTable[aa * 2ull + lz], 2); + std::memcpy(&buf[0], &charTable[aa * 2ULL + lz], 2); buf -= lz; - std::memcpy(&buf[2], &charTable[2ull * bb], 2); + std::memcpy(&buf[2], &charTable[2ULL * bb], 2); - return buf + 4ull; + return buf + 4ULL; } else if (val < 1000000) { aa = uint32_t((uint64_t(val) * 429497) >> 32); bbcc = val - aa * 10000; bb = (bbcc * 5243) >> 19; cc = bbcc - bb * 100; lz = aa < 10; - std::memcpy(buf, charTable.data() + aa * 2ull + lz, 2); + std::memcpy(buf, charTable + aa * 2ULL + lz, 2); buf -= lz; - std::memcpy(buf + 2ull, charTable.data() + bb * 2ull, 2); - std::memcpy(buf + 4ull, charTable.data() + cc * 2ull, 2); - return buf + 6ull; + std::memcpy(buf + 2ULL, charTable + bb * 2ULL, 2); + std::memcpy(buf + 4ULL, charTable + cc * 2ULL, 2); + return buf + 6ULL; } else if (val < 100000000) { aabb = uint32_t((uint64_t(val) * 109951163) >> 40); ccdd = val - aabb * 10000; @@ -616,11 +613,11 @@ namespace JsonifierInternal { bb = aabb - aa * 100; dd = ccdd - cc * 100; lz = aa < 10; - std::memcpy(buf, charTable.data() + aa * 2ull + lz, 2); + std::memcpy(buf, charTable + aa * 2ULL + lz, 2); buf -= lz; - std::memcpy(buf + 2ull, charTable.data() + bb * 2ull, 2); - std::memcpy(buf + 4ull, charTable.data() + cc * 2ull, 2); - std::memcpy(buf + 6ull, charTable.data() + dd * 2ull, 2); + std::memcpy(buf + 2ULL, charTable + bb * 2ULL, 2); + std::memcpy(buf + 4ULL, charTable + cc * 2ULL, 2); + std::memcpy(buf + 6ULL, charTable + dd * 2ULL, 2); return buf + 8; } else { aabbcc = uint32_t((uint64_t(val) * 3518437209ul) >> 45); @@ -632,24 +629,24 @@ namespace JsonifierInternal { cc = bbcc - bb * 100; ee = ddee - dd * 100; lz = aa < 10; - std::memcpy(buf, charTable.data() + aa * 2ull + lz, 2); + std::memcpy(buf, charTable + aa * 2ULL + lz, 2); buf -= lz; - std::memcpy(buf + 2ull, charTable.data() + bb * 2ull, 2); - std::memcpy(buf + 4ull, charTable.data() + cc * 2ull, 2); - std::memcpy(buf + 6ull, charTable.data() + dd * 2ull, 2); - std::memcpy(buf + 8, charTable.data() + ee * 2ull, 2); + std::memcpy(buf + 2ULL, charTable + bb * 2ULL, 2); + std::memcpy(buf + 4ULL, charTable + cc * 2ULL, 2); + std::memcpy(buf + 6ULL, charTable + dd * 2ULL, 2); + std::memcpy(buf + 8, charTable + ee * 2ULL, 2); return buf + 10; } } - template static inline auto* toChars(auto* buf, ValueType val) { + template inline static auto* toChars(auto* buf, value_type val) { uint32_t neg = uint32_t(-val); uint64_t sign = val < 0; *buf = '-'; return toChars(buf + sign, sign ? uint32_t(neg) : uint32_t(val)); } - static inline auto* toCharsU64Len8(auto* buf, uint32_t val) { + inline static auto* toCharsU64Len8(auto* buf, uint32_t val) { uint32_t aa, bb, cc, dd, aabb, ccdd; aabb = uint32_t((uint64_t(val) * 109951163) >> 40); ccdd = val - aabb * 10000; @@ -657,49 +654,49 @@ namespace JsonifierInternal { cc = (ccdd * 5243) >> 19; bb = aabb - aa * 100; dd = ccdd - cc * 100; - std::memcpy(buf, charTable.data() + aa * 2ull, 2); - std::memcpy(buf + 2ull, charTable.data() + bb * 2ull, 2); - std::memcpy(buf + 4ull, charTable.data() + cc * 2ull, 2); - std::memcpy(buf + 6ull, charTable.data() + dd * 2ull, 2); + std::memcpy(buf, charTable + aa * 2ULL, 2); + std::memcpy(buf + 2ULL, charTable + bb * 2ULL, 2); + std::memcpy(buf + 4ULL, charTable + cc * 2ULL, 2); + std::memcpy(buf + 6ULL, charTable + dd * 2ULL, 2); return buf + 8; } - static inline auto* toCharsU64Len4(auto* buf, uint32_t val) { + inline static auto* toCharsU64Len4(auto* buf, uint32_t val) { uint32_t aa, bb; aa = (val * 5243) >> 19; bb = val - aa * 100; - std::memcpy(buf, charTable.data() + aa * 2ull, 2); - std::memcpy(buf + 2ull, charTable.data() + bb * 2ull, 2); - return buf + 4ull; + std::memcpy(buf, charTable + aa * 2ULL, 2); + std::memcpy(buf + 2ULL, charTable + bb * 2ULL, 2); + return buf + 4ULL; } - static inline auto* toCharsU64Len18(auto* buf, uint32_t val) { + inline static auto* toCharsU64Len18(auto* buf, uint32_t val) { uint32_t aa, bb, cc, dd, aabb, bbcc, ccdd, lz; if (val < 100) { lz = val < 10; - std::memcpy(buf, charTable.data() + val * 2ull + lz, 2); + std::memcpy(buf, charTable + val * 2ULL + lz, 2); buf -= lz; - return buf + 2ull; + return buf + 2ULL; } else if (val < 10000) { aa = (val * 5243) >> 19; bb = val - aa * 100; lz = aa < 10; - std::memcpy(buf, charTable.data() + aa * 2ull + lz, 2); + std::memcpy(buf, charTable + aa * 2ULL + lz, 2); buf -= lz; - std::memcpy(buf + 2ull, charTable.data() + bb * 2ull, 2); - return buf + 4ull; + std::memcpy(buf + 2ULL, charTable + bb * 2ULL, 2); + return buf + 4ULL; } else if (val < 1000000) { aa = uint32_t((uint64_t(val) * 429497) >> 32); bbcc = val - aa * 10000; bb = (bbcc * 5243) >> 19; cc = bbcc - bb * 100; lz = aa < 10; - std::memcpy(buf, charTable.data() + aa * 2ull + lz, 2); + std::memcpy(buf, charTable + aa * 2ULL + lz, 2); buf -= lz; - std::memcpy(buf + 2ull, charTable.data() + bb * 2ull, 2); - std::memcpy(buf + 4ull, charTable.data() + cc * 2ull, 2); - return buf + 6ull; + std::memcpy(buf + 2ULL, charTable + bb * 2ULL, 2); + std::memcpy(buf + 4ULL, charTable + cc * 2ULL, 2); + return buf + 6ULL; } else { aabb = uint32_t((uint64_t(val) * 109951163) >> 40); ccdd = val - aabb * 10000; @@ -708,16 +705,16 @@ namespace JsonifierInternal { bb = aabb - aa * 100; dd = ccdd - cc * 100; lz = aa < 10; - std::memcpy(buf, charTable.data() + aa * 2ull + lz, 2); + std::memcpy(buf, charTable + aa * 2ULL + lz, 2); buf -= lz; - std::memcpy(buf + 2ull, charTable.data() + bb * 2ull, 2); - std::memcpy(buf + 4ull, charTable.data() + cc * 2ull, 2); - std::memcpy(buf + 6ull, charTable.data() + dd * 2ull, 2); + std::memcpy(buf + 2ULL, charTable + bb * 2ULL, 2); + std::memcpy(buf + 4ULL, charTable + cc * 2ULL, 2); + std::memcpy(buf + 6ULL, charTable + dd * 2ULL, 2); return buf + 8; } } - static inline auto* toCharsU64Len58(auto* buf, uint32_t val) { + inline static auto* toCharsU64Len58(auto* buf, uint32_t val) { uint32_t aa, bb, cc, dd, aabb, bbcc, ccdd, lz; if (val < 1000000) { @@ -726,11 +723,11 @@ namespace JsonifierInternal { bb = (bbcc * 5243) >> 19; cc = bbcc - bb * 100; lz = aa < 10; - std::memcpy(buf, charTable.data() + aa * 2ull + lz, 2); + std::memcpy(buf, charTable + aa * 2ULL + lz, 2); buf -= lz; - std::memcpy(buf + 2ull, charTable.data() + bb * 2ull, 2); - std::memcpy(buf + 4ull, charTable.data() + cc * 2ull, 2); - return buf + 6ull; + std::memcpy(buf + 2ULL, charTable + bb * 2ULL, 2); + std::memcpy(buf + 4ULL, charTable + cc * 2ULL, 2); + return buf + 6ULL; } else { aabb = uint32_t((uint64_t(val) * 109951163) >> 40); ccdd = val - aabb * 10000; @@ -739,25 +736,25 @@ namespace JsonifierInternal { bb = aabb - aa * 100; dd = ccdd - cc * 100; lz = aa < 10; - std::memcpy(buf, charTable.data() + aa * 2ull + lz, 2); + std::memcpy(buf, charTable + aa * 2ULL + lz, 2); buf -= lz; - std::memcpy(buf + 2ull, charTable.data() + bb * 2ull, 2); - std::memcpy(buf + 4ull, charTable.data() + cc * 2ull, 2); - std::memcpy(buf + 6ull, charTable.data() + dd * 2ull, 2); + std::memcpy(buf + 2ULL, charTable + bb * 2ULL, 2); + std::memcpy(buf + 4ULL, charTable + cc * 2ULL, 2); + std::memcpy(buf + 6ULL, charTable + dd * 2ULL, 2); return buf + 8; } } - template - requires(sizeof(ValueType) == 8) - static inline auto* toChars(auto* buf, ValueType val) { + template + requires(sizeof(value_type) == 8) + inline static auto* toChars(auto* buf, value_type val) { uint64_t tmp, hgh; uint32_t mid, low; if (val < 100000000) { buf = toCharsU64Len18(buf, uint32_t(val)); return buf; - } else if (val < 100000000ull * 100000000ull) { + } else if (val < 100000000ULL * 100000000ULL) { hgh = val / 100000000; low = uint32_t(val - hgh * 100000000); buf = toCharsU64Len18(buf, uint32_t(hgh)); @@ -775,9 +772,9 @@ namespace JsonifierInternal { } } - template - requires(sizeof(ValueType) == 8) - static inline auto* toChars(auto* buf, ValueType val) { + template + requires(sizeof(value_type) == 8) + inline static auto* toChars(auto* buf, value_type val) { uint64_t neg = uint64_t(-val); uint64_t sign = val < 0; *buf = '-'; @@ -795,7 +792,7 @@ namespace JsonifierInternal { https://github.com/jk-jeon/dragonbox/blob/master/other_files/Dragonbox.pdf https://github.com/jk-jeon/dragonbox */ - static inline void f64BinToDec(uint64_t sigRaw, int32_t expRaw, uint64_t sigBin, int32_t expBin, uint64_t* sigDec, int32_t* expDec) { + inline static void f64BinToDec(uint64_t sigRaw, int32_t expRaw, uint64_t sigBin, int32_t expBin, uint64_t* sigDec, int32_t* expDec) { bool isEven, lowerBoundCloser, uInside, wInside, round_up; uint64_t s, sp, cb, cbl, cbr, vb, vbl, vbr, pow10hi, pow10lo, upper, lower, mid; int32_t k, h, exp10; @@ -805,7 +802,7 @@ namespace JsonifierInternal { cbl = 4 * sigBin - 2 + lowerBoundCloser; cb = 4 * sigBin; - cbr = 4 * sigBin + 2ull; + cbr = 4 * sigBin + 2ULL; k = (expBin * 315653 - (lowerBoundCloser ? 131237 : 0)) >> 20; @@ -834,16 +831,16 @@ namespace JsonifierInternal { } uInside = (lower <= 4 * s); - wInside = (upper >= 4 * s + 4ull); + wInside = (upper >= 4 * s + 4ULL); - mid = 4 * s + 2ull; + mid = 4 * s + 2ULL; round_up = (vb > mid) || (vb == mid && (s & 1) != 0); *sigDec = s + ((uInside != wInside) ? wInside : round_up); *expDec = k; } - static inline char* writeU64Len15To17Trim(char* buf, uint64_t sig) { + inline static char* writeU64Len15To17Trim(char* buf, uint64_t sig) { bool lz; uint32_t tz1, tz2, tz; @@ -856,12 +853,12 @@ namespace JsonifierInternal { uint32_t bb = abb - a * 100; uint32_t cc = abbcc - abb * 100; - buf[0] = uint8_t(a + '0'); + buf[0] = static_cast(a + static_cast('0')); buf += a > 0; lz = bb < 10 && a == 0; - std::memcpy(buf, charTable.data() + (bb * 2ull + lz), 2ull); + std::memcpy(buf, charTable + (bb * 2ULL + lz), 2ULL); buf -= lz; - std::memcpy(buf + 2ull, charTable.data() + 2ull * cc, 2ull); + std::memcpy(buf + 2ULL, charTable + 2ULL * cc, 2ULL); if (ffgghhii) { uint32_t dd = (ddee * 5243) >> 19; @@ -870,24 +867,24 @@ namespace JsonifierInternal { uint32_t hhii = ffgghhii - ffgg * 10000; uint32_t ff = (ffgg * 5243) >> 19; uint32_t gg = ffgg - ff * 100; - std::memcpy(buf + 4ull, charTable.data() + 2ull * dd, 2ull); - std::memcpy(buf + 6ull, charTable.data() + 2ull * ee, 2ull); - std::memcpy(buf + 8ull, charTable.data() + 2ull * ff, 2ull); - std::memcpy(buf + 10ull, charTable.data() + 2ull * gg, 2ull); + std::memcpy(buf + 4ULL, charTable + 2ULL * dd, 2ULL); + std::memcpy(buf + 6ULL, charTable + 2ULL * ee, 2ULL); + std::memcpy(buf + 8ULL, charTable + 2ULL * ff, 2ULL); + std::memcpy(buf + 10ULL, charTable + 2ULL * gg, 2ULL); if (hhii) { uint32_t hh = (hhii * 5243) >> 19; uint32_t ii = hhii - hh * 100; - std::memcpy(buf + 12ull, charTable.data() + 2ull * hh, 2ull); - std::memcpy(buf + 14ull, charTable.data() + 2ull * ii, 2ull); + std::memcpy(buf + 12ULL, charTable + 2ULL * hh, 2ULL); + std::memcpy(buf + 14ULL, charTable + 2ULL * ii, 2ULL); tz1 = decTrailingZeroTable[hh]; tz2 = decTrailingZeroTable[ii]; - tz = ii ? tz2 : (tz1 + 2ull); + tz = ii ? tz2 : (tz1 + 2ULL); buf += 16 - tz; return buf; } else { tz1 = decTrailingZeroTable[ff]; tz2 = decTrailingZeroTable[gg]; - tz = gg ? tz2 : (tz1 + 2ull); + tz = gg ? tz2 : (tz1 + 2ULL); buf += 12 - tz; return buf; } @@ -895,11 +892,11 @@ namespace JsonifierInternal { if (ddee) { uint32_t dd = (ddee * 5243) >> 19; uint32_t ee = ddee - dd * 100; - std::memcpy(buf + 4ull, charTable.data() + 2ull * dd, 2ull); - std::memcpy(buf + 6ull, charTable.data() + 2ull * ee, 2ull); + std::memcpy(buf + 4ULL, charTable + 2ULL * dd, 2ULL); + std::memcpy(buf + 6ULL, charTable + 2ULL * ee, 2ULL); tz1 = decTrailingZeroTable[dd]; tz2 = decTrailingZeroTable[ee]; - tz = ee ? tz2 : (tz1 + 2ull); + tz = ee ? tz2 : (tz1 + 2ULL); buf += 8 - tz; return buf; } else { @@ -916,27 +913,27 @@ namespace JsonifierInternal { return x < 2 ? x : 1 + numbits(x >> 1); } - template - requires std::same_as || std::same_as - static inline char* toChars(char* buffer, ValueType val) { - static_assert(std::numeric_limits::is_iec559); - static_assert(std::numeric_limits::radix == 2); - static_assert(std::same_as || std::same_as); + template + requires std::same_as || std::same_as + inline static char* toChars(char* buffer, value_type val) { + static_assert(std::numeric_limits::is_iec559); + static_assert(std::numeric_limits::radix == 2); + static_assert(std::same_as || std::same_as); static_assert(sizeof(float) == 4 && sizeof(double) == 8); - using raw_t = std::conditional_t, uint32_t, uint64_t>; + using raw_t = std::conditional_t, uint32_t, uint64_t>; raw_t raw{}; - std::memcpy(&raw, &val, sizeof(ValueType)); + std::memcpy(&raw, &val, sizeof(value_type)); - static constexpr uint32_t exponentBits = numbits(std::numeric_limits::max_exponent - std::numeric_limits::min_exponent + 1); + static constexpr uint32_t exponentBits = numbits(std::numeric_limits::max_exponent - std::numeric_limits::min_exponent + 1); static constexpr raw_t sigMask = raw_t(-1) >> (exponentBits + 1); - bool sign = (raw >> (sizeof(ValueType) * 8 - 1)); + bool sign = (raw >> (sizeof(value_type) * 8 - 1)); uint64_t sigRaw = raw & sigMask; - int32_t expRaw = raw << 1 >> (sizeof(raw_t) * 8 - exponentBits); + int32_t expRaw = static_cast(raw << 1 >> (sizeof(raw_t) * 8 - exponentBits)); if (expRaw == (uint32_t(1) << exponentBits) - 1) [[unlikely]] { std::memcpy(buffer, "null", 4); - return buffer + 4ull; + return buffer + 4ULL; } if (sign) { *buffer = '-'; @@ -947,50 +944,50 @@ namespace JsonifierInternal { int32_t expBin; if (expRaw == 0) [[unlikely]] { sigBin = sigRaw; - expBin = 1 - (std::numeric_limits::max_exponent - 1) - (std::numeric_limits::digits - 1); + expBin = 1 - (std::numeric_limits::max_exponent - 1) - (std::numeric_limits::digits - 1); } else { - sigBin = sigRaw | uint64_t(1ull << (std::numeric_limits::digits - 1)); - expBin = int32_t(expRaw) - (std::numeric_limits::max_exponent - 1) - (std::numeric_limits::digits - 1); + sigBin = sigRaw | uint64_t(1ULL << (std::numeric_limits::digits - 1)); + expBin = int32_t(expRaw) - (std::numeric_limits::max_exponent - 1) - (std::numeric_limits::digits - 1); } uint64_t sigDec; int32_t expDec; f64BinToDec(sigRaw, expRaw, sigBin, expBin, &sigDec, &expDec); - if constexpr (std::same_as) { + if constexpr (std::same_as) { sigDec *= 100000000; expDec -= 8; } int32_t sigLen = 17; - sigLen -= (sigDec < 100000000ull * 100000000ull); - sigLen -= (sigDec < 100000000ull * 10000000ull); + sigLen -= (sigDec < 100000000ULL * 100000000ULL); + sigLen -= (sigDec < 100000000ULL * 10000000ULL); int32_t dotPos = sigLen + expDec; if (-6 < dotPos && dotPos <= 21) { if (dotPos <= 0) { - auto numHdr = buffer + (2ull - dotPos); + auto numHdr = buffer + (2ULL - dotPos); auto numEnd = writeU64Len15To17Trim(numHdr, sigDec); buffer[0] = '0'; buffer[1] = '.'; - buffer += 2ull; + buffer += 2ULL; for (; buffer < numHdr; ++buffer) *buffer = '0'; return numEnd; } else { memset(buffer, '0', 8); - memset(buffer + 8ull, '0', 8); - memset(buffer + 16ull, '0', 8); - auto numHdr = buffer + 1ull; + memset(buffer + 8ULL, '0', 8); + memset(buffer + 16ULL, '0', 8); + auto numHdr = buffer + 1ULL; auto numEnd = writeU64Len15To17Trim(numHdr, sigDec); for (int32_t x = 0; x < dotPos; x++) - buffer[x] = buffer[x + 1ull]; + buffer[x] = buffer[x + 1ULL]; buffer[dotPos] = '.'; return ((numEnd - numHdr) <= dotPos) ? buffer + dotPos : numEnd; } } else { auto end = writeU64Len15To17Trim(buffer + 1, sigDec); - end -= (end == buffer + 2ull); + end -= (end == buffer + 2ULL); expDec += sigLen - 1; buffer[0] = buffer[1]; buffer[1] = '.'; @@ -1001,14 +998,14 @@ namespace JsonifierInternal { expDec = std::abs(expDec); if (expDec < 100) { uint32_t lz = expDec < 10; - std::memcpy(buffer, charTable.data() + (expDec * 2ull + lz), 2ull); - return buffer + 2ull - lz; + std::memcpy(buffer, charTable + (expDec * 2ULL + lz), 2ULL); + return buffer + 2ULL - lz; } else { uint32_t hi = (uint32_t(expDec) * 656) >> 16; uint32_t lo = uint32_t(expDec) - hi * 100; buffer[0] = uint8_t(hi) + '0'; - std::memcpy(&buffer[1], charTable.data() + (lo * 2ull), 2ull); - return buffer + 3ull; + std::memcpy(&buffer[1], charTable + (lo * 2ULL), 2ULL); + return buffer + 3ULL; } } } else [[unlikely]] { @@ -1019,16 +1016,16 @@ namespace JsonifierInternal { -}// namespace JsonifierInternal +}// namespace jsonifier_internal -namespace Jsonifier { +namespace jsonifier { - template Jsonifier::StringBase toString(const ValueType01& value) { - StringBase returnString{}; - returnString.resize(64); - auto newPtr = JsonifierInternal::toChars(returnString.data(), value); - returnString.resize(newPtr - returnString.data()); - return returnString; + template inline jsonifier::string_base toString(const value_type01& value) { + string_base returnstring{}; + returnstring.resize(64); + auto newPtr = jsonifier_internal::toChars(returnstring.data(), value); + returnstring.resize(static_cast(newPtr - returnstring.data())); + return returnstring; } -} +} \ No newline at end of file diff --git a/Include/jsonifier/Pair.hpp b/Include/jsonifier/Pair.hpp index a462995ae..3505a0423 100644 --- a/Include/jsonifier/Pair.hpp +++ b/Include/jsonifier/Pair.hpp @@ -19,16 +19,16 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/// https://github.com/RealTimeChris/Jsonifier +/// https://github.com/RealTimeChris/jsonifier /// Feb 20, 2023 #pragma once #include #include -namespace JsonifierInternal { +namespace jsonifier_internal { - template class Pair { + template class pair { public: using first_type = FirstType; using second_type = SecondType; @@ -36,26 +36,28 @@ namespace JsonifierInternal { first_type first; second_type second; - constexpr Pair() noexcept = default; + constexpr pair() = default; - template constexpr Pair(FirstTypeNew&& firstNew, SecondTypeNew&& secondNew) + template constexpr pair(FirstTypeNew&& firstNew, SecondTypeNew&& secondNew) : first{ std::forward(firstNew) }, second{ std::forward(secondNew) } { } template requires(std::same_as) - constexpr Pair(FirstTypeNew&& firstNew) : first{ std::forward(firstNew) } {} + constexpr pair(FirstTypeNew&& firstNew) : first{ std::forward(firstNew) } { + } template requires(std::same_as) - constexpr Pair(SecondTypeNew&& firstNew) : second{ std::forward(firstNew) } {} + constexpr pair(SecondTypeNew&& firstNew) : second{ std::forward(firstNew) } { + } - constexpr bool operator==(const Pair& other) const { + constexpr bool operator==(const pair& other) const { return first == other.first && second == other.second; } }; - template using UnwrapRefDecayT = typename std::unwrap_ref_decay::type; + template using unwrap_ref_decay_t = typename std::unwrap_ref_decay::type; - template Pair(A, B) -> Pair, UnwrapRefDecayT>; + template pair(a, b) -> pair, unwrap_ref_decay_t>; } diff --git a/Include/jsonifier/Parse_Impl.hpp b/Include/jsonifier/Parse_Impl.hpp index 53b1cd74f..0fb2f4dd1 100644 --- a/Include/jsonifier/Parse_Impl.hpp +++ b/Include/jsonifier/Parse_Impl.hpp @@ -19,7 +19,7 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/// https://github.com/RealTimeChris/Jsonifier +/// https://github.com/RealTimeChris/jsonifier /// Feb 20, 2023 #pragma once @@ -30,97 +30,113 @@ #include #include -namespace JsonifierInternal { +namespace jsonifier_internal { - static inline Jsonifier::StringBase& getCurrentStringBuffer() noexcept { - static thread_local Jsonifier::StringBase currentStringBuffer{}; - return currentStringBuffer; - } + static thread_local jsonifier::string_base currentStringBuffer{}; - static inline Jsonifier::StringBase& getCurrentKeyBuffer() noexcept { - static thread_local Jsonifier::StringBase currentStringBuffer{}; - return currentStringBuffer; - } + static thread_local jsonifier::string_base currentKeyBuffer{}; - template struct ParseImpl { - inline static void op(ValueType&& value, StructuralIterator& iter) { + template struct parse_impl { + inline static void op(value_type&& value, structural_iterator& iter) { value = parseBool(*iter); ++iter; return; } }; - template struct ParseImpl { - inline static void op(ValueType&& value, StructuralIterator& iter) { + template struct parse_impl { + inline static void op(value_type&& value, structural_iterator& iter) { parseNumber(value, *iter); ++iter; return; } }; - template struct ParseImpl { - inline static void op(ValueType&& value, StructuralIterator& iter) { + template struct parse_impl { + inline static void op(value_type&& value, structural_iterator& iter) { auto newValue = static_cast(value); auto newValueOld = static_cast(value); parseNumber(newValue, *iter); newValue |= newValueOld; - value = static_cast(newValue); + value = static_cast(newValue); ++iter; return; } }; - template struct ParseImpl { - inline static void op(ValueType&& value, StructuralIterator& iter) { - value = std::make_unique(); - Parse::op(*value, iter); + template struct parse_impl { + inline static void op(value_type&& value, structural_iterator& iter) { + value = std::make_unique(); + parse::op(*value, iter); return; } }; - template struct ParseImpl { - inline static void op(ValueType&& value, StructuralIterator& iter) { - auto newPtr = *iter; - Derailleur::skipValue(iter); - int64_t sizeNew = static_cast(*iter - newPtr); - value.resize(sizeNew); - std::memcpy(value.data(), newPtr, sizeNew); + template struct parse_impl { + inline static void op(value_type&& value, structural_iterator& iter) { + switch (**iter) { + case '"': { + auto newPtr = *iter + 1; + derailleur::skipValue(iter); + int64_t sizeNew = *iter - newPtr - 1; + if (sizeNew > 0) { + value.resize(sizeNew); + std::memcpy(value.data(), newPtr, sizeNew); + } + break; + } + default: { + auto newPtr = *iter; + derailleur::skipValue(iter); + uint64_t sizeNew = static_cast(*iter - newPtr); + if (static_cast(sizeNew) > 0) { + value.resize(sizeNew); + std::memcpy(value.data(), newPtr, sizeNew); + } + break; + } + } } }; - template struct ParseImpl { - inline static void op(ValueType&& value, StructuralIterator& iter) { - auto newPtr = *iter; - ++iter; - int64_t sizeNew = static_cast(*iter - newPtr); - auto newerSize = sizeNew + (BytesPerStep - (sizeNew % BytesPerStep)); - getCurrentStringBuffer().resize(newerSize * 2); - auto newerPtr = parseString((newPtr) + 1, getCurrentStringBuffer().data(), newerSize); + template struct parse_impl { + inline static void op(value_type&& value, structural_iterator& iter) { + if (derailleur::template checkForMatchOpen<'n'>(iter)) [[unlikely]] { + ++iter; + return; + } + auto newPtr = iter; + if (!derailleur::template checkForMatchClosed<'"'>(iter)) [[unlikely]] { + return; + } + int64_t sizeNew = *iter - *newPtr; + currentStringBuffer.resize(sizeNew); + auto newerPtr = parsestring((*newPtr) + 1, currentStringBuffer.data(), newPtr.getRemainingLength()); if (newerPtr) { - newerSize = newerPtr - getCurrentStringBuffer().data(); - value.resize(newerSize); - std::memcpy(value.data(), getCurrentStringBuffer().data(), newerSize); + sizeNew = static_cast(newerPtr - currentStringBuffer.data()); + value.resize(sizeNew); + std::memcpy(value.data(), currentStringBuffer.data(), sizeNew); } } }; - template struct ParseImpl { - inline static void op(ValueType&& value, StructuralIterator& iter) { + template struct parse_impl { + inline static void op(value_type&& value, structural_iterator& iter) { auto newPtr = *iter; - value = static_cast(*(newPtr + 1)); + value = static_cast(*(newPtr + 1)); ++iter; } }; - template struct ParseImpl { - inline static void op(ValueType&& value, StructuralIterator& iter) { - if (!Derailleur::template checkForMatchClosed<'['>(iter)) { + template struct parse_impl { + inline static void op(value_type&& value, structural_iterator& iter) { + if (!derailleur::template checkForMatchClosed<'['>(iter)) { return; } - if (Derailleur::template checkForMatchOpen<']'>(iter)) [[unlikely]] { + if (derailleur::template checkForMatchOpen<']'>(iter)) [[unlikely]] { return; } - const auto n = std::min(value.size(), Derailleur::countArrayElements(iter)); + const auto n = std::min(static_cast(value.size()), derailleur::countArrayElements(iter)); auto valueIter = value.begin(); @@ -128,24 +144,24 @@ namespace JsonifierInternal { if (iter == iter) { return; } - Parse::op(*valueIter++, iter); - if (!Derailleur::template checkForMatchOpen<','>(iter)) [[likely]] { - if (!Derailleur::template checkForMatchClosed<']'>(iter)) { + parse::op(*valueIter++, iter); + if (!derailleur::template checkForMatchOpen<','>(iter)) [[likely]] { + if (!derailleur::template checkForMatchClosed<']'>(iter)) { return; } return; } } - Derailleur::template checkForMatchClosed<']'>(iter); + derailleur::template checkForMatchClosed<']'>(iter); } }; - template struct ParseImpl { - inline static void op(ValueType&& value, StructuralIterator& iter) { - if (!Derailleur::template checkForMatchClosed<'['>(iter)) { + template struct parse_impl { + inline static void op(value_type&& value, structural_iterator& iter) { + if (!derailleur::template checkForMatchClosed<'['>(iter)) { return; } - if (Derailleur::template checkForMatchOpen<']'>(iter)) [[unlikely]] { + if (derailleur::template checkForMatchOpen<']'>(iter)) [[unlikely]] { return; } const auto m = value.size(); @@ -156,215 +172,250 @@ namespace JsonifierInternal { if (iter == iter) { return; } - Parse::op(*valueIter++, iter); - if (!Derailleur::template checkForMatchOpen<','>(iter)) [[likely]] { - if (!Derailleur::template checkForMatchClosed<']'>(iter)) { + parse::op(*valueIter++, iter); + if (!derailleur::template checkForMatchOpen<','>(iter)) [[likely]] { + if (!derailleur::template checkForMatchClosed<']'>(iter)) { return; } return; } } while (iter != iter) { - Parse::op(value.emplace_back(), iter); + parse::op(value.emplace_back(), iter); if (iter == iter) { return; } - if (!Derailleur::template checkForMatchOpen<','>(iter)) [[likely]] { - if (!Derailleur::template checkForMatchClosed<']'>(iter)) { + if (!derailleur::template checkForMatchOpen<','>(iter)) [[likely]] { + if (!derailleur::template checkForMatchClosed<']'>(iter)) { return; } return; } } - Derailleur::template checkForMatchClosed<']'>(iter); + derailleur::template checkForMatchClosed<']'>(iter); } }; - template struct ParseImpl { - inline static void op(ValueType&& value, StructuralIterator& iter) { - if (!Derailleur::template checkForMatchClosed<'{'>(iter)) { + template struct parse_impl { + inline static void op(value_type&& value, structural_iterator& iter) { + if (!derailleur::template checkForMatchClosed<'['>(iter)) { + return; + } + static constexpr auto N = []() constexpr { + if constexpr (jsonifier_array_t>) { + return std::tuple_size_v>>; + } else { + return std::tuple_size_v>; + } + }(); + + using V = ref_unwrap; + forEach([&](auto I) { + if constexpr (jsonifier_array_t) { + auto& newMember = getMember(value, tuplet::get(coreV)); + parse::op(newMember, iter); + } else { + parse::op(tuplet::get(value), iter); + } + if (iter == iter) { + return; + } + if (!derailleur::template checkForMatchOpen<','>(iter)) [[likely]] { + if (!derailleur::template checkForMatchClosed<']'>(iter)) { + return; + } + return; + } + }); + derailleur::template checkForMatchClosed<']'>(iter); + } + }; + + template struct parse_impl { + inline static void op(value_type&& value, structural_iterator& iter) { + if (!derailleur::template checkForMatchClosed<'{'>(iter)) { return; } bool first{ true }; while (iter != iter) { - if (Derailleur::template checkForMatchOpen<'}'>(iter)) [[unlikely]] { + if (derailleur::template checkForMatchOpen<'}'>(iter)) [[unlikely]] { return; } else if (first) [[unlikely]] { first = false; } else [[likely]] { - if (!Derailleur::template checkForMatchClosed<','>(iter)) { + if (!derailleur::template checkForMatchClosed<','>(iter)) { return; } } - if constexpr (JsonifierObjectT) { - StructuralIterator start = iter; - if (!Derailleur::template checkForMatchClosed<'"'>(iter)) { + if constexpr (jsonifier_object_t) { + structural_iterator start = iter; + if (!derailleur::template checkForMatchClosed<'"'>(iter)) { return; } - const Jsonifier::StringViewBase key{ *start + 1, static_cast(*iter - *start) - 2 }; - if (!Derailleur::template checkForMatchClosed<':'>(iter)) { + const jsonifier::string_view_base key{ *start + 1, static_cast(*iter - *start) - 2 }; + if (!derailleur::template checkForMatchClosed<':'>(iter)) { return; } - constexpr auto frozenMap = makeMap(); + constexpr auto frozenMap = makeMap(); const auto& memberIt = frozenMap.find(key); - if (Derailleur::template checkForMatchOpen<'n'>(iter)) [[unlikely]] { + if (derailleur::template checkForMatchOpen<'n'>(iter)) [[unlikely]] { continue; } else if (memberIt != frozenMap.end()) [[likely]] { std::visit( [&](auto& memberPtr) { auto& newMember = getMember(value, memberPtr); - Parse::op(newMember, iter); + parse::op(newMember, iter); }, memberIt->second); } else [[unlikely]] { - Derailleur::skipValue(iter); + derailleur::skipValue(iter); } } else { - Parse::op(getCurrentStringBuffer(), iter); - if (!Derailleur::template checkForMatchClosed<':'>(iter)) { + parse::op(currentStringBuffer, iter); + if (!derailleur::template checkForMatchClosed<':'>(iter)) { return; } - if constexpr (StringT) { - Parse::op(value[static_cast(getCurrentStringBuffer())], iter); + if constexpr (string_t) { + parse::op(value[static_cast(currentStringBuffer)], iter); } else { - static thread_local typename ValueType::key_type key_value{}; - Parse::op(key_value, iter); - Parse::op(value[key_value], iter); + static thread_local typename value_type::key_type key_value{}; + parse::op(key_value, iter); + parse::op(value[key_value], iter); } } } } }; - template struct ParseImpl { - inline static void op(ValueType&& value, StructuralIterator& iter) { - if (!Derailleur::template checkForMatchClosed<'{'>(iter)) { + template struct parse_impl { + inline static void op(value_type&& value, structural_iterator& iter) { + if (!derailleur::template checkForMatchClosed<'{'>(iter)) { return; } bool first{ true }; while (iter != iter) { - if (Derailleur::template checkForMatchOpen<'}'>(iter)) [[unlikely]] { + if (derailleur::template checkForMatchOpen<'}'>(iter)) [[unlikely]] { return; } else if (first) [[unlikely]] { first = false; } else [[likely]] { - if (!Derailleur::template checkForMatchClosed<','>(iter)) { + if (!derailleur::template checkForMatchClosed<','>(iter)) { return; } } - if constexpr (JsonifierObjectT) { - StructuralIterator start = iter; - if (!Derailleur::template checkForMatchClosed<'"'>(iter)) { + if constexpr (jsonifier_object_t) { + structural_iterator start = iter; + if (!derailleur::template checkForMatchClosed<'"'>(iter)) { return; } - const Jsonifier::StringViewBase key{ *start + 1, static_cast(*iter - *start) - 2 }; - if (!Derailleur::template checkForMatchClosed<':'>(iter)) { + const jsonifier::string_view_base key{ *start + 1, static_cast(*iter - *start) - 2 }; + if (!derailleur::template checkForMatchClosed<':'>(iter)) { return; } - constexpr auto frozenMap = makeMap(); + constexpr auto frozenMap = makeMap(); const auto& memberIt = frozenMap.find(key); - if (Derailleur::template checkForMatchOpen<'n'>(iter)) [[unlikely]] { + if (derailleur::template checkForMatchOpen<'n'>(iter)) [[unlikely]] { continue; } else if (memberIt != frozenMap.end()) [[likely]] { std::visit( [&](auto& memberPtr) { - auto& newMember = getMember(value, memberPtr); - using newMemberType = decltype(newMember); - if constexpr (HasExcludedKeys) { - Parse::op(newMember, iter, newMember.excludedKeys); + auto& newMember = getMember(value, memberPtr); + using member_type = decltype(newMember); + if constexpr (has_excluded_keys) { + parse::op(newMember, iter, newMember.excludedKeys); } else { - Parse::op(newMember, iter); + parse::op(newMember, iter); } }, memberIt->second); } else [[unlikely]] { - Derailleur::skipValue(iter); + derailleur::skipValue(iter); } } else { - Parse::op(getCurrentStringBuffer(), iter); - if (!Derailleur::template checkForMatchClosed<':'>(iter)) { + parse::op(currentStringBuffer, iter); + if (!derailleur::template checkForMatchClosed<':'>(iter)) { return; } - if constexpr (StringT) { - Parse::op(value[static_cast(getCurrentStringBuffer())], iter); + if constexpr (string_t) { + parse::op(value[static_cast(currentStringBuffer)], iter); } else { - static thread_local typename ValueType::key_type key_value{}; - Parse::op(key_value, iter); - Parse::op(value[key_value], iter); + static thread_local typename value_type::key_type key_value{}; + parse::op(key_value, iter); + parse::op(value[key_value], iter); } } } }; - template inline static void op(ValueType&& value, StructuralIterator& iter, const KeyType& excludedKeys) { - if (!Derailleur::template checkForMatchClosed<'{'>(iter)) { + template inline static void op(value_type&& value, structural_iterator& iter, const KeyType& excludedKeys) { + if (!derailleur::template checkForMatchClosed<'{'>(iter)) { return; } bool first{ true }; while (iter != iter) { - if (Derailleur::template checkForMatchOpen<'}'>(iter)) [[unlikely]] { + if (derailleur::template checkForMatchOpen<'}'>(iter)) [[unlikely]] { return; } else if (first) [[unlikely]] { first = false; } else [[likely]] { - if (!Derailleur::template checkForMatchClosed<','>(iter)) { + if (!derailleur::template checkForMatchClosed<','>(iter)) { return; } } - if constexpr (JsonifierObjectT) { - StructuralIterator start = iter; - if (!Derailleur::template checkForMatchClosed<'"'>(iter)) { - return; - } - const Jsonifier::StringViewBase key{ *start + 1, static_cast(*iter - *start) - 2 }; - if (!Derailleur::template checkForMatchClosed<':'>(iter)) { + if constexpr (jsonifier_object_t) { + structural_iterator start = iter; + if (!derailleur::template checkForMatchClosed<'"'>(iter)) { return; } - getCurrentKeyBuffer().resize(static_cast(*iter - *start) - 2); - std::memcpy(getCurrentKeyBuffer().data(), *start + 1, static_cast(*iter - *start) - 2); - if (excludedKeys.find(static_cast(getCurrentKeyBuffer())) != excludedKeys.end()) { - Derailleur::skipValue(iter); + const jsonifier::string_view_base key{ *start + 1, static_cast(*iter - *start) - 2 }; + currentKeyBuffer.resize(static_cast(*iter - *start) - 2); + std::memcpy(currentKeyBuffer.data(), *start + 1, static_cast(*iter - *start) - 2); + if (excludedKeys.find(static_cast(currentKeyBuffer)) != excludedKeys.end()) { + derailleur::skipToNextValue(iter); continue; } - constexpr auto frozenMap = makeMap(); + if (!derailleur::template checkForMatchClosed<':'>(iter)) { + return; + } + constexpr auto frozenMap = makeMap(); const auto& memberIt = frozenMap.find(key); - if (Derailleur::template checkForMatchOpen<'n'>(iter)) [[unlikely]] { + if (derailleur::template checkForMatchOpen<'n'>(iter)) [[unlikely]] { continue; } else if (memberIt != frozenMap.end()) [[likely]] { std::visit( [&](auto& memberPtr) { - auto& newMember = getMember(value, memberPtr); - using newMemberType = decltype(newMember); - if constexpr (HasExcludedKeys) { - Parse::op(newMember, iter, newMember.excludedKeys); + auto& newMember = getMember(value, memberPtr); + using member_type = decltype(newMember); + if constexpr (has_excluded_keys) { + parse::op(newMember, iter, newMember.excludedKeys); } else { - Parse::op(newMember, iter); + parse::op(newMember, iter); } }, memberIt->second); } else [[unlikely]] { - Derailleur::skipValue(iter); + derailleur::skipValue(iter); } } else { - Parse::op(getCurrentStringBuffer(), iter); - if (!Derailleur::template checkForMatchClosed<':'>(iter)) { + parse::op(currentStringBuffer, iter); + if (!derailleur::template checkForMatchClosed<':'>(iter)) { return; } - if constexpr (StringT) { - Parse::op(value[static_cast(getCurrentStringBuffer())], iter); + if constexpr (string_t) { + parse::op(value[static_cast(currentStringBuffer)], iter); } else { - static thread_local typename ValueType::key_type key_value{}; - Parse::op(key_value, iter); - Parse::op(value[key_value], iter); + static thread_local typename value_type::key_type key_value{}; + parse::op(key_value, iter); + parse::op(value[key_value], iter); } } } - }; + } }; } \ No newline at end of file diff --git a/Include/jsonifier/Parser.hpp b/Include/jsonifier/Parser.hpp index 5364182f9..511c09a7d 100644 --- a/Include/jsonifier/Parser.hpp +++ b/Include/jsonifier/Parser.hpp @@ -19,7 +19,7 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/// https://github.com/RealTimeChris/Jsonifier +/// https://github.com/RealTimeChris/jsonifier /// Feb 3, 2023 #pragma once @@ -30,70 +30,61 @@ #include #include -namespace JsonifierInternal { +namespace jsonifier_internal { - template struct ParseImpl; + template struct parse_impl; - template struct Parse { - template inline static void op(ValueType&& value, StructuralIterator& iter) { - ParseImpl>::op(std::forward>(value), iter); + template struct parse { + template inline static void op(value_type&& value, structural_iterator& iter) { + parse_impl>::op(std::forward>(value), iter); } - template inline static void op(ValueType&& value, StructuralIterator& iter, const KeyType& keys) { - ParseImpl>::op(std::forward>(value), iter, keys); + template inline static void op(value_type&& value, structural_iterator& iter, const KeyType& keys) { + parse_impl>::op(std::forward>(value), iter, keys); } }; - class Parser { + class parser { public: - inline Parser() noexcept = default; - - inline Parser& operator=(Parser&& other) noexcept { - std::swap(section, other.section); - std::swap(string, other.string); - return *this; - }; - - inline Parser(Parser&& other) noexcept { - *this = std::move(other); - }; - - inline Parser& operator=(const Parser&) = delete; - inline Parser(const Parser&) = delete; - - template - void parseJson(ValueType&& data, BufferType&& inStringNew) { + template + inline void parseJson(value_type&& data, buffer_type&& inStringNew) { if (inStringNew.empty()) { return; } - refreshString ? reset(std::forward(inStringNew)) : (string != inStringNew ? reset(std::forward(inStringNew)) : void()); + if constexpr (refreshstring) { + reset(std::forward(inStringNew)); + } else if (inStringNew != string) { + reset(std::forward(inStringNew)); + } auto newIter = begin(); if (!*newIter) { return; } if constexpr (excludeKeys) { - if constexpr (HasExcludedKeys) { - Parse::op(std::forward(data), newIter, data.excludedKeys); + if constexpr (has_excluded_keys) { + parse::op(std::forward(data), newIter, data.excludedKeys); } else { - Parse::op(std::forward(data), newIter); + parse::op(std::forward(data), newIter); } } else { - Parse::op(std::forward(data), newIter); + parse::op(std::forward(data), newIter); } } protected: - SimdStringReader section{}; - Jsonifier::StringBase string{}; + jsonifier::string_base string{}; + simd_string_reader section{}; + int64_t originalLength{}; - template inline void reset(const ValueType& stringNew) { + template inline void reset(value_type&& stringNew) { string.resize(stringNew.size()); + originalLength = stringNew.size(); std::memcpy(string.data(), stringNew.data(), stringNew.size()); - section.reset(static_cast>(string)); + section.reset(string); } - inline StructuralIterator begin() noexcept { - return { §ion }; + inline structural_iterator begin() { + return structural_iterator{ section.getStructurals(), originalLength }; } }; }; diff --git a/Include/jsonifier/RawArray.hpp b/Include/jsonifier/RawArray.hpp index 27b105c99..42e6c5926 100644 --- a/Include/jsonifier/RawArray.hpp +++ b/Include/jsonifier/RawArray.hpp @@ -19,17 +19,17 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/// https://github.com/RealTimeChris/Jsonifier +/// https://github.com/RealTimeChris/jsonifier /// Feb 20, 2023 #pragma once #include -namespace JsonifierInternal { +namespace jsonifier_internal { - template struct RawArray { + template struct raw_array { public: - using value_type = ValueType; + using value_type = value_type_new; using reference = value_type&; using const_reference = const value_type&; using pointer = value_type*; @@ -39,43 +39,39 @@ namespace JsonifierInternal { using size_type = uint64_t; using difference_type = std::ptrdiff_t; - constexpr RawArray() noexcept = default; - constexpr RawArray& operator=(RawArray&&) noexcept = default; - constexpr RawArray(RawArray&&) noexcept = default; - constexpr RawArray& operator=(const RawArray&) noexcept = default; - constexpr RawArray(const RawArray&) noexcept = default; + constexpr raw_array() = default; - template constexpr RawArray(ValueType const (&init)[M]) : RawArray(init, std::make_index_sequence()) { + template constexpr raw_array(value_type const (&init)[M]) : raw_array(init, std::make_index_sequence()) { static_assert(M >= N); } - constexpr RawArray(const std::initializer_list& other) { + constexpr raw_array(const std::initializer_list& other) { for (uint64_t x = 0; x < other.size(); ++x) { operator[](x) = std::move(other.begin()[x]); } } - constexpr iterator begin() noexcept { + constexpr iterator begin() { return dataVal; } - constexpr const_iterator begin() const noexcept { + constexpr const_iterator begin() const { return dataVal; } - constexpr iterator end() noexcept { + constexpr iterator end() { return dataVal + N; } - constexpr const_iterator end() const noexcept { + constexpr const_iterator end() const { return dataVal + N; } - constexpr size_type size() const noexcept { + constexpr size_type size() const { return N; } - constexpr size_type maxSize() const noexcept { + constexpr size_type maxSize() const { return N; } @@ -83,18 +79,18 @@ namespace JsonifierInternal { return dataVal[index]; } - constexpr const_reference operator[](uint64_t index) const noexcept { + constexpr const_reference operator[](uint64_t index) const { return dataVal[index]; } - constexpr reference at(uint64_t index) noexcept { + constexpr reference at(uint64_t index) { if (index > N) { std::abort(); } return dataVal[index]; } - constexpr const_reference at(uint64_t index) const noexcept { + constexpr const_reference at(uint64_t index) const { if (index > N) { std::abort(); } @@ -105,7 +101,7 @@ namespace JsonifierInternal { return dataVal[0]; } - constexpr const_reference front() const noexcept { + constexpr const_reference front() const { return dataVal[0]; } @@ -113,15 +109,15 @@ namespace JsonifierInternal { return dataVal[N - 1]; } - constexpr const_reference back() const noexcept { + constexpr const_reference back() const { return dataVal[N - 1]; } - constexpr value_type* data() noexcept { + constexpr value_type* data() { return dataVal; } - constexpr const value_type* data() const noexcept { + constexpr const value_type* data() const { return dataVal; } @@ -131,15 +127,15 @@ namespace JsonifierInternal { } } - ValueType dataVal[N]{}; + alignas(JSONIFIER_ALIGNMENT) value_type dataVal[N]{}; - template constexpr RawArray(ValueType const (&init)[M], std::index_sequence) : dataVal{ init[I]... } { + template constexpr raw_array(value_type const (&init)[M], std::index_sequence) : dataVal{ init[I]... } { } }; - template class RawArray { + template class raw_array { public: - using value_type = ValueType; + using value_type = value_type_new; using reference = value_type&; using const_reference = const value_type&; using pointer = value_type*; @@ -150,8 +146,6 @@ namespace JsonifierInternal { using const_reverse_iterator = std::reverse_iterator; using size_type = uint64_t; using difference_type = std::ptrdiff_t; - - constexpr RawArray() noexcept = default; }; } diff --git a/Include/jsonifier/RawJsonData.hpp b/Include/jsonifier/RawJsonData.hpp index d848c9e1b..a5e51ebcf 100644 --- a/Include/jsonifier/RawJsonData.hpp +++ b/Include/jsonifier/RawJsonData.hpp @@ -19,18 +19,19 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/// https://github.com/RealTimeChris/Jsonifier +/// https://github.com/RealTimeChris/jsonifier /// Feb 20, 2023 #pragma once #include -namespace Jsonifier { +namespace jsonifier { - struct RawJsonData { - inline RawJsonData() noexcept = default; + class raw_json_data { + public: + inline raw_json_data() = default; - inline RawJsonData& operator=(bool value) noexcept { + inline raw_json_data& operator=(bool value) { if (value) { jsonData = "true"; } else { @@ -39,74 +40,74 @@ namespace Jsonifier { return *this; } - inline RawJsonData(bool value) noexcept { + inline raw_json_data(bool value) { *this = value; } - inline RawJsonData& operator=(double value) noexcept { - jsonData = String{ std::to_string(value) }; + inline raw_json_data& operator=(double value) { + jsonData = string{ std::to_string(value) }; return *this; } - inline RawJsonData(double value) noexcept { + inline raw_json_data(double value) { *this = value; } - inline RawJsonData& operator=(int64_t value) noexcept { - jsonData = String{ std::to_string(value) }; + inline raw_json_data& operator=(int64_t value) { + jsonData = string{ std::to_string(value) }; return *this; } - inline RawJsonData(int64_t value) noexcept { + inline raw_json_data(int64_t value) { *this = value; } - inline RawJsonData& operator=(const Jsonifier::String& value) noexcept { + inline raw_json_data& operator=(const jsonifier::string& value) { jsonData = value; return *this; } - inline RawJsonData(const Jsonifier::String& value) noexcept { + inline raw_json_data(const jsonifier::string& value) { *this = value; } - inline char* data() noexcept { + inline char* data() { return jsonData.data(); } - inline void resize(uint64_t sizeNew) noexcept { + inline void resize(uint64_t sizeNew) { jsonData.resize(sizeNew); } - inline explicit operator StringView() noexcept { + inline explicit operator string_view() { return { jsonData.data(), jsonData.size() }; } - inline operator String() const noexcept { - String newString{}; - newString.resize(jsonData.size()); - std::memcpy(newString.data(), jsonData.data(), jsonData.size()); - return newString; + inline operator string() const { + string newstring{}; + newstring.resize(jsonData.size()); + std::memcpy(newstring.data(), jsonData.data(), jsonData.size()); + return newstring; } - inline operator std::string() const noexcept { + inline operator std::string() const { return jsonData.operator std::string(); } - inline bool operator==(const RawJsonData& other) const { + inline bool operator==(const raw_json_data& other) const { return jsonData == other.jsonData; } - inline RawJsonData operator+(const String& other) { + inline raw_json_data operator+(const string& other) { jsonData += other; return *this; } protected: - String jsonData{}; + string jsonData{}; }; - inline std::ostream& operator<<(std::ostream& os, RawJsonData& jsonValue) noexcept { + inline std::ostream& operator<<(std::ostream& os, raw_json_data& jsonValue) { os << jsonValue.operator std::string(); return os; } diff --git a/Include/jsonifier/RawVector.hpp b/Include/jsonifier/RawVector.hpp index d92847d1c..7397a35a1 100644 --- a/Include/jsonifier/RawVector.hpp +++ b/Include/jsonifier/RawVector.hpp @@ -19,17 +19,17 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/// https://github.com/RealTimeChris/Jsonifier +/// https://github.com/RealTimeChris/jsonifier /// Feb 20, 2023 #pragma once #include -namespace JsonifierInternal { +namespace jsonifier_internal { - template class RawVector { + template class raw_vector { public: - using value_type = ValueType; + using value_type = value_type_new; using reference = value_type&; using const_reference = const value_type&; using pointer = value_type*; @@ -39,26 +39,22 @@ namespace JsonifierInternal { using size_type = uint64_t; using difference_type = std::ptrdiff_t; - constexpr RawVector() noexcept = default; - constexpr RawVector& operator=(RawVector&&) noexcept = default; - constexpr RawVector(RawVector&&) noexcept = default; - constexpr RawVector& operator=(const RawVector&) noexcept = default; - constexpr RawVector(const RawVector&) noexcept = default; + constexpr raw_vector() = default; - constexpr RawVector(size_type count, const auto& value) : dsize(count) { + constexpr raw_vector(size_type count, const auto& value) : dsize(count) { for (size_type x = 0; x < N; ++x) data[x] = value; } - constexpr iterator begin() noexcept { + constexpr iterator begin() { return data; } - constexpr iterator end() noexcept { + constexpr iterator end() { return data + dsize; } - constexpr size_type size() const noexcept { + constexpr size_type size() const { return dsize; } @@ -66,7 +62,7 @@ namespace JsonifierInternal { return data[index]; } - constexpr const_reference operator[](size_type index) const noexcept { + constexpr const_reference operator[](size_type index) const { return data[index]; } @@ -78,11 +74,11 @@ namespace JsonifierInternal { return data[dsize - 1]; } - constexpr const_reference front() const noexcept { + constexpr const_reference front() const { return data[0]; } - constexpr const_reference back() const noexcept { + constexpr const_reference back() const { return data[dsize - 1]; } @@ -103,8 +99,8 @@ namespace JsonifierInternal { } protected: - value_type data[N] = {}; - size_type dsize = 0; + alignas(JSONIFIER_ALIGNMENT) value_type data[N] = {}; + size_type dsize = 0; }; } diff --git a/Include/jsonifier/Serialize_Impl.hpp b/Include/jsonifier/Serialize_Impl.hpp index a6f4d9b02..95b9dd86d 100644 --- a/Include/jsonifier/Serialize_Impl.hpp +++ b/Include/jsonifier/Serialize_Impl.hpp @@ -19,7 +19,7 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/// https://github.com/RealTimeChris/Jsonifier +/// https://github.com/RealTimeChris/jsonifier /// Feb 20, 2023 #pragma once @@ -28,9 +28,9 @@ #include #include -namespace JsonifierInternal { +namespace jsonifier_internal { - template inline void writeCharacter(char c, BufferType&& buffer, uint64_t& index) { + template inline void writeCharacter(char c, buffer_type&& buffer, uint64_t& index) { if (index >= buffer.size()) [[unlikely]] { buffer.resize((buffer.size() + 1) * 2); } @@ -39,14 +39,23 @@ namespace JsonifierInternal { ++index; } - template inline void writeCharacterUnChecked(char c, BufferType&& buffer, uint64_t& index) { + template inline void writeCharacter(buffer_type&& buffer, uint64_t& index) { + if (index >= buffer.size()) [[unlikely]] { + buffer.resize((buffer.size() + 1) * 2); + } + buffer[index] = c; ++index; } - template inline void writeCharacters(BufferType&& buffer, uint64_t& index) { - static constexpr auto s = str; - static constexpr auto n = s.size(); + template inline void writeCharacterUnChecked(char c, buffer_type&& buffer, uint64_t& index) { + buffer[index] = c; + ++index; + } + + template inline void writeCharacters(buffer_type&& buffer, uint64_t& index) { + static constexpr jsonifier::string_view s = str; + static constexpr uint64_t n = s.size(); if (index + n > buffer.size()) [[unlikely]] { buffer.resize(std::max(buffer.size() * 2, index + n)); @@ -56,7 +65,7 @@ namespace JsonifierInternal { index += n; } - template inline void writeCharacters(BufferType&& buffer, uint64_t& index) { + template inline void writeCharacters(buffer_type&& buffer, uint64_t& index) { static constexpr auto s = str; static constexpr auto n = s.size(); @@ -68,7 +77,7 @@ namespace JsonifierInternal { index += n; } - template inline void writeCharacters(const Jsonifier::StringView str, BufferType&& buffer, uint64_t& index) { + template inline void writeCharacters(const jsonifier::string_view str, buffer_type&& buffer, uint64_t& index) { const auto n = str.size(); if (index + n > buffer.size()) [[unlikely]] { buffer.resize(std::max(buffer.size() * 2, index + n)); @@ -78,14 +87,14 @@ namespace JsonifierInternal { index += n; } - template struct SerializeImpl { - template inline static void op(const ValueType&, BufferType&& buffer, uint64_t& index) { + template struct serialize_impl { + template inline static void op(const value_type&, buffer_type&& buffer, uint64_t& index) { writeCharacters<"null">(buffer, index); } }; - template struct SerializeImpl { - template inline static void op(const ValueType& value, BufferType&& buffer, uint64_t& index) { + template struct serialize_impl { + template inline static void op(const value_type& value, buffer_type&& buffer, uint64_t& index) { if (value) { writeCharacters<"true">(buffer, index); } else { @@ -94,8 +103,8 @@ namespace JsonifierInternal { } }; - template struct SerializeImpl { - template inline static void op(const ValueType& value, BufferType&& buffer, uint64_t& index) { + template struct serialize_impl { + template inline static void op(const value_type& value, buffer_type&& buffer, uint64_t& index) { if (index + 32 > buffer.size()) [[unlikely]] { buffer.resize(std::max(buffer.size() * 2, index + 64)); } @@ -105,8 +114,8 @@ namespace JsonifierInternal { } }; - template struct SerializeImpl { - template inline static void op(const ValueType& value, BufferType&& buffer, uint64_t& index) { + template struct serialize_impl { + template inline static void op(const value_type& value, buffer_type&& buffer, uint64_t& index) { if (index + 32 > buffer.size()) [[unlikely]] { buffer.resize(std::max(buffer.size() * 2, index + 64)); } @@ -116,9 +125,9 @@ namespace JsonifierInternal { } }; - template struct SerializeImpl { - template inline static void op(const ValueType& value, BufferType&& buffer, uint64_t& index) { - writeCharacter('"', buffer, index); + template struct serialize_impl { + template inline static void op(const value_type& value, buffer_type&& buffer, uint64_t& index) { + writeCharacter<'"'>(buffer, index); switch (value) { case '"': writeCharacters<"\\\"">(buffer, index); @@ -144,15 +153,15 @@ namespace JsonifierInternal { default: writeCharacter(value, buffer, index); } - writeCharacter('"', buffer, index); + writeCharacter<'"'>(buffer, index); } }; - template struct SerializeImpl { - template inline static void op(const ValueType& value, BufferType&& buffer, uint64_t& index) { + template struct serialize_impl { + template inline static void op(const value_type& value, buffer_type&& buffer, uint64_t& index) { const auto n = value.size(); - if constexpr (HasResize) { + if constexpr (has_resize) { if ((index + (4 * n)) >= buffer.size()) [[unlikely]] { buffer.resize(std::max(buffer.size() * 2, index + (4 * n))); } @@ -199,71 +208,157 @@ namespace JsonifierInternal { } }; - template struct SerializeImpl { - template inline static void op(const ValueType& value, BufferType&& buffer, uint64_t& index) { - Jsonifier::String newValue = static_cast(value); - Serialize::op(newValue, buffer, index); + template struct serialize_impl { + template inline static void op(const value_type& value, buffer_type&& buffer, uint64_t& index) { + jsonifier::string newValue = static_cast(value); + serialize::op(newValue, buffer, index); } }; - template struct SerializeImpl { - template inline static void op(const ValueType& value, BufferType&& buffer, uint64_t& index) { + template struct serialize_impl { + template inline static void op(const value_type& value, buffer_type&& buffer, uint64_t& index) { static constexpr auto N = []() constexpr { - if constexpr (JsonifierArrayT>) { - return std::tuple_size_v>>; + if constexpr (jsonifier_array_t>) { + return std::tuple_size_v>>; } else { - return std::tuple_size_v>; + return std::tuple_size_v>; } }(); - writeCharacter('[', buffer, index); - using V = RefUnwrap; + writeCharacter<'['>(buffer, index); + using V = ref_unwrap; forEach([&](auto I) { - if constexpr (JsonifierArrayT) { - auto& newMember = getMember(value, Tuplet::get(CoreV)); - Serialize::op(newMember, buffer, index); + if constexpr (jsonifier_array_t) { + auto& newMember = getMember(value, tuplet::get(coreV)); + serialize::op(newMember, buffer, index); } else { - Serialize::op(Tuplet::get(value), buffer, index); + serialize::op(tuplet::get(value), buffer, index); } constexpr bool needsComma = I < N - 1; if constexpr (needsComma) { - writeCharacter(',', buffer, index); + writeCharacter<','>(buffer, index); } }); - writeCharacter(']', buffer, index); + writeCharacter<']'>(buffer, index); + } + }; + + template struct serialize_impl { + template inline static void op(const value_type& value, buffer_type&& buffer, uint64_t& index) { + static constexpr auto N = []() constexpr { + if constexpr (jsonifier_array_t>) { + return std::tuple_size_v>>; + } else { + return std::tuple_size_v>; + } + }(); + + writeCharacter<'['>(buffer, index); + using V = ref_unwrap; + forEach([&](auto I) { + if constexpr (jsonifier_array_t) { + auto& newMember = getMember(value, tuplet::get(coreV)); + using MemberType = decltype(newMember); + if constexpr (has_excluded_keys) { + serialize::op(newMember, buffer, index, newMember.excludedKeys); + } else { + serialize::op(newMember, buffer, index); + } + } else { + auto& newMember = tuplet::get(value); + using MemberType = decltype(newMember); + if constexpr (has_excluded_keys) { + serialize::op(newMember, buffer, index, newMember.excludedKeys); + } else { + serialize::op(newMember, buffer, index); + } + } + constexpr bool needsComma = I < N - 1; + if constexpr (needsComma) { + writeCharacter<','>(buffer, index); + } + }); + writeCharacter<']'>(buffer, index); + } + }; + + template struct serialize_impl { + template inline static void op(const value_type& value, buffer_type&& buffer, uint64_t& index) { + const auto n = value.size(); + writeCharacter<'['>(buffer, index); + for (uint64_t x = 0; x < n; ++x) { + serialize::op(value[x], buffer, index); + const bool needsComma = x < n - 1; + if (needsComma) { + writeCharacter<','>(buffer, index); + } + } + writeCharacter<']'>(buffer, index); } }; - template struct SerializeImpl { - template inline static void op(const ValueType& value, BufferType&& buffer, uint64_t& index) { + template struct serialize_impl { + template inline static void op(const value_type& value, buffer_type&& buffer, uint64_t& index) { const auto n = value.size(); - writeCharacter('[', buffer, index); + writeCharacter<'['>(buffer, index); for (uint64_t x = 0; x < n; ++x) { - Serialize::op(value[x], buffer, index); + auto& newMember = value[x]; + using MemberType = decltype(newMember); + if constexpr (has_excluded_keys) { + serialize::op(newMember, buffer, index, newMember.excludedKeys); + } else { + serialize::op(newMember, buffer, index); + } const bool needsComma = x < n - 1; if (needsComma) { - writeCharacter(',', buffer, index); + writeCharacter<','>(buffer, index); } } - writeCharacter(']', buffer, index); + writeCharacter<']'>(buffer, index); } }; - template struct SerializeImpl { - template inline static void op(const ValueType& value, BufferType&& buffer, uint64_t& index) { - writeCharacter('[', buffer, index); + template struct serialize_impl { + template inline static void op(const value_type& value, buffer_type&& buffer, uint64_t& index) { + writeCharacter<'['>(buffer, index); if (value.size()) { - auto it = value.begin(); - Serialize::op(*it, buffer, index); - ++it; - const auto end = value.end(); - for (; it != end; ++it) { - writeCharacter(',', buffer, index); - Serialize::op(*it, buffer, index); + bool first = true; + for (auto iter = value.begin(); iter != value.end(); ++iter) { + if (first) { + first = false; + } else { + writeCharacter<','>(buffer, index); + } + serialize::op(*iter, buffer, index); } } - writeCharacter(']', buffer, index); + writeCharacter<']'>(buffer, index); + } + }; + + template struct serialize_impl { + template inline static void op(const value_type& value, buffer_type&& buffer, uint64_t& index) { + writeCharacter<'['>(buffer, index); + + if (value.size()) { + bool first = true; + for (auto iter = value.begin(); iter != value.end(); ++iter) { + if (first) { + first = false; + } else { + writeCharacter<','>(buffer, index); + } + auto& newMember = *iter; + using MemberType = decltype(newMember); + if constexpr (has_excluded_keys) { + serialize::op(newMember, buffer, index, newMember.excludedKeys); + } else { + serialize::op(newMember, buffer, index); + } + } + } + writeCharacter<']'>(buffer, index); } }; @@ -276,171 +371,186 @@ namespace JsonifierInternal { return false; } - template struct SerializeImpl { - template inline static void op(const ValueType& value, BufferType&& buffer, uint64_t& index) { - writeCharacter('{', buffer, index); - using V = RefUnwrap; - static constexpr auto n = std::tuple_size_v>; + template struct serialize_impl { + template inline static void op(const value_type& value, buffer_type&& buffer, uint64_t& index) { + writeCharacter<'{'>(buffer, index); + using V = ref_unwrap; + static constexpr auto n = std::tuple_size_v>; bool first = true; forEach([&](auto x) { - static constexpr auto item = Tuplet::get(CoreV); + static constexpr auto item = tuplet::get(coreV); using ItemType = decltype(item); using MPtrT = std::tuple_element_t<1, ItemType>; - using ValT = MemberT; + using ValT = member_t; - if constexpr (NullT) { + if constexpr (null_t) { auto isNull = [&]() { if constexpr (std::is_member_pointer_v>) { - return !bool(value.*Tuplet::get<1>(item)); + return !bool(value.*tuplet::get<1>(item)); } else { - return !bool(Tuplet::get<1>(item)(value)); + return !bool(tuplet::get<1>(item)(value)); } }(); - if (isNull) + if (isNull()) { return; + } } if (first) { first = false; } else { - writeCharacter(',', buffer, index); + writeCharacter<','>(buffer, index); } - using Key = RefUnwrap>; + using key = ref_unwrap>; - if constexpr (StringT || CharT) { - static constexpr Jsonifier::StringView key = Tuplet::get<0>(item); + if constexpr (string_t || char_t) { + static constexpr jsonifier::string_view key = tuplet::get<0>(item); if constexpr (needsEscaping(key)) { - Serialize::op(key, buffer, index); - writeCharacter(':', buffer, index); + serialize::op(key, buffer, index); + writeCharacter<':'>(buffer, index); } else { static constexpr auto quoted = JoinV, key, Chars<"\":">>; writeCharacters(buffer, index); } } else { - static constexpr auto quoted = concatArrays(concatArrays("\"", Tuplet::get<0>(item)), "\":", ""); - Serialize::op(quoted, buffer, index); + static constexpr auto quoted = concatArrays(concatArrays("\"", tuplet::get<0>(item)), "\":", ""); + serialize::op(quoted, buffer, index); } - auto& newMember = getMember(value, Tuplet::get<1>(item)); - Serialize::op(newMember, buffer, index); + auto& newMember = getMember(value, tuplet::get<1>(item)); + serialize::op(newMember, buffer, index); }); - writeCharacter('}', buffer, index); + writeCharacter<'}'>(buffer, index); } }; - template struct SerializeImpl { - template inline static void op(const ValueType& value, BufferType&& buffer, uint64_t& index) { - writeCharacter('{', buffer, index); - using V = RefUnwrap; - static constexpr auto n = std::tuple_size_v>; + template struct serialize_impl { + template inline static void op(const value_type& value, buffer_type&& buffer, uint64_t& index) { + writeCharacter<'{'>(buffer, index); + using V = ref_unwrap; + static constexpr auto n = std::tuple_size_v>; bool first = true; forEach([&](auto x) { - static constexpr auto item = Tuplet::get(CoreV); + static constexpr auto item = tuplet::get(coreV); using ItemType = decltype(item); using MPtrT = std::tuple_element_t<1, ItemType>; - using ValT = MemberT; + using ValT = member_t; - if constexpr (NullT) { + if constexpr (null_t) { auto isNull = [&]() { if constexpr (std::is_member_pointer_v>) { - return !bool(value.*Tuplet::get<1>(item)); + return !bool(value.*tuplet::get<1>(item)); } else { - return !bool(Tuplet::get<1>(item)(value)); + return !bool(tuplet::get<1>(item)(value)); } }(); - if (isNull) + if (isNull()) { return; + } } - using Key = RefUnwrap>; + using key = ref_unwrap>; - if constexpr (StringT || CharT) { - static constexpr Jsonifier::StringView key = Tuplet::get<0>(item); + if constexpr (string_t || char_t) { + static constexpr jsonifier::string_view key = tuplet::get<0>(item); if (first) { first = false; } else { - writeCharacter(',', buffer, index); + writeCharacter<','>(buffer, index); } if constexpr (needsEscaping(key)) { - Serialize::op(key, buffer, index); - writeCharacter(':', buffer, index); + serialize::op(key, buffer, index); + writeCharacter<':'>(buffer, index); } else { static constexpr auto quoted = JoinV, key, Chars<"\":">>; writeCharacters(buffer, index); } } else { - static constexpr auto quoted = concatArrays(concatArrays("\"", Tuplet::get<0>(item)), "\":", ""); - Serialize::op(quoted, buffer, index); + static constexpr auto quoted = concatArrays(concatArrays("\"", tuplet::get<0>(item)), "\":", ""); + auto& newMember = quoted; + using MemberType = decltype(newMember); + if constexpr (has_excluded_keys) { + serialize::op(newMember, buffer, index, newMember.excludedKeys); + } else { + serialize::op(newMember, buffer, index); + } } - auto& newMember = getMember(value, Tuplet::get<1>(item)); + auto& newMember = getMember(value, tuplet::get<1>(item)); using MemberType = decltype(newMember); - if constexpr (HasExcludedKeys) { - Serialize::op(newMember, buffer, index, newMember.excludedKeys); + if constexpr (has_excluded_keys) { + serialize::op(newMember, buffer, index, newMember.excludedKeys); } else { - Serialize::op(newMember, buffer, index); + serialize::op(newMember, buffer, index); } }); - writeCharacter('}', buffer, index); + writeCharacter<'}'>(buffer, index); } - template inline static void op(const ValueType& value, BufferType&& buffer, uint64_t& index, const KeyType& excludedKeys) { - writeCharacter('{', buffer, index); - using V = RefUnwrap; - static constexpr auto n = std::tuple_size_v>; + template inline static void op(const value_type& value, buffer_type&& buffer, uint64_t& index, const KeyType& excludedKeys) { + writeCharacter<'{'>(buffer, index); + using V = ref_unwrap; + static constexpr auto n = std::tuple_size_v>; bool first = true; forEach([&](auto x) { - static constexpr auto item = Tuplet::get(CoreV); + static constexpr auto item = tuplet::get(coreV); using ItemType = decltype(item); using MPtrT = std::tuple_element_t<1, ItemType>; - using ValT = MemberT; + using ValT = member_t; - if constexpr (NullT) { + if constexpr (null_t) { auto isNull = [&]() { if constexpr (std::is_member_pointer_v>) { - return !bool(value.*Tuplet::get<1>(item)); + return !bool(value.*tuplet::get<1>(item)); } else { - return !bool(Tuplet::get<1>(item)(value)); + return !bool(tuplet::get<1>(item)(value)); } }(); - if (isNull) + if (isNull()) { return; + } } - using Key = RefUnwrap>; + using key = ref_unwrap>; - if constexpr (StringT || CharT) { - static constexpr Jsonifier::StringView key = Tuplet::get<0>(item); + if constexpr (string_t || char_t) { + static constexpr jsonifier::string_view key = tuplet::get<0>(item); if (excludedKeys.find(static_cast(key)) != excludedKeys.end()) { return; } if (first) { first = false; } else { - writeCharacter(',', buffer, index); + writeCharacter<','>(buffer, index); } if constexpr (needsEscaping(key)) { - Serialize::op(key, buffer, index); - writeCharacter(':', buffer, index); + serialize::op(key, buffer, index); + writeCharacter<':'>(buffer, index); } else { static constexpr auto quoted = JoinV, key, Chars<"\":">>; writeCharacters(buffer, index); } } else { - static constexpr auto quoted = concatArrays(concatArrays("\"", Tuplet::get<0>(item)), "\":", ""); - Serialize::op(quoted, buffer, index); + static constexpr auto quoted = concatArrays(concatArrays("\"", tuplet::get<0>(item)), "\":", ""); + auto& newMember = quoted; + using MemberType = decltype(newMember); + if constexpr (has_excluded_keys) { + serialize::op(newMember, buffer, index, newMember.excludedKeys); + } else { + serialize::op(newMember, buffer, index); + } } - auto& newMember = getMember(value, Tuplet::get<1>(item)); - using NewMemberType = decltype(newMember); - if constexpr (HasExcludedKeys) { - Serialize::op(newMember, buffer, index, newMember.excludedKeys); + auto& newMember = getMember(value, tuplet::get<1>(item)); + using MemberType = decltype(newMember); + if constexpr (has_excluded_keys) { + serialize::op(newMember, buffer, index, newMember.excludedKeys); } else { - Serialize::op(newMember, buffer, index); + serialize::op(newMember, buffer, index); } }); - writeCharacter('}', buffer, index); + writeCharacter<'}'>(buffer, index); } }; } diff --git a/Include/jsonifier/Serializer.hpp b/Include/jsonifier/Serializer.hpp index 7f2fcd547..d11b77e59 100644 --- a/Include/jsonifier/Serializer.hpp +++ b/Include/jsonifier/Serializer.hpp @@ -19,41 +19,40 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/// https://github.com/RealTimeChris/Jsonifier +/// https://github.com/RealTimeChris/jsonifier /// Feb 20, 2023 #pragma once #include #include -namespace JsonifierInternal { +namespace jsonifier_internal { - template struct SerializeImpl; + template struct serialize_impl; - template struct Serialize { - template inline static void op(ValueType&& value, BufferType&& buffer, uint64_t& index) { - SerializeImpl>::op(std::forward(value), std::forward(buffer), index); + template struct serialize { + template inline static void op(value_type&& value, buffer_type&& buffer, uint64_t& index) { + serialize_impl>::op(std::forward(value), std::forward(buffer), index); } - template inline static void op(ValueType&& value, BufferType&& buffer, uint64_t& index, const KeyType& keys) { - SerializeImpl>::op(std::forward(value), std::forward(buffer), index, keys); + template + inline static void op(value_type&& value, buffer_type&& buffer, uint64_t& index, const KeyType& keys) { + serialize_impl>::op(std::forward(value), std::forward(buffer), index, keys); } }; - class Serializer { + class serializer { public: - constexpr Serializer() noexcept = default; - - template inline void serializeJson(ValueType&& data, BufferType&& buffer) { + template inline void serializeJson(value_type&& data, buffer_type&& buffer) { uint64_t index{}; if constexpr (excludeKeys) { - if constexpr (HasExcludedKeys) { - Serialize::op(std::forward(data), stringBuffer, index, data.excludedKeys); + if constexpr (has_excluded_keys) { + serialize::op(std::forward(data), stringBuffer, index, data.excludedKeys); } else { - Serialize::op(std::forward(data), stringBuffer, index); + serialize::op(std::forward(data), stringBuffer, index); } } else { - Serialize::op(std::forward(data), stringBuffer, index); + serialize::op(std::forward(data), stringBuffer, index); } if (buffer.size() != index) [[unlikely]] { buffer.resize(index); @@ -62,7 +61,7 @@ namespace JsonifierInternal { } protected: - Jsonifier::String stringBuffer{}; + jsonifier::string stringBuffer{}; }; } diff --git a/Include/jsonifier/Simd.hpp b/Include/jsonifier/Simd.hpp index 7492ad2e2..867199c05 100644 --- a/Include/jsonifier/Simd.hpp +++ b/Include/jsonifier/Simd.hpp @@ -13,13 +13,13 @@ substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR a PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/// https://github.com/RealTimeChris/Jsonifier +/// https://github.com/RealTimeChris/jsonifier /// Feb 3, 2023 #pragma once @@ -27,212 +27,191 @@ #include #include -namespace JsonifierInternal { +namespace jsonifier_internal { - class StringBlockReader { + template class string_block_reader { public: - inline StringBlockReader(StringViewPtr stringViewNew, uint64_t lengthNew) noexcept { - lengthMinusStep = lengthNew < StepSize ? 0 : lengthNew - StepSize; - inString = stringViewNew; + using size_type = uint64_t; + + inline void reset(string_view_ptr stringViewNew, size_type lengthNew) { + lengthMinusStep = lengthNew < stepSize ? 0 : lengthNew - stepSize; + instring = stringViewNew; length = lengthNew; index = 0; } - inline uint64_t getRemainder(StringBufferPtr dest) const noexcept { + inline size_type getRemainder(string_buffer_ptr dest) const { if (length == index) { return 0; } - std::memset(dest, 0x20, StepSize * 2); - std::memcpy(dest, inString + index, (length - index)); + std::memset(dest, 0x20, stepSize); + std::memcpy(dest, instring + index, (length - index)); return length - index; } - inline StringViewPtr fullBlock() noexcept { - return inString + index; + inline string_view_ptr fullBlock() { + return instring + index; } inline void advanceIndex() { - index += StepSize * 2; + index += stepSize; } - inline bool hasFullBlock() const noexcept { - return index + StepSize < lengthMinusStep; + inline bool hasFullBlock() const { + return index < lengthMinusStep; } protected: - uint64_t lengthMinusStep{}; - StringViewPtr inString{}; - uint64_t length{}; - uint64_t index{}; + size_type lengthMinusStep{}; + string_view_ptr instring{}; + size_type length{}; + size_type index{}; }; - class SimdStringReader { + class simd_string_reader { public: using size_type = uint64_t; - inline SimdStringReader() noexcept = default; - inline SimdStringReader& operator=(SimdStringReader&& other) noexcept = default; - inline SimdStringReader(SimdStringReader&& other) noexcept = default; - inline SimdStringReader& operator=(const SimdStringReader& other) noexcept = delete; - inline SimdStringReader(const SimdStringReader& other) noexcept = delete; - - inline void reset(Jsonifier::StringViewBase stringViewNew) noexcept { - structuralIndices.resize(roundUpToMultipleOfEight(stringViewNew.size() / 2)); - stringView = stringViewNew; - currentValues.reset(); - nextIsEscaped.reset(); - storedLSB01 = false; - whitespace.reset(); - backslash.reset(); - prevInString = 0; + inline void reset(jsonifier::string_view_base stringViewNew) { + structuralIndices.clear(); + structuralIndices.resize(roundUpToMultipleOfEight(stringViewNew.size())); + stringBlockReader.reset(stringViewNew.data(), stringViewNew.size()); + stringView = stringViewNew; + storedLSB01 = false; + prevInstring = 0; stringIndex = 0; tapeIndex = 0; - quotes.reset(); - op.reset(); generateJsonIndices(); } - inline void generateJsonIndices() noexcept { - if (!stringView.empty()) [[likely]] { - StringBlockReader stringReader{ stringView.data(), stringView.size() }; - while (stringReader.hasFullBlock()) { - generateStructurals(stringReader.fullBlock()); - generateStructurals(stringReader.fullBlock() + StepSize); - stringReader.advanceIndex(); - } - uint8_t block[StepSize * 2]; - if (stringReader.getRemainder(block) > 0) { - generateStructurals(block); - generateStructurals(block + StepSize); - } + inline void generateJsonIndices() { + simd_base newPtr[StridesPerStep]{}; + simd_base nextIsEscaped{}; + simd_base currentValues{}; + simd_base whitespace{}; + simd_base backslash{}; + simd_base quotes{}; + simd_base op{}; + while (stringBlockReader.hasFullBlock()) { + generateStructurals(stringBlockReader.fullBlock(), newPtr, currentValues, whitespace, op, quotes, nextIsEscaped, backslash); + generateStructurals(stringBlockReader.fullBlock() + StepSize, newPtr, currentValues, whitespace, op, quotes, nextIsEscaped, backslash); + stringBlockReader.advanceIndex(); + } + uint8_t block[StepSize * 2]; + if (stringBlockReader.getRemainder(block) > 0) { + generateStructurals(block, newPtr, currentValues, whitespace, op, quotes, nextIsEscaped, backslash); + generateStructurals(block + StepSize, newPtr, currentValues, whitespace, op, quotes, nextIsEscaped, backslash); } } - inline size_type getStringLength() noexcept { + inline size_type getstringLength() { return stringView.size(); } - inline Jsonifier::StringViewBase getStringView() noexcept { + inline jsonifier::string_view_base getStringView() { return stringView; } - inline StructuralIndex* getStructurals() noexcept { + inline structural_index* getStructurals() { return structuralIndices.data(); } - inline ~SimdStringReader() noexcept {}; - protected: - inline static const SimdBaseReal oddBits{ makeSimdBase(0xAAAAAAAAAAAAAAAAULL) }; - Jsonifier::Vector structuralIndices{}; - Jsonifier::StringViewBase stringView{}; - SimdBaseReal nextIsEscaped{}; - SimdBaseReal currentValues{}; - SimdBaseReal whitespace{}; - SimdBaseReal backslash{}; - SimdBaseReal newPtr[8]{}; - uint64_t prevInString{}; - uint64_t stringIndex{}; - SimdBaseReal quotes{}; - uint64_t tapeIndex{}; + inline static const simd_base oddBits{ makeSimdBase(0xAAAAAAAAAAAAAAAAULL) }; + jsonifier::vector structuralIndices{}; + string_block_reader stringBlockReader{}; + jsonifier::string_view_base stringView{}; + size_type prevInstring{}; + size_type stringIndex{}; + size_type tapeIndex{}; bool storedLSB01{}; - SimdBaseReal op{}; - inline uint64_t roundUpToMultipleOfEight(uint64_t num) { - uint64_t remainder = num % 8; + inline size_type roundUpToMultipleOfEight(size_type num) { + size_type remainder = num % 8; if (remainder == 0) { return num; } return num + (8 - remainder); } - inline int64_t rollValuesIntoTape(uint64_t currentIndex, uint64_t x, int64_t newBits) noexcept { - structuralIndices[(currentIndex * 8) + tapeIndex] = stringView.data() + static_cast(tzCount64(newBits) + (x * 64ull) + stringIndex); - newBits = blsr(newBits); - structuralIndices[1 + (currentIndex * 8) + tapeIndex] = stringView.data() + static_cast(tzCount64(newBits) + (x * 64ull) + stringIndex); - newBits = blsr(newBits); - structuralIndices[2 + (currentIndex * 8) + tapeIndex] = stringView.data() + static_cast(tzCount64(newBits) + (x * 64ull) + stringIndex); - newBits = blsr(newBits); - structuralIndices[3 + (currentIndex * 8) + tapeIndex] = stringView.data() + static_cast(tzCount64(newBits) + (x * 64ull) + stringIndex); - newBits = blsr(newBits); - structuralIndices[4 + (currentIndex * 8) + tapeIndex] = stringView.data() + static_cast(tzCount64(newBits) + (x * 64ull) + stringIndex); - newBits = blsr(newBits); - structuralIndices[5 + (currentIndex * 8) + tapeIndex] = stringView.data() + static_cast(tzCount64(newBits) + (x * 64ull) + stringIndex); - newBits = blsr(newBits); - structuralIndices[6 + (currentIndex * 8) + tapeIndex] = stringView.data() + static_cast(tzCount64(newBits) + (x * 64ull) + stringIndex); - newBits = blsr(newBits); - structuralIndices[7 + (currentIndex * 8) + tapeIndex] = stringView.data() + static_cast(tzCount64(newBits) + (x * 64ull) + stringIndex); - newBits = blsr(newBits); - return newBits; - } - - inline void generateStructurals(StringViewPtr valueNew) noexcept { - for (uint64_t x = 0; x < 8; ++x) { - newPtr[x] = load(valueNew + (BytesPerStep * x)); + template inline size_type rollValuesIntoTape(size_type currentIndex, size_type newBits) { + if constexpr (index < 8) { + structuralIndices[index + (currentIndex * 8) + tapeIndex] = stringView.data() + static_cast(tzCount(newBits) + (index02 * 64ULL) + stringIndex); + newBits = blsr(newBits); + return rollValuesIntoTape(currentIndex, newBits); + } else { + return newBits; } + } + + template inline void collectStringValues(string_view_ptr valuesNew, simd_base* newPtr) { + if constexpr (index < StridesPerStep) { + newPtr[index] = load(valuesNew + (BytesPerStep * index)); + collectStringValues(valuesNew, newPtr); + } + } + + inline void generateStructurals(string_view_ptr valueNew, simd_base* newPtr, simd_base& currentValues, simd_base& whitespace, + simd_base& op, simd_base& quotes, simd_base& nextIsEscaped, simd_base& backslash) { + collectStringValues(valueNew, newPtr); whitespace.convertWhitespaceToSimdBase(newPtr); backslash.convertBackslashesToSimdBase(newPtr); op.convertStructuralsToSimdBase(newPtr); quotes.convertQuotesToSimdBase(newPtr); - addTapeValues(collectStructurals()); + addTapeValues(collectStructurals(currentValues, quotes, whitespace, op, backslash, nextIsEscaped)); stringIndex += StepSize; } - inline void addTapeValues(SimdBaseReal structurals) noexcept { - alignas(ALIGNMENT) int64_t newBits[SixtyFourPer]{}; - structurals.store(newBits); - for (uint64_t x = 0; x < SixtyFourPer; ++x) { - if (!newBits[x]) { - continue; + template inline void addTapeValues(simd_base&& structurals) { + alignas(JSONIFIER_ALIGNMENT) size_type newBits[StridesPerStep]{}; + structurals.store(newBits); + if constexpr (index < StridesPerStep) { + if (!newBits[index]) { + addTapeValues(std::forward>(structurals)); + return; } - auto cnt = popcnt(newBits[x]); - uint64_t rollsAmount = static_cast(std::ceil(static_cast(cnt) / 8.0f)); - for (uint64_t y = 0; y < rollsAmount; ++y) { - newBits[x] = rollValuesIntoTape(y, x, newBits[x]); + auto cnt = popcnt(newBits[index]); + size_type rollsAmount = static_cast(std::ceil(static_cast(cnt) / 8.0f)); + for (size_type y = 0; y < rollsAmount; ++y) { + newBits[index] = rollValuesIntoTape<0, index>(y, newBits[index]); } tapeIndex += cnt; + addTapeValues(std::forward>(structurals)); } } - inline SimdBaseReal collectEscapedCharacters() { + inline simd_base collectEscapedCharacters(simd_base& currentValues, simd_base& backslash, simd_base& nextIsEscaped) { if (backslash.operator bool()) { - currentValues = backslash.bitAndNot(nextIsEscaped).shl<1>(); - currentValues = currentValues | oddBits; - currentValues = currentValues - backslash.bitAndNot(nextIsEscaped); - currentValues = currentValues ^ oddBits; - SimdBaseReal escaped = currentValues ^ (backslash | nextIsEscaped); + currentValues = backslash.bitAndNot(nextIsEscaped).shl<1>(); + currentValues = currentValues | oddBits; + currentValues = currentValues - backslash.bitAndNot(nextIsEscaped); + currentValues = currentValues ^ oddBits; + simd_base escaped = currentValues ^ (backslash | nextIsEscaped); nextIsEscaped.setLSB((currentValues & backslash).checkMSB()); return escaped; - } else { return {}; } } - inline SimdBaseReal collectStructurals() noexcept { - currentValues = collectEscapedCharacters(); - quotes = quotes.bitAndNot(currentValues); - currentValues = quotes.carrylessMultiplication(prevInString); - SimdBaseReal stringTail = currentValues ^ quotes; - SimdBaseReal scalar = ~(op | whitespace); - currentValues = scalar.bitAndNot(quotes); - currentValues = currentValues.follows(storedLSB01); - currentValues = scalar.bitAndNot(currentValues); - currentValues = op | currentValues; - return currentValues.bitAndNot(stringTail); + inline simd_base collectStructurals(simd_base& currentValues, simd_base& quotes, simd_base& whitespace, simd_base& op, + simd_base& backslash, simd_base& nextIsEscaped) { + currentValues = collectEscapedCharacters(currentValues, backslash, nextIsEscaped); + quotes = quotes.bitAndNot(currentValues); + currentValues = quotes.carrylessMultiplication(prevInstring); + simd_base stringTail = currentValues ^ quotes; + simd_base scalar = ~(op | whitespace); + currentValues = scalar.bitAndNot(quotes); + currentValues = currentValues.follows(storedLSB01); + currentValues = scalar.bitAndNot(currentValues); + currentValues = op | currentValues; + currentValues = currentValues.bitAndNot(stringTail); + return currentValues; } }; } -#ifdef store - #undef store -#endif - -#ifdef load +#if defined(load) #undef load -#endif - -#ifdef set - #undef set -#endif +#endif \ No newline at end of file diff --git a/Include/jsonifier/String.hpp b/Include/jsonifier/String.hpp index 6b61a0e92..b6e9d71a7 100644 --- a/Include/jsonifier/String.hpp +++ b/Include/jsonifier/String.hpp @@ -19,65 +19,31 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/// https://github.com/RealTimeChris/Jsonifier +/// https://github.com/RealTimeChris/jsonifier /// Feb 20, 2023 #pragma once #include +#include -namespace JsonifierInternal { +namespace jsonifier_internal { - template constexpr bool stringConstCompare(const ValueType01& string01, const ValueType02& string02) { + template constexpr bool stringConstCompare(const value_type01& string01, const value_type02& string02) { if (string01.size() != string02.size()) [[unlikely]] { return false; } - using CharType = ValueType01::value_type; + using char_t = value_type01::value_type; for (uint64_t x = 0; x < string01.size(); ++x) { - if (string01[x] != static_cast(string02[x])) [[unlikely]] { + if (string01[x] != static_cast(string02[x])) [[unlikely]] { return false; } } return true; } - template using RefUnwrap = std::decay_t; + template class char_traits : public std::char_traits {}; - template - concept HasSize = requires(ValueType value) { - { value.size() }; - }; - - template - concept HasData = requires(ValueType value) { - { value.data() }; - }; - - template - concept Indexable = requires(ValueType value) { value[std::declval()]; } || requires(ValueType value) { value[std::declval()]; }; - - template - concept CharT = std::same_as || std::same_as || std::same_as || std::same_as || - std::same_as; - - template - concept SearchableStringValue = CharT || Indexable; - - template - concept HasDataAndSize = HasData && HasSize; - - template - concept HasSubstr = requires(ValueType value) { - { value.substr(std::declval(), std::declval()) }; - }; - - template - concept StringT = ( HasSubstr> && HasData> && HasSize> && - !std::same_as> ) || - std::derived_from || std::same_as; - - template class CharTraits : public std::char_traits {}; - - template<> class CharTraits { + template<> class char_traits { public: using value_type = uint8_t; using pointer = value_type*; @@ -120,245 +86,32 @@ namespace JsonifierInternal { } }; -}// namespace JsonifierInternal +}// namespace jsonifier_internal -namespace Jsonifier { +namespace jsonifier { - template class StringBase; + template class string_view_base; - template class StringOpBase { + template class string_base : protected jsonifier_internal::alloc_wrapper { public: - using value_type = ValueTypeInternal; - using size_type = uint64_t; - - inline const ValueTypeNew& getDerivedType() const { - return *static_cast(this); - } - - template inline size_type findLastOf(const StringType& valueToFind, size_type position = 0) const { - if constexpr (std::same_as, value_type> || std::same_as, value_type> || - std::same_as, char>) { - if (getDerivedType().sizeVal && position < getDerivedType().sizeVal) { - return JsonifierInternal::findLastSingleCharacter(getDerivedType().dataVal, getDerivedType().sizeVal - position, valueToFind); - } else { - return ValueTypeNew::npos; - } - } else if constexpr (std::is_pointer_v || std::is_array_v) { - auto sizeValNew = JsonifierInternal::CharTraits>>::length(valueToFind); - if (getDerivedType().sizeVal == 0 || sizeValNew == 0 || position >= getDerivedType().sizeVal) { - return ValueTypeNew::npos; - } - size_type currentHighestIndex{ 0 }; - for (size_type x = 0; x < sizeValNew; ++x) { - auto newIndex = JsonifierInternal::findLastSingleCharacter(getDerivedType().dataVal, getDerivedType().sizeVal - position, valueToFind[x]); - if (newIndex > currentHighestIndex && newIndex != ValueTypeNew::npos) { - currentHighestIndex = newIndex; - } - } - return currentHighestIndex == 0 ? ValueTypeNew::npos : currentHighestIndex - 1; - } else { - auto sizeValNew = valueToFind.size(); - if (getDerivedType().sizeVal == 0 || sizeValNew == 0 || position >= getDerivedType().sizeVal) { - return ValueTypeNew::npos; - } - size_type currentHighestIndex{ 0 }; - for (size_type x = 0; x < sizeValNew; ++x) { - auto newIndex = JsonifierInternal::findLastSingleCharacter(getDerivedType().dataVal, getDerivedType().sizeVal - position, valueToFind[x]); - if (newIndex > currentHighestIndex && newIndex != ValueTypeNew::npos) { - currentHighestIndex = newIndex; - } - } - return currentHighestIndex == 0 ? ValueTypeNew::npos : currentHighestIndex - 1; - } - } - - template inline size_type findFirstOf(const StringType& valueToFind, size_type position = 0) const { - if constexpr (std::same_as, value_type> || std::same_as, value_type> || - std::same_as, char>) { - if (getDerivedType().sizeVal && position < getDerivedType().sizeVal) { - return JsonifierInternal::findSingleCharacter(getDerivedType().dataVal, getDerivedType().sizeVal, valueToFind); - } else { - return ValueTypeNew::npos; - } - } else if constexpr (std::is_pointer_v || std::is_array_v) { - auto sizeValNew = JsonifierInternal::CharTraits>>::length(valueToFind); - if (getDerivedType().sizeVal == 0 || sizeValNew == 0 || position >= getDerivedType().sizeVal) { - return ValueTypeNew::npos; - } - size_type currentHighestIndex{ ValueTypeNew::npos }; - for (size_type x = 0; x < sizeValNew; ++x) { - auto newIndex = JsonifierInternal::findSingleCharacter(getDerivedType().dataVal + position, getDerivedType().sizeVal, valueToFind[x]); - if (newIndex < currentHighestIndex && newIndex != ValueTypeNew::npos) { - currentHighestIndex = newIndex; - } - } - return currentHighestIndex; - } else { - auto sizeValNew = valueToFind.size(); - if (getDerivedType().sizeVal == 0 || sizeValNew == 0 || position >= getDerivedType().sizeVal) { - return ValueTypeNew::npos; - } - size_type currentHighestIndex{ ValueTypeNew::npos }; - for (size_type x = 0; x < sizeValNew; ++x) { - auto newIndex = JsonifierInternal::findSingleCharacter(getDerivedType().dataVal + position, getDerivedType().sizeVal, valueToFind[x]); - if (newIndex < currentHighestIndex && newIndex != ValueTypeNew::npos) { - currentHighestIndex = newIndex; - } - } - return currentHighestIndex; - } - } - - template inline size_type findFirstNotOf(const StringType& valueToFind, size_type position = 0) const { - if constexpr (std::same_as, value_type> || std::same_as, value_type> || - std::same_as, char>) { - if (getDerivedType().sizeVal && position < getDerivedType().sizeVal) { - return JsonifierInternal::findFirstCharacterNotEqual(getDerivedType().dataVal, getDerivedType().sizeVal, valueToFind); - } else { - return ValueTypeNew::npos; - } - } else if constexpr (std::is_pointer_v || std::is_array_v) { - auto sizeValNew = JsonifierInternal::CharTraits>>::length(valueToFind); - if (getDerivedType().sizeVal == 0 || sizeValNew == 0 || position >= getDerivedType().sizeVal) { - return ValueTypeNew::npos; - } - size_type currentHighestIndex{ ValueTypeNew::npos }; - for (size_type x = position; x < getDerivedType().sizeVal; ++x) { - bool didWeFindOne{ false }; - for (size_type y = 0; y < sizeValNew; ++y) { - if (valueToFind[y] == getDerivedType().dataVal[x]) { - didWeFindOne = true; - break; - } - } - if (!didWeFindOne) { - return x; - } - } - return currentHighestIndex; - } else { - auto sizeValNew = valueToFind.size(); - if (getDerivedType().sizeVal == 0 || sizeValNew == 0 || position >= getDerivedType().sizeVal) { - return ValueTypeNew::npos; - } - size_type currentHighestIndex{ ValueTypeNew::npos }; - for (size_type x = position; x < getDerivedType().sizeVal; ++x) { - bool didWeFindOne{ false }; - for (size_type y = 0; y < sizeValNew; ++y) { - if (valueToFind[y] == getDerivedType().dataVal[x]) { - didWeFindOne = true; - break; - } - } - if (!didWeFindOne) { - return x; - } - } - return currentHighestIndex; - } - } - - template inline size_type find(StringType valueToFind, size_type position = 0) const { - if constexpr (std::same_as, value_type> || std::same_as, value_type> || - std::same_as, char>) { - if (getDerivedType().sizeVal && position < getDerivedType().sizeVal) { - return JsonifierInternal::findSingleCharacter(getDerivedType().dataVal, getDerivedType().sizeVal, valueToFind); - } else { - return ValueTypeNew::npos; - } - } else if constexpr (std::is_pointer_v || std::is_array_v) { - auto sizeValNew = JsonifierInternal::CharTraits>>::length(valueToFind); - if (getDerivedType().sizeVal == 0 || sizeValNew == 0 || position >= getDerivedType().sizeVal) { - return ValueTypeNew::npos; - } - auto firstVal = valueToFind[0]; - int64_t currentIndex{ static_cast(position) }; - while (currentIndex < static_cast(getDerivedType().sizeVal)) { - if (auto newIndex = JsonifierInternal::findSingleCharacter(getDerivedType().dataVal + currentIndex, getDerivedType().sizeVal - currentIndex, firstVal); - newIndex != ValueTypeNew::npos) { - bool doWeBreak{ false }; - if (currentIndex + sizeValNew <= getDerivedType().sizeVal) { - if (memcmp(valueToFind, getDerivedType().dataVal + currentIndex, sizeValNew) == 0) { - doWeBreak = true; - } - } else { - return ValueTypeNew::npos; - } - if (doWeBreak) { - return currentIndex; - } - if (newIndex == ValueTypeNew::npos) { - return ValueTypeNew::npos; - } else if (!newIndex) { - ++currentIndex; - } else { - currentIndex += newIndex; - } - } else { - ++currentIndex; - } - } - } else { - auto sizeValNew = valueToFind.size(); - if (getDerivedType().sizeVal == 0 || sizeValNew == 0 || position >= getDerivedType().sizeVal) { - return ValueTypeNew::npos; - } - auto firstVal = valueToFind[0]; - int64_t currentIndex{ static_cast(position) }; - while (currentIndex < static_cast(getDerivedType().sizeVal)) { - if (auto newIndex = JsonifierInternal::findSingleCharacter(getDerivedType().dataVal + currentIndex, getDerivedType().sizeVal - currentIndex, firstVal); - newIndex != ValueTypeNew::npos) { - bool doWeBreak{ false }; - if (currentIndex + sizeValNew <= getDerivedType().sizeVal) { - if (memcmp(valueToFind.data(), getDerivedType().dataVal + currentIndex, sizeValNew) == 0) { - doWeBreak = true; - } - } else { - return ValueTypeNew::npos; - } - if (doWeBreak) { - return currentIndex; - } - if (newIndex == ValueTypeNew::npos) { - return ValueTypeNew::npos; - } else if (!newIndex) { - ++currentIndex; - } else { - currentIndex += newIndex; - } - } else { - ++currentIndex; - } - } - return ValueTypeNew::npos; - } - } - }; - - template class StringViewBase; - - template class StringBase : public StringOpBase, ValueType>, protected JsonifierInternal::AllocWrapper { - public: - using value_type = ValueType; + using value_type = value_type_new; using pointer = value_type*; using const_pointer = const value_type*; using reference = value_type&; using const_reference = const value_type&; - using iterator = JsonifierInternal::Iterator; - using const_iterator = JsonifierInternal::Iterator; + using iterator = jsonifier_internal::iterator; + using const_iterator = jsonifier_internal::iterator; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; using size_type = uint64_t; - using allocator = JsonifierInternal::AllocWrapper; - using traits_type = JsonifierInternal::CharTraits; - - friend StringOpBase; + using allocator = jsonifier_internal::alloc_wrapper; + using traits_type = jsonifier_internal::char_traits; - inline StringBase() noexcept : capacityVal{}, sizeVal{}, dataVal{} {}; + inline string_base() : capacityVal{}, sizeVal{}, dataVal{} {}; - static inline size_type npos{ std::numeric_limits::max() }; + static constexpr size_type npos{ std::numeric_limits::max() }; - inline StringBase& operator=(StringBase&& other) noexcept { + inline string_base& operator=(string_base&& other) noexcept { if (this != &other) { reset(); swap(other); @@ -366,149 +119,206 @@ namespace Jsonifier { return *this; } - inline explicit StringBase(StringBase&& other) noexcept : capacityVal{}, sizeVal{}, dataVal{} { + inline explicit string_base(string_base&& other) noexcept : capacityVal{}, sizeVal{}, dataVal{} { *this = std::move(other); } - inline StringBase& operator=(const StringBase& other) { + inline string_base& operator=(const string_base& other) { if (this != &other) { size_type sizeNew = other.size(); if (sizeNew > 0) { reset(); - StringBase temp{}; + string_base temp{}; temp.resize(sizeNew); std::memcpy(temp.dataVal, other.data(), sizeNew); + temp.getAlloc().construct(&temp[sizeNew], '\0'); swap(temp); } } return *this; } - inline StringBase(const StringBase& other) noexcept : capacityVal{}, sizeVal{}, dataVal{} { + inline string_base(const string_base& other) : capacityVal{}, sizeVal{}, dataVal{} { *this = other; } - template inline StringBase& operator=(const ValueTypeNew& other) noexcept { - size_type sizeNew = other.size(); + template inline string_base& operator=(value_type_newer&& other) { + size_type sizeNew = other.size() * (sizeof(typename jsonifier_internal::ref_unwrap::value_type) / sizeof(value_type)); if (sizeNew > 0) { reset(); - StringBase temp{}; + string_base temp{}; temp.resize(sizeNew); std::memcpy(temp.dataVal, other.data(), sizeNew); + temp.getAlloc().construct(&temp[sizeNew], '\0'); swap(temp); } return *this; } - template inline explicit StringBase(const ValueTypeNew& other) noexcept : capacityVal{}, sizeVal{}, dataVal{} { + template inline explicit string_base(value_type_newer&& other) : capacityVal{}, sizeVal{}, dataVal{} { + *this = std::forward(other); + } + + template inline string_base& operator=(const value_type_newer& other) { + size_type sizeNew = std::size(other) - 1 * (sizeof(value_type_new) / sizeof(value_type)); + if (sizeNew > 0) { + reset(); + string_base temp{}; + temp.resize(sizeNew); + std::memcpy(temp.dataVal, other, sizeNew); + temp.getAlloc().construct(&temp[sizeNew], '\0'); + swap(temp); + } + return *this; + } + + template inline string_base(const value_type_newer& other) : capacityVal{}, sizeVal{}, dataVal{} { *this = other; } - template inline StringBase& operator=(const ValueTypeNew* other) noexcept { - auto sizeNew = JsonifierInternal::CharTraits::length(other); + template inline string_base& operator=(value_type_newer&& other) { + auto sizeNew = + jsonifier_internal::char_traits>::length(other) * (sizeof(std::remove_pointer_t) / sizeof(value_type)); if (sizeNew) [[likely]] { reset(); - StringBase temp{}; + string_base temp{}; temp.resize(sizeNew); std::memcpy(temp.dataVal, other, sizeNew); + temp.getAlloc().construct(&temp[sizeNew], '\0'); swap(temp); } return *this; } - template inline StringBase(const ValueTypeNew* other) noexcept : capacityVal{}, sizeVal{}, dataVal{} { - *this = other; + template inline string_base(value_type_newer&& other) : capacityVal{}, sizeVal{}, dataVal{} { + *this = std::forward(other); } - inline StringBase(const_pointer other, uint64_t sizeNew) noexcept : capacityVal{}, sizeVal{}, dataVal{} { + inline string_base(const_pointer other, uint64_t sizeNew) : capacityVal{}, sizeVal{}, dataVal{} { if (sizeNew) [[likely]] { reset(); - StringBase temp{}; + string_base temp{}; temp.resize(sizeNew); std::memcpy(temp.dataVal, other, sizeNew); + temp.getAlloc().construct(&temp[sizeNew], '\0'); swap(temp); } } - inline StringBase substr(size_type position, size_type count = std::numeric_limits::max()) const { + inline string_base substr(size_type position, size_type count = std::numeric_limits::max()) const { if (position >= sizeVal) { throw std::out_of_range("Substring position is out of range."); } count = std::min(count, sizeVal - position); - StringBase result{}; - result.resize(count); - std::memcpy(result.dataVal, dataVal + position, count * sizeof(value_type)); - result.getAlloc().construct(&result.dataVal[count], '\0'); - + string_base result{}; + if (count > 0) { + result.resize(count); + std::memcpy(result.dataVal, dataVal + position, count * sizeof(value_type)); + result.getAlloc().construct(&result.dataVal[count], static_cast('\0')); + } return result; } - inline iterator begin() noexcept { + inline iterator begin() { return iterator(dataVal); } - inline const_iterator begin() const noexcept { - return const_iterator(dataVal); + inline iterator end() { + return iterator(dataVal + sizeVal); } - inline iterator end() noexcept { - return iterator(dataVal + sizeVal); + inline const_iterator begin() const { + return const_iterator(dataVal); } - inline const_iterator end() const noexcept { + inline const_iterator end() const { return const_iterator(dataVal + sizeVal); } - inline reverse_iterator rbegin() noexcept { + inline reverse_iterator rbegin() { return reverse_iterator(end()); } - inline const_reverse_iterator rbegin() const noexcept { - return const_reverse_iterator(end()); + inline reverse_iterator rend() { + return reverse_iterator(begin()); } - inline reverse_iterator rend() noexcept { - return reverse_iterator(begin()); + inline const_iterator cbegin() const { + return const_iterator(begin()); + } + + inline const_iterator cend() const { + return const_iterator(end()); + } + + inline const_reverse_iterator crbegin() const { + return const_reverse_iterator(cend()); + } + + inline const_reverse_iterator crend() const { + return const_reverse_iterator(cbegin()); + } + + inline size_type find(const_pointer args, size_type position = 0) const { + auto newSize = traits_type::length(args); + if (position + newSize > sizeVal) { + return npos; + } + auto foundValue = jsonifier_internal::find(dataVal + position, sizeVal - position, args, newSize); + return foundValue == npos ? npos : foundValue + position; } - inline const_reverse_iterator rend() const noexcept { - return const_reverse_iterator(begin()); + template inline size_type find(value_type_newer args, size_type position = 0) const { + value_type newValue{ static_cast(args) }; + if (position + 1 > sizeVal) { + return npos; + } + auto foundValue = jsonifier_internal::find(dataVal + position, sizeVal - position, &newValue, 1); + return foundValue == npos ? npos : foundValue + position; + } + + template inline size_type find(const value_type_newer& args, size_type position = 0) const { + if (position + args.size() > sizeVal) { + return npos; + } + auto foundValue = jsonifier_internal::find(dataVal + position, sizeVal - position, args.data(), args.size()); + return foundValue == npos ? npos : foundValue + position; } - inline const_iterator cbegin() const noexcept { - return begin(); + template inline size_type findFirstOf(ArgTypes&&... args) const { + return this->operator std::basic_string_view().find_first_of(std::forward(args)...); } - inline const_iterator cend() const noexcept { - return end(); + template inline size_type findLastOf(ArgTypes&&... args) const { + return this->operator std::basic_string_view().find_last_of(std::forward(args)...); } - inline const_reverse_iterator crbegin() const noexcept { - return rbegin(); + template inline size_type findFirstNotOf(ArgTypes&&... args) const { + return this->operator std::basic_string_view().find_first_not_of(std::forward(args)...); } - inline const_reverse_iterator crend() const noexcept { - return rend(); + template inline size_type findLastNotOf(ArgTypes&&... args) const { + return this->operator std::basic_string_view().find_last_not_of(std::forward(args)...); } - inline void append(const StringBase& sizeNew) { + inline void append(const string_base& sizeNew) { if (sizeVal + sizeNew.size() > capacityVal) { reserve(sizeVal + sizeNew.size()); } std::memcpy(dataVal + sizeVal, sizeNew.data(), sizeNew.size()); sizeVal += sizeNew.size(); - getAlloc().construct(&dataVal[sizeVal], '\0'); + getAlloc().construct(&dataVal[sizeVal], static_cast('\0')); } - inline void append(const_pointer valuesNew, uint64_t sizeNew) { + template inline void append(const value_type_newer* valuesNew, uint64_t sizeNew) { if (sizeVal + sizeNew > capacityVal) { reserve(sizeVal + sizeNew); } std::memcpy(dataVal + sizeVal, valuesNew, sizeNew); sizeVal += sizeNew; - getAlloc().construct(&dataVal[sizeVal], '\0'); + getAlloc().construct(&dataVal[sizeVal], static_cast('\0')); } template inline void insert(Iterator01 where, Iterator02 start, Iterator02 end) { @@ -526,7 +336,7 @@ namespace Jsonifier { std::memmove(dataVal + posNew + sizeNew, dataVal + posNew, (sizeVal - posNew) * sizeof(value_type)); std::memcpy(dataVal + posNew, start.operator->(), sizeNew * sizeof(value_type)); sizeVal += sizeNew; - getAlloc().construct(&dataVal[sizeVal], '\0'); + getAlloc().construct(&dataVal[sizeVal], static_cast('\0')); } inline void insert(iterator valuesNew, value_type toInsert) { @@ -548,7 +358,7 @@ namespace Jsonifier { } traits_type::move(dataVal, dataVal + count, sizeVal - count); sizeVal -= count; - getAlloc().construct(&dataVal[sizeVal], '\0'); + getAlloc().construct(&dataVal[sizeVal], static_cast('\0')); } inline void erase(iterator count) { @@ -560,7 +370,7 @@ namespace Jsonifier { } traits_type::move(dataVal, dataVal + sizeNew, sizeVal - sizeNew); sizeVal -= sizeNew; - getAlloc().construct(&dataVal[sizeVal], '\0'); + getAlloc().construct(&dataVal[sizeVal], static_cast('\0')); } inline void pushBack(value_type value) { @@ -568,7 +378,7 @@ namespace Jsonifier { reserve((sizeVal + 2) * 4); } getAlloc().construct(&dataVal[sizeVal++], value); - getAlloc().construct(&dataVal[sizeVal], '\0'); + getAlloc().construct(&dataVal[sizeVal], static_cast('\0')); } inline const_reference at(size_type index) const { @@ -585,30 +395,30 @@ namespace Jsonifier { return dataVal[index]; } - inline const_reference operator[](size_type index) const noexcept { + inline const_reference operator[](size_type index) const { return dataVal[index]; } - inline reference operator[](size_type index) noexcept { + inline reference operator[](size_type index) { return dataVal[index]; } - inline std::string_view stringView(size_type offSet, size_type count) const noexcept { + inline std::string_view stringView(size_type offSet, size_type count) const { return std::string_view{ data() + offSet, count }; } - template inline explicit operator std::enable_if_t, std::string_view>() const { + inline operator std::basic_string_view() const { return { dataVal, sizeVal }; } - inline operator std::string() const { - std::basic_string returnValue{}; + template inline explicit operator std::basic_string() const { + std::basic_string returnValue{}; returnValue.resize(sizeVal); std::memcpy(returnValue.data(), data(), returnValue.size()); return returnValue; } - inline void clear() noexcept { + inline void clear() { sizeVal = 0; } @@ -619,157 +429,154 @@ namespace Jsonifier { inline void resize(size_type sizeNew) { if (sizeNew > 0) [[likely]] { if (sizeNew > capacityVal) [[likely]] { - pointer newPtr = getAlloc().allocate(sizeNew + 1); + const size_type sizeNewer = (sizeNew + JSONIFIER_ALIGNMENT - 1) / JSONIFIER_ALIGNMENT * JSONIFIER_ALIGNMENT; + pointer newPtr = getAlloc().allocate(sizeNewer + 1); try { if (dataVal) [[likely]] { std::uninitialized_move(dataVal, dataVal + sizeVal, newPtr); getAlloc().deallocate(dataVal, capacityVal + 1); } } catch (...) { - getAlloc().deallocate(newPtr, sizeNew + 1); + getAlloc().deallocate(newPtr, sizeNewer + 1); throw; } - capacityVal = sizeNew; + capacityVal = sizeNewer; dataVal = newPtr; std::uninitialized_value_construct(dataVal + sizeVal, dataVal + capacityVal); } else if (sizeNew > sizeVal) [[unlikely]] { std::uninitialized_value_construct(dataVal + sizeVal, dataVal + capacityVal); } sizeVal = sizeNew; - getAlloc().construct(&dataVal[sizeVal], '\0'); + getAlloc().construct(&dataVal[sizeVal], static_cast('\0')); } else { sizeVal = 0; } } - inline void reserve(size_t capacityValNew) { - if (capacityValNew > capacityVal) [[likely]] { - pointer newPtr = getAlloc().allocate(capacityValNew + 1); + + inline void reserve(size_type sizeNew) { + if (sizeNew > capacityVal) [[likely]] { + const size_type sizeNewer = (sizeNew + JSONIFIER_ALIGNMENT - 1) / JSONIFIER_ALIGNMENT * JSONIFIER_ALIGNMENT; + pointer newPtr = getAlloc().allocate(sizeNewer + 1); try { if (dataVal && sizeVal) [[likely]] { std::uninitialized_move(dataVal, dataVal + sizeVal, newPtr); getAlloc().deallocate(dataVal, capacityVal + 1); } } catch (...) { - getAlloc().deallocate(newPtr, capacityValNew + 1); + getAlloc().deallocate(newPtr, sizeNewer + 1); throw; } - - capacityVal = capacityValNew; + capacityVal = sizeNewer; dataVal = newPtr; } } - inline size_type capacity() const noexcept { + inline size_type capacity() const { return capacityVal; } - inline size_type size() const noexcept { + inline size_type size() const { return sizeVal; } - inline bool empty() const noexcept { + inline bool empty() const { return sizeVal == 0; } - inline pointer data() const noexcept { + inline pointer data() const { return dataVal; } - inline bool operator==(const pointer rhs) const { - if (traits_type::length(rhs) != size()) { + template + inline friend std::enable_if_t, bool> operator==(const string_base& lhs, const value_type_newer& rhs) { + auto rhsLength = traits_type::length(rhs); + if (lhs.size() != rhsLength) { return false; } - return JsonifierInternal::JsonifierCoreInternal::compare(rhs, data(), size()); + return jsonifier_internal::jsonifier_core_internal::compare(rhs, lhs.data(), rhsLength); } - template inline bool operator==(const value_type (&other)[strLength]) const { - if ((strLength - 1) != size()) { + template inline bool operator==(const value_type_newer& rhs) { + auto rhsLength = std::size(rhs) - 1; + if (size() != rhsLength) { return false; } - return JsonifierInternal::JsonifierCoreInternal::compare(other, data(), size()); + return jsonifier_internal::jsonifier_core_internal::compare(rhs, data(), rhsLength); } - template inline friend bool operator==(const StringBase& lhs, const ValueTypeNew& rhs) { + template inline friend bool operator==(const string_base& lhs, const value_type_newer& rhs) { if (rhs.size() != lhs.size()) { return false; } - return JsonifierInternal::JsonifierCoreInternal::compare(rhs.data(), lhs.data(), rhs.size()); - } - - template inline friend bool operator==(const ValueTypeNew* lhs, const StringBase& rhs) { - auto lhsSize = traits_type::length(lhs); - if (rhs.size() != lhsSize) { - return false; - } - return JsonifierInternal::JsonifierCoreInternal::compare(rhs.data(), lhs, lhsSize); + return jsonifier_internal::jsonifier_core_internal::compare(rhs.data(), lhs.data(), rhs.size()); } - inline void swap(StringBase& other) { + inline void swap(string_base& other) { std::swap(capacityVal, other.capacityVal); std::swap(sizeVal, other.sizeVal); std::swap(dataVal, other.dataVal); } - template inline friend StringBase operator+(const StringTypeNew& lhs, const StringBase& rhs) { - StringBase newLhs{ lhs }; + template inline friend string_base operator+(const value_type_newer (&lhs)[N], const string_base& rhs) { + string_base newLhs{ lhs }; newLhs += rhs; return newLhs; } - template inline friend StringBase operator+=(const StringTypeNew& lhs, const StringBase& rhs) { - StringBase newLhs{ lhs }; + template inline friend string_base operator+=(const value_type_newer (&lhs)[N], const string_base& rhs) { + string_base newLhs{ lhs }; newLhs += rhs; return newLhs; } - template inline friend StringBase operator+(const value_type (&lhs)[size], const StringBase& rhs) { - StringBase newLhs{ lhs }; + template inline friend string_base operator+(string_type_new&& lhs, const string_base& rhs) { + string_base newLhs{ lhs }; newLhs += rhs; return newLhs; } - template inline friend StringBase operator+=(const value_type (&lhs)[size], const StringBase& rhs) { - StringBase newLhs{ lhs }; + template inline friend string_base operator+=(string_type_new&& lhs, const string_base& rhs) { + string_base newLhs{ lhs }; newLhs += rhs; return newLhs; } - template inline StringBase operator+(const value_type (&rhs)[strLength]) { - StringBase newLhs{ *this }; - newLhs += rhs; + inline string_base operator+(const value_type& rhs) { + string_base newLhs{ *this }; + newLhs.pushBack(rhs); return newLhs; } - template inline StringBase& operator+=(const value_type (&rhs)[strLength]) { - StringBase newRhs{ rhs }; - append(newRhs); + inline string_base& operator+=(const value_type& rhs) { + pushBack(rhs); return *this; } - inline StringBase operator+(const value_type& rhs) { - StringBase newLhs{ *this }; - newLhs.pushBack(rhs); + template inline string_base operator+(const string_type_new& rhs) const { + string_base newLhs{ *this }; + newLhs += rhs; return newLhs; } - inline StringBase& operator+=(const value_type& rhs) { - pushBack(rhs); + template inline string_base& operator+=(const string_type_new& rhs) { + append(rhs.data(), rhs.size()); return *this; } - template inline StringBase operator+(const StringTypeNew& rhs) noexcept { - StringBase newLhs{ *this }; + template inline string_base operator+(const value_type_newer (&rhs)[N]) const { + string_base newLhs{ *this }; newLhs += rhs; return newLhs; } - template inline StringBase& operator+=(const StringTypeNew& rhs) noexcept { - append(rhs.data(), rhs.size()); + template inline string_base& operator+=(const value_type_newer (&rhs)[N]) { + string_base newLhs{ rhs }; + *this += newLhs; return *this; } - inline ~StringBase() { + inline ~string_base() { reset(); } @@ -784,18 +591,21 @@ namespace Jsonifier { inline void reset() { if (dataVal && capacityVal) { + if (sizeVal) { + std::destroy(dataVal, dataVal + sizeVal + 1); + sizeVal = 0; + } getAlloc().deallocate(dataVal, capacityVal + 1); dataVal = nullptr; - sizeVal = 0; capacityVal = 0; } } }; - using String = StringBase; + using string = string_base; - template inline std::ostream& operator<<(std::ostream& os, const StringBase& string) { + template inline std::ostream& operator<<(std::ostream& os, const string_base& string) { os << string.operator typename std::string(); return os; } -}// namespace Jsonifier +}// namespace jsonifier diff --git a/Include/jsonifier/StringUtils.hpp b/Include/jsonifier/StringUtils.hpp index a9453db90..b4fe3719c 100644 --- a/Include/jsonifier/StringUtils.hpp +++ b/Include/jsonifier/StringUtils.hpp @@ -19,7 +19,7 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/// https://github.com/RealTimeChris/Jsonifier +/// https://github.com/RealTimeChris/jsonifier /// Feb 3, 2023 /// Most of the code in this header was sampled fromSimdjson - https://github.com/simdjson #pragma once @@ -30,16 +30,16 @@ #include #include -namespace JsonifierInternal { +namespace jsonifier_internal { - template class BackslashAndQuote { + template class backslash_and_quote { public: - static const StringParsingType bytesProcessed = BytesPerStep; + static constexpr string_parsing_type bytesProcessed = BytesPerStep; - inline BackslashAndQuote static copyAndFind(StringViewPtr source, StringBufferPtr dest) { - SimdBase values(source); + inline backslash_and_quote static copyAndFind(string_view_ptr source, string_buffer_ptr dest) { + simd_base_internal values(source); values.store(dest); - BackslashAndQuote returnData{}; + backslash_and_quote returnData{}; returnData.bsBits = { values == uint8_t{ '\\' } }; returnData.quoteBits = { values == uint8_t{ '\"' } }; return returnData; @@ -53,28 +53,28 @@ namespace JsonifierInternal { return ((quoteBits - 1) & bsBits) != 0; } - inline StringParsingType quoteIndex() { + inline string_parsing_type quoteIndex() { return tzCount(quoteBits); } - inline StringParsingType backslashIndex() { + inline string_parsing_type backslashIndex() { return tzCount(bsBits); } protected: - StringParsingType quoteBits{}; - StringParsingType bsBits{}; + string_parsing_type quoteBits{}; + string_parsing_type bsBits{}; }; - inline uint32_t hexToU32NoCheck(StringViewPtr source) { - uint32_t v1 = digitToVal32[630ull + source[0]]; - uint32_t v2 = digitToVal32[420ull + source[1]]; - uint32_t v3 = digitToVal32[210ull + source[2]]; - uint32_t v4 = digitToVal32[0ull + source[3]]; + inline uint32_t hexToU32NoCheck(string_view_ptr source) { + uint32_t v1 = digitToVal32[630ULL + source[0]]; + uint32_t v2 = digitToVal32[420ULL + source[1]]; + uint32_t v3 = digitToVal32[210ULL + source[2]]; + uint32_t v4 = digitToVal32[0ULL + source[3]]; return v1 | v2 | v3 | v4; } - inline uint64_t codePointToUtf8(uint32_t codePoint, StringBufferPtr c) { + inline uint64_t codePointToUtf8(uint32_t codePoint, string_buffer_ptr c) { if (codePoint <= 0x7F) { c[0] = uint8_t(codePoint); return 1; @@ -98,12 +98,12 @@ namespace JsonifierInternal { return 0; } - inline bool handleUnicodeCodePoint(StringViewPtr* srcPtr, StringBufferPtr* dstPtr) { + inline bool handleUnicodeCodePoint(string_view_ptr* srcPtr, string_buffer_ptr* dstPtr) { constexpr uint32_t subCodePoint = 0xfffd; uint32_t codePoint = hexToU32NoCheck(*srcPtr + 2); *srcPtr += 6; if (codePoint >= 0xd800 && codePoint < 0xdc00) { - StringViewPtr srcData = *srcPtr; + string_view_ptr srcData = *srcPtr; if (((srcData[0] << 8) | srcData[1]) != ((static_cast('\\') << 8) | static_cast('u'))) { codePoint = subCodePoint; } else { @@ -124,9 +124,9 @@ namespace JsonifierInternal { return offset > 0; } - inline StringBufferPtr parseString(StringViewPtr source, StringBufferPtr dest, uint64_t maxLength) { + inline string_buffer_ptr parsestring(string_view_ptr source, string_buffer_ptr dest, int64_t maxLength) { while (maxLength > 0) { - auto bsQuote = BackslashAndQuote::copyAndFind(source, dest); + auto bsQuote = backslash_and_quote>::copyAndFind(source, dest); if (bsQuote.hasQuoteFirst()) { return dest + bsQuote.quoteIndex(); } @@ -134,8 +134,8 @@ namespace JsonifierInternal { auto bsDist = bsQuote.backslashIndex(); uint8_t escape_char = source[bsDist + 1]; if (escape_char == 'u') { - source += bsDist; maxLength -= bsDist; + source += bsDist; dest += bsDist; if (!handleUnicodeCodePoint(&source, &dest)) { return nullptr; @@ -146,21 +146,21 @@ namespace JsonifierInternal { return nullptr; } dest[bsDist] = escapeResult; - maxLength -= bsDist + 2ull; - source += bsDist + 2ull; - dest += bsDist + 1ull; + maxLength -= bsDist + 1ULL; + source += bsDist + 2ULL; + dest += bsDist + 1ULL; } } else { - maxLength -= BackslashAndQuote::bytesProcessed; - source += BackslashAndQuote::bytesProcessed; - dest += BackslashAndQuote::bytesProcessed; + maxLength -= backslash_and_quote>::bytesProcessed; + source += backslash_and_quote>::bytesProcessed; + dest += backslash_and_quote>::bytesProcessed; } } return nullptr; } - inline bool parseBool(StringViewPtr json) { + inline bool parseBool(string_view_ptr json) { uint8_t valueNew[5]{ "true" }; return std::memcmp(valueNew, json, 4) == 0; } -}// namespace JsonifierInternal +}// namespace jsonifier_internal diff --git a/Include/jsonifier/StringView.hpp b/Include/jsonifier/StringView.hpp index 5f6bb125f..5955adcde 100644 --- a/Include/jsonifier/StringView.hpp +++ b/Include/jsonifier/StringView.hpp @@ -19,105 +19,79 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/// https://github.com/RealTimeChris/Jsonifier +/// https://github.com/RealTimeChris/jsonifier /// Feb 20, 2023 #pragma once #include -namespace Jsonifier { +namespace jsonifier { - template class StringViewBase : public StringOpBase, ValueType> { + template class string_view_base { public: - using value_type = ValueType; + using value_type = value_type_new; using pointer = value_type*; using const_pointer = const value_type*; using reference = value_type&; using const_reference = const value_type&; - using iterator = JsonifierInternal::Iterator; - using const_iterator = JsonifierInternal::Iterator; + using iterator = jsonifier_internal::iterator; + using const_iterator = jsonifier_internal::iterator; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; using size_type = uint64_t; - using allocator = JsonifierInternal::AllocWrapper; - using traits_type = JsonifierInternal::CharTraits; + using allocator = jsonifier_internal::alloc_wrapper; + using traits_type = jsonifier_internal::char_traits; const_pointer dataVal{}; size_type sizeVal{}; - friend StringOpBase; + static constexpr size_type npos{ std::numeric_limits::max() }; - static constexpr auto npos{ std::numeric_limits::max() }; - - constexpr StringViewBase() noexcept : dataVal(), sizeVal(0) { + constexpr string_view_base() : dataVal(), sizeVal(0) { } - template constexpr StringViewBase& operator=(const ValueTypeNew& stringNew) { + template constexpr string_view_base& operator=(const value_type_newer& stringNew) { dataVal = stringNew.data(); sizeVal = stringNew.size(); return *this; } - template constexpr StringViewBase(const ValueTypeNew& stringNew) { + template constexpr string_view_base(const value_type_newer& stringNew) { *this = stringNew; } - template constexpr StringViewBase(const value_type (&other)[strLength]) { + template constexpr string_view_base(const value_type (&other)[strLength]) { dataVal = other; sizeVal = strLength; } - constexpr StringViewBase(const_pointer pointerNew) noexcept : dataVal(pointerNew), sizeVal(traits_type::length(pointerNew)) { + constexpr string_view_base(const_pointer pointerNew) : dataVal(pointerNew), sizeVal(traits_type::length(pointerNew)) { } - constexpr StringViewBase(const_pointer pointerNew, const size_type countNew) noexcept : dataVal(pointerNew), sizeVal(countNew){}; - - constexpr const_iterator begin() noexcept { - return const_iterator(dataVal); - } + constexpr string_view_base(const_pointer pointerNew, const size_type countNew) : dataVal(pointerNew), sizeVal(countNew){}; - constexpr const_iterator begin() const noexcept { + constexpr const_iterator begin() const { return const_iterator(dataVal); } - constexpr const_iterator end() noexcept { + constexpr const_iterator end() const { return const_iterator(dataVal + sizeVal); } - constexpr const_iterator end() const noexcept { - return const_iterator(dataVal + sizeVal); - } - - constexpr reverse_iterator rbegin() noexcept { - return reverse_iterator(end()); - } - - constexpr const_reverse_iterator rbegin() const noexcept { - return const_reverse_iterator(end()); - } - - constexpr reverse_iterator rend() noexcept { - return reverse_iterator(begin()); + constexpr const_iterator cbegin() const { + return const_iterator(begin()); } - constexpr const_reverse_iterator rend() const noexcept { - return const_reverse_iterator(begin()); + constexpr const_iterator cend() const { + return const_iterator(end()); } - constexpr const_iterator cbegin() const noexcept { - return begin(); + constexpr const_reverse_iterator crbegin() const { + return const_reverse_iterator(cend()); } - constexpr const_iterator cend() const noexcept { - return end(); - } - - constexpr const_reverse_iterator crbegin() const noexcept { - return rbegin(); - } - - constexpr const_reverse_iterator crend() const noexcept { - return rend(); + constexpr const_reverse_iterator crend() const { + return const_reverse_iterator(cbegin()); } constexpr size_type size() const { @@ -142,7 +116,7 @@ namespace Jsonifier { constexpr const_reference at(const size_type offsetNew) const { if (offsetNew >= sizeVal) { - throw std::out_of_range{ "Sorry, but that index is beyond the end of this StringView instance." }; + throw std::out_of_range{ "Sorry, but that index is beyond the end of this string_view instance." }; } return dataVal[offsetNew]; } @@ -159,116 +133,149 @@ namespace Jsonifier { return dataVal[sizeVal - 1]; } - constexpr void swap(StringViewBase& other) { - const StringViewBase temp{ other }; + template constexpr size_type find(ArgTypes&&... args) const { + return this->operator std::basic_string_view().find(std::forward(args)...); + } + + template constexpr size_type findFirstOf(ArgTypes&&... args) const { + return this->operator std::basic_string_view().find_first_of(std::forward(args)...); + } + + template constexpr size_type findLastOf(ArgTypes&&... args) const { + return this->operator std::basic_string_view().find_last_of(std::forward(args)...); + } + + template constexpr size_type findFirstNotOf(ArgTypes&&... args) const { + return this->operator std::basic_string_view().find_first_not_of(std::forward(args)...); + } + + template constexpr size_type findLastNotOf(ArgTypes&&... args) const { + return this->operator std::basic_string_view().find_last_not_of(std::forward(args)...); + } + + constexpr void swap(string_view_base& other) { + const string_view_base temp{ other }; other = *this; *this = temp; } - constexpr StringViewBase substr(const size_type offsetNew = 0, size_type countNew = npos) const { - return StringViewBase(dataVal + offsetNew, countNew); + constexpr string_view_base substr(const size_type offsetNew = 0, size_type countNew = npos) const { + if (offsetNew >= sizeVal) { + throw std::out_of_range("Substring position is out of range."); + } + + countNew = std::min(countNew, sizeVal - offsetNew); + return string_view_base(dataVal + offsetNew, countNew); } - template inline explicit operator std::basic_string() const { - std::basic_string returnValue{}; + template inline explicit operator std::basic_string() const { + std::basic_string returnValue{}; returnValue.resize(sizeVal); std::memcpy(returnValue.data(), data(), returnValue.size()); return returnValue; } - template inline explicit operator StringBase() const { - StringBase returnValue{}; + template inline explicit operator string_base() const { + string_base returnValue{}; returnValue.resize(sizeVal); std::memcpy(returnValue.data(), data(), returnValue.size()); return returnValue; } - constexpr explicit operator std::string_view() const { + constexpr explicit operator std::basic_string_view() const { return { data(), size() }; } - template constexpr bool operator==(const StringType& rhs) const { - if (rhs.size() != size()) { + template + inline friend std::enable_if_t, bool> operator==(const string_view_base& lhs, const value_type_newer& rhs) { + auto rhsLength = traits_type::length(rhs); + if (lhs.size() != rhsLength) { return false; } - return JsonifierInternal::JsonifierCoreInternal::compare(rhs.data(), data(), size()); + return jsonifier_internal::jsonifier_core_internal::compare(rhs, lhs.data(), rhsLength); } - template constexpr bool operator==(const value_type (&rhs)[StrLength]) const { - if (StrLength - 1 != size()) { + template inline bool operator==(const value_type_newer& rhs) { + auto rhsLength = std::size(rhs) - 1; + if (size() != rhsLength) { return false; } - return JsonifierInternal::JsonifierCoreInternal::compare(rhs, data(), size()); + return jsonifier_internal::jsonifier_core_internal::compare(rhs, data(), rhsLength); } - template inline friend StringBase operator+(const StringTypeNew& lhs, const StringViewBase& rhs) { - StringBase newLhs{ lhs }; - newLhs += rhs; - return newLhs; - } - - template inline friend StringBase operator+=(const StringTypeNew& lhs, const StringViewBase& rhs) { - StringBase newLhs{ lhs }; - newLhs += rhs; - return newLhs; + template inline friend bool operator==(const string_view_base& lhs, const value_type_newer& rhs) { + if (rhs.size() != lhs.size()) { + return false; + } + return jsonifier_internal::jsonifier_core_internal::compare(rhs.data(), lhs.data(), rhs.size()); } - template inline friend StringBase operator+(const value_type (&lhs)[size], const StringViewBase& rhs) { - StringBase newLhs{ lhs }; + template inline friend string_base operator+(const value_type_newer (&lhs)[N], const string_view_base& rhs) { + string_base newLhs{ lhs }; newLhs += rhs; return newLhs; } - template inline friend StringBase operator+=(const value_type (&lhs)[size], const StringViewBase& rhs) { - StringBase newLhs{ lhs }; + template inline friend string_base operator+=(const value_type_newer (&lhs)[N], const string_view_base& rhs) { + string_base newLhs{ lhs }; newLhs += rhs; return newLhs; } - template inline StringBase operator+(const value_type (&rhs)[strLength]) { - StringBase newLhs{ *this }; + template inline friend string_base operator+(string_type_new&& lhs, const string_view_base& rhs) { + string_base newLhs{ lhs }; newLhs += rhs; return newLhs; } - template inline StringBase operator+=(const value_type (&rhs)[strLength]) { - StringBase newLhs{ *this }; + template inline friend string_base operator+=(string_type_new&& lhs, const string_view_base& rhs) { + string_base newLhs{ lhs }; newLhs += rhs; return newLhs; } - inline StringBase operator+(const value_type& rhs) { - StringBase newLhs{ *this }; + inline string_base operator+(const value_type& rhs) { + string_base newLhs{ *this }; newLhs.pushBack(rhs); return newLhs; } - inline StringBase operator+=(const value_type& rhs) { - StringBase newLhs{ *this }; + inline string_base operator+=(const value_type& rhs) { + string_base newLhs{ *this }; newLhs.pushBack(rhs); return newLhs; } - template inline StringBase operator+(const StringTypeNew& rhs) noexcept { - StringBase newLhs{ *this }; + template inline string_base operator+(const string_type_new& rhs) const { + string_base newLhs{ *this }; newLhs += rhs; return newLhs; } - template inline StringBase operator+=(const StringTypeNew& rhs) noexcept { - StringBase newLhs{ *this }; + template inline string_base operator+=(const string_type_new& rhs) { + string_base newLhs{ *this }; newLhs.append(rhs.data(), rhs.size()); return newLhs; } - constexpr ~StringViewBase() noexcept = default; + template inline string_base operator+(const value_type_newer (&rhs)[N]) const { + string_base newLhs{ *this }; + newLhs += rhs; + return newLhs; + } + + template inline string_base operator+=(const value_type_newer (&rhs)[N]) { + string_base newLhs{ *this }; + newLhs += rhs; + return newLhs; + } }; - using StringView = StringViewBase; + using string_view = string_view_base; - inline std::ostream& operator<<(std::ostream& oStream, const Jsonifier::StringViewBase& string) { - oStream << string.operator Jsonifier::String(); + inline std::ostream& operator<<(std::ostream& oStream, const jsonifier::string_view_base& string) { + oStream << string.operator jsonifier::string(); return oStream; } -}// namespace Jsonifier +}// namespace jsonifier diff --git a/Include/jsonifier/StructuralIterator.hpp b/Include/jsonifier/StructuralIterator.hpp index 52a2023c0..6c9966f45 100644 --- a/Include/jsonifier/StructuralIterator.hpp +++ b/Include/jsonifier/StructuralIterator.hpp @@ -19,63 +19,64 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/// https://github.com/RealTimeChris/Jsonifier +/// https://github.com/RealTimeChris/jsonifier /// Feb 3, 2023 #pragma once #include #include -namespace JsonifierInternal { +namespace jsonifier_internal { - class StructuralIterator { + class structural_iterator { public: using iterator_category = std::forward_iterator_tag; - using value_type = StringViewPtr; - - inline StructuralIterator() noexcept = default; - - inline StructuralIterator(SimdStringReader* stringReaderNew) noexcept { - stringView = stringReaderNew->getStringView().data(); - stringLength = stringReaderNew->getStringLength(); - currentIndex = stringReaderNew->getStructurals(); - rootIndex = currentIndex; + using value_type = string_view_ptr; + using pointer = value_type*; + using size_type = int64_t; + + inline structural_iterator(pointer rootIndexNew, size_type originalLength) { + stringLength = originalLength; + currentIndex = rootIndexNew; + rootIndex = rootIndexNew; } - inline value_type operator*() const noexcept { + inline value_type operator*() const { return *currentIndex; } - inline StructuralIterator& operator++() noexcept { + inline structural_iterator& operator++() { ++currentIndex; return *this; } - inline int64_t getCurrentIndex() const noexcept { - return *currentIndex - *rootIndex; + inline size_type getCurrentIndex() const { + return (*currentIndex) - (*rootIndex); + } + + inline size_type getRemainingLength() const { + return stringLength - getCurrentIndex(); } - inline bool operator==(const StructuralIterator&) const noexcept { - return checkForNullIndex() || checkForStringOverRun(); + inline bool operator==(const structural_iterator&) const { + return checkForstringOverRun(); } - inline bool operator==(uint8_t other) const noexcept { + inline bool operator==(uint8_t other) const { + if (checkForstringOverRun()) { + return false; + } return ***this == other; } protected: - StructuralIndex* currentIndex{}; - StructuralIndex* rootIndex{}; - StringViewPtr stringView{}; - int64_t stringLength{}; - - inline bool checkForNullIndex() const noexcept { - return !currentIndex; - } + size_type stringLength{}; + pointer currentIndex{}; + pointer rootIndex{}; - inline bool checkForStringOverRun() const noexcept { + inline bool checkForstringOverRun() const { auto currentIndexTemp = getCurrentIndex(); - return currentIndexTemp <= 0 || currentIndexTemp >= stringLength; + return currentIndexTemp < 0 || currentIndexTemp >= stringLength; } }; } diff --git a/Include/jsonifier/Tables.hpp b/Include/jsonifier/Tables.hpp index 1eb2de520..f369a1221 100644 --- a/Include/jsonifier/Tables.hpp +++ b/Include/jsonifier/Tables.hpp @@ -19,7 +19,7 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/// https://github.com/RealTimeChris/Jsonifier +/// https://github.com/RealTimeChris/jsonifier /// Feb 3, 2023 #pragma once @@ -27,58 +27,55 @@ #include -namespace JsonifierInternal { +namespace jsonifier_internal { - constexpr std::array powersOfTenFloat{ 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, - 1e22 }; + constexpr double powersOfTenFloat[23]{ 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22 }; - constexpr std::array powersOfTenInt{ 1ull, 10ull, 100ull, 1000ull, 10000ull, 100000ull, 1000000ull, 10000000ull, 100000000ull, 1000000000ull, 10000000000ull, - 100000000000ull, 1000000000000ull, 10000000000000ull, 100000000000000ull, 1000000000000000ull, 10000000000000000ull, 100000000000000000ull, 1000000000000000000ull, - 10000000000000000000ull }; + constexpr uint64_t powersOfTenInt[20]{ 1ULL, 10ULL, 100ULL, 1000ULL, 10000ULL, 100000ULL, 1000000ULL, 10000000ULL, 100000000ULL, 1000000000ULL, 10000000000ULL, 100000000000ULL, + 1000000000000ULL, 10000000000000ULL, 100000000000000ULL, 1000000000000000ULL, 10000000000000000ULL, 100000000000000000ULL, 1000000000000000000ULL, + 10000000000000000000ULL }; - constexpr std::array decTrailingZeroTable{ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, - 0, 0, 0 }; + constexpr uint8_t decTrailingZeroTable[100]{ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - constexpr std::array digiTable{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x10, 0x00, 0x01, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + constexpr uint8_t digiTable[128]{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x10, 0x00, 0x01, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - constexpr std::array escapeMap{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x22, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0x2f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x5c, 0, 0, 0, 0, - 0, 0x08, 0, 0, 0, 0x0c, 0, 0, 0, 0, 0, 0, 0, 0x0a, 0, 0, 0, 0x0d, 0, 0x09, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + constexpr uint8_t escapeMap[256]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0x2f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x5c, 0, 0, 0, 0, 0, 0x08, 0, + 0, 0, 0x0c, 0, 0, 0, 0, 0, 0, 0, 0x0a, 0, 0, 0, 0x0d, 0, 0x09, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - constexpr std::array charTable{ '0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6', '0', '7', '0', '8', '0', '9', '1', '0', '1', '1', '1', '2', - '1', '3', '1', '4', '1', '5', '1', '6', '1', '7', '1', '8', '1', '9', '2', '0', '2', '1', '2', '2', '2', '3', '2', '4', '2', '5', '2', '6', '2', '7', '2', '8', '2', '9', - '3', '0', '3', '1', '3', '2', '3', '3', '3', '4', '3', '5', '3', '6', '3', '7', '3', '8', '3', '9', '4', '0', '4', '1', '4', '2', '4', '3', '4', '4', '4', '5', '4', '6', - '4', '7', '4', '8', '4', '9', '5', '0', '5', '1', '5', '2', '5', '3', '5', '4', '5', '5', '5', '6', '5', '7', '5', '8', '5', '9', '6', '0', '6', '1', '6', '2', '6', '3', - '6', '4', '6', '5', '6', '6', '6', '7', '6', '8', '6', '9', '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', '7', '5', '7', '6', '7', '7', '7', '8', '7', '9', '8', '0', - '8', '1', '8', '2', '8', '3', '8', '4', '8', '5', '8', '6', '8', '7', '8', '8', '8', '9', '9', '0', '9', '1', '9', '2', '9', '3', '9', '4', '9', '5', '9', '6', '9', '7', - '9', '8', '9', '9' }; + constexpr uint8_t charTable[200]{ '0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6', '0', '7', '0', '8', '0', '9', '1', '0', '1', '1', '1', '2', '1', '3', + '1', '4', '1', '5', '1', '6', '1', '7', '1', '8', '1', '9', '2', '0', '2', '1', '2', '2', '2', '3', '2', '4', '2', '5', '2', '6', '2', '7', '2', '8', '2', '9', '3', '0', + '3', '1', '3', '2', '3', '3', '3', '4', '3', '5', '3', '6', '3', '7', '3', '8', '3', '9', '4', '0', '4', '1', '4', '2', '4', '3', '4', '4', '4', '5', '4', '6', '4', '7', + '4', '8', '4', '9', '5', '0', '5', '1', '5', '2', '5', '3', '5', '4', '5', '5', '5', '6', '5', '7', '5', '8', '5', '9', '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', + '6', '5', '6', '6', '6', '7', '6', '8', '6', '9', '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', '7', '5', '7', '6', '7', '7', '7', '8', '7', '9', '8', '0', '8', '1', + '8', '2', '8', '3', '8', '4', '8', '5', '8', '6', '8', '7', '8', '8', '8', '9', '9', '0', '9', '1', '9', '2', '9', '3', '9', '4', '9', '5', '9', '6', '9', '7', '9', '8', + '9', '9' }; - constexpr std::array structuralOrWhitespaceNegated{ true, true, true, true, true, true, true, true, true, false, false, true, true, false, true, true, true, true, - true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, true, true, true, true, true, true, true, true, true, true, true, false, true, - true, true, true, true, true, true, true, true, true, true, true, true, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, - true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, true, false, true, true, true, true, true, true, true, true, - true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, true, false, true, true, true, true, + constexpr bool structuralOrWhitespaceNegated[256]{ true, true, true, true, true, true, true, true, true, false, false, true, true, false, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, true, true, true, true, false, true, true, true, true, true, true, true, true, true, true, true, false, true, true, true, + true, true, true, true, true, true, true, true, true, true, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, true, false, true, true, true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, true, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, - true, true, true, true, true, true, true, true, true, true, true, true, true, true }; + true, true, true, true, true, true, true, true, true, true, true, true }; - constexpr std::array digitToVal32{ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + constexpr uint32_t digitToVal32[886]{ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, @@ -88,11 +85,11 @@ namespace JsonifierInternal { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x0, 0x10, 0x20, 0x30, 0x40, - 0x50, 0x60, 0x70, 0x80, 0x90, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x0, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, + 0x70, 0x80, 0x90, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, @@ -103,10 +100,11 @@ namespace JsonifierInternal { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0x0, 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700, 0x800, 0x900, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xa00, - 0xb00, 0xc00, 0xd00, 0xe00, 0xf00, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x0, + 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700, 0x800, 0x900, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xa00, 0xb00, 0xc00, + 0xd00, 0xe00, 0xf00, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xa00, 0xb00, 0xc00, 0xd00, 0xe00, 0xf00, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xa00, 0xb00, 0xc00, 0xd00, 0xe00, 0xf00, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, @@ -117,10 +115,10 @@ namespace JsonifierInternal { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x0, 0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000, 0x8000, 0x9000, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xa000, 0xb000, 0xc000, 0xd000, 0xe000, 0xf000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x0, 0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000, 0x8000, 0x9000, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xa000, 0xb000, 0xc000, 0xd000, 0xe000, 0xf000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xa000, 0xb000, 0xc000, 0xd000, 0xe000, 0xf000, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xa000, 0xb000, 0xc000, 0xd000, 0xe000, 0xf000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, @@ -131,9 +129,9 @@ namespace JsonifierInternal { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }; + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }; - constexpr std::array pow10SigTable128{ 0xBF29DCABA82FDEAE, 0x7432EE873880FC33, 0xEEF453D6923BD65A, 0x113FAA2906A13B3F, 0x9558B4661B6565F8, 0x4AC7CA59A424C507, + constexpr uint64_t pow10SigTable128[1336]{ 0xBF29DCABA82FDEAE, 0x7432EE873880FC33, 0xEEF453D6923BD65A, 0x113FAA2906A13B3F, 0x9558B4661B6565F8, 0x4AC7CA59A424C507, 0xBAAEE17FA23EBF76, 0x5D79BCF00D2DF649, 0xE95A99DF8ACE6F53, 0xF4D82C2C107973DC, 0x91D8A02BB6C10594, 0x79071B9B8A4BE869, 0xB64EC836A47146F9, 0x9748E2826CDEE284, 0xE3E27A444D8D98B7, 0xFD1B1B2308169B25, 0x8E6D8C6AB0787F72, 0xFE30F0F5E50E20F7, 0xB208EF855C969F4F, 0xBDBD2D335E51A935, 0xDE8B2B66B3BC4723, 0xAD2C788035E61382, 0x8B16FB203055AC76, 0x4C3BCB5021AFCC31, 0xADDCB9E83C6B1793, 0xDF4ABE242A1BBF3D, 0xD953E8624B85DD78, 0xD71D6DAD34A2AF0D, 0x87D4713D6F33AA6B, 0x8672648C40E5AD68, @@ -301,4 +299,4 @@ namespace JsonifierInternal { 0xD433179D9C8CB841, 0x5FA60692A46151EB, 0x849FEEC281D7F328, 0xDBC7C41BA6BCD333, 0xA5C7EA73224DEFF3, 0x12B9B522906C0800, 0xCF39E50FEAE16BEF, 0xD768226B34870A00, 0x81842F29F2CCE375, 0xE6A1158300D46640, 0xA1E53AF46F801C53, 0x60495AE3C1097FD0, 0xCA5E89B18B602368, 0x385BB19CB14BDFC4, 0xFCF62C1DEE382C42, 0x46729E03DD9ED7B5, 0x9E19DB92B4E31BA9, 0x6C07A2C26A8346D1 }; -}// namespace JsonifierInternal +}// namespace jsonifier_internal diff --git a/Include/jsonifier/Tuple.hpp b/Include/jsonifier/Tuple.hpp index 69fd6571d..fc3e44261 100644 --- a/Include/jsonifier/Tuple.hpp +++ b/Include/jsonifier/Tuple.hpp @@ -20,78 +20,49 @@ DEALINGS IN THE SOFTWARE. */ /// NOTE: Most of the code in this header was sampled from Glaze library: https://github.com/stephenberry/glaze -/// https://github.com/RealTimeChris/Jsonifier +/// https://github.com/RealTimeChris/jsonifier /// Feb 3, 2023 #pragma once +#include #include #include #include #include -namespace JsonifierInternal { +namespace jsonifier_internal { - namespace Tuplet { - template using IdentityT = ValueType; + namespace tuplet { - template using TypeT = typename ValueType::type; + template using identity_t = value_type; - template using Tag = std::integral_constant; + template using type_t = typename value_type::type; - template constexpr Tag TagV{}; + template using tag_range = std::make_index_sequence; - template using TagRange = std::make_index_sequence; + template using BaseListT = typename ref_unwrap::base_list; - template - concept SameAs = std::same_as && std::same_as; + template struct tuple; - template - concept OtherThan = !std::same_as, U>; + template struct type_list {}; - template using BaseListT = typename RefUnwrap::base_list; - - template - concept BaseListTuple = requires() { typename RefUnwrap::base_list; }; - - template - concept Stateless = std::is_empty_v>; - - template - concept Indexable = Stateless || requires(ValueType value) { value[Tag<0>()]; }; - - template - concept AssignableTo = requires(U u, ValueType object) { object = u; }; - - template - concept Ordered = requires(ValueType const& object) { - { object <=> object }; - }; - template - concept EqualityComparable = requires(ValueType const& object) { - { object == object } -> SameAs; - }; - - template struct Tuple; - - template struct TypeList {}; - - template constexpr auto operator+(TypeList, TypeList) { - return TypeList{}; + template constexpr auto operator+(type_list, type_list) { + return type_list{}; } - template struct TypeMap : Bases... { - using base_list = TypeList; - using Bases::operator[]...; - using Bases::declElem...; - auto operator<=>(TypeMap const&) const = default; - bool operator==(TypeMap const&) const = default; + template struct type_map : bases... { + using base_list = type_list; + using bases::operator[]...; + using bases::declElem...; + auto operator<=>(type_map const&) const = default; + bool operator==(type_map const&) const = default; }; - template struct TupleElem { - static inline ValueType declElem(Tag); - using type = ValueType; + template struct tuple_elem { + inline static value_type declElem(Tag); + using type = value_type; - ValueType value; + value_type value; constexpr decltype(auto) operator[](Tag) & { return (value); @@ -104,30 +75,30 @@ namespace JsonifierInternal { constexpr decltype(auto) operator[](Tag) && { return (std::move(*this).value); } - auto operator<=>(TupleElem const&) const = default; - bool operator==(TupleElem const&) const = default; + auto operator<=>(tuple_elem const&) const = default; + bool operator==(tuple_elem const&) const = default; - constexpr auto operator<=>(TupleElem const& other) const noexcept(noexcept(value <=> other.value)) - requires(std::is_reference_v && Ordered) + constexpr auto operator<=>(tuple_elem const& other) const noexcept(noexcept(value <=> other.value)) + requires(std::is_reference_v && ordered) { return value <=> other.value; } - constexpr bool operator==(TupleElem const& other) const noexcept(noexcept(value == other.value)) - requires(std::is_reference_v && EqualityComparable) + constexpr bool operator==(tuple_elem const& other) const noexcept(noexcept(value == other.value)) + requires(std::is_reference_v && equality_comparable) { return value == other.value; } }; - template struct GetTupleBase; + template struct get_tuple_base; - template struct GetTupleBase, ValueType...> { - using type = TypeMap...>; + template struct get_tuple_base, value_type...> { + using type = type_map...>; }; - template constexpr decltype(auto) applyImpl(F&& f, ValueType&& object, TypeList) { - return static_cast(f)(static_cast(object).IdentityT::value...); + template constexpr decltype(auto) applyImpl(f&& fNew, value_type&& object, type_list) { + return static_cast(fNew)(static_cast(object).identity_t::value...); } template constexpr size_t sizetFromDigits() { static_assert((('0' <= D && D <= '9') && ...), "Must be integral literal"); @@ -136,142 +107,137 @@ namespace JsonifierInternal { } template using first_t = First; - template constexpr auto repeatType(TypeList) { - return TypeList...>{}; + template constexpr auto repeatType(type_list) { + return type_list...>{}; } - template constexpr auto getOuterBases(TypeList) { - return (repeatType(BaseListT>{}) + ...); + template constexpr auto getOuterBases(type_list) { + return (repeatType(BaseListT>{}) + ...); } - template constexpr auto getInnerBases(TypeList) { - return (BaseListT>{} + ...); + template constexpr auto getInnerBases(type_list) { + return (BaseListT>{} + ...); } - template constexpr auto catImpl(ValueType tup, TypeList, TypeList) - -> Tuple...> { - return { static_cast&&>(tup.IdentityT::value).IdentityT::value... }; + template constexpr auto catImpl(value_type tup, type_list, type_list) + -> tuple...> { + return { static_cast&&>(tup.identity_t::value).identity_t::value... }; } - template using TupleBaseT = typename GetTupleBase, ValueType...>::type; + template using tuple_base_t = typename get_tuple_base, value_type...>::type; - template struct Tuple : TupleBaseT { - static constexpr size_t N = sizeof...(ValueType); - using super = TupleBaseT; + template struct tuple : tuple_base_t { + static constexpr size_t N = sizeof...(value_type); + using super = tuple_base_t; using super::operator[]; using base_list = typename super::base_list; - using element_list = TypeList; + using element_list = type_list; using super::declElem; - template U> constexpr auto& operator=(U&& tup) { - using tuple2 = RefUnwrap; - if (BaseListTuple) { - eqImpl(static_cast(tup), base_list(), typename tuple2::base_list()); + template u> constexpr auto& operator=(u&& tup) { + using tuple2 = ref_unwrap; + if (base_list_tuple) { + eqImpl(static_cast(tup), base_list(), typename tuple2::base_list()); } else { - eqImpl(static_cast(tup), TagRange()); + eqImpl(static_cast(tup), tag_range()); } return *this; } - auto operator<=>(Tuple const&) const = default; - bool operator==(Tuple const&) const = default; + auto operator<=>(tuple const&) const = default; + bool operator==(tuple const&) const = default; - template constexpr auto map(F&& func) & { - return mapImpl(base_list(), static_cast(func)); + template constexpr auto map(f&& func) & { + return mapImpl(base_list(), static_cast(func)); } - template constexpr auto map(F&& func) const& { - return mapImpl(base_list(), static_cast(func)); + template constexpr auto map(f&& func) const& { + return mapImpl(base_list(), static_cast(func)); } - template constexpr auto map(F&& func) && { - return static_cast(*this).mapImpl(base_list(), static_cast(func)); + template constexpr auto map(f&& func) && { + return static_cast(*this).mapImpl(base_list(), static_cast(func)); } protected: - template constexpr void eqImpl(U&& u, TypeList, TypeList) { + template constexpr void eqImpl(u&& uNew, type_list, type_list) { // See: // https://developercommunity.visualstudio.com/object/fold-expressions-unreliable-in-171-with-c20/1676476 - (void(B1::value = static_cast(u).B2::value), ...); + (void(b1::value = static_cast(uNew).b2::value), ...); } - template constexpr void eqImpl(U&& u, std::index_sequence) { - (void(TupleElem::value = get(static_cast(u))), ...); + template constexpr void eqImpl(u&& uNew, std::index_sequence) { + (void(tuple_elem::value = get(static_cast(uNew))), ...); } - template constexpr auto mapImpl(TypeList, F&& func) & -> Tuple...> { - return { func(B::value)... }; + template constexpr auto mapImpl(type_list, f&& func) & -> tuple...> { + return { func(b::value)... }; } - template constexpr auto mapImpl(TypeList, F&& func) const& -> Tuple...> { - return { func(B::value)... }; + template constexpr auto mapImpl(type_list, f&& func) const& -> tuple...> { + return { func(b::value)... }; } - template - constexpr auto mapImpl(TypeList, F&& func) && -> Tuple(B::value)))>...> { - return { func(static_cast(B::value))... }; + template constexpr auto mapImpl(type_list, f&& func) && -> tuple(b::value)))>...> { + return { func(static_cast(b::value))... }; } }; - template<> struct Tuple<> : TupleBaseT<> { + template<> struct tuple<> : tuple_base_t<> { static constexpr size_t N = 0; - using super = TupleBaseT<>; - using base_list = TypeList<>; - using element_list = TypeList<>; - - template U> - requires Stateless - constexpr auto& operator=(U&&) noexcept { - return *this; - } + using super = tuple_base_t<>; + using base_list = type_list<>; + using element_list = type_list<>; - constexpr auto& assign() noexcept { + template u> + requires stateless + constexpr auto& operator=(u&&) { return *this; } - auto operator<=>(Tuple const&) const = default; - bool operator==(Tuple const&) const = default; + auto operator<=>(tuple const&) const = default; + bool operator==(tuple const&) const = default; - template constexpr void forEach(F&&) const noexcept { + template constexpr void forEach(f&&) const { } - template constexpr bool any(F&&) const noexcept { + template constexpr bool any(f&&) const { return false; } - template constexpr bool all(F&&) const noexcept { + template constexpr bool all(f&&) const { return true; } - template constexpr auto map(F&&) const noexcept { - return Tuple{}; + template constexpr auto map(f&&) const { + return tuple{}; } }; - template Tuple(ValueTypes...) -> Tuple...>; + template tuple(value_types...) -> tuple...>; - template constexpr decltype(auto) get(Tup&& tup) { - return static_cast(tup)[Tag()]; + template constexpr decltype(auto) get(tup&& tupNew) { + return static_cast(tupNew)[Tag()]; } - template constexpr Tuple tie(ValueType&... object) { + template constexpr tuple tie(value_type&... object) { return { object... }; } - template constexpr decltype(auto) apply(F&& func, Tup&& tup) { - return applyImpl(static_cast(func), static_cast(tup), typename RefUnwrap::base_list()); + template constexpr decltype(auto) apply(f&& func, tup&& tupNew) { + return applyImpl(static_cast(func), static_cast(tupNew), typename ref_unwrap::base_list()); } - template constexpr decltype(auto) apply(F&& func, Pair& Pair) { - return static_cast(func)(Pair.first, Pair.second); + template constexpr decltype(auto) apply(f&& func, pair& pair) { + return static_cast(func)(pair.first, pair.second); } - template constexpr decltype(auto) apply(F&& func, Pair const& Pair) { - return static_cast(func)(Pair.first, Pair.second); + template constexpr decltype(auto) apply(f&& func, pair const& pair) { + return static_cast(func)(pair.first, pair.second); } - template constexpr decltype(auto) apply(F&& func, Pair&& Pair) { - return static_cast(func)(std::move(Pair).first, std::move(Pair).second); + template constexpr decltype(auto) apply(f&& func, pair&& pair) { + return static_cast(func)(std::move(pair).first, std::move(pair).second); } - template constexpr auto tupleCat(ValueType&&... ts) { - if constexpr (sizeof...(ValueType) == 0) { - return Tuple<>(); + template constexpr auto tupleCat(value_type&&... ts) { + if constexpr (sizeof...(value_type) == 0) { + return tuple<>(); } else { #if !defined(TUPLET_CAT_BY_FORWARDING_TUPLE) #if defined(__clang__) @@ -281,135 +247,143 @@ namespace JsonifierInternal { #endif #endif #if TUPLET_CAT_BY_FORWARDING_TUPLE - using big_tuple = Tuple; + using big_tuple = tuple; #else - using big_tuple = Tuple...>; + using big_tuple = tuple...>; #endif using outer_bases = BaseListT; constexpr auto outer = getOuterBases(outer_bases{}); constexpr auto inner = getInnerBases(outer_bases{}); - return catImpl(big_tuple{ static_cast(ts)... }, outer, inner); + return catImpl(big_tuple{ static_cast(ts)... }, outer, inner); } } - template constexpr auto makeTuple(ValueTypes&&... args) { - return Tuple...>{ static_cast(args)... }; + template constexpr auto makeTuple(value_types&&... args) { + return tuple...>{ static_cast(args)... }; } - template constexpr auto copyTuple(ValueTypes... args) { - return Tuple{ args... }; + template constexpr auto copyTuple(value_types... args) { + return tuple{ args... }; } - template constexpr auto forwardAsTuple(ValueType&&... a) noexcept { - return Tuple{ static_cast(a)... }; + template constexpr auto forwardAstuple(value_type&&... a) { + return tuple{ static_cast(a)... }; } } - namespace Tuplet::literals { - template constexpr auto operator""_tag() noexcept -> Tag()> { + namespace tuplet::literals { + template constexpr auto operator""_tag() -> Tag()> { return {}; } } } namespace std { - template struct tuple_size> : std::integral_constant {}; - template struct tuple_element> { - using type = decltype(JsonifierInternal::Tuplet::Tuple::declElem(JsonifierInternal::Tuplet::Tag())); + template struct tuple_size> : std::integral_constant {}; + + template struct tuple_element> { + using type = decltype(jsonifier_internal::tuplet::tuple::declElem(jsonifier_internal::Tag())); }; - template struct tuple_size> : std::integral_constant {}; + template struct tuple_size> : std::integral_constant {}; - template struct tuple_element> { + template struct tuple_element> { static_assert(I < 2, "tuplet::pair only has 2 elements"); - using type = std::conditional_t; + using type = std::conditional_t; }; }; -namespace JsonifierInternal { +namespace jsonifier_internal { - template auto tupleSplit(Tuple&& tuple) { - static constexpr auto N = std::tuple_size_v; + template auto tupleSplit(tuple&& tupleNew) { + static constexpr auto N = std::tuple_size_v; static constexpr auto is = std::make_index_sequence{}; - return std::make_pair(tupleSplitImpl<0>(tuple, is), tupleSplitImpl<1>(tuple, is)); + return std::make_pair(tupleSplitImpl<0>(tupleNew, is), tupleSplitImpl<1>(tupleNew, is)); } - template constexpr auto shrinkIndexArray(auto& arrayNew) { - RawArray res{}; - for (size_t x = 0; x < N; ++x) { - res[x] = arrayNew[x]; + template constexpr void shrinkIndexArrayHelper(auto& arrayNew01, auto& arrayNew02) { + if constexpr (index < indexLimit) { + arrayNew01[index] = arrayNew02[index]; + shrinkIndexArrayHelper(arrayNew01, arrayNew02); } + } + + template constexpr auto shrinkIndexArray(auto& arrayNew) { + raw_array res{}; + shrinkIndexArrayHelper<0, N>(res, arrayNew); return res; } - template constexpr auto filter() { - constexpr auto n = std::tuple_size_v; - RawArray indices{}; + template constexpr auto filter() { + constexpr auto n = std::tuple_size_v; + raw_array indices{}; size_t x = 0; forEach([&](auto I) { - using ValueType = RefUnwrap>; - if constexpr (!std::convertible_to) { + using value_type = ref_unwrap>; + if constexpr (!std::convertible_to) { indices[x++] = I - 1; } }); return std::make_pair(indices, x); } - template constexpr auto mapTuple(Func&& f, Tuple&& tuple) { - constexpr auto N = std::tuple_size_v>; - return mapTuple(f, tuple, std::make_index_sequence{}); + template constexpr auto mapTuple(Func&& f, tuple&& tupleNew) { + constexpr auto N = std::tuple_size_v>; + return mapTuple(f, tupleNew, std::make_index_sequence{}); } - template constexpr auto groupSizes(const RawArray& indices, size_t n_total) { - RawArray diffs; - - for (size_t x = 0; x < n_groups - 1; ++x) { - diffs[x] = indices[x + 1] - indices[x]; + template constexpr void groupSizesHelper(auto& diffs, auto& indices) { + if constexpr (index < indexLimit) { + diffs[index] = indices[index + 1] - indices[index]; + groupSizesHelper(diffs, indices); } + } + + template constexpr auto groupSizes(const raw_array& indices, size_t n_total) { + raw_array diffs; + groupSizesHelper<0, n_groups - 1>(diffs, indices); diffs[n_groups - 1] = n_total - indices[n_groups - 1]; return diffs; } - template constexpr auto makeGroup(Tuple&& object, std::index_sequence) { + template constexpr auto makeGroup(tuple&& object, std::index_sequence) { auto get_elem = [&](auto x) { constexpr auto I = decltype(x)::value; if constexpr (I == 1) { - return Tuplet::get(object); + return tuplet::get(object); } else { - return Jsonifier::StringView(Tuplet::get(object)); + return jsonifier::string_view(tuplet::get(object)); } }; - auto r = Tuplet::copyTuple(get_elem(std::integral_constant{})...); + auto r = tuplet::copyTuple(get_elem(std::integral_constant{})...); return r; } - template - constexpr auto makeGroupsImpl(Tuple&& object, std::index_sequence) { - return Tuplet::copyTuple(makeGroup(GroupStartArr)>(object, std::make_index_sequence(GroupSizeArr)>{})...); + template constexpr auto makeGroupsImpl(tuple&& object, std::index_sequence) { + return tuplet::copyTuple(makeGroup(GroupStartArr)>(object, std::make_index_sequence(GroupSizeArr)>{})...); } - template constexpr auto makeGroupsHelper() { - constexpr auto N = std::tuple_size_v; + template constexpr auto makeGroupsHelper() { + constexpr auto N = std::tuple_size_v; - constexpr auto filtered = filter(); + constexpr auto filtered = filter(); constexpr auto starts = shrinkIndexArray(filtered.first); constexpr auto sizes = groupSizes(starts, N); - return Tuplet::makeTuple(starts, sizes); + return tuplet::makeTuple(starts, sizes); } - template struct GroupBuilder { - static constexpr auto h = makeGroupsHelper(); - static constexpr auto starts = Tuplet::get<0>(h); - static constexpr auto sizes = Tuplet::get<1>(h); + template struct GroupBuilder { + static constexpr auto h = makeGroupsHelper(); + static constexpr auto starts = tuplet::get<0>(h); + static constexpr auto sizes = tuplet::get<1>(h); - static constexpr auto op(Tuple&& object) { + static constexpr auto op(tuple&& object) { constexpr auto n_groups = starts.size(); - return makeGroupsImpl(std::forward(object), std::make_index_sequence{}); + return makeGroupsImpl(std::forward(object), std::make_index_sequence{}); } }; - } \ No newline at end of file diff --git a/Include/jsonifier/Vector.hpp b/Include/jsonifier/Vector.hpp index 51f9c54b2..fc3686a82 100644 --- a/Include/jsonifier/Vector.hpp +++ b/Include/jsonifier/Vector.hpp @@ -19,7 +19,7 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/// https://github.com/RealTimeChris/Jsonifier +/// https://github.com/RealTimeChris/jsonifier /// Feb 20, 2023 #pragma once @@ -29,32 +29,26 @@ #include #include -#if defined __linux__ - #if !defined _tzcnt_u16 - #define _tzcnt_u16 __tzcnt_u16 - #endif -#endif +namespace jsonifier { -namespace Jsonifier { - - template class Vector : protected std::equal_to, protected JsonifierInternal::AllocWrapper { + template class vector : protected std::equal_to, protected jsonifier_internal::alloc_wrapper { public: - using value_type = ValueType; + using value_type = value_type_new; using pointer = value_type*; using const_pointer = const value_type*; using reference = value_type&; using const_reference = const value_type&; - using iterator = JsonifierInternal::Iterator; - using const_iterator = JsonifierInternal::Iterator; + using iterator = jsonifier_internal::iterator; + using const_iterator = jsonifier_internal::iterator; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; using object_compare = std::equal_to; using size_type = uint64_t; - using allocator = JsonifierInternal::AllocWrapper; + using allocator = jsonifier_internal::alloc_wrapper; - inline Vector() noexcept = default; + inline vector() = default; - inline Vector& operator=(Vector&& other) noexcept { + inline vector& operator=(vector&& other) noexcept { if (this != &other && dataVal != other.dataVal) { reset(); swap(other); @@ -62,11 +56,11 @@ namespace Jsonifier { return *this; } - inline Vector(Vector&& other) noexcept : capacityVal{}, sizeVal{}, dataVal{} { + inline vector(vector&& other) noexcept : capacityVal{}, sizeVal{}, dataVal{} { *this = std::move(other); } - inline Vector& operator=(const Vector& other) { + inline vector& operator=(const vector& other) { if (this != &other) { reset(); auto sizeValNew = other.size(); @@ -77,11 +71,11 @@ namespace Jsonifier { return *this; } - inline Vector(const Vector& other) : capacityVal{}, sizeVal{}, dataVal{} { + inline vector(const vector& other) : capacityVal{}, sizeVal{}, dataVal{} { *this = other; } - inline Vector& operator=(std::vector&& other) { + inline vector& operator=(std::vector&& other) { reset(); auto sizeValNew = other.size(); reserve(sizeValNew); @@ -90,11 +84,11 @@ namespace Jsonifier { return *this; } - inline explicit Vector(std::vector&& other) : capacityVal{}, sizeVal{}, dataVal{} { + inline explicit vector(std::vector&& other) : capacityVal{}, sizeVal{}, dataVal{} { *this = std::move(other); } - inline Vector& operator=(const std::vector& other) { + inline vector& operator=(const std::vector& other) { reset(); auto sizeValNew = other.size(); reserve(sizeValNew); @@ -103,11 +97,11 @@ namespace Jsonifier { return *this; } - inline explicit Vector(const std::vector& other) : capacityVal{}, sizeVal{}, dataVal{} { + inline explicit vector(const std::vector& other) : capacityVal{}, sizeVal{}, dataVal{} { *this = other; } - inline Vector& operator=(std::initializer_list other) { + inline vector& operator=(std::initializer_list other) { reset(); auto sizeValNew = other.size(); reserve(sizeValNew); @@ -116,11 +110,11 @@ namespace Jsonifier { return *this; } - inline explicit Vector(std::initializer_list other) : capacityVal{}, sizeVal{}, dataVal{} { + inline explicit vector(std::initializer_list other) : capacityVal{}, sizeVal{}, dataVal{} { *this = other; } - inline explicit Vector(value_type&& other, size_type sizeNew) : capacityVal{}, sizeVal{}, dataVal{} { + inline explicit vector(value_type&& other, size_type sizeNew) : capacityVal{}, sizeVal{}, dataVal{} { reset(); auto sizeValNew = sizeNew; reserve(sizeValNew); @@ -128,12 +122,12 @@ namespace Jsonifier { sizeVal = sizeValNew; } - inline Vector& operator=(value_type other) { + inline vector& operator=(value_type other) { emplace_back(other); return *this; } - inline Vector(value_type other) : capacityVal{}, sizeVal{}, dataVal{} { + inline vector(value_type other) : capacityVal{}, sizeVal{}, dataVal{} { *this = other; } @@ -160,7 +154,7 @@ namespace Jsonifier { sizeVal = newSize; } - template inline void insert(iterator where, ValueTypeNew&& value) { + template inline void insert(iterator where, value_type_newer&& value) { size_type insertCount = 1; if (insertCount == 0) { @@ -181,72 +175,72 @@ namespace Jsonifier { sizeVal = newSize; } - inline iterator begin() noexcept { + inline iterator begin() { return iterator(dataVal); } - inline const_iterator begin() const noexcept { - return const_iterator(dataVal); + inline iterator end() { + return iterator(dataVal + sizeVal); } - inline iterator end() noexcept { - return iterator(dataVal + sizeVal); + inline const_iterator begin() const { + return const_iterator(dataVal); } - inline const_iterator end() const noexcept { + inline const_iterator end() const { return const_iterator(dataVal + sizeVal); } - inline reverse_iterator rbegin() noexcept { + inline reverse_iterator rbegin() { return reverse_iterator(end()); } - inline const_reverse_iterator rbegin() const noexcept { - return const_reverse_iterator(end()); + inline reverse_iterator rend() { + return reverse_iterator(begin()); } - inline reverse_iterator rend() noexcept { - return reverse_iterator(begin()); + inline const_iterator cbegin() const { + return const_iterator(begin()); } - inline const_reverse_iterator rend() const noexcept { - return const_reverse_iterator(begin()); + inline const_iterator cend() const { + return const_iterator(end()); } - inline const_iterator cbegin() const noexcept { - return begin(); + inline const_reverse_iterator crbegin() const { + return const_reverse_iterator(cend()); } - inline const_iterator cend() const noexcept { - return end(); + inline const_reverse_iterator crend() const { + return const_reverse_iterator(cbegin()); } - inline const_reverse_iterator crbegin() const noexcept { - return rbegin(); + inline reference front() { + return dataVal[0]; } - inline const_reverse_iterator crend() const noexcept { - return rend(); + inline reference back() { + return dataVal[sizeVal - 1]; } - inline reference front() { + inline const_reference front() const { return dataVal[0]; } - inline reference back() { + inline const_reference back() const { return dataVal[sizeVal - 1]; } inline reference at(size_type index) { if (index >= sizeVal) { - throw std::out_of_range{ "Sorry, but that index is beyond the end of this Vector's bounds." }; + throw std::out_of_range{ "Sorry, but that index is beyond the end of this vector's bounds." }; } return dataVal[index]; } inline const_reference at(size_type index) const { if (index >= sizeVal) { - throw std::out_of_range{ "Sorry, but that index is beyond the end of this Vector's bounds." }; + throw std::out_of_range{ "Sorry, but that index is beyond the end of this vector's bounds." }; } return dataVal[index]; } @@ -267,7 +261,7 @@ namespace Jsonifier { return sizeVal; } - inline pointer data() const { + inline const_pointer data() const { return dataVal; } @@ -287,18 +281,17 @@ namespace Jsonifier { return std::numeric_limits::max() / sizeof(value_type); } - template inline reference emplace_back(ValueTypes&&... c) { + template inline reference emplace_back(value_types&&... c) { if (sizeVal + 1 >= capacityVal) { reserve(capacityVal * 2 + 2); } - getAlloc().construct(&dataVal[sizeVal++], std::forward(c)...); + getAlloc().construct(&dataVal[sizeVal++], std::forward(c)...); return dataVal[sizeVal - 1]; } inline void erase(size_type count) { if (count >= sizeVal) { - clear(); return; } size_type newSize = sizeVal - count; @@ -314,11 +307,10 @@ namespace Jsonifier { inline void erase(iterator iter) { if (iter < begin() || iter >= end()) { - clear(); return; } - size_type eraseIndex = iter - begin(); + size_type eraseIndex = static_cast(iter - begin()); size_type newSize = sizeVal - 1; getAlloc().destroy(dataVal + eraseIndex); @@ -393,29 +385,29 @@ namespace Jsonifier { sizeVal = 0; } - inline void swap(Vector& other) { + inline void swap(vector& other) { std::swap(capacityVal, other.capacityVal); std::swap(sizeVal, other.sizeVal); std::swap(dataVal, other.dataVal); } - inline bool operator==(const Vector& rhs) const { + inline bool operator==(const vector& rhs) const { if (rhs.size() != size()) { return false; } - if constexpr (std::is_fundamental_v) { - return JsonifierInternal::JsonifierCoreInternal::compare(rhs.data(), data(), size()); - } else { + if constexpr (!std::is_fundamental_v) { for (size_type x = 0; x < sizeVal; ++x) { if (!getObjectComparitor()(rhs.dataVal[x], dataVal[x])) { return false; } } + return true; + } else { + return jsonifier_internal::jsonifier_core_internal::compare(rhs.data(), data(), size()); } - return true; } - inline ~Vector() { + inline ~vector() { reset(); }; @@ -445,4 +437,4 @@ namespace Jsonifier { } }; -}// namespace Jsonifier \ No newline at end of file +}// namespace jsonifier diff --git a/ReadMe.md b/ReadMe.md index 1f6033638..77d084238 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -21,7 +21,7 @@ ## Usage - Serialization/Parsing ---- -- Create a specialization of the `Jsonifier::Core` class template for whichever data structure you would like to parse/serialize, within the Jsonifier namespace as follows... +- Create a specialization of the `jsonifier::core` class template for whichever data structure you would like to parse/serialize, within the Jsonifier namespace as follows... ---- ```cpp namespace TestNS { @@ -66,61 +66,61 @@ namespace TestNS { namespace Jsonifier { - template<> struct Core { + template<> struct core { using ValueType = TestNS::fixed_object_t; - static constexpr auto parseValue = object("int_array", &ValueType::int_array, "float_array", &ValueType::float_array, "double_array", &ValueType::double_array); + static constexpr auto parseValue = createObject("int_array", &ValueType::int_array, "float_array", &ValueType::float_array, "double_array", &ValueType::double_array); }; - template<> struct Core { + template<> struct core { using ValueType = TestNS::fixed_name_object_t; - static constexpr auto parseValue = object("name0", &ValueType::name0, "name1", &ValueType::name1, "name2", &ValueType::name2, "name3", &ValueType::name3, "name4", &ValueType::name4); + static constexpr auto parseValue = createObject("name0", &ValueType::name0, "name1", &ValueType::name1, "name2", &ValueType::name2, "name3", &ValueType::name3, "name4", &ValueType::name4); }; - template<> struct Core { + template<> struct core { using ValueType = TestNS::nested_object_t; - static constexpr auto parseValue = object("v3s", &ValueType::v3s, "id", &ValueType::id); + static constexpr auto parseValue = createObject("v3s", &ValueType::v3s, "id", &ValueType::id); }; - template<> struct Core { + template<> struct core { using ValueType = TestNS::another_object_t; static constexpr auto parseValue = - object("string", &ValueType::string, "another_string", &ValueType::another_string, "boolean", &ValueType::boolean, "nested_object", &ValueType::nested_object); + createObject("string", &ValueType::string, "another_string", &ValueType::another_string, "boolean", &ValueType::boolean, "nested_object", &ValueType::nested_object); }; - template<> struct Core { + template<> struct core { using ValueType = TestNS::obj_t; static constexpr auto parseValue = - object("fixed_object", &ValueType::fixed_object, "fixed_name_object", &ValueType::fixed_name_object, "another_object", &ValueType::another_object, "string_array", + createObject("fixed_object", &ValueType::fixed_object, "fixed_name_object", &ValueType::fixed_name_object, "another_object", &ValueType::another_object, "string_array", &ValueType::string_array, "string", &ValueType::string, "number", &ValueType::number, "boolean", &ValueType::boolean, "another_bool", &ValueType::another_bool); }; } ``` ### Usage - Parsing -- Create an instance of the `Jsonifier::JsonifierCore` class, and pass to its function `parseJson()` a reference to the intended parsing target, along with a reference to a `std::string` or equivalent, to be parsed from, as follows... +- Create an instance of the `jsonifier::jsonifier_core` class, and pass to its function `parseJson()` a reference to the intended parsing target, along with a reference to a `std::string` or equivalent, to be parsed from, as follows... - Note: You can save parsing time by reusing a previously-allocated object, that has been used for previous parses. ```cpp std::string buffer{ json0 }; obj_t obj{}; -Jsonifier::JsonifierCore parser{}; +jsonifier::jsonifier_core parser{}; parser.parseJson(obj, buffer); ``` ### Usage - Serialization -- Create an instance of the `Jsonifier::JsonifierCore` class, and pass to its function `serializeJson()` a reference to the intended serialization target, along with a reference to a `std::string` or equivalent, to be serialized into, as follows... +- Create an instance of the `jsonifier::jsonifier_core` class, and pass to its function `serializeJson()` a reference to the intended serialization target, along with a reference to a `std::string` or equivalent, to be serialized into, as follows... - Note: You can save serialization time by reusing a previously-allocated buffer, that has been used for previous serializations. ```cpp std::string buffer{}; obj_t obj{}; -Jsonifier::JsonifierCore serializer{}; +jsonifier::jsonifier_core serializer{}; serializer.serializeJson(obj, buffer); ``` ## Excluding Keys from Serialization at Runtime ---- -To exclude certain keys from being serialized at runtime using the Jsonifier library, you can create a member in your object called excludedKeys and add the keys you want to exclude to this set. You can then call the `serializeJson` member function of the `Jsonifier::JsonifierCore` class with `true` passed into its first template parameter, to serialize the object to a JSON string, excluding the keys in the `excludedKeys` set. +To exclude certain keys from being serialized at runtime using the Jsonifier library, you can create a member in your object called excludedKeys and add the keys you want to exclude to this set. You can then call the `serializeJson` member function of the `jsonifier::jsonifier_core` class with `true` passed into its first template parameter, to serialize the object to a JSON string, excluding the keys in the `excludedKeys` set. Here's an example of how you can do this: ```c++ @@ -140,7 +140,7 @@ public: int32_t main() { MyObject obj("John", 30); - Jsonifier::JsonifierCore jsonifier{}; + jsonifier::jsonifier_core jsonifier{}; std::string jsonBuffer{}; jsonifier.serializeJson(obj, jsonBuffer); // {"name":"John"} return 0; @@ -149,11 +149,11 @@ int32_t main() { In this example, we have a class called `MyObject` with three member variables: `name`, `age`, and `excludedKeys`. The `excludedKeys` variable is a set of strings that will contain the keys we want to exclude from the serialized output. -In the constructor of `MyObject`, we add the key "age" to the `excludedKeys` set using the `insert` function. This means that when we serialize this object using the `serializeJson` member function of the `Jsonifier::JsonifierCore` class, the "age" key will be excluded from the resulting JSON string. +In the constructor of `MyObject`, we add the key "age" to the `excludedKeys` set using the `insert` function. This means that when we serialize this object using the `serializeJson` member function of the `jsonifier::jsonifier_core` class, the "age" key will be excluded from the resulting JSON string. -In the `main` function, we create an instance of `MyObject` with the name "John" and age 30. We then create an instance of `Jsonifier::JsonifierCore` and call its `serializeJson` member function to serialize the object to a JSON string. Since we added the "age" key to the `excludedKeys` set in the constructor, the resulting JSON string only contains the "name" key. +In the `main` function, we create an instance of `MyObject` with the name "John" and age 30. We then create an instance of `jsonifier::jsonifier_core` and call its `serializeJson` member function to serialize the object to a JSON string. Since we added the "age" key to the `excludedKeys` set in the constructor, the resulting JSON string only contains the "name" key. -By using the `excludedKeys` member variable and adding keys to the set, you can easily exclude certain keys from being serialized at runtime using the Jsonifier library. And with the `serializeJson` member function of the `Jsonifier::JsonifierCore` class, you can easily serialize objects with excluded keys to JSON strings. +By using the `excludedKeys` member variable and adding keys to the set, you can easily exclude certain keys from being serialized at runtime using the Jsonifier library. And with the `serializeJson` member function of the `jsonifier::jsonifier_core` class, you can easily serialize objects with excluded keys to JSON strings. ## Enabling Error Message Output in Jsonifier ---- @@ -209,28 +209,34 @@ Happy parsing with Jsonifier! Jsonifier is a JSON parsing library that supports various CPU architectures to optimize code generation and enhance performance. This page explains the relevant portion of the CMakeLists.txt file in Jsonifier, which detects the CPU architecture and sets the appropriate compiler flags for the supported architectures: x64, AVX, AVX2, and AVX-512. ### CPU Architecture Detection Configuration - The CPU architecture detection and configuration in Jsonifier's CMakeLists.txt file are designed to support the following architectures: x64, AVX, AVX2, and AVX-512. Let's explore each architecture in detail: #### x64 Architecture - The x64 architecture, also known as x86-64 or AMD64, is a 64-bit extension of the x86 instruction set architecture. It provides increased memory addressability and larger general-purpose registers, enabling more efficient processing of 64-bit data. The x64 architecture is widely used in modern CPUs, offering improved performance and expanded capabilities compared to its 32-bit predecessor. #### AVX (Advanced Vector Extensions) - AVX, short for Advanced Vector Extensions, is an extension to the x86 instruction set architecture. AVX provides SIMD (Single Instruction, Multiple Data) instructions for performing parallel processing on vectors of data. It introduces 128-bit vector registers (XMM registers) and new instructions to accelerate floating-point and integer calculations. AVX is supported by many modern CPUs and offers significant performance benefits for applications that can utilize parallel processing. #### AVX2 (Advanced Vector Extensions 2) - AVX2 is an extension of the AVX instruction set architecture. It builds upon the foundation of AVX and introduces additional instructions and capabilities for SIMD processing. AVX2 expands the vector register size to 256 bits (YMM registers) and introduces new integer and floating-point operations, enabling further optimization of vectorized code. CPUs that support AVX2 offer enhanced performance for applications that leverage these advanced instructions. -#### AVX-512 - +#### AVX-512 (Advanced Vector Extensions 512-bit) AVX-512 is an extension of the AVX instruction set architecture, designed to provide even higher levels of vector parallelism. AVX-512 introduces 512-bit vector registers (ZMM registers) and a broad range of new instructions for both floating-point and integer operations. With AVX-512, CPUs can process larger amounts of data in parallel, offering significant performance improvements for applications that can effectively utilize these capabilities. -### Configuration Explanation +### Manual Configuration +In addition to automatic CPU architecture detection, Jsonifier's CMake configuration also allows for manual control over specific CPU instructions. You can manually set the JSONIFIER_CPU_INSTRUCTIONS variable in the CMake configuration to fine-tune the instruction sets used. Here are the values you can use for different instruction sets: + +- JSONIFIER_CPU_INSTRUCTIONS for AVX-512: Set to 1 << 5 +- JSONIFIER_CPU_INSTRUCTIONS for AVX2: Set to 1 << 4 +- JSONIFIER_CPU_INSTRUCTIONS for AVX: Set to 1 << 3 +- JSONIFIER_CPU_INSTRUCTIONS for BMI: Set to 1 << 2 +- JSONIFIER_CPU_INSTRUCTIONS for LZCOUNT: Set to 1 << 1 +- JSONIFIER_CPU_INSTRUCTIONS for POPCNT: Set to 1 << 0 -The configuration script in Jsonifier's CMakeLists.txt file detects the CPU architecture and sets the appropriate compiler flags based on the supported architectures. It ensures that the generated code takes full advantage of the available instruction sets and achieves the best possible performance on the target CPU. +You can combine LZCNT, BMI, and POPCNT with each other or any of the three AVX types (AVX, AVX2, AVX-512) to optimize Jsonifier for your specific use case. However, please note that you cannot combine multiple AVX types together, as they are distinct and cannot be used simultaneously. This flexibility in instruction set configuration allows you to tailor Jsonifier's performance to your target CPU architecture and application requirements effectively. + +### Configuration Explanation +The configuration script in Jsonifier's CMakeLists.txt file detects the CPU architecture and sets the appropriate compiler flags based on the supported architectures. It ensures that the generated code takes full advantage of the available instruction sets and achieves the best possible performance on the target CPU. Additionally, the manual configuration option allows you to customize the instruction sets for further optimization according to your specific needs. ## Installation (Vcpkg) - Requirements: diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 4ab0dfcc1..ceb13ad50 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -1,30 +1,9 @@ -cmake_minimum_required(VERSION 3.18) - -project( - "Json-Performance" - VERSION 0.1 - LANGUAGES CXX -) - set(CMAKE_CXX_STANDARD 20) -if (DEFINED GITHUB_BRANCH_TYPE) - string (REPLACE "/" ";" GITHUB_BRANCH_TYPE "${GITHUB_BRANCH_TYPE}") - list(GET GITHUB_BRANCH_TYPE 2 BRANCH) -else() - set(BRANCH "dev") -endif() +set(CMAKE_INSTALL_PREFIX "${CMAKE_SOURCE_DIR}/Install/") include(FetchContent) -FetchContent_Declare( - Jsonifier - GIT_REPOSITORY https://github.com/RealTimeChris/Jsonifier.git - GIT_TAG "${BRANCH}" - GIT_SHALLOW TRUE -) -FetchContent_MakeAvailable(Jsonifier) - FetchContent_Declare( glaze GIT_REPOSITORY https://github.com/stephenberry/glaze.git @@ -50,11 +29,11 @@ FetchContent_Declare( FetchContent_MakeAvailable(fmt) add_executable( - "${PROJECT_NAME}" + "Json-Performance" "main.cpp" ) target_link_libraries( - "${PROJECT_NAME}" PRIVATE - Jsonifier glaze::glaze simdjson fmt::fmt + "Json-Performance" PUBLIC + Jsonifier::Jsonifier glaze::glaze simdjson fmt::fmt ) diff --git a/Tests/main.cpp b/Tests/main.cpp index a7392d555..d76485ed8 100644 --- a/Tests/main.cpp +++ b/Tests/main.cpp @@ -1,7 +1,10 @@ #include "glaze/core/macros.hpp" -#include "glaze/glaze.hpp" -#include + #include "glaze/glaze.hpp" +#ifdef JSONIFIER_CPU_INSTRUCTIONS +//#undef JSONIFIER_CPU_INSTRUCTIONS +#endif + #include constexpr static std::string_view json0 = R"({"fixed_object": { "int_array": [0, 1, 2, 3, 4, 5, 6], @@ -100,62 +103,55 @@ struct obj_t { }; template<> struct glz::meta { - using OTy = fixed_object_t; + using OTy = fixed_object_t; constexpr static auto value = object("int_array", &OTy::int_array, "float_array", &OTy::float_array, "double_array", &OTy::double_array); }; template<> struct glz::meta { - using OTy = fixed_name_object_t; - constexpr static auto value = - object("name0", &OTy::name0, "name1", &OTy::name1, "name2", &OTy::name2, "name3", &OTy::name3, "name4", &OTy::name4); + using OTy = fixed_name_object_t; + constexpr static auto value = object("name0", &OTy::name0, "name1", &OTy::name1, "name2", &OTy::name2, "name3", &OTy::name3, "name4", &OTy::name4); }; template<> struct glz::meta { - using OTy = nested_object_t; + using OTy = nested_object_t; constexpr static auto value = object("v3s", &OTy::v3s, "id", &OTy::id); }; template<> struct glz::meta { - using OTy = another_object_t; - constexpr static auto value = - object("string", &OTy::string, "another_string", &OTy::another_string, "boolean", &OTy::boolean, "nested_object", &OTy::nested_object); + using OTy = another_object_t; + constexpr static auto value = object("string", &OTy::string, "another_string", &OTy::another_string, "boolean", &OTy::boolean, "nested_object", &OTy::nested_object); }; template<> struct glz::meta { - using OTy = obj_t; - constexpr static auto value = glz::object("fixed_object", &OTy::fixed_object, "fixed_name_object", &OTy::fixed_name_object, - "another_object", &OTy::another_object, "string_array", &OTy::string_array, "string", &OTy::string, "number", &OTy::number, "boolean", - &OTy::boolean, "another_bool", &OTy::another_bool); + using OTy = obj_t; + constexpr static auto value = glz::object("fixed_object", &OTy::fixed_object, "fixed_name_object", &OTy::fixed_name_object, "another_object", &OTy::another_object, + "string_array", &OTy::string_array, "string", &OTy::string, "number", &OTy::number, "boolean", &OTy::boolean, "another_bool", &OTy::another_bool); }; -template<> struct Jsonifier::Core { - using OTy = fixed_object_t; - constexpr static auto parseValue = - object("int_array", &OTy::int_array, "float_array", &OTy::float_array, "double_array", &OTy::double_array); +template<> struct jsonifier::core { + using OTy = fixed_object_t; + constexpr static auto parseValue = createObject("int_array", &OTy::int_array, "float_array", &OTy::float_array, "double_array", &OTy::double_array); }; -template<> struct Jsonifier::Core { - using OTy = fixed_name_object_t; - constexpr static auto parseValue = - object("name0", &OTy::name0, "name1", &OTy::name1, "name2", &OTy::name2, "name3", &OTy::name3, "name4", &OTy::name4); +template<> struct jsonifier::core { + using OTy = fixed_name_object_t; + constexpr static auto parseValue = createObject("name0", &OTy::name0, "name1", &OTy::name1, "name2", &OTy::name2, "name3", &OTy::name3, "name4", &OTy::name4); }; -template<> struct Jsonifier::Core { - using OTy = nested_object_t; - constexpr static auto parseValue = object("v3s", &OTy::v3s, "id", &OTy::id); +template<> struct jsonifier::core { + using OTy = nested_object_t; + constexpr static auto parseValue = createObject("v3s", &OTy::v3s, "id", &OTy::id); }; -template<> struct Jsonifier::Core { - using OTy = another_object_t; - constexpr static auto parseValue = - object("string", &OTy::string, "another_string", &OTy::another_string, "boolean", &OTy::boolean, "nested_object", &OTy::nested_object); +template<> struct jsonifier::core { + using OTy = another_object_t; + constexpr static auto parseValue = createObject("string", &OTy::string, "another_string", &OTy::another_string, "boolean", &OTy::boolean, "nested_object", &OTy::nested_object); }; -template<> struct Jsonifier::Core { - using OTy = obj_t; - constexpr static auto parseValue = object("fixed_object", &OTy::fixed_object, "fixed_name_object", &OTy::fixed_name_object, - "another_object", &OTy::another_object, "string_array", &OTy::string_array, "string", &OTy::string, "number", &OTy::number, "boolean", - &OTy::boolean, "another_bool", &OTy::another_bool); +template<> struct jsonifier::core { + using OTy = obj_t; + constexpr static auto parseValue = createObject("fixed_object", &OTy::fixed_object, "fixed_name_object", &OTy::fixed_name_object, "another_object", &OTy::another_object, + "string_array", &OTy::string_array, "string", &OTy::string, "number", &OTy::number, "boolean", &OTy::boolean, "another_bool", &OTy::another_bool); }; template struct Test { @@ -166,9 +162,8 @@ template struct Test { v.resize(1000); for (uint64_t x = 0; x < 1000; ++x) { if constexpr (std::same_as || std::same_as) { - v[x] = std::to_string(1000000000000000) + std::to_string(1000000000000000) + std::to_string(1000000000000000) + - std::to_string(1000000000000000) + std::to_string(1000000000000000) + std::to_string(1000000000000000) + - std::to_string(1000000000000000) + std::to_string(1000000000000000); + v[x] = std::to_string(1000000000000000) + std::to_string(1000000000000000) + std::to_string(1000000000000000) + std::to_string(1000000000000000) + + std::to_string(1000000000000000) + std::to_string(1000000000000000) + std::to_string(1000000000000000) + std::to_string(1000000000000000); } else { v[x] = static_cast(100000000000000000); } @@ -209,32 +204,32 @@ GLZ_META(Test, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s GLZ_META(Test, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z); GLZ_META(Test, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z); -template<> struct Jsonifier::Core> { - using OTy = Test; - constexpr static auto parseValue = object("a", &OTy::a, "b", &OTy::b, "c", &OTy::c, "d", &OTy::d, "e", &OTy::e, "f", &OTy::f, "g", &OTy::g, - "h", &OTy::h, "i", &OTy::i, "j", &OTy::j, "k", &OTy::k, "l", &OTy::l, "m", &OTy::m, "n", &OTy::n, "o", &OTy::o, "p", &OTy::p, "q", &OTy::q, - "r", &OTy::r, "s", &OTy::s, "t", &OTy::t, "u", &OTy::u, "v", &OTy::v, "w", &OTy::w, "x", &OTy::x, "y", &OTy::y, "z", &OTy::z); +template<> struct jsonifier::core> { + using OTy = Test; + constexpr static auto parseValue = createObject("a", &OTy::a, "b", &OTy::b, "c", &OTy::c, "d", &OTy::d, "e", &OTy::e, "f", &OTy::f, "g", &OTy::g, "h", &OTy::h, "i", &OTy::i, + "j", &OTy::j, "k", &OTy::k, "l", &OTy::l, "m", &OTy::m, "n", &OTy::n, "o", &OTy::o, "p", &OTy::p, "q", &OTy::q, "r", &OTy::r, "s", &OTy::s, "t", &OTy::t, "u", &OTy::u, "v", + &OTy::v, "w", &OTy::w, "x", &OTy::x, "y", &OTy::y, "z", &OTy::z); }; -template<> struct Jsonifier::Core> { - using OTy = Test; - constexpr static auto parseValue = object("a", &OTy::a, "b", &OTy::b, "c", &OTy::c, "d", &OTy::d, "e", &OTy::e, "f", &OTy::f, "g", &OTy::g, - "h", &OTy::h, "i", &OTy::i, "j", &OTy::j, "k", &OTy::k, "l", &OTy::l, "m", &OTy::m, "n", &OTy::n, "o", &OTy::o, "p", &OTy::p, "q", &OTy::q, - "r", &OTy::r, "s", &OTy::s, "t", &OTy::t, "u", &OTy::u, "v", &OTy::v, "w", &OTy::w, "x", &OTy::x, "y", &OTy::y, "z", &OTy::z); +template<> struct jsonifier::core> { + using OTy = Test; + constexpr static auto parseValue = createObject("a", &OTy::a, "b", &OTy::b, "c", &OTy::c, "d", &OTy::d, "e", &OTy::e, "f", &OTy::f, "g", &OTy::g, "h", &OTy::h, "i", &OTy::i, + "j", &OTy::j, "k", &OTy::k, "l", &OTy::l, "m", &OTy::m, "n", &OTy::n, "o", &OTy::o, "p", &OTy::p, "q", &OTy::q, "r", &OTy::r, "s", &OTy::s, "t", &OTy::t, "u", &OTy::u, "v", + &OTy::v, "w", &OTy::w, "x", &OTy::x, "y", &OTy::y, "z", &OTy::z); }; -template<> struct Jsonifier::Core> { - using OTy = Test; - constexpr static auto parseValue = object("a", &OTy::a, "b", &OTy::b, "c", &OTy::c, "d", &OTy::d, "e", &OTy::e, "f", &OTy::f, "g", &OTy::g, - "h", &OTy::h, "i", &OTy::i, "j", &OTy::j, "k", &OTy::k, "l", &OTy::l, "m", &OTy::m, "n", &OTy::n, "o", &OTy::o, "p", &OTy::p, "q", &OTy::q, - "r", &OTy::r, "s", &OTy::s, "t", &OTy::t, "u", &OTy::u, "v", &OTy::v, "w", &OTy::w, "x", &OTy::x, "y", &OTy::y, "z", &OTy::z); +template<> struct jsonifier::core> { + using OTy = Test; + constexpr static auto parseValue = createObject("a", &OTy::a, "b", &OTy::b, "c", &OTy::c, "d", &OTy::d, "e", &OTy::e, "f", &OTy::f, "g", &OTy::g, "h", &OTy::h, "i", &OTy::i, + "j", &OTy::j, "k", &OTy::k, "l", &OTy::l, "m", &OTy::m, "n", &OTy::n, "o", &OTy::o, "p", &OTy::p, "q", &OTy::q, "r", &OTy::r, "s", &OTy::s, "t", &OTy::t, "u", &OTy::u, "v", + &OTy::v, "w", &OTy::w, "x", &OTy::x, "y", &OTy::y, "z", &OTy::z); }; -template<> struct Jsonifier::Core> { - using OTy = Test; - constexpr static auto parseValue = object("a", &OTy::a, "b", &OTy::b, "c", &OTy::c, "d", &OTy::d, "e", &OTy::e, "f", &OTy::f, "g", &OTy::g, - "h", &OTy::h, "i", &OTy::i, "j", &OTy::j, "k", &OTy::k, "l", &OTy::l, "m", &OTy::m, "n", &OTy::n, "o", &OTy::o, "p", &OTy::p, "q", &OTy::q, - "r", &OTy::r, "s", &OTy::s, "t", &OTy::t, "u", &OTy::u, "v", &OTy::v, "w", &OTy::w, "x", &OTy::x, "y", &OTy::y, "z", &OTy::z); +template<> struct jsonifier::core> { + using OTy = Test; + constexpr static auto parseValue = createObject("a", &OTy::a, "b", &OTy::b, "c", &OTy::c, "d", &OTy::d, "e", &OTy::e, "f", &OTy::f, "g", &OTy::g, "h", &OTy::h, "i", &OTy::i, + "j", &OTy::j, "k", &OTy::k, "l", &OTy::l, "m", &OTy::m, "n", &OTy::n, "o", &OTy::o, "p", &OTy::p, "q", &OTy::q, "r", &OTy::r, "s", &OTy::s, "t", &OTy::t, "u", &OTy::u, "v", + &OTy::v, "w", &OTy::w, "x", &OTy::x, "y", &OTy::y, "z", &OTy::z); }; template struct AbcTest { @@ -245,9 +240,8 @@ template struct AbcTest { v.resize(1000); for (uint64_t x = 0; x < 1000; ++x) { if constexpr (std::same_as || std::same_as) { - v[x] = std::to_string(1000000000000000) + std::to_string(1000000000000000) + std::to_string(1000000000000000) + - std::to_string(1000000000000000) + std::to_string(1000000000000000) + std::to_string(1000000000000000) + - std::to_string(1000000000000000) + std::to_string(1000000000000000); + v[x] = std::to_string(1000000000000000) + std::to_string(1000000000000000) + std::to_string(1000000000000000) + std::to_string(1000000000000000) + + std::to_string(1000000000000000) + std::to_string(1000000000000000) + std::to_string(1000000000000000) + std::to_string(1000000000000000); } else { v[x] = static_cast(100000000000000000); } @@ -288,39 +282,39 @@ GLZ_META(AbcTest, z, y, x, w, v, u, t, s, r, q, p, o, n, m, l, k, j, i GLZ_META(AbcTest, z, y, x, w, v, u, t, s, r, q, p, o, n, m, l, k, j, i, h, g, f, e, d, c, b, a); GLZ_META(AbcTest, z, y, x, w, v, u, t, s, r, q, p, o, n, m, l, k, j, i, h, g, f, e, d, c, b, a); -template<> struct Jsonifier::Core> { - using OTy = AbcTest; - constexpr static auto parseValue = object("z", &OTy::z, "y", &OTy::y, "x", &OTy::x, "w", &OTy::w, "v", &OTy::v, "u", &OTy::u, "t", &OTy::t, - "s", &OTy::s, "r", &OTy::r, "q", &OTy::q, "p", &OTy::p, "o", &OTy::o, "n", &OTy::n, "m", &OTy::m, "l", &OTy::l, "k", &OTy::k, "j", &OTy::j, - "i", &OTy::i, "h", &OTy::h, "g", &OTy::g, "f", &OTy::f, "e", &OTy::e, "d", &OTy::d, "c", &OTy::c, "b", &OTy::b, "a", &OTy::a); +template<> struct jsonifier::core> { + using OTy = AbcTest; + constexpr static auto parseValue = createObject("z", &OTy::z, "y", &OTy::y, "x", &OTy::x, "w", &OTy::w, "v", &OTy::v, "u", &OTy::u, "t", &OTy::t, "s", &OTy::s, "r", &OTy::r, + "q", &OTy::q, "p", &OTy::p, "o", &OTy::o, "n", &OTy::n, "m", &OTy::m, "l", &OTy::l, "k", &OTy::k, "j", &OTy::j, "i", &OTy::i, "h", &OTy::h, "g", &OTy::g, "f", &OTy::f, "e", + &OTy::e, "d", &OTy::d, "c", &OTy::c, "b", &OTy::b, "a", &OTy::a); }; -template<> struct Jsonifier::Core> { - using OTy = AbcTest; - constexpr static auto parseValue = object("z", &OTy::z, "y", &OTy::y, "x", &OTy::x, "w", &OTy::w, "v", &OTy::v, "u", &OTy::u, "t", &OTy::t, - "s", &OTy::s, "r", &OTy::r, "q", &OTy::q, "p", &OTy::p, "o", &OTy::o, "n", &OTy::n, "m", &OTy::m, "l", &OTy::l, "k", &OTy::k, "j", &OTy::j, - "i", &OTy::i, "h", &OTy::h, "g", &OTy::g, "f", &OTy::f, "e", &OTy::e, "d", &OTy::d, "c", &OTy::c, "b", &OTy::b, "a", &OTy::a); +template<> struct jsonifier::core> { + using OTy = AbcTest; + constexpr static auto parseValue = createObject("z", &OTy::z, "y", &OTy::y, "x", &OTy::x, "w", &OTy::w, "v", &OTy::v, "u", &OTy::u, "t", &OTy::t, "s", &OTy::s, "r", &OTy::r, + "q", &OTy::q, "p", &OTy::p, "o", &OTy::o, "n", &OTy::n, "m", &OTy::m, "l", &OTy::l, "k", &OTy::k, "j", &OTy::j, "i", &OTy::i, "h", &OTy::h, "g", &OTy::g, "f", &OTy::f, "e", + &OTy::e, "d", &OTy::d, "c", &OTy::c, "b", &OTy::b, "a", &OTy::a); }; -template<> struct Jsonifier::Core> { - using OTy = AbcTest; - constexpr static auto parseValue = object("z", &OTy::z, "y", &OTy::y, "x", &OTy::x, "w", &OTy::w, "v", &OTy::v, "u", &OTy::u, "t", &OTy::t, - "s", &OTy::s, "r", &OTy::r, "q", &OTy::q, "p", &OTy::p, "o", &OTy::o, "n", &OTy::n, "m", &OTy::m, "l", &OTy::l, "k", &OTy::k, "j", &OTy::j, - "i", &OTy::i, "h", &OTy::h, "g", &OTy::g, "f", &OTy::f, "e", &OTy::e, "d", &OTy::d, "c", &OTy::c, "b", &OTy::b, "a", &OTy::a); +template<> struct jsonifier::core> { + using OTy = AbcTest; + constexpr static auto parseValue = createObject("z", &OTy::z, "y", &OTy::y, "x", &OTy::x, "w", &OTy::w, "v", &OTy::v, "u", &OTy::u, "t", &OTy::t, "s", &OTy::s, "r", &OTy::r, + "q", &OTy::q, "p", &OTy::p, "o", &OTy::o, "n", &OTy::n, "m", &OTy::m, "l", &OTy::l, "k", &OTy::k, "j", &OTy::j, "i", &OTy::i, "h", &OTy::h, "g", &OTy::g, "f", &OTy::f, "e", + &OTy::e, "d", &OTy::d, "c", &OTy::c, "b", &OTy::b, "a", &OTy::a); }; -template<> struct Jsonifier::Core> { - using OTy = AbcTest; - constexpr static auto parseValue = object("z", &OTy::z, "y", &OTy::y, "x", &OTy::x, "w", &OTy::w, "v", &OTy::v, "u", &OTy::u, "t", &OTy::t, - "s", &OTy::s, "r", &OTy::r, "q", &OTy::q, "p", &OTy::p, "o", &OTy::o, "n", &OTy::n, "m", &OTy::m, "l", &OTy::l, "k", &OTy::k, "j", &OTy::j, - "i", &OTy::i, "h", &OTy::h, "g", &OTy::g, "f", &OTy::f, "e", &OTy::e, "d", &OTy::d, "c", &OTy::c, "b", &OTy::b, "a", &OTy::a); +template<> struct jsonifier::core> { + using OTy = AbcTest; + constexpr static auto parseValue = createObject("z", &OTy::z, "y", &OTy::y, "x", &OTy::x, "w", &OTy::w, "v", &OTy::v, "u", &OTy::u, "t", &OTy::t, "s", &OTy::s, "r", &OTy::r, + "q", &OTy::q, "p", &OTy::p, "o", &OTy::o, "n", &OTy::n, "m", &OTy::m, "l", &OTy::l, "k", &OTy::k, "j", &OTy::j, "i", &OTy::i, "h", &OTy::h, "g", &OTy::g, "f", &OTy::f, "e", + &OTy::e, "d", &OTy::d, "c", &OTy::c, "b", &OTy::b, "a", &OTy::a); }; -#if defined NDEBUG -constexpr static uint64_t iterations = 1000; +#if defined(NDEBUG) +constexpr static uint64_t iterations = 1000; constexpr static uint64_t iterations_abc = 1000; #else -constexpr static uint64_t iterations = 1; +constexpr static uint64_t iterations = 1; constexpr static uint64_t iterations_abc = 1; #endif @@ -411,51 +405,51 @@ struct results { std::string json_stats() { std::string write{}; std::string read{}; - std::string finalString{}; + std::string finalstring{}; bool wasThereOneBeforeThis{ false }; if (json_read) { - write = json_write ? fmt::format("{}", static_cast(*json_byte_length / (*json_write) * 1000.0f)) : "N/A"; - read = json_read ? fmt::format("{}", static_cast(*json_byte_length / (*json_read) * 1000.0f)) : "N/A"; - finalString = fmt::format("| [**{}**]({}) | **{}** | **{}** | **{}** |", name, url, "Mixed", write, read); + write = json_write ? fmt::format("{}", static_cast(*json_byte_length / (*json_write) * 1000.0f)) : "N/A"; + read = json_read ? fmt::format("{}", static_cast(*json_byte_length / (*json_read) * 1000.0f)) : "N/A"; + finalstring = fmt::format("| [**{}**]({}) | **{}** | **{}** | **{}** |", name, url, "Mixed", write, read); wasThereOneBeforeThis = true; } if (json_read_double) { if (wasThereOneBeforeThis) { - finalString += +"\n"; + finalstring += +"\n"; } write = json_write_double ? fmt::format("{}", static_cast(*json_byte_length_double / (*json_write_double) * 1000.0f)) : "N/A"; - read = fmt::format("{}", static_cast(*json_byte_length_double / (*json_read_double) * 1000.0f)); - finalString += fmt::format("| [**{}**]({}) | **{}** | **{}** | **{}** |", name, url, "Double", write, read); + read = fmt::format("{}", static_cast(*json_byte_length_double / (*json_read_double) * 1000.0f)); + finalstring += fmt::format("| [**{}**]({}) | **{}** | **{}** | **{}** |", name, url, "Double", write, read); wasThereOneBeforeThis = true; } if (json_read_string) { if (wasThereOneBeforeThis) { - finalString += +"\n"; + finalstring += +"\n"; } write = json_write_string ? fmt::format("{}", static_cast(*json_byte_length_string / (*json_write_string) * 1000.0f)) : "N/A"; - read = fmt::format("{}", static_cast(*json_byte_length_string / (*json_read_string) * 1000.0f)); - finalString += fmt::format("| [**{}**]({}) | **{}** | **{}** | **{}** |", name, url, "String", write, read); + read = fmt::format("{}", static_cast(*json_byte_length_string / (*json_read_string) * 1000.0f)); + finalstring += fmt::format("| [**{}**]({}) | **{}** | **{}** | **{}** |", name, url, "string", write, read); wasThereOneBeforeThis = true; } if (json_read_uint64) { if (wasThereOneBeforeThis) { - finalString += +"\n"; + finalstring += +"\n"; } write = json_write_uint64 ? fmt::format("{}", static_cast(*json_byte_length_uint64 / (*json_write_uint64) * 1000.0f)) : "N/A"; - read = fmt::format("{}", static_cast(*json_byte_length_uint64 / (*json_read_uint64) * 1000.0f)); - finalString += fmt::format("| [**{}**]({}) | **{}** | **{}** | **{}** |", name, url, "Uint64", write, read); + read = fmt::format("{}", static_cast(*json_byte_length_uint64 / (*json_read_uint64) * 1000.0f)); + finalstring += fmt::format("| [**{}**]({}) | **{}** | **{}** | **{}** |", name, url, "Uint64", write, read); wasThereOneBeforeThis = true; } if (json_read_int64) { if (wasThereOneBeforeThis) { - finalString += +"\n"; + finalstring += +"\n"; } write = json_write_int64 ? fmt::format("{}", static_cast(*json_byte_length_int64 / (*json_write_int64) * 1000.0f)) : "N/A"; - read = fmt::format("{}", static_cast(*json_byte_length_int64 / (*json_read_int64) * 1000.0f)); - finalString += fmt::format("| [**{}**]({}) | **{}** | **{}** | **{}** |", name, url, "Int64", write, read); + read = fmt::format("{}", static_cast(*json_byte_length_int64 / (*json_read_int64) * 1000.0f)); + finalstring += fmt::format("| [**{}**]({}) | **{}** | **{}** | **{}** |", name, url, "Int64", write, read); wasThereOneBeforeThis = true; } - return finalString; + return finalstring; } }; @@ -463,7 +457,7 @@ struct results { class FileLoader { public: FileLoader(const char* filePathNew) { - filePath = filePathNew; + filePath = filePathNew; auto theStream = std::ofstream{ filePath, std::ios::out | std::ios::in }; std::stringstream inputStream{}; inputStream << theStream.rdbuf(); @@ -527,7 +521,7 @@ auto glaze_test() { iterations); r.json_byte_length = buffer.size(); - r.json_read = result; + r.json_read = result; buffer.clear(); glz::write_json(obj, buffer); @@ -557,7 +551,7 @@ auto glaze_test() { iterations); r.json_byte_length_uint64 = buffer.size(); - r.json_write_uint64 = result; + r.json_write_uint64 = result; if (auto error = glz::read_json(uint64Test, buffer)) { std::cout << "glaze Error: " << error << std::endl; @@ -594,7 +588,7 @@ auto glaze_test() { iterations); r.json_byte_length_int64 = buffer.size(); - r.json_write_int64 = result; + r.json_write_int64 = result; if (auto error = glz::read_json(int64Test, buffer)) { std::cout << "glaze Error: " << error << std::endl; @@ -632,7 +626,7 @@ auto glaze_test() { iterations); r.json_byte_length_string = buffer.size(); - r.json_write_string = result; + r.json_write_string = result; if (auto error = glz::read_json(stringTest, buffer)) { std::cout << "glaze Error: " << error << std::endl; @@ -670,7 +664,7 @@ auto glaze_test() { iterations); r.json_byte_length_double = buffer.size(); - r.json_write_double = result; + r.json_write_double = result; if (auto error = glz::read_json(doubleTest, buffer)) { std::cout << "glaze Error: " << error << std::endl; @@ -718,7 +712,7 @@ auto glaze_single_test() { 1); r.json_byte_length = buffer.size(); - r.json_read = result; + r.json_read = result; buffer.clear(); glz::write_json(obj, buffer); @@ -748,7 +742,7 @@ auto glaze_single_test() { 1); r.json_byte_length_uint64 = buffer.size(); - r.json_write_uint64 = result; + r.json_write_uint64 = result; if (auto error = glz::read_json(uint64Test, buffer)) { std::cout << "glaze Error: " << error << std::endl; @@ -785,7 +779,7 @@ auto glaze_single_test() { 1); r.json_byte_length_int64 = buffer.size(); - r.json_write_int64 = result; + r.json_write_int64 = result; if (auto error = glz::read_json(int64Test, buffer)) { std::cout << "glaze Error: " << error << std::endl; @@ -823,7 +817,7 @@ auto glaze_single_test() { 1); r.json_byte_length_string = buffer.size(); - r.json_write_string = result; + r.json_write_string = result; if (auto error = glz::read_json(stringTest, buffer)) { std::cout << "glaze Error: " << error << std::endl; @@ -861,7 +855,7 @@ auto glaze_single_test() { 1); r.json_byte_length_double = buffer.size(); - r.json_write_double = result; + r.json_write_double = result; if (auto error = glz::read_json(doubleTest, buffer)) { std::cout << "glaze Error: " << error << std::endl; @@ -903,7 +897,7 @@ auto glaze_abc_test() { iterations_abc); r.json_byte_length_uint64 = buffer.size(); - r.json_write_uint64 = result; + r.json_write_uint64 = result; if (auto error = glz::read_json(uint64AbcTest, buffer)) { std::cout << "glaze Error: " << error << std::endl; @@ -940,7 +934,7 @@ auto glaze_abc_test() { iterations_abc); r.json_byte_length_int64 = buffer.size(); - r.json_write_int64 = result; + r.json_write_int64 = result; if (auto error = glz::read_json(int64AbcTest, buffer)) { std::cout << "glaze Error: " << error << std::endl; @@ -977,7 +971,7 @@ auto glaze_abc_test() { iterations_abc); r.json_byte_length_string = buffer.size(); - r.json_write_string = result; + r.json_write_string = result; if (auto error = glz::read_json(stringAbcTest, buffer)) { std::cout << "glaze Error: " << error << std::endl; @@ -1015,7 +1009,7 @@ auto glaze_abc_test() { iterations_abc); r.json_byte_length_double = buffer.size(); - r.json_write_double = result; + r.json_write_double = result; if (auto error = glz::read_json(doubleAbcTest, buffer)) { std::cout << "glaze Error: " << error << std::endl; @@ -1040,13 +1034,13 @@ auto glaze_abc_test() { return r; } -auto Jsonifier_test() { +auto jsonifier_test() { std::string buffer{ json0 }; obj_t obj{}; - results r{ "Jsonifier", "https://github.com/RealTimeChris/Jsonifier", iterations }; - Jsonifier::JsonifierCore jsonifier{}; + results r{ "jsonifier", "https://github.com/RealTimeChris/jsonifier", iterations }; + jsonifier::jsonifier_core jsonifier{}; jsonifier.parseJson(obj, buffer); auto result = benchmark( @@ -1054,13 +1048,13 @@ auto Jsonifier_test() { try { jsonifier.parseJson(obj, buffer); } catch (std::runtime_error& e) { - std::cout << "Jsonifier Error: " << e.what() << std::endl; + std::cout << "jsonifier Error: " << e.what() << std::endl; } }, iterations); r.json_byte_length = buffer.size(); - r.json_read = result; + r.json_read = result; buffer.clear(); jsonifier.serializeJson(obj, buffer); @@ -1069,7 +1063,7 @@ auto Jsonifier_test() { try { jsonifier.serializeJson(obj, buffer); } catch (std::runtime_error& e) { - std::cout << "Jsonifier Error: " << e.what() << std::endl; + std::cout << "jsonifier Error: " << e.what() << std::endl; } }, iterations); @@ -1084,13 +1078,13 @@ auto Jsonifier_test() { try { jsonifier.serializeJson(uint64Test, buffer); } catch (std::runtime_error& e) { - std::cout << "Jsonifier Error: " << e.what() << std::endl; + std::cout << "jsonifier Error: " << e.what() << std::endl; } }, iterations); r.json_byte_length_uint64 = buffer.size(); - r.json_write_uint64 = result; + r.json_write_uint64 = result; jsonifier.parseJson(uint64Test, buffer); @@ -1099,7 +1093,7 @@ auto Jsonifier_test() { try { jsonifier.parseJson(uint64Test, buffer); } catch (std::runtime_error& e) { - std::cout << "Jsonifier Error: " << e.what() << std::endl; + std::cout << "jsonifier Error: " << e.what() << std::endl; } }, iterations); @@ -1117,13 +1111,13 @@ auto Jsonifier_test() { jsonifier.serializeJson(int64Test, buffer); } catch (std::runtime_error& e) { - std::cout << "Jsonifier Error: " << e.what() << std::endl; + std::cout << "jsonifier Error: " << e.what() << std::endl; } }, iterations); r.json_byte_length_int64 = buffer.size(); - r.json_write_int64 = result; + r.json_write_int64 = result; jsonifier.parseJson(int64Test, buffer); @@ -1133,7 +1127,7 @@ auto Jsonifier_test() { jsonifier.parseJson(int64Test, buffer); } catch (std::runtime_error& e) { - std::cout << "Jsonifier Error: " << e.what() << std::endl; + std::cout << "jsonifier Error: " << e.what() << std::endl; } }, iterations); @@ -1151,13 +1145,13 @@ auto Jsonifier_test() { jsonifier.serializeJson(stringTest, buffer); } catch (std::runtime_error& e) { - std::cout << "Jsonifier Error: " << e.what() << std::endl; + std::cout << "jsonifier Error: " << e.what() << std::endl; } }, iterations); r.json_byte_length_string = buffer.size(); - r.json_write_string = result; + r.json_write_string = result; jsonifier.parseJson(stringTest, buffer); @@ -1167,7 +1161,7 @@ auto Jsonifier_test() { jsonifier.parseJson(stringTest, buffer); } catch (std::runtime_error& e) { - std::cout << "Jsonifier Error: " << e.what() << std::endl; + std::cout << "jsonifier Error: " << e.what() << std::endl; } }, iterations); @@ -1185,13 +1179,13 @@ auto Jsonifier_test() { jsonifier.serializeJson(doubleTest, buffer); } catch (std::runtime_error& e) { - std::cout << "Jsonifier Error: " << e.what() << std::endl; + std::cout << "jsonifier Error: " << e.what() << std::endl; } }, iterations); r.json_byte_length_double = buffer.size(); - r.json_write_double = result; + r.json_write_double = result; jsonifier.parseJson(doubleTest, buffer); @@ -1201,7 +1195,7 @@ auto Jsonifier_test() { jsonifier.parseJson(doubleTest, buffer); } catch (std::runtime_error& e) { - std::cout << "Jsonifier Error: " << e.what() << std::endl; + std::cout << "jsonifier Error: " << e.what() << std::endl; } }, iterations); @@ -1212,13 +1206,13 @@ auto Jsonifier_test() { return r; } -auto Jsonifier_single_test() { +auto jsonifier_single_test() { std::string buffer{ json0 }; obj_t obj{}; - results r{ "Jsonifier", "https://github.com/RealTimeChris/Jsonifier", 1 }; - Jsonifier::JsonifierCore jsonifier{}; + results r{ "jsonifier", "https://github.com/RealTimeChris/jsonifier", 1 }; + jsonifier::jsonifier_core jsonifier{}; jsonifier.parseJson(obj, buffer); auto result = benchmark( @@ -1226,13 +1220,13 @@ auto Jsonifier_single_test() { try { jsonifier.parseJson(obj, buffer); } catch (std::runtime_error& e) { - std::cout << "Jsonifier Error: " << e.what() << std::endl; + std::cout << "jsonifier Error: " << e.what() << std::endl; } }, 1); r.json_byte_length = buffer.size(); - r.json_read = result; + r.json_read = result; buffer.clear(); jsonifier.serializeJson(obj, buffer); @@ -1241,7 +1235,7 @@ auto Jsonifier_single_test() { try { jsonifier.serializeJson(obj, buffer); } catch (std::runtime_error& e) { - std::cout << "Jsonifier Error: " << e.what() << std::endl; + std::cout << "jsonifier Error: " << e.what() << std::endl; } }, 1); @@ -1256,13 +1250,13 @@ auto Jsonifier_single_test() { try { jsonifier.serializeJson(uint64Test, buffer); } catch (std::runtime_error& e) { - std::cout << "Jsonifier Error: " << e.what() << std::endl; + std::cout << "jsonifier Error: " << e.what() << std::endl; } }, 1); r.json_byte_length_uint64 = buffer.size(); - r.json_write_uint64 = result; + r.json_write_uint64 = result; jsonifier.parseJson(uint64Test, buffer); @@ -1271,7 +1265,7 @@ auto Jsonifier_single_test() { try { jsonifier.parseJson(uint64Test, buffer); } catch (std::runtime_error& e) { - std::cout << "Jsonifier Error: " << e.what() << std::endl; + std::cout << "jsonifier Error: " << e.what() << std::endl; } }, 1); @@ -1289,13 +1283,13 @@ auto Jsonifier_single_test() { jsonifier.serializeJson(int64Test, buffer); } catch (std::runtime_error& e) { - std::cout << "Jsonifier Error: " << e.what() << std::endl; + std::cout << "jsonifier Error: " << e.what() << std::endl; } }, 1); r.json_byte_length_int64 = buffer.size(); - r.json_write_int64 = result; + r.json_write_int64 = result; jsonifier.parseJson(int64Test, buffer); @@ -1305,7 +1299,7 @@ auto Jsonifier_single_test() { jsonifier.parseJson(int64Test, buffer); } catch (std::runtime_error& e) { - std::cout << "Jsonifier Error: " << e.what() << std::endl; + std::cout << "jsonifier Error: " << e.what() << std::endl; } }, 1); @@ -1323,13 +1317,13 @@ auto Jsonifier_single_test() { jsonifier.serializeJson(stringTest, buffer); } catch (std::runtime_error& e) { - std::cout << "Jsonifier Error: " << e.what() << std::endl; + std::cout << "jsonifier Error: " << e.what() << std::endl; } }, 1); r.json_byte_length_string = buffer.size(); - r.json_write_string = result; + r.json_write_string = result; jsonifier.parseJson(stringTest, buffer); @@ -1339,7 +1333,7 @@ auto Jsonifier_single_test() { jsonifier.parseJson(stringTest, buffer); } catch (std::runtime_error& e) { - std::cout << "Jsonifier Error: " << e.what() << std::endl; + std::cout << "jsonifier Error: " << e.what() << std::endl; } }, 1); @@ -1357,13 +1351,13 @@ auto Jsonifier_single_test() { jsonifier.serializeJson(doubleTest, buffer); } catch (std::runtime_error& e) { - std::cout << "Jsonifier Error: " << e.what() << std::endl; + std::cout << "jsonifier Error: " << e.what() << std::endl; } }, 1); r.json_byte_length_double = buffer.size(); - r.json_write_double = result; + r.json_write_double = result; jsonifier.parseJson(doubleTest, buffer); @@ -1373,7 +1367,7 @@ auto Jsonifier_single_test() { jsonifier.parseJson(doubleTest, buffer); } catch (std::runtime_error& e) { - std::cout << "Jsonifier Error: " << e.what() << std::endl; + std::cout << "jsonifier Error: " << e.what() << std::endl; } }, 1); @@ -1384,11 +1378,11 @@ auto Jsonifier_single_test() { return r; } -auto Jsonifier_abc_test() { +auto jsonifier_abc_test() { std::string buffer{}; - results r{ "Jsonifier", "https://github.com/RealTimeChris/Jsonifier", iterations_abc }; - Jsonifier::JsonifierCore jsonifier{}; + results r{ "jsonifier", "https://github.com/RealTimeChris/jsonifier", iterations_abc }; + jsonifier::jsonifier_core jsonifier{}; AbcTest uint64AbcTest{}; jsonifier.serializeJson(uint64AbcTest, buffer); @@ -1397,13 +1391,13 @@ auto Jsonifier_abc_test() { try { jsonifier.serializeJson(uint64AbcTest, buffer); } catch (std::runtime_error& e) { - std::cout << "Jsonifier Error: " << e.what() << std::endl; + std::cout << "jsonifier Error: " << e.what() << std::endl; } }, iterations_abc); r.json_byte_length_uint64 = buffer.size(); - r.json_write_uint64 = result; + r.json_write_uint64 = result; jsonifier.parseJson(uint64AbcTest, buffer); @@ -1412,7 +1406,7 @@ auto Jsonifier_abc_test() { try { jsonifier.parseJson(uint64AbcTest, buffer); } catch (std::runtime_error& e) { - std::cout << "Jsonifier Error: " << e.what() << std::endl; + std::cout << "jsonifier Error: " << e.what() << std::endl; } }, iterations_abc); @@ -1430,13 +1424,13 @@ auto Jsonifier_abc_test() { jsonifier.serializeJson(int64AbcTest, buffer); } catch (std::runtime_error& e) { - std::cout << "Jsonifier Error: " << e.what() << std::endl; + std::cout << "jsonifier Error: " << e.what() << std::endl; } }, iterations_abc); r.json_byte_length_int64 = buffer.size(); - r.json_write_int64 = result; + r.json_write_int64 = result; jsonifier.parseJson(int64AbcTest, buffer); @@ -1446,7 +1440,7 @@ auto Jsonifier_abc_test() { jsonifier.parseJson(int64AbcTest, buffer); } catch (std::runtime_error& e) { - std::cout << "Jsonifier Error: " << e.what() << std::endl; + std::cout << "jsonifier Error: " << e.what() << std::endl; } }, iterations_abc); @@ -1464,13 +1458,13 @@ auto Jsonifier_abc_test() { jsonifier.serializeJson(stringAbcTest, buffer); } catch (std::runtime_error& e) { - std::cout << "Jsonifier Error: " << e.what() << std::endl; + std::cout << "jsonifier Error: " << e.what() << std::endl; } }, iterations_abc); r.json_byte_length_string = buffer.size(); - r.json_write_string = result; + r.json_write_string = result; jsonifier.parseJson(stringAbcTest, buffer); @@ -1480,7 +1474,7 @@ auto Jsonifier_abc_test() { jsonifier.parseJson(stringAbcTest, buffer); } catch (std::runtime_error& e) { - std::cout << "Jsonifier Error: " << e.what() << std::endl; + std::cout << "jsonifier Error: " << e.what() << std::endl; } }, iterations_abc); @@ -1498,13 +1492,13 @@ auto Jsonifier_abc_test() { jsonifier.serializeJson(doubleAbcTest, buffer); } catch (std::runtime_error& e) { - std::cout << "Jsonifier Error: " << e.what() << std::endl; + std::cout << "jsonifier Error: " << e.what() << std::endl; } }, iterations_abc); r.json_byte_length_double = buffer.size(); - r.json_write_double = result; + r.json_write_double = result; jsonifier.parseJson(doubleAbcTest, buffer); @@ -1514,7 +1508,7 @@ auto Jsonifier_abc_test() { jsonifier.parseJson(doubleAbcTest, buffer); } catch (std::runtime_error& e) { - std::cout << "Jsonifier Error: " << e.what() << std::endl; + std::cout << "jsonifier Error: " << e.what() << std::endl; } }, iterations_abc); @@ -1534,13 +1528,13 @@ struct on_demand { bool readDouble(Test& obj, const padded_string& json); bool readUint64(Test& obj, const padded_string& json); bool readInt64(Test& obj, const padded_string& json); - bool readString(Test& obj, const padded_string& json); + bool readstring(Test& obj, const padded_string& json); protected: ondemand::parser parser{}; }; -template void simdPull(const char* x, ValueType02& obj, simdjson::ondemand::document& doc) { +template inline void simdPull(const char* x, value_type02& obj, simdjson::ondemand::document& doc) { ondemand::array xNew = doc[x]; for (const OTy& value: xNew) { obj.x.emplace_back(value); @@ -1696,7 +1690,7 @@ bool on_demand::readInt64(Test& obj, const padded_string& json) { return false; } -bool on_demand::readString(Test& obj, const padded_string& json) { +bool on_demand::readstring(Test& obj, const padded_string& json) { ondemand::document doc = parser.iterate(json).value(); SIMD_STRING_PULL(a); @@ -1730,7 +1724,7 @@ bool on_demand::readString(Test& obj, const padded_string& json) { } bool on_demand::read_in_order(obj_t& obj, const padded_string& json) { - auto doc = parser.iterate(json); + auto doc = parser.iterate(json); ondemand::object fixed_object = doc["fixed_object"]; ondemand::array int_array = fixed_object["int_array"]; @@ -1752,19 +1746,19 @@ bool on_demand::read_in_order(obj_t& obj, const padded_string& json) { } ondemand::object fixed_name_object = doc["fixed_name_object"]; - obj.fixed_name_object.name0 = std::string_view(fixed_name_object["name0"]); - obj.fixed_name_object.name1 = std::string_view(fixed_name_object["name1"]); - obj.fixed_name_object.name2 = std::string_view(fixed_name_object["name2"]); - obj.fixed_name_object.name3 = std::string_view(fixed_name_object["name3"]); - obj.fixed_name_object.name4 = std::string_view(fixed_name_object["name4"]); - - ondemand::object another_object = doc["another_object"]; - obj.another_object.string = std::string_view(another_object["string"]); + obj.fixed_name_object.name0 = std::string_view(fixed_name_object["name0"]); + obj.fixed_name_object.name1 = std::string_view(fixed_name_object["name1"]); + obj.fixed_name_object.name2 = std::string_view(fixed_name_object["name2"]); + obj.fixed_name_object.name3 = std::string_view(fixed_name_object["name3"]); + obj.fixed_name_object.name4 = std::string_view(fixed_name_object["name4"]); + + ondemand::object another_object = doc["another_object"]; + obj.another_object.string = std::string_view(another_object["string"]); obj.another_object.another_string = std::string_view(another_object["another_string"]); - obj.another_object.boolean = bool(another_object["boolean"]); + obj.another_object.boolean = bool(another_object["boolean"]); ondemand::object nested_object = another_object["nested_object"]; - ondemand::array v3s = nested_object["v3s"]; + ondemand::array v3s = nested_object["v3s"]; obj.another_object.nested_object.v3s.clear(); for (ondemand::array v3: v3s) { uint64_t i = 0; @@ -1783,9 +1777,9 @@ bool on_demand::read_in_order(obj_t& obj, const padded_string& json) { obj.string_array[index++] = x; } - obj.string = std::string_view(doc["string"]); - obj.number = double(doc["number"]); - obj.boolean = bool(doc["boolean"]); + obj.string = std::string_view(doc["string"]); + obj.number = double(doc["number"]); + obj.boolean = bool(doc["boolean"]); obj.another_bool = bool(doc["another_bool"]); return false; @@ -1815,7 +1809,7 @@ auto simdjson_test() { results r{ "simdjson (on demand)", "https://github.com/simdjson/simdjson", iterations }; r.json_byte_length = buffer.size(); - r.json_read = result; + r.json_read = result; Test objDouble{}; buffer.clear(); @@ -1836,17 +1830,17 @@ auto simdjson_test() { iterations); r.json_byte_length_double = buffer.size(); - r.json_read_double = result; + r.json_read_double = result; - Test objString{}; + Test objstring{}; buffer.clear(); - buffer = glz::write_json(objString); + buffer = glz::write_json(objstring); - error = parser.readString(objString, buffer); + error = parser.readstring(objstring, buffer); result = benchmark( [&]() { - error = parser.readString(objString, buffer); + error = parser.readstring(objstring, buffer); if (error) { std::cerr << "simdjson error" << std::endl; } @@ -1854,7 +1848,7 @@ auto simdjson_test() { iterations); r.json_byte_length_string = buffer.size(); - r.json_read_string = result; + r.json_read_string = result; Test objInt64{}; buffer.clear(); @@ -1872,7 +1866,7 @@ auto simdjson_test() { iterations); r.json_byte_length_int64 = buffer.size(); - r.json_read_int64 = result; + r.json_read_int64 = result; Test objUint64{}; buffer.clear(); @@ -1890,7 +1884,7 @@ auto simdjson_test() { iterations); r.json_byte_length_uint64 = buffer.size(); - r.json_read_uint64 = result; + r.json_read_uint64 = result; r.print(); @@ -1918,7 +1912,7 @@ auto simdjson_single_test() { results r{ "simdjson (on demand)", "https://github.com/simdjson/simdjson", 1 }; r.json_byte_length = buffer.size(); - r.json_read = result; + r.json_read = result; Test objDouble{}; buffer.clear(); @@ -1936,17 +1930,17 @@ auto simdjson_single_test() { 1); r.json_byte_length_double = buffer.size(); - r.json_read_double = result; + r.json_read_double = result; - Test objString{}; + Test objstring{}; buffer.clear(); - buffer = glz::write_json(objString); + buffer = glz::write_json(objstring); - error = parser.readString(objString, buffer); + error = parser.readstring(objstring, buffer); result = benchmark( [&]() { - error = parser.readString(objString, buffer); + error = parser.readstring(objstring, buffer); if (error) { std::cerr << "simdjson error" << std::endl; } @@ -1954,7 +1948,7 @@ auto simdjson_single_test() { 1); r.json_byte_length_string = buffer.size(); - r.json_read_string = result; + r.json_read_string = result; Test objInt64{}; buffer.clear(); @@ -1972,7 +1966,7 @@ auto simdjson_single_test() { 1); r.json_byte_length_int64 = buffer.size(); - r.json_read_int64 = result; + r.json_read_int64 = result; Test objUint64{}; buffer.clear(); @@ -1990,7 +1984,7 @@ auto simdjson_single_test() { 1); r.json_byte_length_uint64 = buffer.size(); - r.json_read_uint64 = result; + r.json_read_uint64 = result; r.print(); @@ -2002,7 +1996,7 @@ struct on_demand_abc { bool readDouble(AbcTest& obj, const padded_string& json); bool readUint64(AbcTest& obj, const padded_string& json); bool readInt64(AbcTest& obj, const padded_string& json); - bool readString(AbcTest& obj, const padded_string& json); + bool readstring(AbcTest& obj, const padded_string& json); protected: ondemand::parser parser{}; @@ -2105,7 +2099,7 @@ bool on_demand_abc ::readInt64(AbcTest& obj, const padded_string& json) return false; } -bool on_demand_abc ::readString(AbcTest& obj, const padded_string& json) { +bool on_demand_abc ::readstring(AbcTest& obj, const padded_string& json) { ondemand ::document doc = parser.iterate(json).value(); SIMD_STRING_PULL(a); @@ -2159,15 +2153,15 @@ auto simdjson_abc_test() { results r{ "simdjson (on demand)", "https://github.com/simdjson/simdjson", iterations_abc }; r.json_byte_length_double = buffer.size(); - r.json_read_double = result; + r.json_read_double = result; - AbcTest objString{}; + AbcTest objstring{}; buffer.clear(); - buffer = glz::write_json(objString); + buffer = glz::write_json(objstring); result = benchmark( [&]() { - error = parser.readString(objString, buffer); + error = parser.readstring(objstring, buffer); if (error) { std::cerr << "simdjson error" << std::endl; } @@ -2175,7 +2169,7 @@ auto simdjson_abc_test() { iterations_abc); r.json_byte_length_string = buffer.size(); - r.json_read_string = result; + r.json_read_string = result; AbcTest objInt64{}; buffer.clear(); @@ -2191,7 +2185,7 @@ auto simdjson_abc_test() { iterations_abc); r.json_byte_length_int64 = buffer.size(); - r.json_read_int64 = result; + r.json_read_int64 = result; AbcTest objUint64{}; buffer.clear(); @@ -2207,7 +2201,7 @@ auto simdjson_abc_test() { iterations_abc); r.json_byte_length_uint64 = buffer.size(); - r.json_read_uint64 = result; + r.json_read_uint64 = result; r.print(); @@ -2221,7 +2215,7 @@ static std::string table_header = R"( std::string regular_test() { std::vector results{}; results.emplace_back(glaze_test()); - results.emplace_back(Jsonifier_test()); + results.emplace_back(jsonifier_test()); results.emplace_back(simdjson_test()); std::string table{}; @@ -2239,7 +2233,7 @@ std::string regular_test() { std::string abc_test() { std::vector results{}; results.emplace_back(glaze_abc_test()); - results.emplace_back(Jsonifier_abc_test()); + results.emplace_back(jsonifier_abc_test()); results.emplace_back(simdjson_abc_test()); std::string table{}; @@ -2257,7 +2251,7 @@ std::string abc_test() { std::string single_test() { std::vector results{}; results.emplace_back(glaze_single_test()); - results.emplace_back(Jsonifier_single_test()); + results.emplace_back(jsonifier_single_test()); results.emplace_back(simdjson_single_test()); std::string table{}; @@ -2272,29 +2266,27 @@ std::string single_test() { return table; } -int main() { +int32_t main() { try { auto singlTestResults = single_test(); auto multiTestResults = regular_test(); - auto abcTestResults = abc_test(); -#if defined _WIN32 + auto abcTestResults = abc_test(); +#if defined(_WIN32) FileLoader fileLoader{ "../../../ReadMe.md" }; #else FileLoader fileLoader{ "../ReadMe.md" }; #endif - std::string newString = fileLoader; - std::string section01 = - newString.substr(0, newString.find("Single Iteration Test Results:") + std::string("Single Iteration Test Results:").size() + 1); - auto section02 = newString.substr(newString.find("> 1000 iterations on a 6 core (Intel i7 8700k)"), - newString.find("performance regardless of the JSON document's scale.") + - std::string{ "performance regardless of the JSON document's scale." }.size() - - newString.find("> 1000 iterations on a 6 core (Intel i7 8700k)")); - - std::string newerString = section01 + singlTestResults + "\n\nMulti Iteration Test Results:\n" + multiTestResults + "\n" + section02; - newerString += "\n" + abcTestResults + "\n> 1001 iterations on a 6 core (Intel i7 8700k)"; - fileLoader.saveFile(newerString); + std::string newstring = fileLoader; + std::string section01 = newstring.substr(0, newstring.find("Single Iteration Test Results:") + std::string("Single Iteration Test Results:").size() + 1); + auto section02 = newstring.substr(newstring.find("> 1000 iterations on a 6 core (Intel i7 8700k)"), + newstring.find("performance regardless of the JSON document's scale.") + std::string{ "performance regardless of the JSON document's scale." }.size() - + newstring.find("> 1000 iterations on a 6 core (Intel i7 8700k)")); + + std::string newerstring = section01 + singlTestResults + "\n\nMulti Iteration Test Results:\n" + multiTestResults + "\n" + section02; + newerstring += "\n" + abcTestResults + "\n> 1001 iterations on a 6 core (Intel i7 8700k)"; + fileLoader.saveFile(newerstring); } catch (std::exception& e) { std::cout << e.what() << std::endl; } return 0; -} +} \ No newline at end of file diff --git a/Vcpkg/ports/jsonifier/portfile.cmake b/Vcpkg/ports/jsonifier/portfile.cmake index 004fdb5b5..2b2d7d399 100644 --- a/Vcpkg/ports/jsonifier/portfile.cmake +++ b/Vcpkg/ports/jsonifier/portfile.cmake @@ -2,7 +2,7 @@ vcpkg_from_github( OUT_SOURCE_PATH SOURCE_PATH REPO realtimechris/jsonifier REF "v${VERSION}" - SHA512 2e8132da6109a8a82c717ced831ef0d0523310c09fbbf2821dea6660fedd6d43ba653024abbee068f10597207a1c4a15df2e7978f516077a3cb6caa56793704d + SHA512 de60d6a6dd979c7845353eaecfd23ebd407e8f2224cdf3d24c0c3224f57f6ff63e794f2e49731a4109dd2f5b9f340ccbe259c93b6a9fec902ce5f4734de87cd5 HEAD_REF main ) diff --git a/Vcpkg/ports/jsonifier/vcpkg.json b/Vcpkg/ports/jsonifier/vcpkg.json index 130ad4cb4..6038fd9b9 100644 --- a/Vcpkg/ports/jsonifier/vcpkg.json +++ b/Vcpkg/ports/jsonifier/vcpkg.json @@ -1,10 +1,10 @@ { "name": "jsonifier", - "version": "0.9.8", + "version": "0.9.9", "description": "A few classes for parsing and serializing json - very rapidly.", "homepage": "https://github.com/realtimechris/jsonifier", "license": "MIT", - "supports": "(windows & x64 & !uwp & !xbox) | (linux & x64) | (osx & x64)", + "supports": "(windows & x64 & !xbox) | (linux & x64) | (osx & x64)", "dependencies": [ { "name": "vcpkg-cmake", diff --git a/Vcpkg/versions/j-/jsonifier.json b/Vcpkg/versions/j-/jsonifier.json index 2f2bffb6c..c4374a219 100644 --- a/Vcpkg/versions/j-/jsonifier.json +++ b/Vcpkg/versions/j-/jsonifier.json @@ -1,7 +1,12 @@ { "versions": [ { - "git-tree": "7af838919ac8d956f1dfeefe33022783a9f6a8c6", + "git-tree": "f7f91d1744af469af9cdb1067fd6dbfd18ff3895", + "version": "0.9.9", + "port-version": 0 + }, + { + "git-tree": "3e076a2668e15aa6ad44ff29f45356467f745766", "version": "0.9.8", "port-version": 0 },