diff --git a/.github/workflows/CLANG_18-Ubuntu.yml b/.github/workflows/CLANG_18-Ubuntu.yml index 69c424c20..924430eb7 100644 --- a/.github/workflows/CLANG_18-Ubuntu.yml +++ b/.github/workflows/CLANG_18-Ubuntu.yml @@ -8,7 +8,7 @@ on: jobs: Build: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest strategy: fail-fast: false diff --git a/.github/workflows/MSVC_2022-Windows.yml b/.github/workflows/MSVC_2022-Windows.yml index f430f9f23..525a09c29 100644 --- a/.github/workflows/MSVC_2022-Windows.yml +++ b/.github/workflows/MSVC_2022-Windows.yml @@ -8,7 +8,7 @@ on: jobs: Build: - runs-on: windows-2022 + runs-on: windows-latest strategy: fail-fast: false diff --git a/BuildTools/Classes/Packager/Vcpkg.php b/BuildTools/Classes/Packager/Vcpkg.php index ad0fc704f..92039201e 100644 --- a/BuildTools/Classes/Packager/Vcpkg.php +++ b/BuildTools/Classes/Packager/Vcpkg.php @@ -137,22 +137,26 @@ function constructPortAndVersionFile(string $sha512 = "0"): string $portFileContent = 'vcpkg_from_github( OUT_SOURCE_PATH SOURCE_PATH REPO realtimechris/jsonifier - REF "v${VERSION}" + REF "v${VERSION}" SHA512 ' . $sha512 . ' HEAD_REF main + PATCHES + uninstall-head.patch ) +set(VCPKG_BUILD_TYPE release) # header-only + vcpkg_cmake_configure( SOURCE_PATH "${SOURCE_PATH}" ) vcpkg_cmake_install() -file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug") - vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/License.md") '; - // ./Vcpkg/ports/jsonifier/vcpkg.json + + +// ./Vcpkg/ports/jsonifier/vcpkg.json $versionFileContent = '{ "name": "jsonifier", "version": ' . json_encode($this->getVersion()) . ', @@ -164,10 +168,6 @@ function constructPortAndVersionFile(string $sha512 = "0"): string { "name": "vcpkg-cmake", "host": true - }, - { - "name": "vcpkg-cmake-config", - "host": true } ] }'; diff --git a/CMake/JsonifierDetectArchitecture.cmake b/CMake/JsonifierDetectArchitecture.cmake index 41589773c..719891cd9 100644 --- a/CMake/JsonifierDetectArchitecture.cmake +++ b/CMake/JsonifierDetectArchitecture.cmake @@ -48,19 +48,19 @@ function(jsonifier_check_instruction_set INSTRUCTION_SET_NAME INSTRUCTION_SET_IN endfunction() set(INSTRUCTION_SET_NAMES "POPCNT" "LZCNT" "BMI" "BMI2" "AVX" "AVX2" "AVX512") -set (INSTRUCTION_SET_CODE +set(INSTRUCTION_SET_CODE "auto result = _mm_popcnt_u64(uint64_t{})" "auto result = _lzcnt_u64(int64_t{})" "auto result = _blsr_u64(uint64_t{}).result = _tzcnt_u32(uint16_t{})" "auto result = _pdep_u64(uint64_t{}, uint64_t{})" - "auto result = _mm_castsi128_pd(__m128i{}).auto result02 = _mm_setzero_si128()" + "auto result = _mm_castsi128_pd(__m128i{}).auto result01 = _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{})" + "auto result = _mm_abs_epi64 (__m128i{}).auto result01 = _mm512_abs_epi16(__m512i{})" ) set(INDEX_SET "0" "1" "2" "3" "4" "5" "6") -if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") +if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") set(INSTRUCTION_SET_IN_FLAGS "/arch:AVX" "/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:AVX" "/arch:AVX2" "/arch:AVX512") else() @@ -70,7 +70,7 @@ 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")) +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) @@ -90,29 +90,29 @@ endif() set(AVX_FLAG) set(JSONIFIER_CPU_INSTRUCTIONS 0) -if (NOT "${POPCNT}" STREQUAL "") +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 "") +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 "") +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 "${BMI2}" STREQUAL "") +if(NOT "${BMI2}" STREQUAL "") list(APPEND AVX_FLAG "${BMI2}") math(EXPR JSONIFIER_CPU_INSTRUCTIONS "${JSONIFIER_CPU_INSTRUCTIONS} | 1 << 3" OUTPUT_FORMAT DECIMAL) endif() -if (NOT "${AVX512}" STREQUAL "") +if(NOT "${AVX512}" STREQUAL "") list(APPEND AVX_FLAG "${AVX512}") math(EXPR JSONIFIER_CPU_INSTRUCTIONS "${JSONIFIER_CPU_INSTRUCTIONS} | 1 << 6" OUTPUT_FORMAT DECIMAL) -elseif (NOT "${AVX2}" STREQUAL "") +elseif(NOT "${AVX2}" STREQUAL "") list(APPEND AVX_FLAG "${AVX2}") math(EXPR JSONIFIER_CPU_INSTRUCTIONS "${JSONIFIER_CPU_INSTRUCTIONS} | 1 << 5" OUTPUT_FORMAT DECIMAL) -elseif (NOT "${AVX}" STREQUAL "") +elseif(NOT "${AVX}" STREQUAL "") list(APPEND AVX_FLAG "${AVX}") math(EXPR JSONIFIER_CPU_INSTRUCTIONS "${JSONIFIER_CPU_INSTRUCTIONS} | 1 << 4" OUTPUT_FORMAT DECIMAL) endif() diff --git a/Documentation/Custom/doxygen-awesome.css b/Documentation/Custom/doxygen-awesome.css index 72039a8df..1728d7466 100644 --- a/Documentation/Custom/doxygen-awesome.css +++ b/Documentation/Custom/doxygen-awesome.css @@ -942,7 +942,7 @@ code, div.fragment, pre.fragment { } code { - display: jsonifier_inline; + display: inline; background: var(--code-background); color: var(--code-foreground); padding: 2px 6px; @@ -1026,7 +1026,7 @@ div.fragment span.preprocessor { } div.fragment span.lineno { - display: jsonifier_inline-block; + display: inline-block; width: 27px; border-right: none; background: var(--fragment-linenumber-background); @@ -1100,7 +1100,7 @@ dl.deprecated dt a { } dl.section dd, dl.bug dd, dl.deprecated dd { - margin-jsonifier_inline-start: 0px; + margin-inline-start: 0px; } dl.invariant, dl.pre { @@ -1429,7 +1429,7 @@ address.footer { .navpath li.navelem a { text-shadow: none; - display: jsonifier_inline-block; + display: inline-block; color: var(--primary-color) !important; } @@ -1481,7 +1481,7 @@ li.navelem:first-child:before { */ doxygen-awesome-dark-mode-toggle { - display: jsonifier_inline-block; + display: inline-block; margin: 0 0 0 var(--spacing-small); padding: 0; width: var(--searchbar-height); diff --git a/Documentation/Doxyfile b/Documentation/Doxyfile index cf75a335e..3a8fae60b 100644 --- a/Documentation/Doxyfile +++ b/Documentation/Doxyfile @@ -440,7 +440,7 @@ SUBGROUPING = NO INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions -# with only public data fields or simple typedef fields will be shown jsonifier_inline in +# with only public data fields or simple typedef fields will be shown inline in # the documentation of the scope in which they are defined (i.e. file, # namespace, or group documentation), provided this scope is documented. If set # to NO, structs, classes, and unions are shown on a separate page (for HTML and @@ -648,8 +648,8 @@ SHOW_GROUPED_MEMB_INC = NO FORCE_LOCAL_INCLUDES = NO -# If the INLINE_INFO tag is set to YES then a tag [jsonifier_inline] is inserted in the -# documentation for jsonifier_inline members. +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. # The default value is: YES. INLINE_INFO = YES diff --git a/Include/jsonifier/Allocator.hpp b/Include/jsonifier/Allocator.hpp index babc3999a..4a7eeef87 100644 --- a/Include/jsonifier/Allocator.hpp +++ b/Include/jsonifier/Allocator.hpp @@ -28,40 +28,61 @@ namespace jsonifier_internal { - template jsonifier_inline uint64_t roundUpToMultiple(uint64_t num) { + template JSONIFIER_INLINE uint64_t roundUpToMultiple(uint64_t num) { uint64_t remainder = num % multiple; return remainder == 0 ? num : num + (multiple - remainder); } - template jsonifier_inline uint64_t roundDownToMultiple(int64_t value) { + template JSONIFIER_INLINE uint64_t roundDownToMultiple(int64_t value) { return static_cast(value >= 0 ? (value / multiple) * multiple : ((value - multiple + 1) / multiple) * multiple); } - template class aligned_allocator : public std::pmr::polymorphic_allocator { +#if defined(_MSC_VER) + + template JSONIFIER_INLINE value_type* jsonifierAlignedAlloc(uint64_t size) { + return static_cast(_aligned_malloc(roundUpToMultiple(size * sizeof(value_type)), BytesPerStep)); + } + + JSONIFIER_INLINE void jsonifierFree(void* ptr) { + _aligned_free(ptr); + } + +#else + + template JSONIFIER_INLINE value_type* jsonifierAlignedAlloc(uint64_t size) { + return static_cast(std::aligned_alloc(BytesPerStep, roundUpToMultiple(size * sizeof(value_type)))); + } + + JSONIFIER_INLINE void jsonifierFree(void* ptr) { + free(ptr); + } + +#endif + + template class aligned_allocator { public: using value_type = value_type_new; using pointer = value_type*; using size_type = uint64_t; - using allocator = std::pmr::polymorphic_allocator; - jsonifier_inline pointer allocate(size_type n) { + JSONIFIER_INLINE pointer allocate(size_type n) { if (n == 0) { return nullptr; } - return static_cast(allocator::allocate_bytes(roundUpToMultiple(n * sizeof(value_type)), BytesPerStep)); + return jsonifierAlignedAlloc(n); } - jsonifier_inline void deallocate(pointer ptr, size_type n) { + JSONIFIER_INLINE void deallocate(pointer ptr, size_type) { if (ptr) { - allocator::deallocate_bytes(ptr, roundUpToMultiple(n * sizeof(value_type)), BytesPerStep); + jsonifierFree(ptr); } } - template jsonifier_inline void construct(pointer p, Args&&... args) { - new (p) value_type(std::forward(args)...); + template JSONIFIER_INLINE void construct(pointer p, arg_types&&... args) { + new (p) value_type(std::forward(args)...); } - jsonifier_inline void destroy(pointer p) { + JSONIFIER_INLINE void destroy(pointer p) { p->~value_type(); } }; @@ -74,23 +95,23 @@ namespace jsonifier_internal { using allocator = aligned_allocator; using allocator_traits = std::allocator_traits; - jsonifier_inline pointer allocate(size_type count) { + JSONIFIER_INLINE pointer allocate(size_type count) { return allocator_traits::allocate(*this, count); } - jsonifier_inline void deallocate(pointer ptr, size_type count) { + JSONIFIER_INLINE void deallocate(pointer ptr, size_type count) { allocator_traits::deallocate(*this, ptr, count); } - template jsonifier_inline void construct(pointer ptr, Args&&... args) { - allocator_traits::construct(*this, ptr, std::forward(args)...); + template JSONIFIER_INLINE void construct(pointer ptr, arg_types&&... args) { + allocator_traits::construct(*this, ptr, std::forward(args)...); } - jsonifier_inline static size_type maxSize() { - return allocator_traits::max_size(allocator{}); + JSONIFIER_INLINE size_type maxSize() { + return allocator_traits::max_size(*this); } - jsonifier_inline void destroy(pointer ptr) { + JSONIFIER_INLINE void destroy(pointer ptr) { allocator_traits::destroy(*this, ptr); } }; diff --git a/Include/jsonifier/Base.hpp b/Include/jsonifier/Base.hpp index 848e31523..b6b415338 100644 --- a/Include/jsonifier/Base.hpp +++ b/Include/jsonifier/Base.hpp @@ -26,68 +26,37 @@ #include #include #include -#include #include #include #include namespace jsonifier_internal { - template struct false_t : std::false_type {}; - - struct random_core_type; - - template<> struct false_t : std::true_type {}; - - template jsonifier_constexpr bool falseV = false_t::value; - - template jsonifier_constexpr auto indexer(std::index_sequence) { - return [](auto&& f) -> 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 jsonifier_constexpr auto indexer() { - return indexer(std::make_index_sequence{}); - } - - template jsonifier_constexpr auto forEach(Func&& f) { - return indexer()([&](auto&&... i) { - (std::forward>(f)(i), ...); + template constexpr auto forEach(funtion_type&& f) { + return indexer(std::make_index_sequence{})([&](auto... x) { + (std::forward>(f)(x), ...); }); } - template struct make_static { - static jsonifier_constexpr auto value = newArr; - }; - - template jsonifier_constexpr jsonifier::string_view join() { - jsonifier_constexpr auto joinedArr = []() { - jsonifier_constexpr size_t len = (strings.size() + ... + 0); - ctime_array arr{}; - auto append = [i = 0, &arr](const auto& s) mutable { - for (auto c: s) - arr[static_cast(i++)] = c; - }; - (append(strings), ...); - arr[len] = 0; - return arr; - }(); - auto& staticArr = make_static::value; - return { staticArr.data(), staticArr.maxSize() - 1 }; + template constexpr decltype(auto) convSv(value_type&& value) noexcept { + if constexpr (std::is_convertible_v) { + return jsonifier::string_view{ value }; + } else { + return std::forward(value); + } } - template jsonifier_constexpr auto JoinV = join(); - - jsonifier_inline decltype(auto) getMember(auto&& value, auto& member_ptr) { + JSONIFIER_INLINE decltype(auto) getMember(auto&& value, auto& member_ptr) { using value_type = jsonifier::concepts::unwrap; - if jsonifier_constexpr (std::is_member_object_pointer_v) { + if constexpr (std::is_member_object_pointer_v) { return value.*member_ptr; - } else if jsonifier_constexpr (std::is_member_function_pointer_v) { - return member_ptr; - } else if jsonifier_constexpr (std::invocable) { - return std::invoke(member_ptr, value); - } else if jsonifier_constexpr (std::is_pointer_v) { + } else if constexpr (std::is_pointer_v) { return *member_ptr; } else { return member_ptr; @@ -100,35 +69,35 @@ namespace jsonifier_internal { public: using hr_clock = std::chrono::high_resolution_clock; - jsonifier_inline stop_watch(uint64_t newTime) { + JSONIFIER_INLINE stop_watch(uint64_t newTime) { totalNumberOfTimeUnits.store(value_type{ newTime }, std::memory_order_release); } - jsonifier_inline stop_watch(value_type newTime) { + JSONIFIER_INLINE stop_watch(value_type newTime) { totalNumberOfTimeUnits.store(newTime, std::memory_order_release); } - jsonifier_inline stop_watch& operator=(stop_watch&& other) { + JSONIFIER_INLINE stop_watch& operator=(stop_watch&& other) { totalNumberOfTimeUnits.store(other.totalNumberOfTimeUnits.load(std::memory_order_acquire), std::memory_order_release); startTimeInTimeUnits.store(other.startTimeInTimeUnits.load(std::memory_order_acquire), std::memory_order_release); return *this; } - jsonifier_inline stop_watch(stop_watch&& other) { + JSONIFIER_INLINE stop_watch(stop_watch&& other) { *this = std::move(other); } - jsonifier_inline stop_watch& operator=(const stop_watch& other) { + JSONIFIER_INLINE stop_watch& operator=(const stop_watch& other) { totalNumberOfTimeUnits.store(other.totalNumberOfTimeUnits.load(std::memory_order_acquire), std::memory_order_release); startTimeInTimeUnits.store(other.startTimeInTimeUnits.load(std::memory_order_acquire), std::memory_order_release); return *this; } - jsonifier_inline stop_watch(const stop_watch& other) { + JSONIFIER_INLINE stop_watch(const stop_watch& other) { *this = other; } - jsonifier_inline bool hasTimeElapsed() { + JSONIFIER_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; @@ -137,7 +106,7 @@ namespace jsonifier_internal { } } - jsonifier_inline void reset(value_type newTimeValue = value_type{}) { + JSONIFIER_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); @@ -146,11 +115,11 @@ namespace jsonifier_internal { } } - jsonifier_inline value_type getTotalWaitTime() const { + JSONIFIER_INLINE value_type getTotalWaitTime() const { return totalNumberOfTimeUnits.load(std::memory_order_acquire); } - jsonifier_inline value_type totalTimeElapsed() { + JSONIFIER_INLINE value_type totalTimeElapsed() { return std::chrono::duration_cast(hr_clock::now().time_since_epoch()) - startTimeInTimeUnits.load(std::memory_order_acquire); } @@ -164,17 +133,23 @@ namespace jsonifier_internal { namespace jsonifier { - jsonifier_constexpr auto createArray(auto&&... args) { - return array{ jsonifier_internal::copyTuple(args...) }; + template constexpr auto createArray(value_types&&... args) { + constexpr auto newSize = sizeof...(value_types); + if constexpr (newSize > 0) { + return jsonifier_internal::array{ std::make_tuple(std::forward(args)...) }; + } else { + return jsonifier_internal::array{ jsonifier::concepts::empty_val{} }; + } } - template jsonifier_constexpr auto createObject(Args&&... args) { - if jsonifier_constexpr (sizeof...(args) == 0) { - return object{ std::tuple<>{} }; + template constexpr auto createObject(value_types&&... args) { + constexpr auto newSize = sizeof...(value_types); + if constexpr (newSize > 0) { + auto newTuple = std::make_tuple(jsonifier_internal::convSv(std::forward(args))...); + using tuple_type = jsonifier::concepts::unwrap; + return jsonifier_internal::object{ jsonifier_internal::group_builder::op(std::move(newTuple)) }; } else { - auto newTuple = jsonifier_internal::copyTuple(args...); - using tuple_type = decltype(newTuple); - return object{ jsonifier_internal::GroupBuilder::op(std::move(newTuple)) }; + return jsonifier_internal::object{ jsonifier::concepts::empty_val{} }; } } diff --git a/Include/jsonifier/CTimeArray.hpp b/Include/jsonifier/CTimeArray.hpp deleted file mode 100644 index 27413d5dc..000000000 --- a/Include/jsonifier/CTimeArray.hpp +++ /dev/null @@ -1,132 +0,0 @@ -/* - 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 20, 2023 -#pragma once - -#include - -namespace jsonifier_internal { - - template struct ctime_array { - public: - using value_type = value_type_new; - using reference = value_type&; - using const_reference = const value_type&; - using pointer = value_type*; - using const_pointer = const value_type*; - using iterator = pointer; - using const_iterator = const_pointer; - using size_type = uint64_t; - using difference_type = std::ptrdiff_t; - - jsonifier_constexpr ctime_array() = default; - - template jsonifier_constexpr ctime_array(value_type const (&init)[M]) : ctime_array(init, std::make_index_sequence()) { - static_assert(M >= count); - } - - jsonifier_constexpr ctime_array(const std::initializer_list& other) { - for (uint64_t x = 0; x < count; ++x) { - operator[](x) = std::move(other.begin()[x]); - } - } - - jsonifier_constexpr iterator begin() { - return dataVal; - } - - jsonifier_constexpr iterator end() { - return dataVal + count; - } - - jsonifier_constexpr const_iterator begin() const { - return dataVal; - } - - jsonifier_constexpr const_iterator end() const { - return dataVal + count; - } - - jsonifier_constexpr size_type maxSize() const { - return count; - } - - jsonifier_constexpr reference operator[](uint64_t index) { - return dataVal[index]; - } - - jsonifier_constexpr const_reference operator[](uint64_t index) const { - return dataVal[index]; - } - - jsonifier_constexpr const_reference at(uint64_t index) const { - if (index > count) { - std::abort(); - } - return dataVal[index]; - } - - jsonifier_constexpr size_type size() const { - return count; - } - - jsonifier_constexpr const_reference front() const { - return dataVal[0]; - } - - jsonifier_constexpr const_reference back() const { - return dataVal[count - 1]; - } - - jsonifier_constexpr const_pointer data() const { - return dataVal; - } - - jsonifier_constexpr void fill(const value_type& value) { - for (uint64_t x = 0; x < count; ++x) { - dataVal[x] = value; - } - } - - value_type dataVal[count]{}; - - template jsonifier_constexpr ctime_array(value_type const (&init)[M], std::index_sequence) : dataVal{ init[I]... } { - } - }; - - template class ctime_array { - public: - using value_type = value_type_new; - using reference = value_type&; - using const_reference = const value_type&; - using pointer = value_type*; - using const_pointer = const pointer; - using iterator = value_type*; - using const_iterator = const_pointer; - using reverse_iterator = std::reverse_iterator; - using const_reverse_iterator = std::reverse_iterator; - using size_type = uint64_t; - using difference_type = std::ptrdiff_t; - }; - -} diff --git a/Include/jsonifier/CTimeVector.hpp b/Include/jsonifier/CTimeVector.hpp index e24816a01..d859bd974 100644 --- a/Include/jsonifier/CTimeVector.hpp +++ b/Include/jsonifier/CTimeVector.hpp @@ -23,6 +23,7 @@ /// Feb 20, 2023 #pragma once +#include #include namespace jsonifier_internal { @@ -34,63 +35,63 @@ namespace jsonifier_internal { using const_reference = const value_type&; using pointer = value_type*; using const_pointer = const value_type*; - using iterator = pointer; - using const_iterator = const_pointer; + using iterator = jsonifier_internal::iterator; + using const_iterator = jsonifier_internal::iterator; using size_type = uint64_t; using difference_type = std::ptrdiff_t; - jsonifier_constexpr ctime_vector() = default; + constexpr ctime_vector() = default; - jsonifier_constexpr ctime_vector(size_type count, const auto& value) : sizeVal(count) { + constexpr ctime_vector(size_type count, const auto& value) : sizeVal(count) { for (size_type x = 0; x < N; ++x) data[x] = value; } - jsonifier_constexpr iterator begin() { + constexpr iterator begin() { return data; } - jsonifier_constexpr iterator end() { + constexpr iterator end() { return data + sizeVal; } - jsonifier_constexpr size_type size() const { + constexpr size_type size() const { return sizeVal; } - jsonifier_constexpr reference operator[](size_type index) { + constexpr reference operator[](size_type index) { return data[index]; } - jsonifier_constexpr const_reference operator[](size_type index) const { + constexpr const_reference operator[](size_type index) const { return data[index]; } - jsonifier_constexpr reference front() { + constexpr reference front() { return data[0]; } - jsonifier_constexpr reference back() { + constexpr reference back() { return data[sizeVal - 1]; } - jsonifier_constexpr const_reference front() const { + constexpr const_reference front() const { return data[0]; } - jsonifier_constexpr const_reference back() const { + constexpr const_reference back() const { return data[sizeVal - 1]; } - template jsonifier_constexpr void push_back(value_type_newer&& a) { + template constexpr void pushBack(value_type_newer&& a) { data[sizeVal++] = std::forward(a); } - jsonifier_constexpr void pop_back() { + constexpr void pop_back() { --sizeVal; } - jsonifier_constexpr void clear() { + constexpr void clear() { sizeVal = 0; } diff --git a/Include/jsonifier/Compare.hpp b/Include/jsonifier/Compare.hpp index d0d04dfda..aa64d7e39 100644 --- a/Include/jsonifier/Compare.hpp +++ b/Include/jsonifier/Compare.hpp @@ -29,9 +29,8 @@ namespace jsonifier_internal { #if JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX512) - template - jsonifier_inline uint64_t find(const value_type01* str, uint64_t length, const value_type02* sub, uint64_t subLength = 1) { - static jsonifier_constexpr uint64_t vecSize = sizeof(simd_int_512); + template JSONIFIER_INLINE uint64_t find(const char_type01* str, uint64_t length, const char_type02* sub, uint64_t subLength = 1) { + static constexpr uint64_t vecSize = sizeof(simd_int_512); uint64_t remainingBytes{ length }; uint64_t index{}; @@ -61,10 +60,10 @@ namespace jsonifier_internal { } 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; + for (int64_t x = 0; x < static_cast(remainingBytes); ++x) { + if (str[index + x] == sub[0]) { + if (memcmp(str + index + x, sub, subLength) == 0) { + return index + x; } } } @@ -73,18 +72,18 @@ namespace jsonifier_internal { return std::numeric_limits::max(); } - template jsonifier_inline bool compareValues(const value_type01* string1, const value_type02* string2, uint64_t length); + template JSONIFIER_INLINE bool compareValues(const value_type01* string1, const value_type02* string2, uint64_t length); - template jsonifier_constexpr uint64_t getIntervalCount(uint64_t originalLength) { + template constexpr uint64_t getIntervalCount(uint64_t originalLength) { return originalLength * sizeof(value_type) / sizeof(IndexType); } template - jsonifier_inline bool compareValues16(const value_type01* string1, const value_type02* string2, uint64_t length) { - static jsonifier_constexpr uint64_t vectorSize = sizeof(simd_int_128) / sizeof(value_type01); - const uint64_t intervalCount = getIntervalCount(length); - const uint64_t remainder = length % vectorSize; - static jsonifier_constexpr uint16_t maskValue{ 0xffff }; + JSONIFIER_INLINE bool compareValues16(const value_type01* string1, const value_type02* string2, uint64_t length) { + static constexpr uint64_t vectorSize = sizeof(simd_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 = gatherValuesU(string1); auto sourcevector = gatherValuesU(string2); @@ -107,11 +106,11 @@ namespace jsonifier_internal { return true; } - template jsonifier_inline bool compareValues16(const value_type01* string1, const value_type02* string2, uint64_t length) { - static jsonifier_constexpr uint64_t vectorSize = sizeof(simd_int_128) / sizeof(value_type01); - const uint64_t intervalCount = getIntervalCount(length); - const uint64_t remainder = length % vectorSize; - static jsonifier_constexpr uint16_t maskValue{ 0xffff }; + template JSONIFIER_INLINE bool compareValues16(const value_type01* string1, const value_type02* string2, uint64_t length) { + static constexpr uint64_t vectorSize = sizeof(simd_int_128) / sizeof(value_type01); + const uint64_t intervalCount = getIntervalCount(length); + const uint64_t remainder = length % vectorSize; + static constexpr uint16_t maskValue{ 0xFFFF }; simd_int_128 destvector = gatherValuesU(string1); simd_int_128 sourcevector = gatherValuesU(string2); if (_mm_movemask_epi8(_mm_cmpeq_epi8(destvector, sourcevector)) != maskValue) { @@ -131,11 +130,11 @@ namespace jsonifier_internal { } template - jsonifier_inline bool compareValues32(const value_type01* string1, const value_type02* string2, uint64_t length) { - static jsonifier_constexpr uint64_t vectorSize = sizeof(simd_int_256) / sizeof(value_type01); - const uint64_t intervalCount = getIntervalCount(length); - const uint64_t remainder = length % vectorSize; - static jsonifier_constexpr uint32_t maskValue{ 0xffffffffu }; + JSONIFIER_INLINE bool compareValues32(const value_type01* string1, const value_type02* string2, uint64_t length) { + static constexpr uint64_t vectorSize = sizeof(simd_int_256) / sizeof(value_type01); + const uint64_t intervalCount = getIntervalCount(length); + const uint64_t remainder = length % vectorSize; + static constexpr uint32_t maskValue{ 0xFFFFFFFFu }; simd_float_256 destvector = gatherValuesU(string1); simd_float_256 sourcevector = gatherValuesU(string2); if (_mm256_movemask_pd(_mm256_cmp_pd(destvector, sourcevector, _CMP_EQ_OQ)) != maskValue) { @@ -154,11 +153,11 @@ namespace jsonifier_internal { return true; } - template jsonifier_inline bool compareValues32(const value_type01* string1, const value_type02* string2, uint64_t length) { - static jsonifier_constexpr uint64_t vectorSize = sizeof(simd_int_256) / sizeof(value_type01); - const uint64_t intervalCount = getIntervalCount(length); - const uint64_t remainder = length % vectorSize; - static jsonifier_constexpr uint32_t maskValue{ 0xffffffffu }; + template JSONIFIER_INLINE bool compareValues32(const value_type01* string1, const value_type02* string2, uint64_t length) { + static constexpr uint64_t vectorSize = sizeof(simd_int_256) / sizeof(value_type01); + const uint64_t intervalCount = getIntervalCount(length); + const uint64_t remainder = length % vectorSize; + static constexpr uint32_t maskValue{ 0xFFFFFFFFu }; simd_int_256 destvector = gatherValuesU(string1); simd_int_256 sourcevector = gatherValuesU(string2); if (_mm256_movemask_epi8(_mm256_cmpeq_epi8(destvector, sourcevector)) != maskValue) { @@ -178,11 +177,11 @@ namespace jsonifier_internal { } template - jsonifier_inline bool compareValues64(const value_type01* string1, const value_type02* string2, uint64_t length) { - static jsonifier_constexpr uint64_t vectorSize = sizeof(simd_int_512) / sizeof(value_type01); - const uint64_t intervalCount = getIntervalCount(length); - const uint64_t remainder = length % vectorSize; - static jsonifier_constexpr uint64_t maskValue{ 0xffffffffffffffff }; + JSONIFIER_INLINE bool compareValues64(const value_type01* string1, const value_type02* string2, uint64_t length) { + static constexpr uint64_t vectorSize = sizeof(simd_int_512) / sizeof(value_type01); + const uint64_t intervalCount = getIntervalCount(length); + const uint64_t remainder = length % vectorSize; + static constexpr uint64_t maskValue{ 0xFFFFFFFFFFFFFFF }; auto destvector = gatherValuesU(string1); auto sourcevector = gatherValuesU(string2); if (_mm512_cmpeq_epi8_mask(destvector, sourcevector) != maskValue) { @@ -201,11 +200,11 @@ namespace jsonifier_internal { return true; } - template jsonifier_inline bool compareValues64(const value_type01* string1, const value_type02* string2, uint64_t length) { - static jsonifier_constexpr uint64_t vectorSize = sizeof(simd_int_512) / sizeof(value_type01); - const uint64_t intervalCount = getIntervalCount(length); - const uint64_t remainder = length % vectorSize; - static jsonifier_constexpr uint64_t maskValue{ 0xffffffffffffffff }; + template JSONIFIER_INLINE bool compareValues64(const value_type01* string1, const value_type02* string2, uint64_t length) { + static constexpr uint64_t vectorSize = sizeof(simd_int_512) / sizeof(value_type01); + const uint64_t intervalCount = getIntervalCount(length); + const uint64_t remainder = length % vectorSize; + static constexpr uint64_t maskValue{ 0xFFFFFFFFFFFFFFF }; simd_int_512 destvector = gatherValuesU(string1); simd_int_512 sourcevector = gatherValuesU(string2); if (_mm512_cmpeq_epi8_mask(destvector, sourcevector) != maskValue) { @@ -224,7 +223,7 @@ namespace jsonifier_internal { return true; } - template jsonifier_inline bool compareValues(const value_type01* string1, const value_type02* string2, uint64_t length) { + template JSONIFIER_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) { @@ -238,9 +237,8 @@ namespace jsonifier_internal { #elif JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX2) - template - jsonifier_inline uint64_t find(const value_type01* str, uint64_t length, const value_type02* sub, uint64_t subLength = 1) { - static jsonifier_constexpr uint64_t vecSize = sizeof(simd_int_256); + template JSONIFIER_INLINE uint64_t find(const char_type01* str, uint64_t length, const char_type02* sub, uint64_t subLength = 1) { + static constexpr uint64_t vecSize = sizeof(simd_int_256); uint64_t remainingBytes{ length }; uint64_t index{}; @@ -270,10 +268,10 @@ namespace jsonifier_internal { } 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; + for (int64_t x = 0; x < static_cast(remainingBytes); ++x) { + if (str[index + x] == sub[0]) { + if (memcmp(str + index + x, sub, subLength) == 0) { + return index + x; } } } @@ -282,18 +280,18 @@ namespace jsonifier_internal { return std::numeric_limits::max(); } - template jsonifier_inline bool compareValues(const value_type01* string1, const value_type02* string2, uint64_t length); + template JSONIFIER_INLINE bool compareValues(const value_type01* string1, const value_type02* string2, uint64_t length); - template jsonifier_constexpr uint64_t getIntervalCount(uint64_t originalLength) { + template constexpr uint64_t getIntervalCount(uint64_t originalLength) { return originalLength * sizeof(value_type) / sizeof(IndexType); } template - jsonifier_inline bool compareValues16(const value_type01* string1, const value_type02* string2, uint64_t length) { - static jsonifier_constexpr uint64_t vectorSize = sizeof(simd_int_128) / sizeof(value_type01); - const uint64_t intervalCount = getIntervalCount(length); - const uint64_t remainder = length % vectorSize; - static jsonifier_constexpr uint16_t maskValue{ 0xffff }; + JSONIFIER_INLINE bool compareValues16(const value_type01* string1, const value_type02* string2, uint64_t length) { + static constexpr uint64_t vectorSize = sizeof(simd_int_128) / sizeof(value_type01); + const uint64_t intervalCount = getIntervalCount(length); + const uint64_t remainder = length % vectorSize; + static constexpr uint16_t maskValue{ 0xFFFF }; simd_float_128 destvector = gatherValuesU(string1); simd_float_128 sourcevector = gatherValuesU(string2); @@ -316,11 +314,11 @@ namespace jsonifier_internal { return true; } - template jsonifier_inline bool compareValues16(const value_type01* string1, const value_type02* string2, uint64_t length) { - static jsonifier_constexpr uint64_t vectorSize = sizeof(simd_int_128) / sizeof(value_type01); - const uint64_t intervalCount = getIntervalCount(length); - const uint64_t remainder = length % vectorSize; - static jsonifier_constexpr uint16_t maskValue{ 0xffff }; + template JSONIFIER_INLINE bool compareValues16(const value_type01* string1, const value_type02* string2, uint64_t length) { + static constexpr uint64_t vectorSize = sizeof(simd_int_128) / sizeof(value_type01); + const uint64_t intervalCount = getIntervalCount(length); + const uint64_t remainder = length % vectorSize; + static constexpr uint16_t maskValue{ 0xFFFF }; simd_int_128 destvector = gatherValuesU(string1); simd_int_128 sourcevector = gatherValuesU(string2); if (_mm_movemask_epi8(_mm_cmpeq_epi8(destvector, sourcevector)) != maskValue) { @@ -340,11 +338,11 @@ namespace jsonifier_internal { } template - jsonifier_inline bool compareValues32(const value_type01* string1, const value_type02* string2, uint64_t length) { - static jsonifier_constexpr uint64_t vectorSize = sizeof(simd_int_256) / sizeof(value_type01); - const uint64_t intervalCount = getIntervalCount(length); - const uint64_t remainder = length % vectorSize; - static jsonifier_constexpr uint32_t maskValue{ 0xffffffffu }; + JSONIFIER_INLINE bool compareValues32(const value_type01* string1, const value_type02* string2, uint64_t length) { + static constexpr uint64_t vectorSize = sizeof(simd_int_256) / sizeof(value_type01); + const uint64_t intervalCount = getIntervalCount(length); + const uint64_t remainder = length % vectorSize; + static constexpr uint32_t maskValue{ 0xFFFFFFFFu }; simd_float_256 destvector = gatherValuesU(string1); simd_float_256 sourcevector = gatherValuesU(string2); if (_mm256_movemask_pd(_mm256_cmp_pd(destvector, sourcevector, _CMP_EQ_OQ)) != maskValue) { @@ -363,11 +361,11 @@ namespace jsonifier_internal { return true; } - template jsonifier_inline bool compareValues32(const value_type01* string1, const value_type02* string2, uint64_t length) { - static jsonifier_constexpr uint64_t vectorSize = sizeof(simd_int_256) / sizeof(value_type01); - const uint64_t intervalCount = getIntervalCount(length); - const uint64_t remainder = length % vectorSize; - static jsonifier_constexpr uint32_t maskValue{ 0xffffffffu }; + template JSONIFIER_INLINE bool compareValues32(const value_type01* string1, const value_type02* string2, uint64_t length) { + static constexpr uint64_t vectorSize = sizeof(simd_int_256) / sizeof(value_type01); + const uint64_t intervalCount = getIntervalCount(length); + const uint64_t remainder = length % vectorSize; + static constexpr uint32_t maskValue{ 0xFFFFFFFFu }; simd_int_256 destvector = gatherValuesU(string1); simd_int_256 sourcevector = gatherValuesU(string2); if (_mm256_movemask_epi8(_mm256_cmpeq_epi8(destvector, sourcevector)) != static_cast(maskValue)) { @@ -386,7 +384,7 @@ namespace jsonifier_internal { return true; } - template jsonifier_inline bool compareValues(const value_type01* string1, const value_type02* string2, uint64_t length) { + template JSONIFIER_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) { @@ -398,9 +396,8 @@ namespace jsonifier_internal { #elif JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX) - template - jsonifier_inline uint64_t find(const value_type01* str, uint64_t length, const value_type02* sub, uint64_t subLength = 1) { - static jsonifier_constexpr uint64_t vecSize = sizeof(simd_int_128); + template JSONIFIER_INLINE uint64_t find(const char_type01* str, uint64_t length, const char_type02* sub, uint64_t subLength = 1) { + static constexpr uint64_t vecSize = sizeof(simd_int_128); uint64_t remainingBytes{ length }; uint64_t index{}; @@ -430,10 +427,10 @@ namespace jsonifier_internal { } 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; + for (int64_t x = 0; x < static_cast(remainingBytes); ++x) { + if (str[index + x] == sub[0]) { + if (memcmp(str + index + x, sub, subLength) == 0) { + return index + x; } } } @@ -442,18 +439,18 @@ namespace jsonifier_internal { return std::numeric_limits::max(); } - template jsonifier_inline bool compareValues(const value_type01* string1, const value_type02* string2, uint64_t length) { + template JSONIFIER_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 - template jsonifier_inline uint64_t find(const value_type01* str, uint64_t length, value_type02* target, uint64_t subLength = 1) { + template JSONIFIER_INLINE uint64_t find(const value_type01* str, uint64_t length, value_type02* target, uint64_t subLength = 1) { std::basic_string_view> newString{ target, subLength }; return std::basic_string_view{ static_cast(str), length }.find(newString); } - template jsonifier_inline bool compareValues(const void* destvector, const void* sourcevector, uint64_t length) { + template JSONIFIER_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 }; } @@ -463,7 +460,7 @@ namespace jsonifier_internal { class jsonifier_core_internal { public: template - jsonifier_inline static bool compare(const value_type01* destvector, const value_type02* sourcevector, uint64_t length) { + JSONIFIER_INLINE static bool compare(const value_type01* destvector, const value_type02* sourcevector, uint64_t length) { return compareValues(destvector, sourcevector, length); } }; diff --git a/Include/jsonifier/DToStr.hpp b/Include/jsonifier/DToStr.hpp new file mode 100644 index 000000000..0f6d21a6a --- /dev/null +++ b/Include/jsonifier/DToStr.hpp @@ -0,0 +1,331 @@ +/* + 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. +*/ +/// Note: Most of the code in this header was sampled from Glaze library: https://github.com/stephenberry/glaze +/// https://github.com/RealTimeChris/jsonifier +/// Nov 13, 2023 +#pragma once + +#include +#include + +#include +#include +#include +#include + +#if defined(_M_X64) || defined(_M_ARM64) + #include +#endif + +namespace jsonifier_internal { + + JSONIFIER_INLINE void u128Mul(uint64_t a, uint64_t b, uint64_t* hi, uint64_t* lo) noexcept { +#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__) || defined(__GNUG__) + #pragma GCC diagnostic pop + #endif + *hi = m >> 64; + *lo = m; +#elif defined(_M_X64) + *lo = _umul128(a, b, hi); +#elif defined(_M_ARM64) + *hi = __umulh(a, b); + *lo = a * b; +#else + uint64_t a0 = a, a1 = (a >> 32); + uint64_t b0 = (b), b1 = (b >> 32); + uint64_t p00 = a0 * b0, p01 = a0 * b1; + uint64_t p10 = a1 * b0, p11 = a1 * b1; + uint64_t m0 = p01 + (p00 >> 32); + uint64_t m00 = (m0), m01 = (m0 >> 32); + uint64_t m1 = p10 + m00; + uint64_t m10 = (m1), m11 = (m1 >> 32); + *hi = p11 + m01 + m11; + *lo = (m10 << 32) | p00; +#endif + } + + JSONIFIER_INLINE void u128MulAdd(uint64_t a, uint64_t b, uint64_t c, uint64_t* hi, uint64_t* lo) noexcept { +#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__) || defined(__GNUG__) + #pragma GCC diagnostic pop + #endif + *hi = m >> 64; + *lo = m; +#else + uint64_t h{}, l{}, t{}; + u128Mul(a, b, &h, &l); + t = l + c; + h += ((t < l) | (t < c)); + *hi = h; + *lo = t; +#endif + } + + JSONIFIER_INLINE uint64_t roundToOdd(uint64_t hi, uint64_t lo, uint64_t cp) noexcept { + uint64_t xHi{}, xLo{}, yHi{}, yLo{}; + u128Mul(cp, lo, &xHi, &xLo); + u128MulAdd(cp, hi, xHi, &yHi, &yLo); + return yHi | (yLo > 1); + } + + constexpr auto pow10SigTable128MinExp = -343; + constexpr auto pow10SigTable128MaxExp = 324; + constexpr auto pow10SigTable128MinExactExp = 0; + constexpr auto pow10SigTable128MaxExactExp = 55; + + JSONIFIER_INLINE void pow10TableGetSig128(const int64_t exp10, uint64_t hilo[2]) noexcept { + const int64_t idx = exp10 - (pow10SigTable128MinExp); + std::memcpy(hilo, pow10SigTable128 + idx * 2, 16); + } + + JSONIFIER_INLINE void f64BiniToDec(uint64_t sigRaw, int64_t expRaw, uint64_t sigBin, int64_t expBin, uint64_t* sigDec, int64_t* expDec) noexcept { + uint64_t sp{}, mid{}; + + const bool isEven = !(sigBin & 1); + const bool lowerBoundCloser = (sigRaw == 0 && expRaw > 1); + + const uint64_t cb = 4 * sigBin; + const uint64_t cbl = cb - 2 + lowerBoundCloser; + const uint64_t cbr = cb + 2; + + const int64_t k = (expBin * 315653 - (lowerBoundCloser ? 131237 : 0)) >> 20; + + const int64_t exp10 = -k; + const int64_t h = expBin + ((exp10 * 217707) >> 16) + 1; + + uint64_t pow10hilo[2]; + pow10TableGetSig128(exp10, pow10hilo); + const uint64_t& pow10hi = pow10hilo[0]; + uint64_t& pow10lo = pow10hilo[1]; + pow10lo += (exp10 < pow10SigTable128MinExactExp || exp10 > pow10SigTable128MaxExactExp); + const uint64_t vbl = roundToOdd(pow10hi, pow10lo, cbl << h); + const uint64_t vb = roundToOdd(pow10hi, pow10lo, cb << h); + const uint64_t vbr = roundToOdd(pow10hi, pow10lo, cbr << h); + + const uint64_t lower = vbl + !isEven; + const uint64_t upper = vbr - !isEven; + + bool uInside{}, wInside{}; + + const uint64_t s = vb / 4; + if (s >= 10) { + sp = s / 10; + uInside = (lower <= 40 * sp); + wInside = (upper >= 40 * sp + 40); + if (uInside != wInside) { + *sigDec = sp + wInside; + *expDec = k + 1; + return; + } + } + + uInside = (lower <= 4 * s); + wInside = (upper >= 4 * s + 4); + + mid = 4 * s + 2; + const bool roundUp = (vb > mid) || (vb == mid && (s & 1) != 0); + + *sigDec = s + ((uInside != wInside) ? wInside : roundUp); + *expDec = k; + } + + template JSONIFIER_INLINE value_type* writeUint64TLen15To17Trim(value_type* buf, uint64_t sig) noexcept { + uint64_t abbccddee = sig / 100000000ull; + uint64_t ffgghhii = sig - abbccddee * 100000000ull; + uint64_t abbcc = abbccddee / 10000ull; + uint64_t ddee = abbccddee - abbcc * 10000ull; + uint64_t abb = (abbcc * 167773ull) >> 24; + uint64_t a = (abb * 41) >> 12; + uint64_t bb = abb - a * 100; + uint64_t cc = abbcc - abb * 100; + + buf[0] = static_cast(a + 0x30u); + buf += a > 0; + bool lz = bb < 10 && a == 0; + std::memcpy(buf, charTable + (bb * 2 + lz), 2); + buf -= lz; + std::memcpy(buf + 2, charTable + 2 * cc, 2); + + if (ffgghhii) { + uint64_t dd = (ddee * 5243) >> 19; + uint64_t ee = ddee - dd * 100; + uint64_t ffgg = (ffgghhii * 109951163ull) >> 40; + uint64_t hhii = ffgghhii - ffgg * 10000; + uint64_t ff = (ffgg * 5243) >> 19; + uint64_t gg = ffgg - ff * 100; + std::memcpy(buf + 4, charTable + 2 * dd, 2); + std::memcpy(buf + 6, charTable + 2 * ee, 2); + std::memcpy(buf + 8, charTable + 2 * ff, 2); + std::memcpy(buf + 10, charTable + 2 * gg, 2); + if (hhii) { + uint64_t hh = (hhii * 5243) >> 19; + uint64_t ii = hhii - hh * 100; + std::memcpy(buf + 12, charTable + 2 * hh, 2); + std::memcpy(buf + 14, charTable + 2 * ii, 2); + uint64_t tz1 = decTrailingZeroTable[hh]; + uint64_t tz2 = decTrailingZeroTable[ii]; + uint64_t tz = ii ? tz2 : (tz1 + 2); + buf += 16 - tz; + return buf; + } else { + uint64_t tz1 = decTrailingZeroTable[ff]; + uint64_t tz2 = decTrailingZeroTable[gg]; + uint64_t tz = gg ? tz2 : (tz1 + 2); + buf += 12 - tz; + return buf; + } + } else { + if (ddee) { + uint64_t dd = (ddee * 5243) >> 19; + uint64_t ee = ddee - dd * 100; + std::memcpy(buf + 4, charTable + 2 * dd, 2); + std::memcpy(buf + 6, charTable + 2 * ee, 2); + uint64_t tz1 = decTrailingZeroTable[dd]; + uint64_t tz2 = decTrailingZeroTable[ee]; + uint64_t tz = ee ? tz2 : (tz1 + 2); + buf += 8 - tz; + return buf; + } else { + uint64_t tz1 = decTrailingZeroTable[bb]; + uint64_t tz2 = decTrailingZeroTable[cc]; + uint64_t tz = cc ? tz2 : (tz1 + tz2); + buf += 4 - tz; + return buf; + } + } + } + + consteval uint64_t numbits(uint64_t x) noexcept { + return x < 2 ? x : 1 + numbits(x >> 1); + } + + template JSONIFIER_INLINE char_type* toChars(char_type* buffer, value_type01 val) noexcept { + 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 uint64_t = std::conditional_t, uint64_t, uint64_t>; + + uint64_t raw{}; + std::memcpy(&raw, &val, sizeof(value_type01)); + + constexpr uint64_t exponentBits = numbits(std::numeric_limits::max_exponent - std::numeric_limits::min_exponent + 1); + constexpr uint64_t sigMask = uint64_t(-1) >> (exponentBits + 1); + bool sign = (raw >> (sizeof(value_type01) * 8 - 1)); + uint64_t sigRaw = raw & sigMask; + int64_t expRaw = static_cast(raw << 1 >> (sizeof(uint64_t) * 8 - exponentBits)); + + if (expRaw == (uint64_t(1) << exponentBits) - 1) [[unlikely]] { + std::memcpy(buffer, "null", 4); + return buffer + 4; + } + if (sign) { + *buffer = 0x2Du; + ++buffer; + } + if ((raw << 1) != 0) [[likely]] { + uint64_t sigBin; + int64_t expBin; + if (expRaw == 0) [[unlikely]] { + sigBin = sigRaw; + 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 = static_cast(expRaw) - (std::numeric_limits::max_exponent - 1) - (std::numeric_limits::digits - 1); + } + + uint64_t sigDec; + int64_t expDec; + f64BiniToDec(sigRaw, expRaw, sigBin, expBin, &sigDec, &expDec); + if constexpr (std::same_as) { + sigDec *= 100000000; + expDec -= 8; + } + + int64_t sigLen = 17; + sigLen -= (sigDec < 100000000ull * 100000000ull); + sigLen -= (sigDec < 100000000ull * 10000000ull); + + int64_t dotPos = sigLen + expDec; + + if (-6 < dotPos && dotPos <= 21) { + if (dotPos <= 0) { + auto numHdr = buffer + (2 - dotPos); + auto numEnd = writeUint64TLen15To17Trim(numHdr, sigDec); + buffer[0] = 0x30u; + buffer[1] = 0x2Eu; + buffer += 2; + for (; buffer < numHdr; ++buffer) + *buffer = 0x30u; + return numEnd; + } else { + std::memset(buffer, 0x30u, 8); + std::memset(buffer + 8, 0x30u, 8); + std::memset(buffer + 16, 0x30u, 8); + auto numHdr = buffer + 1; + auto numEnd = writeUint64TLen15To17Trim(numHdr, sigDec); + for (int32_t x = 0; x < dotPos; x++) + buffer[x] = buffer[x + 1]; + buffer[dotPos] = 0x2Eu; + return ((numEnd - numHdr) <= dotPos) ? buffer + dotPos : numEnd; + } + } else { + auto end = writeUint64TLen15To17Trim(buffer + 1, sigDec); + end -= (end == buffer + 2); + expDec += sigLen - 1; + buffer[0] = buffer[1]; + buffer[1] = 0x2Eu; + end[0] = 0x45u; + buffer = end + 1; + buffer[0] = 0x2Du; + buffer += expDec < 0; + expDec = std::abs(expDec); + if (expDec < 100) { + uint64_t lz = expDec < 10; + std::memcpy(buffer, charTable + (expDec * 2 + lz), 2); + return buffer + 2 - lz; + } else { + const uint64_t hi = (static_cast(expDec) * 656) >> 16; + const uint64_t lo = static_cast(expDec) - hi * 100; + buffer[0] = static_cast(hi) + static_cast(0x30u); + std::memcpy(&buffer[1], charTable + (lo * 2), 2); + return buffer + 3; + } + } + } else [[unlikely]] { + *buffer = 0x30u; + return buffer + 1; + } + } + +} \ No newline at end of file diff --git a/Include/jsonifier/Derailleur.hpp b/Include/jsonifier/Derailleur.hpp index e6bb195ff..77bb5f005 100644 --- a/Include/jsonifier/Derailleur.hpp +++ b/Include/jsonifier/Derailleur.hpp @@ -23,21 +23,21 @@ /// Feb 20, 2023 #pragma once -#include +#include #include #include namespace jsonifier_internal { - template jsonifier_inline static bool containsValue(uint8_t value) { + template JSONIFIER_INLINE bool containsValue(uint8_t value) { return static_cast(currentValue) == value; } - template<> jsonifier_inline bool containsValue(uint8_t value) { + template<> JSONIFIER_INLINE bool containsValue(uint8_t value) { return value == 0x74u || value == 0x66u; } - template<> jsonifier_inline bool containsValue(uint8_t value) { + template<> JSONIFIER_INLINE bool containsValue(uint8_t value) { return numberTable[value]; } @@ -45,7 +45,7 @@ namespace jsonifier_internal { public: using size_type = uint64_t; - template jsonifier_inline static bool checkForMatchClosed(structural_iterator& iter) { + template JSONIFIER_INLINE static bool checkForMatchClosed(iterator&& iter) { if (containsValue(*iter)) { ++iter; return true; @@ -54,8 +54,8 @@ namespace jsonifier_internal { } } - template - jsonifier_inline static bool checkForMatchClosed(iterator& iter, iterator& end, std::source_location location = std::source_location::current()) { + template + JSONIFIER_INLINE static bool checkForMatchClosed(iterator&& iter, iterator&& end, std::source_location location = std::source_location::current()) { auto oldValue = *iter; if (containsValue(*iter)) { ++iter; @@ -67,7 +67,7 @@ namespace jsonifier_internal { } } - template jsonifier_inline static bool checkForMatchOpen(structural_iterator& iter) { + template JSONIFIER_INLINE static bool checkForMatchOpen(iterator&& iter) { if (*iter == static_cast(c)) { ++iter; return true; @@ -76,8 +76,8 @@ namespace jsonifier_internal { } } - template jsonifier_inline static void skipKey(iterator& iter, iterator& end) { - if jsonifier_constexpr (std::same_as) { + template JSONIFIER_INLINE static void skipKey(iterator&& iter, iterator&& end) { + if constexpr (std::same_as, jsonifier::jsonifier_core>, iterator>) { ++iter; return; } else { @@ -97,7 +97,7 @@ namespace jsonifier_internal { } } - jsonifier_inline static void skipToEndOfArray(structural_iterator& iter) { + template JSONIFIER_INLINE static void skipToEndOfArray(iterator&& iter) { size_type currentDepth{ 1 }; while (iter != iter && currentDepth > 0) { switch (*iter) { @@ -119,7 +119,7 @@ namespace jsonifier_internal { } } - jsonifier_inline static void skipToEndOfObject(structural_iterator& iter) { + template JSONIFIER_INLINE static void skipToEndOfObject(iterator&& iter) { size_type currentDepth{ 1 }; while (iter != iter && currentDepth > 0) { switch (*iter) { @@ -141,18 +141,18 @@ namespace jsonifier_internal { } } - jsonifier_inline static void skipToNextValue(structural_iterator& iter) { + template JSONIFIER_INLINE static void skipToNextValue(iterator&& iter) { while (iter != iter && *iter != 0x2Cu) { switch (*iter) { case 0x7B: { - skipObject(iter); + skipObject(std::forward(iter)); break; } case 0x5B: { - skipArray(iter); + skipArray(std::forward(iter)); break; } - case 0x00: { + case 0x00ll: { return; } default: { @@ -162,18 +162,18 @@ namespace jsonifier_internal { } } - template jsonifier_inline static void skipToNextValue(iterator& iter, iterator end) { + template JSONIFIER_INLINE static void skipToNextValue(iterator&& iter, iterator&& end) { while (iter != end && *iter != 0x2Cu) { switch (*iter) { case 0x7B: { - skipObject(iter, end); + skipObject(std::forward(iter), std::forward(end)); break; } case 0x5B: { - skipArray(iter, end); + skipArray(std::forward(iter), std::forward(end)); break; } - case 0x00: { + case 0x00ll: { return; } default: { @@ -183,17 +183,17 @@ namespace jsonifier_internal { } } - jsonifier_inline static void skipValue(structural_iterator& iter) { + template JSONIFIER_INLINE static void skipValue(iterator&& iter) { switch (*iter) { case 0x7B: { - skipObject(iter); + skipObject(std::forward(iter)); break; } case 0x5B: { - skipArray(iter); + skipArray(std::forward(iter)); break; } - case 0x00: { + case 0x00ll: { return; } default: { @@ -202,17 +202,17 @@ namespace jsonifier_internal { } } - template jsonifier_inline static void skipValue(iterator& iter, iterator end) { + template JSONIFIER_INLINE static void skipValue(iterator&& iter, iterator&& end) { switch (*iter) { case 0x7B: { - skipObject(iter, end); + skipObject(std::forward(iter), std::forward(end)); break; } case 0x5B: { - skipArray(iter, end); + skipArray(std::forward(iter), std::forward(end)); break; } - case 0x00: { + case 0x00ll: { return; } default: { @@ -221,7 +221,7 @@ namespace jsonifier_internal { } } - template jsonifier_inline static size_type countValueElements(iterator iter, iterator end) { + template JSONIFIER_INLINE static size_type countValueElements(iterator iter, iterator end) { size_type currentDepth{ 1 }; size_type currentCount{ 0 }; while (iter != end && currentDepth > 0) { @@ -263,7 +263,7 @@ namespace jsonifier_internal { } protected: - jsonifier_inline static void skipObject(structural_iterator& iter) { + template JSONIFIER_INLINE static void skipObject(iterator&& iter) { ++iter; size_type currentDepth{ 1 }; while (iter != iter && currentDepth > 0) { @@ -286,7 +286,7 @@ namespace jsonifier_internal { } } - template jsonifier_inline static void skipObject(iterator& iter, iterator end) { + template JSONIFIER_INLINE static void skipObject(iterator&& iter, iterator&& end) { ++iter; size_type currentDepth{ 1 }; while (iter != end && currentDepth > 0) { @@ -309,7 +309,7 @@ namespace jsonifier_internal { } } - jsonifier_inline static void skipArray(structural_iterator& iter) { + template JSONIFIER_INLINE static void skipArray(iterator&& iter) { ++iter; size_type currentDepth{ 1 }; while (iter != iter && currentDepth > 0) { @@ -332,7 +332,7 @@ namespace jsonifier_internal { } } - template jsonifier_inline static void skipArray(iterator& iter, iterator end) { + template JSONIFIER_INLINE static void skipArray(iterator&& iter, iterator&& end) { ++iter; size_type currentDepth{ 1 }; while (iter != end && currentDepth > 0) { diff --git a/Include/jsonifier/Error.hpp b/Include/jsonifier/Error.hpp index d37b580c4..74c760863 100644 --- a/Include/jsonifier/Error.hpp +++ b/Include/jsonifier/Error.hpp @@ -23,10 +23,10 @@ /// Feb 3, 2023 #pragma once -#include #include #include #include +#include #include #include #include @@ -45,7 +45,8 @@ namespace jsonifier_internal { Key_Parsing_Error = 7, Invalid_Escape = 8, Wrong_Type = 9, - Damaged_Input = 10 + Damaged_Input = 10, + Serialize_Error = 11 }; enum class json_structural_type : uint8_t { @@ -62,27 +63,27 @@ namespace jsonifier_internal { Null = 0x6Eu }; - jsonifier_inline static std::unordered_map errorMap{ { error_code::Success, "Success" }, { error_code::Parse_Error, "Parse Error." }, + inline std::unordered_map errorMap{ { error_code::Success, "Success" }, { error_code::Parse_Error, "Parse Error." }, { error_code::Number_Error, "Number Error." }, { error_code::Unknown_Key, "Unknown Key" }, { error_code::Incorrect_Type, "Incorrect Type" }, { error_code::Setup_Error, "Setup Error." }, { error_code::Inadequate_String_Length, "Inadequate String Length" }, { error_code::Key_Parsing_Error, "Key Parsing Error" } }; - jsonifier_inline bool isTypeType(uint8_t c) { - static jsonifier_constexpr uint8_t array01[]{ "0123456789-ftn\"{[" }; + JSONIFIER_INLINE bool isTypeType(uint8_t c) { + static constexpr uint8_t array01[]{ "0123456789-ftn\"{[" }; return find(array01, std::size(array01), &c, 1) != jsonifier::string::npos; } - jsonifier_inline bool isDigitType(uint8_t c) { + JSONIFIER_INLINE bool isDigitType(uint8_t c) { return numberTable[c]; } - jsonifier_inline jsonifier::string_view getValueType(uint8_t charToCheck) { - static jsonifier_constexpr jsonifier::string_view array{ "Array" }; - static jsonifier_constexpr jsonifier::string_view object{ "Object" }; - static jsonifier_constexpr jsonifier::string_view boolean{ "Bool" }; - static jsonifier_constexpr jsonifier::string_view number{ "Number" }; - static jsonifier_constexpr jsonifier::string_view str{ "String" }; - static jsonifier_constexpr jsonifier::string_view null{ "Null" }; - static jsonifier_constexpr jsonifier::string_view unset{ "Unset" }; + JSONIFIER_INLINE 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" }; + static constexpr jsonifier::string_view unset{ "Unset" }; if (isDigitType(charToCheck)) { return number; } else if (charToCheck == 0x74u || charToCheck == 0x66u) { @@ -95,14 +96,12 @@ namespace jsonifier_internal { return str; } else if (charToCheck == 0x6Eu) { return null; - } else if (charToCheck == 0x00u) { - return unset; } else { - return {}; + return unset; } } - jsonifier_inline static error_code collectMisReadType(uint8_t c, uint8_t currentValue) { + JSONIFIER_INLINE error_code collectMisReadType(uint8_t c, uint8_t currentValue) { if (isTypeType(currentValue) && isTypeType(c)) { return error_code::Wrong_Type; } else { @@ -112,15 +111,16 @@ namespace jsonifier_internal { class error { public: + friend error createError(error_code errorCode); friend class derailleur; - jsonifier_inline error() noexcept = default; - - jsonifier_inline error(structural_iterator iter, json_structural_type typeNew, std::source_location locationNew = std::source_location::current()) noexcept { + JSONIFIER_INLINE error() noexcept = default; + template + JSONIFIER_INLINE error(const iterator& iter, json_structural_type typeNew, std::source_location locationNew = std::source_location::current()) noexcept { intendedValue = static_cast(typeNew); errorIndex = static_cast(iter.getCurrentStringIndex()); errorIndexReal = roundDownToMultiple(static_cast(iter.getCurrentStringIndex())); - if (errorIndexReal < jsonifier::string::maxSize()) { + if (errorIndexReal < jsonifier::string{}.maxSize()) { stringView = iter.getRootPtr(); } stringLength = static_cast(iter.getEndPtr() - iter.getRootPtr()); @@ -129,10 +129,11 @@ namespace jsonifier_internal { errorType = collectMisReadType(static_cast(typeNew), errorValue); } - jsonifier_inline error(structural_iterator& iter, error_code typeNew, std::source_location locationNew = std::source_location::current()) noexcept { + template + JSONIFIER_INLINE error(const iterator& iter, error_code typeNew, std::source_location locationNew = std::source_location::current()) noexcept { errorIndex = static_cast(iter.getCurrentStringIndex()); errorIndexReal = roundDownToMultiple(static_cast(iter.getCurrentStringIndex())); - if (errorIndexReal < jsonifier::string::maxSize()) { + if (errorIndexReal < jsonifier::string{}.maxSize()) { stringView = iter.getRootPtr(); } location = locationNew; @@ -140,29 +141,29 @@ namespace jsonifier_internal { errorValue = *iter; } - jsonifier_inline error& operator=(error_code errorNew) { + JSONIFIER_INLINE error& operator=(error_code errorNew) { errorType = errorNew; return *this; } - jsonifier_inline error(error_code errorNew) { + JSONIFIER_INLINE error(error_code errorNew) { *this = errorNew; } - jsonifier_inline operator bool() { + JSONIFIER_INLINE operator bool() { return errorType != error_code::Success; } - jsonifier_inline bool operator==(const error& rhs) const { + JSONIFIER_INLINE bool operator==(const error& rhs) const { return errorType == rhs.errorType && errorIndex == rhs.errorIndex && errorValue == rhs.errorValue && intendedValue == rhs.intendedValue; } - jsonifier_inline jsonifier::string reportError() const { + JSONIFIER_INLINE jsonifier::string reportError() const { #if defined(DEV) simd_string_reader section{}; std::string resultString{}; if (stringView) { - resultString = section.resetWithErrorPrintOut(jsonifier::string_view_base{ stringView, stringLength }, errorIndexReal); + resultString = section.resetWithErrorPrintOut(stringView, stringLength, errorIndexReal); } #endif switch (errorType) { @@ -229,6 +230,10 @@ namespace jsonifier_internal { case error_code::Setup_Error: { [[fallthrough]]; } + case error_code::Serialize_Error: { + jsonifier::string returnValue{ "Serialize error - you must provide a resizeable buffer." }; + return returnValue; + } default: { return {}; } @@ -246,17 +251,25 @@ namespace jsonifier_internal { uint8_t errorValue{}; }; - template jsonifier_inline error createError(structural_iterator& iter, std::source_location locationNew = std::source_location::current()) { + template + JSONIFIER_INLINE error createError(const iterator& iter, std::source_location locationNew = std::source_location::current()) { error newError{ iter, typeNew, locationNew }; return newError; } - template jsonifier_inline error createError(structural_iterator& iter, std::source_location locationNew = std::source_location::current()) { + JSONIFIER_INLINE error createError(error_code errorCode) { + error newError{}; + newError.errorType = errorCode; + return newError; + } + + template + JSONIFIER_INLINE error createError(const iterator& iter, std::source_location locationNew = std::source_location::current()) { error newError{ iter, typeNew, locationNew }; return newError; } - jsonifier_inline std::ostream& operator<<(std::ostream& os, const error& errorNew) { + JSONIFIER_INLINE std::ostream& operator<<(std::ostream& os, const error& errorNew) { os << errorNew.reportError(); return os; } diff --git a/Include/jsonifier/Expected.hpp b/Include/jsonifier/Expected.hpp index 62f5a7bed..771bdc873 100644 --- a/Include/jsonifier/Expected.hpp +++ b/Include/jsonifier/Expected.hpp @@ -23,313 +23,159 @@ /// Feb 20, 2023 #pragma once +#include #include namespace jsonifier_internal { - template class unexpected { + template class unexpected { public: - jsonifier_constexpr unexpected(){}; - - jsonifier_constexpr unexpected& operator=(unexpected_type&& other) { - std::uninitialized_move(&other, (&other) + 1, &unex); - return *this; - } - - jsonifier_constexpr unexpected(unexpected_type&& other) { - *this = std::move(other); - } + using unexpected_type = unexpected_type_new; - jsonifier_constexpr unexpected& operator=(const unexpected_type& other) { - unex = other; + template unexpected_type_newer> constexpr unexpected& operator=(unexpected_type_newer&& other) { + unex = std::forward(other); return *this; } - jsonifier_constexpr unexpected(const unexpected_type& other) { - *this = other; - } - - jsonifier_constexpr const unexpected_type&& error() const&& { - return std::move(unex); + template unexpected_type_newer> constexpr unexpected(unexpected_type_newer&& other) { + *this = std::forward(other); } - jsonifier_constexpr unexpected_type&& error() && { + constexpr unexpected_type&& error() const&& { return std::move(unex); } - jsonifier_constexpr const unexpected_type& error() const& { - return unex; - } - - jsonifier_constexpr unexpected_type& error() & { + constexpr unexpected_type& error() const& { return unex; } - jsonifier_constexpr void swap(unexpected& other) { - std::swap(unex, other.unex); - } - - friend jsonifier_constexpr bool operator==(const unexpected& lhs, const unexpected& rhs) { - return lhs.unex == rhs.unex; - } - - jsonifier_constexpr ~unexpected(){}; - protected: unexpected_type unex{}; }; - template unexpected(unexpected_type) -> unexpected; - template class expected { public: - using value_type = expected_type; - using pointer = value_type*; - using error_type = unexpected_type_new; - using unexpected_type = unexpected_type_new; - template using rebind = expected; + using value_type = expected_type; + using pointer = value_type*; + using unexpected_type = unexpected; - jsonifier_constexpr expected(){}; - - jsonifier_constexpr expected& operator=(expected&& other) { - hasValue = other.hasValue; + constexpr expected& operator=(expected&& other) { + std::swap(hasValue, other.hasValue); if (hasValue) { - val = std::move(other.val); + std::construct_at(&val, std::move(other.val)); } else { - unex = std::move(other.unex); + std::construct_at(&unex, std::move(other.unex)); } return *this; } - jsonifier_constexpr expected(expected&& other) : unex{} { + constexpr expected(expected&& other) : unex{} { *this = std::move(other); } - jsonifier_constexpr expected& operator=(const expected& other) { + constexpr expected& operator=(const expected& other) { hasValue = other.hasValue; if (hasValue) { - val = other.val; + std::construct_at(&val, other.val); } else { - unex = other.unex; + std::construct_at(&unex, other.unex); } return *this; } - jsonifier_constexpr expected(const expected& other) : unex{} { - *this = other; - } - - template jsonifier_constexpr expected& operator=(unexpected&& other) { - unex = std::move(other.error()); - hasValue = false; - return *this; - } - - template jsonifier_constexpr expected(unexpected&& other) { - *this = std::move(other); - } - - template jsonifier_constexpr expected& operator=(const unexpected& other) { - hasValue = false; - return *this; - } - - template jsonifier_constexpr expected(const unexpected& other) { - *this = other; - } - - jsonifier_constexpr expected& operator=(error_type&& other) { - unex = std::move(other); - hasValue = false; - return *this; - } - - jsonifier_constexpr expected(error_type&& other) { - *this = std::move(other); - } - - jsonifier_constexpr expected& operator=(const error_type& other) { - unex = other; - hasValue = false; - return *this; - } - - jsonifier_constexpr expected(const error_type& other) { + constexpr expected(const expected& other) : unex{} { *this = other; } - jsonifier_constexpr expected& operator=(value_type&& other) { - val = std::move(other); + template expected_type_newer> constexpr expected& operator=(expected_type_newer&& other) { + val = std::forward(other); hasValue = true; return *this; } - jsonifier_constexpr expected(value_type&& v) { - *this = std::move(v); + template expected_type_newer> constexpr expected(expected_type_newer&& other) { + *this = std::forward(other); } - jsonifier_constexpr expected& operator=(const value_type& other) { - val = other; - hasValue = true; + template unexpected_type_newer> constexpr expected& operator=(unexpected_type_newer&& other) { + unex = std::forward(other); + hasValue = false; return *this; } - jsonifier_constexpr expected(const value_type& v) { - *this = v; + template unexpected_type_newer> constexpr expected(unexpected_type_newer&& other) { + *this = std::forward(other); } - jsonifier_constexpr void swap(expected& other) { + constexpr void swap(expected& other) { + std::swap(hasValue, other.hasValue); if (hasValue) { std::swap(val, other.val); } else { std::swap(unex, other.unex); } - std::swap(hasValue, other.hasValue); - } - - jsonifier_constexpr pointer operator->() const { - return &val; } - jsonifier_constexpr pointer operator->() { + constexpr pointer operator->() const { return &val; } - jsonifier_constexpr const value_type&& operator*() const&& { - return std::move(val); - } - - jsonifier_constexpr value_type&& operator*() && { + constexpr value_type&& operator*() const&& { return std::move(val); } - jsonifier_constexpr const value_type& operator*() const& { - return val; - } - - jsonifier_constexpr value_type& operator*() & { + constexpr value_type& operator*() const& { return val; } - jsonifier_constexpr explicit operator bool() const { + constexpr explicit operator bool() const { return hasValue; } - jsonifier_constexpr bool has_value() const { + constexpr bool has_value() const { return hasValue; } - jsonifier_constexpr const value_type&& value() const&& { + constexpr value_type value() const&& { return std::move(val); } - jsonifier_constexpr value_type&& value() && { - return std::move(val); - } - - jsonifier_constexpr const value_type& value() const& { - return val; - } - - jsonifier_constexpr value_type& value() & { + constexpr value_type value() const& { return val; } - jsonifier_constexpr const unexpected_type&& error() const&& { - return std::move(unex); - } - - jsonifier_constexpr unexpected_type&& error() && { + constexpr unexpected_type error() const&& { return std::move(unex); } - jsonifier_constexpr const unexpected_type& error() const& { - return unex; - } - - jsonifier_constexpr unexpected_type& error() & { + constexpr unexpected_type error() const& { return unex; } - friend jsonifier_constexpr bool operator==(const expected& x, const expected& y) { - return x.hasValue == y.hasValue && x.unex == y.unex && x.val == y.val; + friend constexpr bool operator==(const expected& x, const expected& y) { + if (x.hasValue == y.hasValue) { + if (x.hasValue) { + return x.val == y.val; + } else { + return x.unex == y.unex; + } + } + return false; } - jsonifier_constexpr ~expected(){}; + constexpr ~expected() { + if (hasValue) { + std::destroy_at(&val); + } else { + std::destroy_at(&unex); + } + }; protected: bool hasValue{}; union { - value_type val{}; unexpected_type unex; - }; - }; - - template - requires std::is_void_v - class expected { - public: - using value_type = value_type_new; - using error_type = unexpected_type_new; - using unexpected_type = unexpected_type_new; - - template using rebind = expected; - - jsonifier_constexpr expected(){}; - - template jsonifier_constexpr expected& operator=(unexpected&& other) { - return *this; - } - - template jsonifier_constexpr expected(unexpected&& other) { - *this = std::move(other); - } - - template jsonifier_constexpr expected& operator=(const unexpected& other) { - return *this; - } - - template jsonifier_constexpr expected(const unexpected& other) { - *this = other; - } - - jsonifier_constexpr void swap(expected& other) { - std::swap(unex, other.unex); - } - - jsonifier_constexpr explicit operator bool() const { - return false; - } - - jsonifier_constexpr bool has_value() const { - return false; - } - - jsonifier_constexpr const unexpected_type&& error() const&& { - return std::move(unex); - } - - jsonifier_constexpr unexpected_type&& error() && { - return std::move(unex); - } - - jsonifier_constexpr const unexpected_type& error() const& { - return unex; - } - - jsonifier_constexpr unexpected_type& error() & { - return unex; - } - - template friend jsonifier_constexpr bool operator==(const expected& x, const expected& y) { - return x.unex == y.unex; - } - - jsonifier_constexpr ~expected(){}; - - protected: - union { - unexpected_type unex{}; + value_type val; }; }; diff --git a/Include/jsonifier/Hash.hpp b/Include/jsonifier/Hash.hpp index f47184eed..84f97914a 100644 --- a/Include/jsonifier/Hash.hpp +++ b/Include/jsonifier/Hash.hpp @@ -30,21 +30,26 @@ namespace jsonifier_internal { - template jsonifier_constexpr uint64_t fnv1aHash(const string_t& value) { - uint64_t d = 5381; - for (const auto& c: value) - d = d * 33 + static_cast(c); - return d; + // https://en.wikipedia.org/wiki/Fowler�Noll�Vo_hash_function + // http://www.isthe.com/chongo/tech/comp/fnv/index.html#FNV-param + static constexpr uint64_t fnv64OffsetBasis{ 0xcbf29ce484222325ull }; + static constexpr uint64_t fnv64Prime{ 0x00000100000001B3ull }; + + template constexpr uint64_t fnv1aHash(const string_t& value) { + uint64_t d{ fnv64OffsetBasis }; + for (const auto& c: value) { + d = (d ^ static_cast(c)) * static_cast(fnv64Prime); + } + return d >> 8; } - // https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function - // With the lowest bits removed, based on experimental setup. - template jsonifier_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); + template constexpr uint64_t fnv1aHash(const string_t& value, uint64_t seed) { + uint64_t d = (fnv64OffsetBasis ^ seed) * static_cast(fnv64Prime); + for (const auto& c: value) { + d = (d ^ static_cast(c)) * static_cast(fnv64Prime); + } return d >> 8; } template struct hash; -} +} \ No newline at end of file diff --git a/Include/jsonifier/HashMap.hpp b/Include/jsonifier/HashMap.hpp index 0fd3e2a91..498a298b1 100644 --- a/Include/jsonifier/HashMap.hpp +++ b/Include/jsonifier/HashMap.hpp @@ -19,12 +19,12 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 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 /// Feb 20, 2023 #pragma once #include -#include #include #include #include @@ -35,22 +35,7 @@ namespace jsonifier_internal { - template jsonifier_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) { - res |= static_cast(bytes[x]) << (8 * x); - } - return res; - } else { - uint64_t res{}; - std::memcpy(&res, bytes, n); - return res; - } - } - - template jsonifier_constexpr uint64_t toUint64N(const value_type* bytes) { - static_assert(n == 8); + template constexpr uint64_t toUint64(const char_type* bytes, const uint64_t n) { if (std::is_constant_evaluated()) { uint64_t res{}; for (uint64_t x = 0; x < n; ++x) { @@ -65,9 +50,9 @@ namespace jsonifier_internal { } struct string_compare_helper { - template jsonifier_constexpr bool operator()(T0&& lhs, T1&& rhs) const { + template constexpr bool operator()(string_type01&& lhs, string_type02&& rhs) const { if (std::is_constant_evaluated()) { - return stringConstCompare(std::forward(lhs), std::forward(rhs)); + return stringConstCompare(std::forward(lhs), std::forward(rhs)); } else { if (lhs.size() == rhs.size()) { return jsonifier_core_internal::compare(lhs.data(), rhs.data(), rhs.size()); @@ -77,17 +62,17 @@ namespace jsonifier_internal { } }; - jsonifier_constexpr auto nextHighestPowerOfTwo(uint64_t v) { + constexpr uint64_t nextHighestPowerOfTwo(uint64_t v) { // https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 - jsonifier_constexpr auto tripCount = std::numeric_limits::digits; - v--; + constexpr uint64_t tripCount = std::numeric_limits::digits; + --v; for (uint64_t x = 1; x < tripCount; x <<= 1) v |= v >> x; ++v; return v; } - template jsonifier_constexpr auto log(value_type v) { + template constexpr uint64_t log(value_type v) { uint64_t n = 0; while (v > 1) { n += 1; @@ -96,450 +81,77 @@ namespace jsonifier_internal { return n; } - jsonifier_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(uint64_t)) + - (n <= 128ULL); - } - - template jsonifier_inline uint64_t selectUintLeast(std::integral_constant) { - static_assert(n < 2, "Unsupported type size."); - return {}; - } - - template using SelectUintLeastT = decltype(selectUintLeast(std::integral_constant())); - - template jsonifier_constexpr void primitiveSwap(value_type&& a, value_type&& b) { - auto tmp = std::move(a); - a = std::move(b); - b = std::move(tmp); - } - - template jsonifier_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 jsonifier_constexpr void primitiveSwap(std::tuple&& a, std::tuple&& b, std::index_sequence) { - using swallow = int32_t[]; - ( void )swallow{ (primitiveSwap(std::forward(get(a)), std::forward(get(b))), 0)... }; - } - - template jsonifier_constexpr void primitiveSwap(std::tuple& a, std::tuple& b) { - primitiveSwap(a, b, std::make_index_sequence()); - } - - template jsonifier_constexpr iterator partition(iterator&& left, iterator&& right, const compare& compareNew) { + template constexpr iterator partition(iterator&& left, iterator&& right, const compare& compareNew) { auto pivot = left + (right - left) / 2; auto value = *pivot; - primitiveSwap(*right, *pivot); + std::swap(*right, *pivot); for (auto it = left; 0 < right - it; ++it) { if (compareNew(*it, value)) { - primitiveSwap(*it, *left); + std::swap(*it, *left); ++left; } } - primitiveSwap(*right, *left); + std::swap(*right, *left); return left; } - template jsonifier_constexpr void quicksort(iterator&& left, iterator&& right, const compare& compareNew) { + template constexpr void quicksort(iterator&& left, iterator&& right, const compare& compareNew) { while (0 < right - left) { - auto new_pivot = partition(left, right, compareNew); - quicksort(left, new_pivot, compareNew); - left = new_pivot + 1; + auto newPivot = jsonifier_internal::partition(left, right, compareNew); + quicksort(left, newPivot, compareNew); + left = newPivot + 1; } } - template - jsonifier_constexpr ctime_array quicksort(ctime_array const& array, const compare& compareNew) { - ctime_array res = array; + template constexpr std::array quicksort(std::array const& array, const compare& compareNew) { + std::array res = array; quicksort(res.begin(), res.end() - 1, compareNew); return res; } - template jsonifier_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; - } - } - return true; - } - template class linear_congruential_engine { - static_assert(std::is_unsigned::value, "uint_type must be an unsigned integral type."); - template static jsonifier_constexpr uint_type modulo(value_type value, std::integral_constant) { - return static_cast(value); - } - template static jsonifier_constexpr uint_type modulo(value_type value, std::integral_constant) { - return static_cast(value % m2); - } - public: - using result_type = uint_type; - static jsonifier_constexpr result_type default_seed = 1u; + constexpr linear_congruential_engine() = default; - jsonifier_constexpr linear_congruential_engine() = default; - - jsonifier_constexpr linear_congruential_engine(result_type S) { + constexpr linear_congruential_engine(uint_type S) { seed(S); } - jsonifier_constexpr void seed(result_type S = default_seed) const { - state_ = S; + constexpr void seed(uint_type S = 1u) const { + state = S; } - jsonifier_constexpr result_type operator()() { - using uint_least_t = SelectUintLeastT; - uint_least_t tmp = static_cast(multiplier) * state_ + increment; + constexpr uint_type operator()() { + using uint_least_t = uint64_t; + uint_least_t tmp = static_cast(multiplier) * state + increment; - state_ = modulo(tmp, std::integral_constant()); - return state_; + state = modulo(tmp, std::integral_constant()); + return state; } - jsonifier_constexpr void discard(uint64_t n) const { - while (n--) + constexpr void discard(uint64_t n) const { + while (n--) { operator()(); - } - - jsonifier_constexpr bool operator==(linear_congruential_engine const& other) const { - return state_ == other.state_; - } - - protected: - result_type state_ = default_seed; - }; - - using default_prg_t = linear_congruential_engine; - - // https://en.wikipedia.org/wiki/Fowler�Noll�Vo_hash_function - // http://www.isthe.com/chongo/tech/comp/fnv/index.html#FNV-param - static jsonifier_constexpr uint64_t fnv64Prime = 1099511628211; - static jsonifier_constexpr uint64_t fnv64OffsetBasis = 0xcbf29ce484222325; - - template struct xsm1 {}; - - template<> struct xsm1 { - jsonifier_constexpr xsm1() noexcept = default; - template jsonifier_constexpr uint64_t operator()(value_type&& value, const uint64_t seed) { - uint64_t h = (fnv64OffsetBasis ^ seed) * fnv64Prime; - const auto n = value.size(); - - if (n < 8) { - auto shift = 64 - 8 * n; - h ^= toUint64(value.data(), n) << shift; - h ^= h >> 33; - h *= fnv64Prime; - return h; - } - using string_type = jsonifier::concepts::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; - h *= fnv64Prime; - } - - const uint64_t nm8 = n - 8; - h ^= toUint64N<8>(value.data() + nm8); - h ^= h >> 33; - h *= fnv64Prime; - return h; - } - }; - - template<> struct xsm1 { - jsonifier_constexpr xsm1() noexcept = default; - jsonifier_constexpr uint32_t operator()(auto&& value, const uint32_t seed) { - uint64_t hash = xsm1{}(value, seed); - return hash >> 32; - } - }; - - jsonifier_constexpr bool contains(auto&& data, auto&& value) { - const auto n = data.size(); - for (uint64_t x = 0; x < n; ++x) { - if (data[x] == value) { - return true; - } - } - return false; - } - - template jsonifier_constexpr auto naiveBucketSize() { - return n < 8 ? 2 * n : 4 * n; - } - - template jsonifier_constexpr uint32_t naivePerfectHash(auto&& keys) { - static_assert(n <= 20); - jsonifier_constexpr uint64_t m = naiveBucketSize(); - ctime_array hashes{}; - ctime_array buckets{}; - - default_prg_t gen{}; - for (uint64_t x = 0; x < 1024; ++x) { - uint32_t seed = gen(); - uint64_t index = 0; - for (const auto& key: keys) { - auto hash = xsm1{}(key, seed); - if (contains(std::span{ hashes.data(), index }, hash)) - break; - hashes[index] = hash; - - auto bucket = hash % m; - if (contains(std::span{ buckets.data(), index }, bucket)) - break; - buckets[index] = bucket; - - ++index; - } - - if (index == n) - return seed; - } - - return std::numeric_limits::max(); - } - - template struct naive_map { - static_assert(n <= 20); - static jsonifier_constexpr uint64_t m = naiveBucketSize(); - uint32_t seed{}; - ctime_array, n> items{}; - ctime_array hashes{}; - ctime_array table{}; - - jsonifier_constexpr decltype(auto) begin() const { - return items.begin(); - } - - jsonifier_constexpr decltype(auto) end() const { - return items.end(); - } - - jsonifier_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(error_code::Unknown_Key); } - return item.second; - } - - jsonifier_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(); - return items.begin() + index; - } - }; - - template jsonifier_constexpr auto makeNaiveMap(std::initializer_list> pairs) { - static_assert(n <= 20); - if (pairs.size() != n) { - throw std::runtime_error{ "pairs.size() != n" }; - } - naive_map ht{}; - jsonifier_constexpr uint64_t m = naiveBucketSize(); - - ctime_array keys{}; - uint64_t x = 0; - for (const auto& pair: pairs) { - ht.items[x] = pair; - keys[x] = pair.first; - ++x; - } - ht.seed = naivePerfectHash(keys); - if (ht.seed == std::numeric_limits::max()) { - throw std::runtime_error{ "Unable to find perfect hash." }; } - for (x = 0; x < n; ++x) { - const auto hash = xsm1{}(keys[x], ht.seed); - ht.hashes[x] = hash; - ht.table[hash % m] = static_cast(x); + constexpr bool operator==(linear_congruential_engine const& other) const { + return state == other.state; } - return ht; - } - - 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 jsonifier_constexpr single_char_hash_desc singleCharHash(const ctime_array& v) { - if jsonifier_constexpr (n > 255) { - return {}; - } - - ctime_array hashes; - for (uint64_t x = 0; x < n; ++x) { - if (v[x].size() == 0) { - return {}; - } - if jsonifier_constexpr (IsFrontHash) { - hashes[x] = static_cast(v[x][0]); - } else { - hashes[x] = static_cast(v[x].back()); - } - } - - std::sort(hashes.begin(), hashes.end()); - - 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 = static_cast(hashes[x + 1] - hashes[x]); - } - } - - return single_char_hash_desc{ n, min_diff > 0, min_diff, hashes.front(), hashes.back(), IsFrontHash }; - } - - template struct single_char_map { - static jsonifier_constexpr auto n = D.n; - static_assert(n < 256); - ctime_array, n> items{}; - static jsonifier_constexpr uint64_t N_table = static_cast(D.back) - D.front + 1; - ctime_array table{}; - - jsonifier_inline decltype(auto) begin() const { - return items.begin(); - } - jsonifier_inline decltype(auto) end() const { - return items.end(); - } - - jsonifier_constexpr expected, error_code> at(auto&& key) const { - if (key.size() == 0) [[unlikely]] { - return unexpected(error_code::Unknown_Key); - } - - if jsonifier_constexpr (D.is_front_hash) { - const auto k = static_cast(key[0] - D.front); - if (k >= N_table) [[unlikely]] { - return unexpected(error_code::Unknown_Key); - } - const auto index = table[k]; - const auto& item = items[index]; - if (!stringConstCompare(item.first, key)) [[unlikely]] { - 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(error_code::Unknown_Key); - } - const auto index = table[k]; - const auto& item = items[index]; - if (!stringConstCompare(item.first, key)) [[unlikely]] { - return unexpected(error_code::Unknown_Key); - } - return item.second; - } - } - - jsonifier_constexpr decltype(auto) find(auto&& key) const { - if (key.size() == 0) [[unlikely]] { - return items.end(); - } - - if jsonifier_constexpr (D.is_front_hash) { - const auto k = static_cast(key[0] - D.front); - if (k >= N_table) [[unlikely]] { - return items.end(); - } - const auto index = table[k]; - const auto& item = items[index]; - if (!stringConstCompare(item.first, key)) [[unlikely]] - return items.end(); - return items.begin() + index; - } else { - const auto k = static_cast(key.back() - D.front); - if (k >= N_table) [[unlikely]] { - return items.end(); - } - const auto index = table[k]; - const auto& item = items[index]; - if (!stringConstCompare(item.first, key)) [[unlikely]] - return items.end(); - return items.begin() + index; - } - } - }; - - template jsonifier_constexpr auto makeSingleCharMap(std::initializer_list> pairs) { - static_assert(D.n < 256); - single_char_map ht{}; - - uint8_t x = 0; - for (const auto& pair: pairs) { - ht.items[x] = pair; - if jsonifier_constexpr (D.is_front_hash) { - ht.table[static_cast(pair.first[0] - D.front)] = x; - } else { - ht.table[static_cast(pair.first.back() - D.front)] = x; - } - ++x; - } - - return ht; - } - - template struct single_item { - ctime_array, 1> items{}; + protected: + uint_type state{ 1u }; - jsonifier_constexpr decltype(auto) end() const { - return items.end(); + static_assert(std::unsigned_integral, "uint_type must be an unsigned integral type."); + template static constexpr uint_type modulo(value_type value, std::integral_constant) { + return static_cast(value); } - - jsonifier_constexpr decltype(auto) find(auto&& key) const { - if (stringConstCompare(S, key)) [[likely]] { - return items.begin(); - } else [[unlikely]] { - return items.end(); - } + template static constexpr uint_type modulo(value_type value, std::integral_constant) { + return static_cast(value % m2); } }; - template struct double_item { - ctime_array, 2> items{}; - - static jsonifier_constexpr auto s0 = string01; - static jsonifier_constexpr auto s1 = string02; - - jsonifier_constexpr decltype(auto) end() const { - return items.end(); - } - - static jsonifier_constexpr bool sameSize = s0.size() == s1.size(); - - jsonifier_constexpr decltype(auto) find(auto&& key) const { - if jsonifier_constexpr (sameSize) { - jsonifier_constexpr auto n = s0.size(); - if (key.size() != n) { - return items.end(); - } - } - if (stringConstCompare(string01, key)) { - return items.begin(); - } else if (stringConstCompare(string02, key)) { - return items.begin() + 1; - } else [[unlikely]] { - return items.end(); - } - } - }; + using default_prg_t = linear_congruential_engine; // from // https://stackoverflow.com/questions/55941964/how-to-filter-duplicate-types-from-std::tuple-c @@ -558,9 +170,9 @@ namespace jsonifier_internal { template struct tuple_ptr_variant> : unique, std::add_pointer_t...> {}; - template struct tuple_ptr_variant> : unique, std::add_pointer_t...> {}; + template struct tuple_ptr_variant> : unique, std::add_pointer_t...> {}; - template::value>> struct value_tuple_variant; + template>> struct value_tuple_variant; template struct value_tuple_variant> { using type = typename tuple_variant>>>()...))>::type; @@ -569,54 +181,54 @@ namespace jsonifier_internal { template using value_tuple_variant_t = typename value_tuple_variant::type; struct bucket_size_compare { - template bool jsonifier_constexpr operator()(b const& b0, b const& b1) const { + template bool constexpr operator()(b const& b0, b const& b1) const { return b0.size() > b1.size(); } }; template struct pmh_buckets { - static jsonifier_constexpr auto bucket_max = 2 * (1u << (log(m) / 2)); + static constexpr auto bucket_max = 2 * (1u << (log(m) / 2)); using bucket_t = ctime_vector; - ctime_array buckets; + std::array buckets; uint64_t seed; struct bucket_ref { - unsigned hash; + uint32_t hash; const bucket_t* values; using value_type = typename bucket_t::value_type; using const_iterator = typename bucket_t::const_iterator; - jsonifier_constexpr auto size() const { + constexpr auto size() const { return values->size(); } - jsonifier_constexpr const auto& operator[](uint64_t idx) const { + constexpr const auto& operator[](uint64_t idx) const { return (*values)[idx]; } - jsonifier_constexpr auto begin() const { + constexpr auto begin() const { return values->begin(); } - jsonifier_constexpr auto end() const { + constexpr auto end() const { return values->end(); } }; - template ctime_array jsonifier_constexpr makeBucketRefs(std::index_sequence) const { + template std::array constexpr makeBucketRefs(std::index_sequence) const { return { { bucket_ref{ Is, &buckets[Is] }... } }; } - ctime_array jsonifier_constexpr getSortedBuckets() const { - ctime_array result{ makeBucketRefs(std::make_index_sequence()) }; + std::array constexpr getSortedBuckets() const { + std::array result{ makeBucketRefs(std::make_index_sequence()) }; quicksort(result.begin(), result.end() - 1, bucket_size_compare{}); return result; } }; - template - pmh_buckets jsonifier_constexpr makePmhBuckets(const ctime_array& items, key const& keyNew, default_prg_t& prg) { + template pmh_buckets constexpr makePmhBuckets(const std::array& items) { + default_prg_t prg{}; using result_t = pmh_buckets; using hasher = hash; result_t result{}; @@ -628,12 +240,12 @@ namespace jsonifier_internal { result.seed = prg(); rejected = false; for (uint64_t x = 0; x < n; ++x) { - auto& bucket = result.buckets[hasher{}(keyNew(items[x]), static_cast(result.seed)) % m]; + auto& bucket = result.buckets[hasher{}(items[x].first, static_cast(result.seed)) % m]; if (bucket.size() >= result_t::bucket_max) [[unlikely]] { rejected = true; break; } - bucket.push_back(x); + bucket.pushBack(x); } if (!rejected) [[likely]] { return result; @@ -641,7 +253,7 @@ namespace jsonifier_internal { } } - template jsonifier_constexpr bool allDifferentFrom(ctime_vector& data, value_type& a) { + template constexpr bool allDifferentFrom(ctime_vector& data, value_type& a) { for (uint64_t x = 0; x < data.size(); ++x) if (data[x] == a) [[unlikely]] { return false; @@ -653,63 +265,63 @@ namespace jsonifier_internal { using value_type = uint64_t; protected: - static jsonifier_constexpr value_type MinusOne = std::numeric_limits::max(); - static jsonifier_constexpr value_type HighBit = ~(MinusOne >> 1); + static constexpr value_type MinusOne = std::numeric_limits::max(); + static constexpr value_type HighBit = ~(MinusOne >> 1); value_type val{ 0 }; public: - jsonifier_constexpr value_type value() const { + constexpr seed_or_index(const value_type& valueNew) { + val = valueNew; + } + + constexpr value_type value() const { return val; } - jsonifier_constexpr bool isSeed() const { + constexpr bool isSeed() const { return val & HighBit; } - jsonifier_constexpr seed_or_index(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)) { } - jsonifier_constexpr seed_or_index() = default; + constexpr seed_or_index() = default; }; - template struct pmh_tables { - jsonifier_constexpr pmh_tables() = default; - jsonifier_constexpr pmh_tables(uint64_t firstSeedNew, ctime_array firstTableNew, ctime_array secondTableNew) { - firstSeed = firstSeedNew; - firstTable = firstTableNew; - secondTable = secondTableNew; - } - uint64_t firstSeed; - ctime_array firstTable; - ctime_array secondTable; - - template using hasher = hash; - - template jsonifier_constexpr const hasher getHasher() const { - return hasher{}; - } - - template jsonifier_constexpr uint64_t lookup(const KeyType& key) const { - auto const d = firstTable[getHasher()(key, static_cast(firstSeed)) % m]; + template struct pmh_tables : public hash, + public hash>, + public hash>, + public hash> { + constexpr pmh_tables() = default; + constexpr pmh_tables(uint64_t firstSeedNew, std::array firstTableNew, std::array secondTableNew) + : firstSeed{ firstSeedNew }, firstTable{ firstTableNew }, secondTable{ secondTableNew } {}; + uint64_t firstSeed{}; + std::array firstTable{}; + std::array secondTable{}; + + template using hasher = hash; + + template constexpr uint64_t lookup(const key_type& key) const { + auto const d = m > 0 ? firstTable[hasher::operator()(key, static_cast(firstSeed)) % m] : seed_or_index{}; if (!d.isSeed()) [[unlikely]] { - return static_cast(d.value()); + return m > 0 ? static_cast(d.value()) : 0; } else [[likely]] { - return secondTable[getHasher()(key, static_cast(d.value())) % m]; + return m > 0 ? secondTable[hasher::operator()(key, static_cast(d.value())) % m] : 0; } } }; - template - pmh_tables jsonifier_constexpr makePmhTables(const ctime_array& items, key const& keyNew, default_prg_t prg) { - auto step_one = makePmhBuckets(items, keyNew, prg); - auto buckets = step_one.getSortedBuckets(); + template pmh_tables constexpr makePmhTables(const std::array& items) { + default_prg_t prg{}; + auto stepOne = makePmhBuckets(items); + auto buckets = stepOne.getSortedBuckets(); - ctime_array G; + std::array G; using hasher = hash>; - jsonifier_constexpr uint64_t UNUSED = std::numeric_limits::max(); - ctime_array H; + constexpr uint64_t UNUSED = std::numeric_limits::max(); + std::array H; H.fill(UNUSED); for (const auto& bucket: buckets) { @@ -719,23 +331,23 @@ namespace jsonifier_internal { G[bucket.hash] = { false, static_cast(bucket[0]) }; } else if (bsize > 1) { seed_or_index d{ true, prg() }; - ctime_vector bucket_slots; + ctime_vector bucketSlots; - while (bucket_slots.size() < bsize) { - auto slot = hasher{}(keyNew(items[bucket[bucket_slots.size()]]), d.value()) % m; + while (bucketSlots.size() < bsize) { + auto slot = hasher{}(items[bucket[bucketSlots.size()]].first, d.value()) % m; - if (H[slot] != UNUSED || !allDifferentFrom(bucket_slots, slot)) { - bucket_slots.clear(); + if (H[slot] != UNUSED || !allDifferentFrom(bucketSlots, slot)) { + bucketSlots.clear(); d = { true, prg() }; continue; } - bucket_slots.push_back(slot); + bucketSlots.pushBack(slot); } G[bucket.hash] = d; for (uint64_t x = 0; x < bsize; ++x) - H[bucket_slots[x]] = bucket[x]; + H[bucketSlots[x]] = bucket[x]; } } @@ -743,128 +355,57 @@ namespace jsonifier_internal { if (H[x] == UNUSED) H[x] = 0; - return { step_one.seed, G, H }; + return { stepOne.seed, G, H }; } - struct get_key { - template jsonifier_constexpr auto const& operator()(KV const& kv) const { - return kv.first; - } - }; - - template - class unordered_map : protected string_compare_helper, protected ctime_array, n>, protected pmh_tables { + template class unordered_map : protected std::array, n>, + protected string_compare_helper, + protected pmh_tables { public: - static jsonifier_constexpr auto storageSize = nextHighestPowerOfTwo(n) * (n < 32 ? 2 : 1); - using container_type = ctime_array, n>; - using tables_type = pmh_tables; - - 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 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; - using const_pointer = typename container_type::const_pointer; - using iterator = typename container_type::iterator; - using const_iterator = typename container_type::const_iterator; - - jsonifier_constexpr unordered_map() = default; - - jsonifier_constexpr unordered_map(container_type items) : container_type{ items }, tables_type{ makePmhTables(items, get_key{}, default_prg_t{}) } { - } + static constexpr auto storageSize = nextHighestPowerOfTwo(n) * (n < 32 ? 2 : 1); + using container_type = std::array, n>; + using tables_type = pmh_tables; - jsonifier_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."); - } + using value_type = typename container_type::value_type; + using key_equal = string_compare_helper; + using const_iterator = typename container_type::const_iterator; + + constexpr unordered_map() = default; + + constexpr unordered_map(container_type items) : container_type{ items }, tables_type{ makePmhTables(items) } {}; - jsonifier_constexpr const_iterator begin() const { + constexpr const_iterator begin() const { return container_type::begin(); } - jsonifier_constexpr const_iterator end() const { + constexpr const_iterator end() const { return container_type::end(); } - template jsonifier_constexpr const_iterator find(const key_type_new& keyNew) const { - auto& kv = lookup(keyNew); - if (keyEq()(kv.first, keyNew)) { - return &kv; + template constexpr const_iterator find(key_type_newer&& keyNew) const { + auto kv = static_cast(tables_type::lookup(keyNew)); + auto newIter = container_type::begin() + kv; + if (key_equal::operator()(newIter->first, keyNew)) { + return newIter; } else { return end(); } } - - protected: - template jsonifier_constexpr const auto& lookup(const key_type_new& keyNew) const { - return container_type::operator[](tables_type::lookup(keyNew)); - } - - jsonifier_constexpr const key_equal& keyEq() const { - return *this; - } }; - template jsonifier_constexpr auto makeUnorderedMap(pair const (&items)[n]) { - return unordered_map{ items }; - } - - template struct core_sv { - static jsonifier_constexpr jsonifier::string_view value = get<0>(get(jsonifier::concepts::coreV)); - }; - - template jsonifier_constexpr auto makeMapImpl(std::index_sequence) { - using value_t = value_tuple_variant_t>; - jsonifier_constexpr auto n = std::tuple_size_v>; - jsonifier_constexpr auto size = sizeof...(I); - static_assert(size == n); - auto naiveOrNormalHash = [&] { - if jsonifier_constexpr (size <= 20) { - return makeNaiveMap({ pair(jsonifier::string_view(get<0>(get(jsonifier::concepts::coreV))), - get<1>(get(jsonifier::concepts::coreV)))... }); - } else { - return makeUnorderedMap({ pair( - jsonifier::string_view(get<0>(get(jsonifier::concepts::coreV))), get<1>(get(jsonifier::concepts::coreV)))... }); - } - }; - - jsonifier_constexpr bool n128 = n < 128; - if jsonifier_constexpr (n == 0) { - static_assert(falseV, "Empty object in jsonifier::core."); - } else if jsonifier_constexpr (n == 1) { - return single_item::value...>{ ctime_array, n>{ pair( - jsonifier::string_view(get<0>(get(jsonifier::concepts::coreV))), get<1>(get(jsonifier::concepts::coreV)))... } }; - } else if jsonifier_constexpr (n == 2) { - return double_item::value...>{ ctime_array, n>{ pair( - jsonifier::string_view(get<0>(get(jsonifier::concepts::coreV))), get<1>(get(jsonifier::concepts::coreV)))... } }; - } else if jsonifier_constexpr (n128) { - jsonifier_constexpr auto frontDesc = - singleCharHash(ctime_array{ jsonifier::string_view{ get<0>(get(jsonifier::concepts::coreV)) }... }); - - if jsonifier_constexpr (frontDesc.valid) { - return makeSingleCharMap({ pair(jsonifier::string_view(get<0>(get(jsonifier::concepts::coreV))), - get<1>(get(jsonifier::concepts::coreV)))... }); - } else { - jsonifier_constexpr auto backDesc = - singleCharHash(ctime_array{ jsonifier::string_view{ get<0>(get(jsonifier::concepts::coreV)) }... }); - - if jsonifier_constexpr (backDesc.valid) { - return makeSingleCharMap({ pair( - jsonifier::string_view(get<0>(get(jsonifier::concepts::coreV))), get<1>(get(jsonifier::concepts::coreV)))... }); - } else { - return naiveOrNormalHash(); - } - } + template constexpr auto makeMapImpl(std::index_sequence) { + using value_t = value_tuple_variant_t>; + constexpr auto n = std::tuple_size_v>; + if constexpr (n == 0) { + return unordered_map{}; } else { - return naiveOrNormalHash(); + static_assert(sizeof...(I) == n); + return unordered_map({ std::pair( + jsonifier::string_view(get<0>(get(jsonifier::concepts::coreV))), get<1>(get(jsonifier::concepts::coreV)))... }); } } - template jsonifier_constexpr auto makeMap() { - jsonifier_constexpr auto indices = std::make_index_sequence>>{}; - return makeMapImpl>(indices); + template constexpr auto makeMap() { + return makeMapImpl>(std::make_index_sequence>>{}); } } \ No newline at end of file diff --git a/Include/jsonifier/ISADetection.hpp b/Include/jsonifier/ISADetection.hpp index 7db214fd3..fe64768fa 100644 --- a/Include/jsonifier/ISADetection.hpp +++ b/Include/jsonifier/ISADetection.hpp @@ -34,13 +34,13 @@ namespace jsonifier_internal { - jsonifier_inline static void printBits(uint64_t values, const std::string& valuesTitle) { + JSONIFIER_INLINE void printBits(uint64_t values, const std::string& valuesTitle) { std::cout << valuesTitle; std::cout << std::bitset<64>{ values }; std::cout << std::endl; } - template jsonifier_inline static const simd_type& printBits(const simd_type& value, const std::string& valuesTitle) noexcept { + template JSONIFIER_INLINE const simd_type& printBits(const simd_type& value, const std::string& valuesTitle) noexcept { alignas(BytesPerStep) uint8_t values[sizeof(simd_type)]{}; std::stringstream theStream{}; store(value, values); @@ -54,13 +54,13 @@ namespace jsonifier_internal { return value; } - jsonifier_inline static std::string printBits(bool value) noexcept { + JSONIFIER_INLINE std::string printBits(bool value) noexcept { std::stringstream theStream{}; theStream << std::boolalpha << value << std::endl; return theStream.str(); } - template jsonifier_inline static std::string printBits(const simd_type& value) noexcept { + template JSONIFIER_INLINE std::string printBits(const simd_type& value) noexcept { alignas(BytesPerStep) uint8_t values[sizeof(simd_type)]{}; std::stringstream theStream{}; store(value, values); diff --git a/Include/jsonifier/ISADetection/AVX.hpp b/Include/jsonifier/ISADetection/AVX.hpp index b41d19db4..bb4c28a1f 100644 --- a/Include/jsonifier/ISADetection/AVX.hpp +++ b/Include/jsonifier/ISADetection/AVX.hpp @@ -27,54 +27,54 @@ namespace jsonifier_internal { -#if JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX) && !JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX2) && !JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX512) +#if JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX) - jsonifier_inline string_parsing_type simd_base::cmpeq(const simd_int_t& other, const simd_int_t& value) { + JSONIFIER_INLINE string_parsing_type simd_base::cmpeq(const simd_int_t& value, const simd_int_t& other) { return static_cast(_mm_movemask_epi8(_mm_cmpeq_epi8(value, other))); } - jsonifier_inline simd_int_t simd_base::bitAndNot(const simd_int_t& value, const simd_int_t& other) { - return _mm_andnot_si128(other, value); - } - - jsonifier_inline simd_int_t simd_base::shuffle(const simd_int_t& value, const simd_int_t& other) { + JSONIFIER_INLINE simd_int_t simd_base::opShuffle(const simd_int_t& value, const simd_int_t& other) { return _mm_shuffle_epi8(value, other); } - jsonifier_inline simd_int_t simd_base::opOr(const simd_int_t& other, const simd_int_t& value) { - return _mm_or_si128(value, other); + JSONIFIER_INLINE simd_int_t simd_base::opAndNot(const simd_int_t& value, const simd_int_t& other) { + return _mm_andnot_si128(other, value); } - jsonifier_inline simd_int_t simd_base::opAnd(const simd_int_t& other, const simd_int_t& value) { + JSONIFIER_INLINE simd_int_t simd_base::opAnd(const simd_int_t& value, const simd_int_t& other) { return _mm_and_si128(value, other); } - jsonifier_inline simd_int_t simd_base::opXor(const simd_int_t& other, const simd_int_t& value) { + JSONIFIER_INLINE simd_int_t simd_base::opXor(const simd_int_t& value, const simd_int_t& other) { return _mm_xor_si128(value, other); } - jsonifier_inline simd_int_t simd_base::setLSB(const simd_int_t& value, bool valueNew) { + JSONIFIER_INLINE simd_int_t simd_base::opOr(const simd_int_t& value, const simd_int_t& other) { + return _mm_or_si128(value, other); + } + + JSONIFIER_INLINE simd_int_t simd_base::setLSB(const simd_int_t& value, bool valueNew) { if (valueNew) { - return _mm_or_si128(value, _mm_set_epi64x(0x00, 0x01)); + return _mm_or_si128(value, _mm_set_epi64x(0x00ll, 0x01ll)); } else { - return _mm_andnot_si128(_mm_set_epi64x(0x00, 0x01), value); + return _mm_andnot_si128(_mm_set_epi64x(0x00ll, 0x01ll), value); } } - jsonifier_inline simd_int_t simd_base::opNot(const simd_int_t& value) { - return _mm_xor_si128(value, _mm_set1_epi64x(static_cast(std::numeric_limits::max()))); + JSONIFIER_INLINE simd_int_t simd_base::opNot(const simd_int_t& value) { + return _mm_xor_si128(value, _mm_set1_epi64x(0xFFFFFFFFFFFFFFFFll)); } - jsonifier_inline bool simd_base::getMSB(const simd_int_t& value) { - simd_int_t result = _mm_and_si128(value, _mm_set_epi64x(0x8000000000000000, 0x00)); + JSONIFIER_INLINE bool simd_base::getMSB(const simd_int_t& value) { + simd_int_t result = _mm_and_si128(value, _mm_set_epi64x(0x8000000000000000ll, 0x00ll)); return !_mm_testz_si128(result, result); } - jsonifier_inline bool simd_base::opBool(const simd_int_t& value) { + JSONIFIER_INLINE bool simd_base::opBool(const simd_int_t& value) { return !_mm_testz_si128(value, value); } - jsonifier_inline simd_int_t simd_base::reset() { + JSONIFIER_INLINE simd_int_t simd_base::reset() { return _mm_setzero_si128(); } diff --git a/Include/jsonifier/ISADetection/AVX2.hpp b/Include/jsonifier/ISADetection/AVX2.hpp index 78f7c9adb..2f8740808 100644 --- a/Include/jsonifier/ISADetection/AVX2.hpp +++ b/Include/jsonifier/ISADetection/AVX2.hpp @@ -27,54 +27,51 @@ namespace jsonifier_internal { -#if JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX2) && !JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX) && !JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX512) +#if JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX2) - jsonifier_inline string_parsing_type simd_base::cmpeq(const simd_int_t& other, const simd_int_t& value) { + JSONIFIER_INLINE string_parsing_type simd_base::cmpeq(const simd_int_t& value, const simd_int_t& other) { return static_cast(_mm256_movemask_epi8(_mm256_cmpeq_epi8(value, other))); } - jsonifier_inline simd_int_t simd_base::bitAndNot(const simd_int_t& value, const simd_int_t& other) { - return _mm256_andnot_si256(other, value); - } - - jsonifier_inline simd_int_t simd_base::shuffle(const simd_int_t& value, const simd_int_t& other) { + JSONIFIER_INLINE simd_int_t simd_base::opShuffle(const simd_int_t& value, const simd_int_t& other) { return _mm256_shuffle_epi8(value, other); } - jsonifier_inline simd_int_t simd_base::opOr(const simd_int_t& other, const simd_int_t& value) { - return _mm256_or_si256(value, other); + JSONIFIER_INLINE simd_int_t simd_base::opAndNot(const simd_int_t& value, const simd_int_t& other) { + return _mm256_andnot_si256(other, value); } - jsonifier_inline simd_int_t simd_base::opAnd(const simd_int_t& other, const simd_int_t& value) { + JSONIFIER_INLINE simd_int_t simd_base::opAnd(const simd_int_t& value, const simd_int_t& other) { return _mm256_and_si256(value, other); } - jsonifier_inline simd_int_t simd_base::opXor(const simd_int_t& other, const simd_int_t& value) { + JSONIFIER_INLINE simd_int_t simd_base::opXor(const simd_int_t& value, const simd_int_t& other) { return _mm256_xor_si256(value, other); } - jsonifier_inline simd_int_t simd_base::setLSB(const simd_int_t& value, bool valueNew) { - if (valueNew) { - return _mm256_or_si256(value, _mm256_set_epi64x(0x00, 0x00, 0x00, 0x01)); - } else { - return _mm256_andnot_si256(_mm256_set_epi64x(0x00, 0x00, 0x00, 0x01), value); - } + JSONIFIER_INLINE simd_int_t simd_base::opOr(const simd_int_t& value, const simd_int_t& other) { + return _mm256_or_si256(value, other); + } + + JSONIFIER_INLINE simd_int_t simd_base::setLSB(const simd_int_t& value, bool valueNew) { + simd_int_t mask = _mm256_set_epi64x(0x00ll, 0x00ll, 0x00ll, 0x01ll); + return valueNew ? _mm256_or_si256(value, mask) : _mm256_andnot_si256(mask, value); } - jsonifier_inline simd_int_t simd_base::opNot(const simd_int_t& value) { - return _mm256_xor_si256(value, _mm256_set1_epi64x(static_cast(std::numeric_limits::max()))); + JSONIFIER_INLINE simd_int_t simd_base::opNot(const simd_int_t& value) { + return _mm256_xor_si256(value, _mm256_set1_epi64x(0xFFFFFFFFFFFFFFFFll)); } - jsonifier_inline bool simd_base::getMSB(const simd_int_t& value) { - simd_int_t result = _mm256_and_si256(value, _mm256_set_epi64x(0x8000000000000000, 0x00, 0x00, 0x00)); + JSONIFIER_INLINE bool simd_base::getMSB(const simd_int_t& value) { + simd_int_t result = _mm256_and_si256(value, _mm256_set_epi64x(0x8000000000000000ll, 0x00ll, 0x00ll, 0x00ll)); return !_mm256_testz_si256(result, result); } - jsonifier_inline bool simd_base::opBool(const simd_int_t& value) { + JSONIFIER_INLINE bool simd_base::opBool(const simd_int_t& value) { return !_mm256_testz_si256(value, value); } - jsonifier_inline simd_int_t simd_base::reset() { + JSONIFIER_INLINE simd_int_t simd_base::reset() { return _mm256_setzero_si256(); } diff --git a/Include/jsonifier/ISADetection/AVX512.hpp b/Include/jsonifier/ISADetection/AVX512.hpp index 59c42ff9d..f8d256ed8 100644 --- a/Include/jsonifier/ISADetection/AVX512.hpp +++ b/Include/jsonifier/ISADetection/AVX512.hpp @@ -27,54 +27,54 @@ namespace jsonifier_internal { -#if JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX512) && !JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX) && !JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX2) +#if JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX512) - jsonifier_inline string_parsing_type simd_base::cmpeq(const simd_int_t& other, const simd_int_t& value) { + JSONIFIER_INLINE string_parsing_type simd_base::cmpeq(const simd_int_t& value, const simd_int_t& other) { return static_cast(_mm512_cmpeq_epi8_mask(value, other)); } - jsonifier_inline simd_int_t simd_base::bitAndNot(const simd_int_t& value, const simd_int_t& other) { - return _mm512_andnot_si512(other, value); - } - - jsonifier_inline simd_int_t simd_base::shuffle(const simd_int_t& value, const simd_int_t& other) { + JSONIFIER_INLINE simd_int_t simd_base::opShuffle(const simd_int_t& value, const simd_int_t& other) { return _mm512_shuffle_epi8(value, other); } - jsonifier_inline simd_int_t simd_base::opOr(const simd_int_t& other, const simd_int_t& value) { - return _mm512_or_si512(value, other); + JSONIFIER_INLINE simd_int_t simd_base::opAndNot(const simd_int_t& value, const simd_int_t& other) { + return _mm512_andnot_si512(other, value); } - jsonifier_inline simd_int_t simd_base::opAnd(const simd_int_t& other, const simd_int_t& value) { + JSONIFIER_INLINE simd_int_t simd_base::opAnd(const simd_int_t& value, const simd_int_t& other) { return _mm512_and_si512(value, other); } - jsonifier_inline simd_int_t simd_base::opXor(const simd_int_t& other, const simd_int_t& value) { + JSONIFIER_INLINE simd_int_t simd_base::opXor(const simd_int_t& value, const simd_int_t& other) { return _mm512_xor_si512(value, other); } - jsonifier_inline simd_int_t simd_base::setLSB(const simd_int_t& value, bool valueNew) { + JSONIFIER_INLINE simd_int_t simd_base::opOr(const simd_int_t& value, const simd_int_t& other) { + return _mm512_or_si512(value, other); + } + + JSONIFIER_INLINE simd_int_t simd_base::setLSB(const simd_int_t& value, bool valueNew) { if (valueNew) { - return _mm512_or_si512(value, _mm512_set_epi64(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01)); + return _mm512_or_si512(value, _mm512_set_epi64(0x00ll, 0x00ll, 0x00ll, 0x00ll, 0x00ll, 0x00ll, 0x00ll, 0x01ll)); } else { - return _mm512_andnot_si512(_mm512_set_epi64(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01), value); + return _mm512_andnot_si512(_mm512_set_epi64(0x00ll, 0x00ll, 0x00ll, 0x00ll, 0x00ll, 0x00ll, 0x00ll, 0x01ll), value); } } - jsonifier_inline simd_int_t simd_base::opNot(const simd_int_t& value) { - return _mm512_xor_si512(value, _mm512_set1_epi64(static_cast(std::numeric_limits::max()))); + JSONIFIER_INLINE simd_int_t simd_base::opNot(const simd_int_t& value) { + return _mm512_xor_si512(value, _mm512_set1_epi64(0xFFFFFFFFFFFFFFFFll)); } - jsonifier_inline bool simd_base::getMSB(const simd_int_t& value) { - simd_int_t result = _mm512_and_si512(value, _mm512_set_epi64(0x8000000000000000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)); + JSONIFIER_INLINE bool simd_base::getMSB(const simd_int_t& value) { + simd_int_t result = _mm512_and_si512(value, _mm512_set_epi64(0x8000000000000000ll, 0x00ll, 0x00ll, 0x00ll, 0x00ll, 0x00ll, 0x00ll, 0x00ll)); return _mm512_test_epi64_mask(result, result); } - jsonifier_inline bool simd_base::opBool(const simd_int_t& value) { + JSONIFIER_INLINE bool simd_base::opBool(const simd_int_t& value) { return _mm512_test_epi64_mask(value, value); } - jsonifier_inline simd_int_t simd_base::reset() { + JSONIFIER_INLINE simd_int_t simd_base::reset() { return _mm512_setzero_si512(); } diff --git a/Include/jsonifier/ISADetection/Bmi.hpp b/Include/jsonifier/ISADetection/Bmi.hpp index 71d8bb698..71206cd8e 100644 --- a/Include/jsonifier/ISADetection/Bmi.hpp +++ b/Include/jsonifier/ISADetection/Bmi.hpp @@ -31,19 +31,19 @@ namespace jsonifier_internal { #include - template jsonifier_inline static value_type blsr(value_type value) { + template JSONIFIER_INLINE value_type blsr(value_type value) { return static_cast(_blsr_u32(static_cast(value))); } - template jsonifier_inline static value_type blsr(value_type value) { + template JSONIFIER_INLINE value_type blsr(value_type value) { return _blsr_u32(value); } - template jsonifier_inline static value_type blsr(value_type value) { + template JSONIFIER_INLINE value_type blsr(value_type value) { return _blsr_u64(value); } - template jsonifier_inline static value_type tzcnt(value_type value) { + template JSONIFIER_INLINE value_type tzcnt(value_type value) { #if defined(__linux__) return __tzcnt_u16(value); #else @@ -51,17 +51,17 @@ namespace jsonifier_internal { #endif } - template jsonifier_inline static value_type tzcnt(value_type value) { + template JSONIFIER_INLINE value_type tzcnt(value_type value) { return _tzcnt_u32(value); } - template jsonifier_inline static value_type tzcnt(value_type value) { + template JSONIFIER_INLINE value_type tzcnt(value_type value) { return _tzcnt_u64(value); } #else - template jsonifier_inline static value_type blsr(value_type value) { + template JSONIFIER_INLINE value_type blsr(value_type value) { if (value == 0) { return 0; } @@ -69,7 +69,7 @@ namespace jsonifier_internal { return value & (value - 1); } - template jsonifier_inline static value_type tzcnt(value_type value) { + template JSONIFIER_INLINE value_type tzcnt(value_type value) { if (value == 0) { return sizeof(value_type) * 8; } diff --git a/Include/jsonifier/ISADetection/Bmi2.hpp b/Include/jsonifier/ISADetection/Bmi2.hpp index 7465e9537..4845fe32d 100644 --- a/Include/jsonifier/ISADetection/Bmi2.hpp +++ b/Include/jsonifier/ISADetection/Bmi2.hpp @@ -33,11 +33,11 @@ namespace jsonifier_internal { #else - template jsonifier_inline static value_type pdep(value_type src, value_type mask) { + template JSONIFIER_INLINE value_type pdep(value_type src, value_type mask) { value_type result = 0; value_type src_bit = 1; - for (int32_t i = 0; i < 64; i++) { + for (int32_t x = 0; x < 64; x++) { if (mask & 1) { result |= (src & src_bit); src_bit <<= 1; diff --git a/Include/jsonifier/ISADetection/Fallback.hpp b/Include/jsonifier/ISADetection/Fallback.hpp index 73667342b..45f1fd683 100644 --- a/Include/jsonifier/ISADetection/Fallback.hpp +++ b/Include/jsonifier/ISADetection/Fallback.hpp @@ -29,190 +29,146 @@ namespace jsonifier_internal { #if !JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX) && !JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX2) && !JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX512) - template jsonifier_inline void movemaskEpi8Helper02(int16_t& result, const simd_int_t& a) { - if jsonifier_constexpr (index < 8) { - uint8_t value = (a.m128x_uint64[index02] >> (index * 8)) & 0xff; - int16_t mask = (value >> 7) & 1; - result |= mask << (index02 * 8 + index); - movemaskEpi8Helper02(result, a); - } + template JSONIFIER_INLINE void _mm128_movemask_epi8_helper00(const simd_int_t& a, int16_t& result, std::index_sequence) { + int16_t mask{}; + uint8_t value{}; + uint64_t newIndex01{}; + uint64_t newIndex02{}; + (((newIndex01 = index * 8), (newIndex02 = indices * 8), (value = (a.m128x_uint64[index] >> (newIndex02)) & 0xFF, (mask = (value >> 7) & 1)), + (result |= mask << (newIndex01 + indices))), + ...); } - template jsonifier_inline int16_t movemaskEpi8(const simd_int_t& a) { + template JSONIFIER_INLINE int16_t _mm128_movemask_epi8(const simd_int_t& a, std::index_sequence) { int16_t result{}; - if jsonifier_constexpr (index < 2) { - movemaskEpi8Helper02<0, index>(result, a); - result |= movemaskEpi8(a); - } + ((_mm128_movemask_epi8_helper00(a, result, std::make_index_sequence<8>{})), ...); return result; } - jsonifier_inline simd_int_t orSi128(const simd_int_t& valOne, const simd_int_t& valTwo) { + JSONIFIER_INLINE simd_int_t _mm128_or_si128(const simd_int_t& valOne, const simd_int_t& valTwo) { simd_int_t value{}; value.m128x_uint64[0] = valOne.m128x_uint64[0] | valTwo.m128x_uint64[0]; value.m128x_uint64[1] = valOne.m128x_uint64[1] | valTwo.m128x_uint64[1]; return value; } - jsonifier_inline simd_int_t andSi128(const simd_int_t& valOne, const simd_int_t& valTwo) { + JSONIFIER_INLINE simd_int_t _mm128_and_si128(const simd_int_t& valOne, const simd_int_t& valTwo) { simd_int_t value{}; value.m128x_uint64[0] = valOne.m128x_uint64[0] & valTwo.m128x_uint64[0]; value.m128x_uint64[1] = valOne.m128x_uint64[1] & valTwo.m128x_uint64[1]; return value; } - jsonifier_inline simd_int_t andNotSi128(const simd_int_t& valOne, const simd_int_t& valTwo) { + JSONIFIER_INLINE simd_int_t _mm128_andnot_si128(const simd_int_t& valOne, const simd_int_t& valTwo) { simd_int_t result{}; result.m128x_uint64[0] = valTwo.m128x_uint64[0] & (~valOne.m128x_uint64[0]); result.m128x_uint64[1] = valTwo.m128x_uint64[1] & (~valOne.m128x_uint64[1]); return result; } - jsonifier_inline simd_int_t xorSi128(const simd_int_t& valOne, const simd_int_t& valTwo) { + JSONIFIER_INLINE simd_int_t _mm128_xor_si128(const simd_int_t& valOne, const simd_int_t& valTwo) { simd_int_t value{}; value.m128x_uint64[0] = valOne.m128x_uint64[0] ^ valTwo.m128x_uint64[0]; value.m128x_uint64[1] = valOne.m128x_uint64[1] ^ valTwo.m128x_uint64[1]; return value; } - jsonifier_inline simd_int_t subEpi64(const simd_int_t& valOne, const simd_int_t& valTwo) { - simd_int_t result{}; - result.m128x_uint64[0] = valOne.m128x_uint64[0] - valTwo.m128x_uint64[0]; - result.m128x_uint64[1] = valOne.m128x_uint64[1] - valTwo.m128x_uint64[1]; - return result; - } - - template jsonifier_inline void cmpeqEpi8Helper(simd_int_t& result, const simd_int_t& a, const simd_int_t& b) { - if jsonifier_constexpr (index < 8) { - uint8_t a8 = (a.m128x_uint64[index02] >> (index * 8)) & 0xff; - uint8_t b8 = (b.m128x_uint64[index02] >> (index * 8)) & 0xff; - result.m128x_uint64[index02] |= (a8 == b8 ? 0xFFULL : 0) << (index * 8); - cmpeqEpi8Helper(result, a, b); - } + template + JSONIFIER_INLINE void _mm128_cmpeq_epi8_helper(simd_int_t& result, const simd_int_t& a, const simd_int_t& b, std::index_sequence) { + uint8_t a8{}; + uint8_t b8{}; + (((a8 = (a.m128x_uint64[index02] >> (indices * 8)) & 0xFF), (b8 = (b.m128x_uint64[index02] >> (indices * 8)) & 0xFF), + (result.m128x_uint64[index02] |= (a8 == b8 ? 0xFFull : 0) << (indices * 8))), + ...); } - template jsonifier_inline simd_int_t cmpeqEpi8(const simd_int_t& a, const simd_int_t& b) { + template JSONIFIER_INLINE simd_int_t _mm128_cmpeq_epi8(const simd_int_t& a, const simd_int_t& b, std::index_sequence) { simd_int_t result{}; - if jsonifier_constexpr (index < 2) { - cmpeqEpi8Helper<0, index>(result, a, b); - result = orSi128(result, cmpeqEpi8(a, b)); - } + (((_mm128_cmpeq_epi8_helper(result, a, b, std::make_index_sequence<8>{})), + (result = _mm128_or_si128(result, _mm128_cmpeq_epi8(a, b, std::make_index_sequence{})))), + ...); return result; } - jsonifier_inline bool testzSi128(const simd_int_t& valOne, const simd_int_t& valTwo) { + JSONIFIER_INLINE bool _mm128_testz_si128(const simd_int_t& valOne, const simd_int_t& valTwo) { simd_int_t result{}; result.m128x_uint64[0] = valOne.m128x_uint64[0] & valTwo.m128x_uint64[0]; result.m128x_uint64[1] = valOne.m128x_uint64[1] & valTwo.m128x_uint64[1]; return result.m128x_uint64[0] == 0 && result.m128x_uint64[1] == 0; } - jsonifier_inline simd_int_t setEpi64x(uint64_t argOne, uint64_t argTwo) { + JSONIFIER_INLINE simd_int_t _mm128_set_epi64x(uint64_t argOne, uint64_t argTwo) { simd_int_t returnValue{}; returnValue.m128x_uint64[0] = argTwo; returnValue.m128x_uint64[1] = argOne; return returnValue; } - jsonifier_inline simd_int_t set1Epi64x(uint64_t argOne) { + JSONIFIER_INLINE simd_int_t _mm128_set1_epi64x(uint64_t argOne) { simd_int_t returnValue{}; returnValue.m128x_uint64[0] = argOne; returnValue.m128x_uint64[1] = argOne; return returnValue; } - template jsonifier_inline void shuffleEpi8Helper02(uint64_t& result, const simd_int_t& b) { - if jsonifier_constexpr (index >= index02) { - result = (result << 1) | ((b.m128x_uint64[index >> 6] >> (index & 0x3F)) & 1); - shuffleEpi8Helper02(result, b); - } - } - - template jsonifier_inline void shuffleEpi8Helper03(simd_int_t& result, uint64_t& result02, const simd_int_t& a) { - if jsonifier_constexpr (index < index02) { - result.m128x_uint64[index >> 6] |= ((a.m128x_uint64[result02 >> 6] >> (result02 & 0x3F)) & 1ULL) << (index & 0x3F); - result02++; - shuffleEpi8Helper03(result, result02, a); - } - } - - template jsonifier_inline simd_int_t shuffleEpi8(const simd_int_t& a, const simd_int_t& b) { + template JSONIFIER_INLINE simd_int_t _mm128_shuffle_epi8(const simd_int_t& a, const simd_int_t& b, std::index_sequence) { simd_int_t result{}; - if jsonifier_constexpr (index < 16) { - jsonifier_constexpr uint64_t i = index * 8; - jsonifier_constexpr uint64_t bitIndex = i + 7; - - if ((b.m128x_uint64[bitIndex >> 6] & (1ULL << (bitIndex & 0x3F))) == (1ULL << (bitIndex & 0x3F))) { - result.m128x_uint64[bitIndex >> 6] &= ~(1ULL << (bitIndex & 0x3F)); - } else { - uint64_t indexNew = 0; - shuffleEpi8Helper02(indexNew, b); - - uint64_t aIndex = indexNew * 8; - shuffleEpi8Helper03(result, aIndex, a); - } - result = orSi128(result, shuffleEpi8(a, b)); - } + int32_t index{}; + (((index = b.m128x_uint8[indices] & 0x0F), (result.m128x_uint8[indices] = a.m128x_uint8[index])), ...); return result; } - jsonifier_inline simd_int_t setZeroSi128() { + JSONIFIER_INLINE simd_int_t _mm128_setzero_si128() { return simd_int_t{}; } - jsonifier_inline simd_int_t set1Epi8(int8_t valueNew) { - simd_int_t returnValue{}; - std::memset(&returnValue, valueNew, sizeof(simd_int_t)); - return returnValue; - } - - jsonifier_inline string_parsing_type simd_base::cmpeq(const simd_int_t& other, const simd_int_t& value) { - return static_cast(movemaskEpi8(cmpeqEpi8(value, other))); + JSONIFIER_INLINE string_parsing_type simd_base::cmpeq(const simd_int_t& value, const simd_int_t& other) { + return static_cast(_mm128_movemask_epi8(_mm128_cmpeq_epi8(value, other, std::make_index_sequence<2>{}), std::make_index_sequence<2>{})); } - jsonifier_inline simd_int_t simd_base::bitAndNot(const simd_int_t& value, const simd_int_t& other) { - return andNotSi128(other, value); + JSONIFIER_INLINE simd_int_t simd_base::opShuffle(const simd_int_t& value, const simd_int_t& other) { + return _mm128_shuffle_epi8(value, other, std::make_index_sequence<16>{}); } - jsonifier_inline simd_int_t simd_base::shuffle(const simd_int_t& value, const simd_int_t& other) { - return shuffleEpi8(value, other); + JSONIFIER_INLINE simd_int_t simd_base::opAndNot(const simd_int_t& value, const simd_int_t& other) { + return _mm128_andnot_si128(other, value); } - jsonifier_inline simd_int_t simd_base::opOr(const simd_int_t& other, const simd_int_t& value) { - return orSi128(value, other); + JSONIFIER_INLINE simd_int_t simd_base::opAnd(const simd_int_t& value, const simd_int_t& other) { + return _mm128_and_si128(value, other); } - jsonifier_inline simd_int_t simd_base::opAnd(const simd_int_t& other, const simd_int_t& value) { - return andSi128(value, other); + JSONIFIER_INLINE simd_int_t simd_base::opXor(const simd_int_t& value, const simd_int_t& other) { + return _mm128_xor_si128(value, other); } - jsonifier_inline simd_int_t simd_base::opXor(const simd_int_t& other, const simd_int_t& value) { - return xorSi128(value, other); + JSONIFIER_INLINE simd_int_t simd_base::opOr(const simd_int_t& value, const simd_int_t& other) { + return _mm128_or_si128(value, other); } - jsonifier_inline simd_int_t simd_base::setLSB(const simd_int_t& value, bool valueNew) { + JSONIFIER_INLINE simd_int_t simd_base::setLSB(const simd_int_t& value, bool valueNew) { if (valueNew) { - return orSi128(value, setEpi64x(0x00, 0x01)); + return _mm128_or_si128(value, _mm128_set_epi64x(0x00ll, 0x01ll)); } else { - return andNotSi128(setEpi64x(0x00, 0x01), value); + return _mm128_andnot_si128(_mm128_set_epi64x(0x00ll, 0x01ll), value); } } - jsonifier_inline simd_int_t simd_base::opNot(const simd_int_t& value) { - return xorSi128(value, set1Epi64x(static_cast(std::numeric_limits::max()))); + JSONIFIER_INLINE simd_int_t simd_base::opNot(const simd_int_t& value) { + return _mm128_xor_si128(value, _mm128_set1_epi64x(0xFFFFFFFFFFFFFFFFll)); } - jsonifier_inline bool simd_base::getMSB(const simd_int_t& value) { - simd_int_t result = andSi128(value, setEpi64x(0x8000000000000000, 0x00)); - return !testzSi128(result, result); + JSONIFIER_INLINE bool simd_base::getMSB(const simd_int_t& value) { + simd_int_t result = _mm128_and_si128(value, _mm128_set_epi64x(0x8000000000000000ll, 0x00ll)); + return !_mm128_testz_si128(result, result); } - jsonifier_inline bool simd_base::opBool(const simd_int_t& value) { - return !testzSi128(value, value); + JSONIFIER_INLINE bool simd_base::opBool(const simd_int_t& value) { + return !_mm128_testz_si128(value, value); } - jsonifier_inline simd_int_t simd_base::reset() { - return setZeroSi128(); + JSONIFIER_INLINE simd_int_t simd_base::reset() { + return _mm128_setzero_si128(); } #endif diff --git a/Include/jsonifier/ISADetection/ISADetectionBase.hpp b/Include/jsonifier/ISADetection/ISADetectionBase.hpp index 271d2b08f..27790a17f 100644 --- a/Include/jsonifier/ISADetection/ISADetectionBase.hpp +++ b/Include/jsonifier/ISADetection/ISADetectionBase.hpp @@ -24,22 +24,31 @@ #pragma once #if !defined(__GNUC__) - #pragma warning(disable : 4710) - #pragma warning(disable : 4711) - #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 : 5267) - #pragma warning(disable : 5026) - #pragma warning(disable : 5027) #pragma warning(disable : 5045) #pragma warning(disable : 5246) #endif +#if defined(__clang__) || defined(__GNUC__) + #if !defined(JSONIFIER_USE_ALWAYS_INLINE) + #define JSONIFIER_USE_ALWAYS_INLINE + #endif +#endif + +#if defined(JSONIFIER_USE_ALWAYS_INLINE) && defined(NDEBUG) + #if !defined(JSONIFIER_INLINE) + #if defined(__clang__) + #define JSONIFIER_INLINE inline __attribute__((always_inline)) + #else + #define JSONIFIER_INLINE inline + #endif + #endif +#endif + +#if !defined(JSONIFIER_INLINE) + #define JSONIFIER_INLINE inline +#endif + #if !defined(JSONIFIER_CPU_INSTRUCTIONS) #define JSONIFIER_CPU_INSTRUCTIONS 0 #endif @@ -48,6 +57,10 @@ #define JSONIFIER_CHECK_FOR_INSTRUCTION(x) (JSONIFIER_CPU_INSTRUCTIONS & x) #endif +#if !defined(JSONIFIER_CHECK_FOR_AVX) + #define JSONIFIER_CHECK_FOR_AVX(x) (JSONIFIER_CPU_INSTRUCTIONS >= x) +#endif + #if !defined(JSONIFIER_POPCNT) #define JSONIFIER_POPCNT (1 << 0) #endif @@ -79,12 +92,10 @@ #endif #include -#include #include #include #include #include -#include #include #include @@ -105,8 +116,8 @@ using simd_float_128 = __m128d; #else -typedef union __m128x { - int8_t m128x_int8[16]; +union __m128x { + int8_t m128x_int8[16]{}; int16_t m128x_int16[8]; int32_t m128x_int32[4]; int64_t m128x_int64[2]; @@ -114,7 +125,7 @@ typedef union __m128x { int16_t m128x_uint16[8]; int32_t m128x_uint32[4]; uint64_t m128x_uint64[2]; -} __m128x; +}; using simd_int_128 = __m128x; @@ -122,473 +133,309 @@ using simd_int_128 = __m128x; #if JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX512) -jsonifier_constexpr uint64_t BitsPerStep{ 512 }; -jsonifier_constexpr uint64_t BytesPerStep{ BitsPerStep / 8 }; -jsonifier_constexpr uint64_t SixtyFourBitsPerStep{ BitsPerStep / 64 }; -jsonifier_constexpr uint64_t StridesPerStep{ BitsPerStep / BytesPerStep }; +constexpr uint64_t BitsPerStep{ 512 }; using string_parsing_type = uint64_t; using simd_int_t = simd_int_512; #elif JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX2) -jsonifier_constexpr uint64_t BitsPerStep{ 256 }; -jsonifier_constexpr uint64_t BytesPerStep{ BitsPerStep / 8 }; -jsonifier_constexpr uint64_t SixtyFourBitsPerStep{ BitsPerStep / 64 }; -jsonifier_constexpr uint64_t StridesPerStep{ BitsPerStep / BytesPerStep }; +constexpr uint64_t BitsPerStep{ 256 }; using string_parsing_type = uint32_t; using simd_int_t = simd_int_256; -#elif JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_AVX) - -jsonifier_constexpr uint64_t BitsPerStep{ 128 }; -jsonifier_constexpr uint64_t BytesPerStep{ BitsPerStep / 8 }; -jsonifier_constexpr uint64_t SixtyFourBitsPerStep{ BitsPerStep / 64 }; -jsonifier_constexpr uint64_t StridesPerStep{ BitsPerStep / BytesPerStep }; -using string_parsing_type = uint16_t; -using simd_int_t = simd_int_128; - #else -jsonifier_constexpr uint64_t BitsPerStep{ 128 }; -jsonifier_constexpr uint64_t BytesPerStep{ BitsPerStep / 8 }; -jsonifier_constexpr uint64_t SixtyFourBitsPerStep{ BitsPerStep / 64 }; -jsonifier_constexpr uint64_t StridesPerStep{ BitsPerStep / BytesPerStep }; +constexpr uint64_t BitsPerStep{ 128 }; using string_parsing_type = uint16_t; using simd_int_t = simd_int_128; #endif +constexpr uint64_t BytesPerStep{ BitsPerStep / 8 }; +constexpr uint64_t SixtyFourBitsPerStep{ BitsPerStep / 64 }; +constexpr uint64_t StridesPerStep{ BitsPerStep / BytesPerStep }; + namespace jsonifier_internal { - jsonifier_inline static void printBits(uint64_t values, const std::string& valuesTitle); + template + constexpr return_type createArray(const value_type (&newArray)[N], std::index_sequence) { + return return_type{ newArray[indices % N]... }; + } + + template constexpr return_type simdFromValue(uint8_t value) { +#if defined(_WIN32) + char newArray[16]{}; + std::fill(newArray, newArray + 16, value); +#else + int64_t newArray[16 / sizeof(int64_t)]{}; + for (size_t x = 0; x < 16; ++x) { + newArray[x / sizeof(int64_t)] |= static_cast(value) << ((x % 8) * 8); + } +#endif + return_type returnValue{ createArray(newArray, std::make_index_sequence{}) }; + return returnValue; + } + + template constexpr return_type simdFromTable(const uint8_t (&valuesNew01)[16]) { +#if defined(_WIN32) + char newArray[16]{}; + std::copy(valuesNew01, valuesNew01 + std::size(newArray), newArray); +#else + int64_t newArray[16 / sizeof(int64_t)]{}; + for (size_t x = 0; x < 16; ++x) { + newArray[x / sizeof(int64_t)] |= static_cast(valuesNew01[x % 16]) << ((x % 8) * 8); + } +#endif + return_type returnValue{ createArray(newArray, std::make_index_sequence{}) }; + return returnValue; + } + + template JSONIFIER_INLINE const simd_type& printBits(const simd_type& value, const std::string& valuesTitle) noexcept; - template jsonifier_inline static std::string printBits(const simd_type& value) noexcept; + template JSONIFIER_INLINE std::string printBits(const simd_type& value) noexcept; - template jsonifier_inline static const simd_type& printBits(const simd_type& value, const std::string& valuesTitle) noexcept; + JSONIFIER_INLINE void printBits(uint64_t values, const std::string& valuesTitle); using string_view_ptr = const uint8_t*; using structural_index = string_view_ptr; using string_buffer_ptr = uint8_t*; -#if JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_ANY_AVX) +#if JSONIFIER_CHECK_FOR_AVX(JSONIFIER_AVX) template concept simd_int_128_t = std::same_as, simd_int_128>; - template - concept simd_int_256_t = std::same_as, simd_int_256>; - - template - concept simd_int_512_t = std::same_as, simd_int_512>; - template concept simd_float_128_t = std::same_as, simd_float_128>; - template - concept simd_float_256_t = std::same_as, simd_float_256>; - - template - concept simd_float_512_t = std::same_as, simd_float_512>; - - template jsonifier_inline simd_type gatherValues(char_type* str) { + template JSONIFIER_INLINE simd_type gatherValues(char_type* str) { return _mm_load_si128(reinterpret_cast(str)); } - template jsonifier_inline simd_type gatherValues(char_type* str) { - return _mm256_load_si256(reinterpret_cast(str)); + template JSONIFIER_INLINE simd_type gatherValuesU(char_type* str) { + return _mm_loadu_si128(reinterpret_cast(str)); } - template jsonifier_inline simd_type gatherValues(char_type* str) { - return _mm512_load_si512(str); + template JSONIFIER_INLINE simd_type gatherValues(char_type* str) { + return _mm_loadu_pd(str); } - template jsonifier_inline simd_type gatherValuesU(char_type* str) { - return _mm_loadu_si128(reinterpret_cast(str)); + template JSONIFIER_INLINE void storeu(const simd_int_128& value, char_type* storageLocation) { + _mm_storeu_si128(reinterpret_cast<__m128i*>(storageLocation), value); } - template jsonifier_inline simd_type gatherValuesU(char_type* str) { - return _mm256_loadu_si256(reinterpret_cast(str)); + template JSONIFIER_INLINE void store(const simd_int_128& value, char_type* storageLocation) { + _mm_store_si128(reinterpret_cast<__m128i*>(storageLocation), value); } - template jsonifier_inline simd_type gatherValuesU(char_type* str) { - return _mm512_loadu_si512(str); - } + #if JSONIFIER_CHECK_FOR_AVX(JSONIFIER_AVX2) - template jsonifier_inline simd_type gatherValues(char_type* str) { - return _mm_loadu_pd(str); - } + template + concept simd_int_256_t = std::same_as, simd_int_256>; - template jsonifier_inline simd_type gatherValues(char_type* str) { - return _mm256_loadu_pd(str); + template + concept simd_float_256_t = std::same_as, simd_float_256>; + + template JSONIFIER_INLINE simd_type gatherValues(char_type* str) { + return _mm256_load_si256(reinterpret_cast(str)); } - template jsonifier_inline simd_type gatherValues(char_type* str) { - return _mm512_loadu_pd(str); + template JSONIFIER_INLINE simd_type gatherValuesU(char_type* str) { + return _mm256_loadu_si256(reinterpret_cast(str)); } - template jsonifier_inline void storeu(const simd_int_128& value, value_type* storageLocation) { - _mm_storeu_si128(reinterpret_cast<__m128i*>(storageLocation), value); + template JSONIFIER_INLINE simd_type gatherValues(char_type* str) { + return _mm256_loadu_pd(str); } - template jsonifier_inline void storeu(const simd_int_256& value, value_type* storageLocation) { + template JSONIFIER_INLINE void storeu(const simd_int_256& value, char_type* storageLocation) { _mm256_storeu_si256(reinterpret_cast<__m256i*>(storageLocation), value); } - template jsonifier_inline void storeu(const simd_int_512& value, value_type* storageLocation) { - _mm512_storeu_si512(storageLocation, value); + template JSONIFIER_INLINE void store(const simd_int_256& value, char_type* storageLocation) { + _mm256_store_si256(reinterpret_cast<__m256i*>(storageLocation), value); } - template jsonifier_inline void store(const simd_int_128& value, value_type* storageLocation) { - _mm_store_si128(reinterpret_cast<__m128i*>(storageLocation), value); - } + #if JSONIFIER_CHECK_FOR_AVX(JSONIFIER_AVX512) - template jsonifier_inline void store(const simd_int_256& value, value_type* storageLocation) { - _mm256_store_si256(reinterpret_cast<__m256i*>(storageLocation), value); - } + template + concept simd_int_512_t = std::same_as, simd_int_512>; - template jsonifier_inline void store(const simd_int_512& value, value_type* storageLocation) { - _mm512_store_si512(storageLocation, value); - } + template + concept simd_float_512_t = std::same_as, simd_float_512>; - template jsonifier_constexpr return_type simdFromTable(std::array arrayNew01) { - #if !defined(_WIN32) - int64_t newArray[sizeof(return_type) / sizeof(uint64_t)]{}; - for (uint64_t x = 0; x < sizeof(return_type) / sizeof(uint64_t); ++x) { - newArray[x] |= static_cast(arrayNew01[((x * 8) + 7)]) << 56; - newArray[x] |= static_cast(arrayNew01[((x * 8) + 6)]) << 48; - newArray[x] |= static_cast(arrayNew01[((x * 8) + 5)]) << 40; - newArray[x] |= static_cast(arrayNew01[((x * 8) + 4)]) << 32; - newArray[x] |= static_cast(arrayNew01[((x * 8) + 3)]) << 24; - newArray[x] |= static_cast(arrayNew01[((x * 8) + 2)]) << 16; - newArray[x] |= static_cast(arrayNew01[((x * 8) + 1)]) << 8; - newArray[x] |= static_cast(arrayNew01[((x * 8) + 0)]); - } - return_type returnValue{ newArray[0], newArray[1] }; - #else - return_type returnValue{}; - for (uint64_t x = 0; x < sizeof(return_type); ++x) { - returnValue.m128i_u8[x] = arrayNew01[x]; - } - #endif - return returnValue; + template JSONIFIER_INLINE simd_type gatherValues(char_type* str) { + return _mm512_load_si512(str); } - template jsonifier_constexpr return_type simdFromValue(uint8_t value) { - #if !defined(_WIN32) - int64_t newArray[sizeof(return_type) / sizeof(uint64_t)]{}; - for (uint64_t x = 0; x < sizeof(return_type) / sizeof(uint64_t); ++x) { - newArray[x] |= static_cast(value) << 56; - newArray[x] |= static_cast(value) << 48; - newArray[x] |= static_cast(value) << 40; - newArray[x] |= static_cast(value) << 32; - newArray[x] |= static_cast(value) << 24; - newArray[x] |= static_cast(value) << 16; - newArray[x] |= static_cast(value) << 8; - newArray[x] |= static_cast(value); - } - return_type returnValue{ newArray[0], newArray[1] }; - #else - return_type returnValue{}; - for (uint64_t x = 0; x < sizeof(return_type); ++x) { - returnValue.m128i_u8[x] = value; - } - #endif - return returnValue; + template JSONIFIER_INLINE simd_type gatherValuesU(char_type* str) { + return _mm512_loadu_si512(str); } - template jsonifier_constexpr return_type simdFromTable(std::array arrayNew01) { - #if !defined(_WIN32) - int64_t newArray[sizeof(return_type) / sizeof(uint64_t)]{}; - for (uint64_t x = 0; x < sizeof(return_type) / sizeof(uint64_t); ++x) { - newArray[x] |= static_cast(arrayNew01[((x * 8) + 7) % 16]) << 56; - newArray[x] |= static_cast(arrayNew01[((x * 8) + 6) % 16]) << 48; - newArray[x] |= static_cast(arrayNew01[((x * 8) + 5) % 16]) << 40; - newArray[x] |= static_cast(arrayNew01[((x * 8) + 4) % 16]) << 32; - newArray[x] |= static_cast(arrayNew01[((x * 8) + 3) % 16]) << 24; - newArray[x] |= static_cast(arrayNew01[((x * 8) + 2) % 16]) << 16; - newArray[x] |= static_cast(arrayNew01[((x * 8) + 1) % 16]) << 8; - newArray[x] |= static_cast(arrayNew01[((x * 8) + 0) % 16]); - } - return_type returnValue{ newArray[0], newArray[1], newArray[2], newArray[3] }; - #else - return_type returnValue{}; - for (uint64_t x = 0; x < sizeof(return_type); ++x) { - returnValue.m256i_u8[x] = arrayNew01[x % 16]; - } - #endif - return returnValue; + template JSONIFIER_INLINE simd_type gatherValues(char_type* str) { + return _mm512_loadu_pd(str); } - template jsonifier_constexpr return_type simdFromValue(uint8_t value) { - #if !defined(_WIN32) - int64_t newArray[sizeof(return_type) / sizeof(uint64_t)]{}; - for (uint64_t x = 0; x < sizeof(return_type) / sizeof(uint64_t); ++x) { - newArray[x] |= static_cast(value) << 56; - newArray[x] |= static_cast(value) << 48; - newArray[x] |= static_cast(value) << 40; - newArray[x] |= static_cast(value) << 32; - newArray[x] |= static_cast(value) << 24; - newArray[x] |= static_cast(value) << 16; - newArray[x] |= static_cast(value) << 8; - newArray[x] |= static_cast(value); - } - return_type returnValue{ newArray[0], newArray[1], newArray[2], newArray[3] }; - #else - return_type returnValue{}; - for (uint64_t x = 0; x < sizeof(return_type); ++x) { - returnValue.m256i_u8[x] = value; - } - #endif - return returnValue; + template JSONIFIER_INLINE void storeu(const simd_int_512& value, char_type* storageLocation) { + _mm512_storeu_si512(storageLocation, value); } - template jsonifier_constexpr return_type simdFromTable(std::array arrayNew01) { - #if !defined(_WIN32) - int64_t newArray[sizeof(return_type) / sizeof(uint64_t)]{}; - for (uint64_t x = 0; x < sizeof(return_type) / sizeof(uint64_t); ++x) { - newArray[x] |= static_cast(arrayNew01[((x * 8) + 7) % 16]) << 56; - newArray[x] |= static_cast(arrayNew01[((x * 8) + 6) % 16]) << 48; - newArray[x] |= static_cast(arrayNew01[((x * 8) + 5) % 16]) << 40; - newArray[x] |= static_cast(arrayNew01[((x * 8) + 4) % 16]) << 32; - newArray[x] |= static_cast(arrayNew01[((x * 8) + 3) % 16]) << 24; - newArray[x] |= static_cast(arrayNew01[((x * 8) + 2) % 16]) << 16; - newArray[x] |= static_cast(arrayNew01[((x * 8) + 1) % 16]) << 8; - newArray[x] |= static_cast(arrayNew01[((x * 8) + 0) % 16]); - } - return_type returnValue{ newArray[0], newArray[1], newArray[2], newArray[3], newArray[4], newArray[5], newArray[6], newArray[7] }; - #else - return_type returnValue{}; - for (uint64_t x = 0; x < sizeof(return_type); ++x) { - returnValue.m512i_u8[x] = arrayNew01[x % 16]; - } - #endif - return returnValue; + template JSONIFIER_INLINE void store(const simd_int_512& value, char_type* storageLocation) { + _mm512_store_si512(storageLocation, value); } - template jsonifier_constexpr return_type simdFromValue(uint8_t value) { - #if !defined(_WIN32) - int64_t newArray[sizeof(return_type) / sizeof(uint64_t)]{}; - for (uint64_t x = 0; x < sizeof(return_type) / sizeof(uint64_t); ++x) { - newArray[x] |= static_cast(value) << 56; - newArray[x] |= static_cast(value) << 48; - newArray[x] |= static_cast(value) << 40; - newArray[x] |= static_cast(value) << 32; - newArray[x] |= static_cast(value) << 24; - newArray[x] |= static_cast(value) << 16; - newArray[x] |= static_cast(value) << 8; - newArray[x] |= static_cast(value); - } - return_type returnValue{ newArray[0], newArray[1], newArray[2], newArray[3], newArray[4], newArray[5], newArray[6], newArray[7] }; - #else - return_type returnValue{}; - for (uint64_t x = 0; x < sizeof(return_type); ++x) { - returnValue.m512i_u8[x] = value; - } + #endif + #endif - return returnValue; - } #else template concept simd_int_128_t = std::same_as, simd_int_128>; - template jsonifier_inline simd_type gatherValues(char_type* str) { + template JSONIFIER_INLINE simd_type gatherValues(char_type* str) { simd_type returnValue{}; std::memcpy(&returnValue, str, sizeof(simd_type)); return returnValue; } - template jsonifier_inline simd_type gatherValuesU(char_type* str) { + template JSONIFIER_INLINE simd_type gatherValuesU(char_type* str) { simd_type returnValue{}; std::memcpy(&returnValue, str, sizeof(simd_type)); return returnValue; } - template jsonifier_inline void storeu(const simd_int_t& value, value_type* storageLocation) { + template JSONIFIER_INLINE void storeu(const simd_int_128& value, char_type* storageLocation) { std::memcpy(storageLocation, &value, sizeof(simd_int_t)); } - template jsonifier_inline void store(const simd_int_t& value, value_type* storageLocation) { + template JSONIFIER_INLINE void store(const simd_int_128& value, char_type* storageLocation) { std::memcpy(storageLocation, &value, sizeof(simd_int_t)); } - template jsonifier_constexpr return_type simdFromTable(std::array arrayNew01) { - simd_int_128 returnValue{}; - for (uint64_t x = 0; x < sizeof(simd_int_128); ++x) { - returnValue.m128x_uint8[x] = arrayNew01[x]; - } - return returnValue; - } - - template jsonifier_constexpr return_type simdFromValue(uint8_t value) { - simd_int_128 returnValue{}; - for (uint64_t x = 0; x < sizeof(simd_int_128); ++x) { - returnValue.m128x_uint8[x] = value; - } - return returnValue; - } - #endif class simd_base { public: - static jsonifier_constexpr std::array whitespaceArray{ 0x20u, 0x64u, 0x64u, 0x64u, 0x11u, 0x64u, 0x71u, 0x02u, 0x64u, 0x09u, 0x0Au, 0x70u, 0x64u, 0x0Du, 0x64u, - 0x64u }; - static jsonifier_constexpr std::array opArray{ 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x3Au, 0x7Bu, 0x2Cu, 0x7Du, 0x00u, - 0x00u }; - static jsonifier_constexpr std::array escapeableArray01{ 0x00u, 0x00u, 0x22u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x08u, 0x09u, 0x0Au, 0x00u, 0x0Cu, 0x0Du, - 0x00u, 0x00u }; - static jsonifier_constexpr std::array escapeableArray02{ 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x5Cu, 0x00u, - 0x00u, 0x00u }; - static jsonifier_constexpr simd_int_t whitespaceTable{ simdFromTable(whitespaceArray) }; - static jsonifier_constexpr simd_int_t opTableVal{ simdFromTable(opArray) }; - static jsonifier_constexpr simd_int_t backslashes{ simdFromValue(0x5Cu) }; - static jsonifier_constexpr simd_int_t quotes{ simdFromValue(0x22u) }; - static jsonifier_constexpr simd_int_t chars{ simdFromValue(0x20u) }; + static constexpr uint8_t whitespaceArray[]{ 0x20u, 0x64u, 0x64u, 0x64u, 0x11u, 0x64u, 0x71u, 0x02u, 0x64u, 0x09u, 0x0Au, 0x70u, 0x64u, 0x0Du, 0x64u, 0x64u }; + static constexpr uint8_t opArray[]{ 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x3Au, 0x7Bu, 0x2Cu, 0x7Du, 0x00u, 0x00u }; + static constexpr uint8_t escapeableArray01[]{ 0x00u, 0x00u, 0x22u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x08u, 0x09u, 0x0Au, 0x00u, 0x0Cu, 0x0Du, 0x00u, 0x00u }; + static constexpr uint8_t escapeableArray02[]{ 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x5Cu, 0x00u, 0x00u, 0x00u }; + static constexpr simd_int_t whitespaceTable{ simdFromTable(whitespaceArray) }; + static constexpr simd_int_t opTableVal{ simdFromTable(opArray) }; + static constexpr simd_int_t backslashes{ simdFromValue(0x5Cu) }; + static constexpr simd_int_t quotes{ simdFromValue(0x22u) }; + static constexpr simd_int_t chars{ simdFromValue(0x20u) }; - jsonifier_inline static string_parsing_type cmpeq(const simd_int_t& other, const simd_int_t& value); + JSONIFIER_INLINE static string_parsing_type cmpeq(const simd_int_t& value, const simd_int_t& other); - jsonifier_inline static simd_int_t bitAndNot(const simd_int_t& value, const simd_int_t& other); + JSONIFIER_INLINE static simd_int_t opShuffle(const simd_int_t& value, const simd_int_t& other); - jsonifier_inline static simd_int_t shuffle(const simd_int_t& value, const simd_int_t& other); + JSONIFIER_INLINE static simd_int_t opAndNot(const simd_int_t& value, const simd_int_t& other); - jsonifier_inline static simd_int_t opOr(const simd_int_t& other, const simd_int_t& value); + JSONIFIER_INLINE static simd_int_t opAnd(const simd_int_t& value, const simd_int_t& other); - jsonifier_inline static simd_int_t opAnd(const simd_int_t& other, const simd_int_t& value); + JSONIFIER_INLINE static simd_int_t opXor(const simd_int_t& value, const simd_int_t& other); - jsonifier_inline static simd_int_t opXor(const simd_int_t& other, const simd_int_t& value); + JSONIFIER_INLINE static simd_int_t opOr(const simd_int_t& value, const simd_int_t& other); - jsonifier_inline static simd_int_t setLSB(const simd_int_t& value, bool valueNew); + JSONIFIER_INLINE static simd_int_t setLSB(const simd_int_t& value, bool valueNew); - jsonifier_inline static simd_int_t opNot(const simd_int_t& value); + JSONIFIER_INLINE static simd_int_t opNot(const simd_int_t& value); - jsonifier_inline static bool getMSB(const simd_int_t& value); + JSONIFIER_INLINE static bool getMSB(const simd_int_t& value); - jsonifier_inline static bool opBool(const simd_int_t& value); + JSONIFIER_INLINE static bool opBool(const simd_int_t& value); - jsonifier_inline static simd_int_t reset(); + JSONIFIER_INLINE static simd_int_t reset(); template - jsonifier_inline static std::enable_if_t, uint16_t> cmpeq(const simd_type& value, const simd_type& other) { - return static_cast(_mm_movemask_epi8(_mm_cmpeq_epi8(value, other))); + JSONIFIER_INLINE static std::enable_if_t, simd_int_128> opShuffle(const simd_type& value, const simd_type& other) { + return _mm_shuffle_epi8(value, other); } template - jsonifier_inline static std::enable_if_t, simd_int_128> shuffle(const simd_type& value, const simd_type& other) { - return _mm_shuffle_epi8(value, other); + JSONIFIER_INLINE static std::enable_if_t, uint16_t> cmpeq(const simd_type& value, const simd_type& other) { + return static_cast(_mm_movemask_epi8(_mm_cmpeq_epi8(value, other))); } - jsonifier_inline static uint64_t subborrow_u64(uint8_t carryIn, uint64_t a, uint64_t b, uint8_t& borrowOut) { - borrowOut = (a < b + carryIn); - return a - b - carryIn; + template JSONIFIER_INLINE static simd_int_t collectStructuralsAsSimdBase(const simd_int_t (&values)[StridesPerStep], std::index_sequence) { + alignas(BytesPerStep) string_parsing_type valuesNew[StridesPerStep]{}; + ((valuesNew[indices] = cmpeq(opShuffle(opTableVal, values[indices]), opOr(chars, values[indices]))), ...); + return gatherValues(valuesNew); } - jsonifier_inline static simd_int_t opSub(const simd_int_t& other, const simd_int_t& value) { - alignas(BytesPerStep) uint64_t valuesNew01[SixtyFourBitsPerStep]{}; - alignas(BytesPerStep) long long unsigned int valuesNew02[SixtyFourBitsPerStep]{}; - uint8_t carryInFlag{}; - store(other, valuesNew01); - store(value, valuesNew02); - for (uint64_t x = 0; x < SixtyFourBitsPerStep; ++x) { - valuesNew02[x] = subborrow_u64(carryInFlag, valuesNew01[x], valuesNew02[x], carryInFlag); - } - return gatherValues(valuesNew02); + template JSONIFIER_INLINE static simd_int_t collectWhitespaceAsSimdBase(const simd_int_t (&values)[StridesPerStep], std::index_sequence) { + alignas(BytesPerStep) string_parsing_type valuesNew[StridesPerStep]{}; + ((valuesNew[indices] = cmpeq(opShuffle(whitespaceTable, values[indices]), values[indices])), ...); + return gatherValues(valuesNew); } - jsonifier_inline static void collectWhitespaceAsSimdBase(simd_int_t& value, const simd_int_t valuesNew[StridesPerStep]) { - alignas(BytesPerStep) string_parsing_type arrayNew[StridesPerStep]{}; - arrayNew[0] = cmpeq(shuffle(whitespaceTable, valuesNew[0]), valuesNew[0]); - arrayNew[1] = cmpeq(shuffle(whitespaceTable, valuesNew[1]), valuesNew[1]); - arrayNew[2] = cmpeq(shuffle(whitespaceTable, valuesNew[2]), valuesNew[2]); - arrayNew[3] = cmpeq(shuffle(whitespaceTable, valuesNew[3]), valuesNew[3]); - arrayNew[4] = cmpeq(shuffle(whitespaceTable, valuesNew[4]), valuesNew[4]); - arrayNew[5] = cmpeq(shuffle(whitespaceTable, valuesNew[5]), valuesNew[5]); - arrayNew[6] = cmpeq(shuffle(whitespaceTable, valuesNew[6]), valuesNew[6]); - arrayNew[7] = cmpeq(shuffle(whitespaceTable, valuesNew[7]), valuesNew[7]); - value = gatherValues(arrayNew); + template JSONIFIER_INLINE static simd_int_t collectBackslashesAsSimdBase(const simd_int_t (&values)[StridesPerStep], std::index_sequence) { + alignas(BytesPerStep) string_parsing_type valuesNew[StridesPerStep]{}; + ((valuesNew[indices] = cmpeq(backslashes, values[indices])), ...); + return gatherValues(valuesNew); } - jsonifier_inline static void collectBackslashesAsSimdBase(simd_int_t& value, const simd_int_t valuesNew[StridesPerStep]) { - alignas(BytesPerStep) string_parsing_type arrayNew[StridesPerStep]{}; - arrayNew[0] = cmpeq(valuesNew[0], backslashes); - arrayNew[1] = cmpeq(valuesNew[1], backslashes); - arrayNew[2] = cmpeq(valuesNew[2], backslashes); - arrayNew[3] = cmpeq(valuesNew[3], backslashes); - arrayNew[4] = cmpeq(valuesNew[4], backslashes); - arrayNew[5] = cmpeq(valuesNew[5], backslashes); - arrayNew[6] = cmpeq(valuesNew[6], backslashes); - arrayNew[7] = cmpeq(valuesNew[7], backslashes); - value = gatherValues(arrayNew); + template JSONIFIER_INLINE static simd_int_t collectQuotesAsSimdBase(const simd_int_t (&values)[StridesPerStep], std::index_sequence) { + alignas(BytesPerStep) string_parsing_type valuesNew[StridesPerStep]{}; + ((valuesNew[indices] = cmpeq(quotes, values[indices])), ...); + return gatherValues(valuesNew); } - jsonifier_inline static void collectStructuralsAsSimdBase(simd_int_t& value, const simd_int_t valuesNew[StridesPerStep]) { - alignas(BytesPerStep) string_parsing_type arrayNew[StridesPerStep]{}; - arrayNew[0] = cmpeq(shuffle(opTableVal, valuesNew[0]), (opOr(valuesNew[0], chars))); - arrayNew[1] = cmpeq(shuffle(opTableVal, valuesNew[1]), (opOr(valuesNew[1], chars))); - arrayNew[2] = cmpeq(shuffle(opTableVal, valuesNew[2]), (opOr(valuesNew[2], chars))); - arrayNew[3] = cmpeq(shuffle(opTableVal, valuesNew[3]), (opOr(valuesNew[3], chars))); - arrayNew[4] = cmpeq(shuffle(opTableVal, valuesNew[4]), (opOr(valuesNew[4], chars))); - arrayNew[5] = cmpeq(shuffle(opTableVal, valuesNew[5]), (opOr(valuesNew[5], chars))); - arrayNew[6] = cmpeq(shuffle(opTableVal, valuesNew[6]), (opOr(valuesNew[6], chars))); - arrayNew[7] = cmpeq(shuffle(opTableVal, valuesNew[7]), (opOr(valuesNew[7], chars))); - value = gatherValues(arrayNew); + constexpr static uint64_t power(size_t base, size_t exponent) { + uint64_t result = 1; + while (exponent > 0) { + if (exponent & 1) { + result *= base; + } + base *= base; + exponent >>= 1; + } + return result; } - jsonifier_inline static void collectQuotesAsSimdBase(simd_int_t& value, const simd_int_t valuesNew[StridesPerStep]) { - alignas(BytesPerStep) string_parsing_type arrayNew[StridesPerStep]{}; - arrayNew[0] = cmpeq(valuesNew[0], quotes); - arrayNew[1] = cmpeq(valuesNew[1], quotes); - arrayNew[2] = cmpeq(valuesNew[2], quotes); - arrayNew[3] = cmpeq(valuesNew[3], quotes); - arrayNew[4] = cmpeq(valuesNew[4], quotes); - arrayNew[5] = cmpeq(valuesNew[5], quotes); - arrayNew[6] = cmpeq(valuesNew[6], quotes); - arrayNew[7] = cmpeq(valuesNew[7], quotes); - value = gatherValues(arrayNew); + template JSONIFIER_INLINE static uint64_t prefixXorHelper(uint64_t prevInString) { + prevInString ^= prevInString << index; + return prevInString; } - jsonifier_inline static int64_t prefixXor(int64_t prevInString) { - prevInString ^= prevInString << 1; - prevInString ^= prevInString << 2; - prevInString ^= prevInString << 4; - prevInString ^= prevInString << 8; - prevInString ^= prevInString << 16; - prevInString ^= prevInString << 32; + template JSONIFIER_INLINE static uint64_t prefixXor(uint64_t prevInString, std::index_sequence) { + ((prevInString = prefixXorHelper(prevInString)), ...); return prevInString; } - jsonifier_inline static simd_int_t carrylessMultiplication(const simd_int_t& value, bool& prevInString) { - alignas(BytesPerStep) int64_t values[SixtyFourBitsPerStep]{}; - uint64_t newValue{}; - if (prevInString) { - newValue = std::numeric_limits::max(); - } + template JSONIFIER_INLINE static simd_int_t carrylessMultiplication(const simd_int_t& value, int64_t& prevInString, std::index_sequence) { + alignas(BytesPerStep) uint64_t values[SixtyFourBitsPerStep]{}; store(value, values); - for (uint64_t x = 0; x < SixtyFourBitsPerStep; ++x) { - values[x] = prefixXor(values[x]) ^ static_cast(newValue); - newValue = uint64_t(values[x] >> 63); - } - prevInString = (newValue >> 63) & 1; + ((values[indices] = prefixXor(values[indices], std::make_index_sequence<6>{}) ^ prevInString, prevInString = static_cast(values[indices]) >> 63), ...); return gatherValues(values); } - template jsonifier_inline static simd_int_t shl(const simd_int_t& value) { - alignas(BytesPerStep) uint64_t newArray00[SixtyFourBitsPerStep]{}; - alignas(BytesPerStep) uint64_t newArray01[SixtyFourBitsPerStep]{}; - store(value, newArray00); - newArray01[0] = (newArray00[0] << amount); - for (uint64_t x = 1; x < SixtyFourBitsPerStep; ++x) { - newArray01[x] = (newArray00[x] << amount) | (newArray00[x - 1] >> (64 - amount)); - } - return gatherValues(newArray01); + template JSONIFIER_INLINE static simd_int_t opSub(const simd_int_t& value, const simd_int_t& other, std::index_sequence) { + alignas(BytesPerStep) uint64_t values01[SixtyFourBitsPerStep]{}; + alignas(BytesPerStep) uint64_t values02[SixtyFourBitsPerStep]{}; + store(value, values01); + store(other, values02); + bool carryInNew{}; + ((values02[indices] = values01[indices] - values02[indices] - static_cast(carryInNew), carryInNew = values02[indices] > values01[indices]), ...); + return gatherValues(values02); } - jsonifier_inline static simd_int_t follows(const simd_int_t& value, bool& overflow) { - simd_int_t result = shl<1>(value); - result = setLSB(result, overflow); - overflow = getMSB(value); - return result; + template JSONIFIER_INLINE static simd_int_t shl(const simd_int_t& value, std::index_sequence) { + alignas(BytesPerStep) uint64_t values01[SixtyFourBitsPerStep]{}; + alignas(BytesPerStep) uint64_t values02[SixtyFourBitsPerStep]{}; + static constexpr uint64_t shiftAmount{ 64 - amount }; + store(value, values01); + values02[0] = values01[0] << amount; + ((values02[indices + 1] = values01[indices + 1] << amount | values01[indices] >> (shiftAmount)), ...); + return gatherValues(values02); + } + + JSONIFIER_INLINE static simd_int_t follows(const simd_int_t& value, bool& overflow) { + bool oldOverflow = overflow; + overflow = getMSB(value); + return setLSB(shl<1>(value, std::make_index_sequence{}), oldOverflow); } }; diff --git a/Include/jsonifier/ISADetection/Lzcount.hpp b/Include/jsonifier/ISADetection/Lzcount.hpp index f7b397a53..0b4a9c7cc 100644 --- a/Include/jsonifier/ISADetection/Lzcount.hpp +++ b/Include/jsonifier/ISADetection/Lzcount.hpp @@ -29,17 +29,13 @@ namespace jsonifier_internal { #if JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_LZCNT) - template jsonifier_inline static value_type lzcnt(value_type value) { + template JSONIFIER_INLINE value_type lzcnt(value_type value) { return _lzcnt_u32(value); } - template jsonifier_inline static value_type lzcnt(value_type value) { - return _lzcnt_u64(value); - } - #else - template jsonifier_inline static value_type lzcnt(value_type value) { + template JSONIFIER_INLINE value_type lzcnt(value_type value) { if (value == 0) { return sizeof(value_type) * 8; } @@ -48,7 +44,7 @@ namespace jsonifier_internal { value_type mask{ static_cast(1) << (std::numeric_limits::digits - 1) }; while ((value & mask) == 0) { - count++; + ++count; mask >>= 1; } diff --git a/Include/jsonifier/ISADetection/Popcount.hpp b/Include/jsonifier/ISADetection/Popcount.hpp index dc5fd72f2..f90d1b137 100644 --- a/Include/jsonifier/ISADetection/Popcount.hpp +++ b/Include/jsonifier/ISADetection/Popcount.hpp @@ -33,7 +33,7 @@ namespace jsonifier_internal { #else - template jsonifier_inline static value_type popcnt(value_type value) { + template JSONIFIER_INLINE value_type popcnt(value_type value) { value_type count{}; while (value > 0) { diff --git a/Include/jsonifier/IToStr.hpp b/Include/jsonifier/IToStr.hpp new file mode 100644 index 000000000..2bc5f6d5a --- /dev/null +++ b/Include/jsonifier/IToStr.hpp @@ -0,0 +1,160 @@ +/* + 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. +*/ +/// Note: Most of the code in this header was sampled from Glaze library: https://github.com/stephenberry/glaze +/// https://github.com/RealTimeChris/jsonifier +/// Nov 13, 2023 +#pragma once + +#include +#include + +#include +#include +#include +#include + +namespace jsonifier_internal { + + template JSONIFIER_INLINE char_type* toCharsU64Len4(char_type* buf, uint64_t val) noexcept { + const uint64_t aa = (val * 5243ull) >> 19; + const uint64_t bb = val - aa * 100ull; + std::memcpy(buf, charTable + aa * 2, 2); + std::memcpy(buf + 2, charTable + bb * 2, 2); + return buf + 4; + } + + template JSONIFIER_INLINE char_type* toCharsU64Len8(char_type* buf, uint64_t val) noexcept { + uint64_t aa{}, bb{}, cc{}, dd{}, aabb{}, ccdd{}; + aabb = (val * 109951163ull) >> 40; + ccdd = val - aabb * 10000ull; + aa = (aabb * 5243ull) >> 19; + cc = (ccdd * 5243ull) >> 19; + bb = aabb - aa * 100ull; + dd = ccdd - cc * 100ull; + std::memcpy(buf, charTable + aa * 2, 2); + std::memcpy(buf + 2, charTable + bb * 2, 2); + std::memcpy(buf + 4, charTable + cc * 2, 2); + std::memcpy(buf + 6, charTable + dd * 2, 2); + return buf + 8; + } + + template JSONIFIER_INLINE char_type* toCharsU64Len18(char_type* buf, uint64_t val) noexcept { + uint64_t aa{}, bb{}, cc{}, dd{}, aabb{}, bbcc{}, ccdd{}, lz{}; + + if (val < 100ull) { + lz = val < 10ull; + std::memcpy(buf, charTable + val * 2 + lz, 2); + buf -= lz; + return buf + 2; + } else if (val < 10000ull) { + aa = (val * 5243ull) >> 19; + bb = val - aa * 100ull; + lz = aa < 10ull; + std::memcpy(buf, charTable + aa * 2 + lz, 2); + buf -= lz; + std::memcpy(buf + 2, charTable + bb * 2, 2); + return buf + 4; + } else if (val < 1000000ull) { + aa = (val * 429497ull) >> 32; + bbcc = val - aa * 10000ull; + bb = (bbcc * 5243ull) >> 19; + cc = bbcc - bb * 100ull; + lz = aa < 10ull; + std::memcpy(buf, charTable + aa * 2 + lz, 2); + buf -= lz; + std::memcpy(buf + 2, charTable + bb * 2, 2); + std::memcpy(buf + 4, charTable + cc * 2, 2); + return buf + 6; + } else { + aabb = (val * 109951163ull) >> 40; + ccdd = val - aabb * 10000ull; + aa = (aabb * 5243ull) >> 19; + cc = (ccdd * 5243ull) >> 19; + bb = aabb - aa * 100ull; + dd = ccdd - cc * 100ull; + lz = aa < 10ull; + std::memcpy(buf, charTable + aa * 2 + lz, 2); + buf -= lz; + std::memcpy(buf + 2, charTable + bb * 2, 2); + std::memcpy(buf + 4, charTable + cc * 2, 2); + std::memcpy(buf + 6, charTable + dd * 2, 2); + return buf + 8; + } + } + + template JSONIFIER_INLINE char_type* toCharsU64Len58(char_type* buf, uint64_t val) noexcept { + if (val < 1000000) { + const uint64_t aa = (val * 429497ull) >> 32; + const uint64_t bbcc = val - aa * 10000ull; + const uint64_t bb = (bbcc * 5243ull) >> 19; + const uint64_t cc = bbcc - bb * 100ull; + const uint64_t lz = aa < 10ull; + std::memcpy(buf, charTable + aa * 2 + lz, 2); + buf -= lz; + std::memcpy(buf + 2, charTable + bb * 2, 2); + std::memcpy(buf + 4, charTable + cc * 2, 2); + return buf + 6; + } else { + const uint64_t aabb = (val * 109951163ull) >> 40; + const uint64_t ccdd = val - aabb * 10000ull; + const uint64_t aa = (aabb * 5243ull) >> 19; + const uint64_t cc = (ccdd * 5243ull) >> 19; + const uint64_t bb = aabb - aa * 100ull; + const uint64_t dd = ccdd - cc * 100ull; + const uint64_t lz = aa < 10ull; + std::memcpy(buf, charTable + aa * 2 + lz, 2); + buf -= lz; + std::memcpy(buf + 2, charTable + bb * 2, 2); + std::memcpy(buf + 4, charTable + cc * 2, 2); + std::memcpy(buf + 6, charTable + dd * 2, 2); + return buf + 8; + } + } + + template JSONIFIER_INLINE char_type* toChars(char_type* buf, value_type01 val) noexcept { + if (val < 100000000) { + buf = toCharsU64Len18(buf, static_cast(val)); + return buf; + } else if (val < 100000000ull * 100000000ull) { + const uint64_t hgh = static_cast(val) / 100000000ull; + const uint64_t low = static_cast(val) - hgh * 100000000ull; + buf = toCharsU64Len18(buf, hgh); + buf = toCharsU64Len8(buf, low); + return buf; + } else { + const uint64_t tmp = static_cast(val) / 100000000ull; + const uint64_t low = static_cast(val) - tmp * 100000000ull; + const uint64_t hgh = tmp / 10000ull; + const uint64_t mid = tmp - hgh * 10000ull; + buf = toCharsU64Len58(buf, hgh); + buf = toCharsU64Len4(buf, mid); + buf = toCharsU64Len8(buf, low); + return buf; + } + } + + template JSONIFIER_INLINE char_type* toChars(char_type* buf, value_type01 val) noexcept { + *buf = 0x2Du; + return toChars(buf + (static_cast(val) < 0), uint64_t(static_cast(val) ^ (static_cast(val) >> 63)) - (static_cast(val) >> 63)); + } + +}// namespace jsonifier_internal diff --git a/Include/jsonifier/Index.hpp b/Include/jsonifier/Index.hpp index 11f9746cd..e7b2f5aa3 100644 --- a/Include/jsonifier/Index.hpp +++ b/Include/jsonifier/Index.hpp @@ -27,7 +27,7 @@ #define NOMINMAX #endif -#include +#include #include #include #include diff --git a/Include/jsonifier/Iterator.hpp b/Include/jsonifier/Iterator.hpp index 2d06c9fbf..762ddc9b8 100644 --- a/Include/jsonifier/Iterator.hpp +++ b/Include/jsonifier/Iterator.hpp @@ -37,94 +37,90 @@ namespace jsonifier_internal { using reference = value_type&; using size_type = int64_t; - jsonifier_constexpr iterator() noexcept = default; - - jsonifier_constexpr iterator(pointer pointerNew) : value{ pointerNew } {}; + constexpr iterator() noexcept : ptr(nullptr) { + } - jsonifier_constexpr reference operator*() const { - return *value; + constexpr iterator(const pointer ptrNew) noexcept : ptr(ptrNew) { } - jsonifier_constexpr pointer operator->() const { - return value; + constexpr reference operator*() const noexcept { + return *operator->(); } - jsonifier_constexpr iterator& operator++() { - ++value; - return *this; + constexpr pointer operator->() const noexcept { + return ptr; } - jsonifier_constexpr iterator operator++(int32_t) { - iterator temp{ *this }; - ++*this; - return temp; + constexpr explicit operator bool() const noexcept { + return ptr != nullptr; } - jsonifier_constexpr iterator& operator--() { - --value; + constexpr iterator& operator++() noexcept { + ++ptr; return *this; } - jsonifier_constexpr iterator operator--(int32_t) { - iterator temp{ *this }; - --*this; + constexpr iterator operator++(int32_t) noexcept { + iterator temp = *this; + ++*this; return temp; } - jsonifier_constexpr iterator& operator+=(const difference_type iter) { - value += iter; + constexpr iterator& operator--() noexcept { + --ptr; return *this; } - jsonifier_constexpr iterator operator+(const difference_type iter) const { - iterator temp{ *this }; - temp += iter; + constexpr iterator operator--(int32_t) noexcept { + iterator temp = *this; + --*this; return temp; } - jsonifier_constexpr iterator& operator-=(const difference_type iter) { - return *this += -iter; + constexpr iterator& operator+=(const difference_type offset) noexcept { + ptr += offset; + return *this; } - jsonifier_constexpr iterator operator-(const difference_type iter) const { - iterator temp{ *this }; - temp -= iter; + constexpr iterator operator+(const difference_type offset) const noexcept { + iterator temp = *this; + temp += offset; return temp; } - jsonifier_constexpr reference operator[](const difference_type iter) const { - return *(*this + iter); - } - - jsonifier_constexpr difference_type operator+(const iterator& iter) const { - return value + iter.value; + friend constexpr iterator operator+(const difference_type offset, const iterator& next) noexcept { + return next + offset; } - jsonifier_constexpr difference_type operator-(const iterator& iter) const { - return value - iter.value; + constexpr iterator& operator-=(const difference_type offset) noexcept { + ptr -= offset; + return *this; } - jsonifier_constexpr bool operator==(const iterator& iter) const { - return value == iter.value; + constexpr iterator operator-(const difference_type offset) const noexcept { + iterator temp = *this; + temp -= offset; + return temp; } - jsonifier_constexpr bool operator>=(const iterator& iter) const { - return value >= iter.value; + constexpr difference_type operator-(const iterator& right) const noexcept { + return static_cast(ptr - right.ptr); } - jsonifier_constexpr bool operator<=(const iterator& iter) const { - return value <= iter.value; + constexpr reference operator[](const difference_type offset) const noexcept { + return *(*this + offset); } - jsonifier_constexpr bool operator>(const iterator& iter) const { - return value > iter.value; + constexpr bool operator==(const iterator& right) const noexcept { + return ptr == right.ptr; } - jsonifier_constexpr bool operator<(const iterator& iter) const { - return value < iter.value; + constexpr std::strong_ordering operator<=>(const iterator& right) const noexcept { + return ptr <=> right.ptr; } - pointer value; + private: + pointer ptr{}; }; }// namespace jsonifier_internal diff --git a/Include/jsonifier/JsonifierCore.hpp b/Include/jsonifier/JsonifierCore.hpp index 19284ca13..222e00710 100644 --- a/Include/jsonifier/JsonifierCore.hpp +++ b/Include/jsonifier/JsonifierCore.hpp @@ -25,9 +25,59 @@ #include #include +#include namespace jsonifier { - class jsonifier_core : public jsonifier_internal::parser, public jsonifier_internal::serializer {}; + class jsonifier_core : public jsonifier_internal::serializer, public jsonifier_internal::parser { + public: + friend class jsonifier_internal::serialization_iterator, jsonifier_core>; + friend class jsonifier_internal::simd_structural_iterator, jsonifier_core>; + friend class serializer; + friend class parser; + + using serializer = jsonifier_internal::serializer; + using parser = jsonifier_internal::parser; + + JSONIFIER_INLINE jsonifier_core() noexcept = default; + + JSONIFIER_INLINE jsonifier_core& operator=(jsonifier_core&& other) noexcept { + stringBuffer = std::move(other.stringBuffer); + section = std::move(other.section); + currentIndex = other.currentIndex; + currentSize = other.currentSize; + rootIndex = other.rootIndex; + errors = other.errors; + return *this; + } + + JSONIFIER_INLINE jsonifier_core(jsonifier_core&& other) noexcept : serializer{}, parser{} { + *this = std::move(other); + } + + JSONIFIER_INLINE jsonifier_core& operator=(const jsonifier_core& other) { + stringBuffer = other.stringBuffer; + currentIndex = other.currentIndex; + currentSize = other.currentSize; + rootIndex = other.rootIndex; + section = other.section; + errors = other.errors; + return *this; + } + + JSONIFIER_INLINE jsonifier_core(const jsonifier_core& other) : serializer{}, parser{} { + *this = other; + } + + JSONIFIER_INLINE jsonifier::vector& getErrors() { + return errors; + } + + JSONIFIER_INLINE ~jsonifier_core() noexcept = default; + + protected: + jsonifier_internal::buffer_string stringBuffer{}; + jsonifier::vector errors{}; + }; } diff --git a/Include/jsonifier/NumberUtils.hpp b/Include/jsonifier/NumberUtils.hpp index a1d1f488f..a68bbc515 100644 --- a/Include/jsonifier/NumberUtils.hpp +++ b/Include/jsonifier/NumberUtils.hpp @@ -27,1338 +27,14 @@ #include #include -#include -#include -#include -#include - -#if defined(_M_X64) || defined(_M_ARM64) - #if !defined(__linux__) - #include - #else - #include - #endif -#endif - -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__) - jsonifier_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); - #pragma GCC diagnostic pop - #endif - return prod >> 64; - } -#elif defined(_M_X64) || defined(_M_ARM64) - #define mulhi64 __umulh -#else - jsonifier_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; - uint64_t bHi = b >> 32; - uint64_t axbHi = aHi * bHi; - uint64_t axbMid = aHi * bLo; - uint64_t bxaMid = bHi * aLo; - uint64_t axbLo = aLo * bLo; - uint64_t carryBit = (( uint64_t )( uint32_t )axbMid + ( uint64_t )( uint32_t )bxaMid + (axbLo >> 32)) >> 32; - uint64_t multhi = axbHi + (axbMid >> 32) + (bxaMid >> 32) + carryBit; - return multhi; - } -#endif - - // Source: https://github.com/ibireme/yyjson/blob/master/src/yyjson.c - static jsonifier_constexpr auto pow10SigTable128MinExp = -343; - static jsonifier_constexpr auto pow10SigTable128MaxExp = 324; - static jsonifier_constexpr auto pow10SigTable128MinExactExp = 0; - static jsonifier_constexpr auto pow10SigTable128MaxExactExp = 55; - - jsonifier_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]; - } - - jsonifier_inline static uint64_t sig2FromExp10(int32_t exp10) { - return pow10SigTable128[static_cast(exp10) - pow10SigTable128MinExp]; - } - - jsonifier_inline static int32_t exp2FromExp10(int32_t exp10) { - return (((exp10 * 217706 - 4128768) >> 16) + 126); - } - - template static jsonifier_constexpr value_type digiTypeZero = 1 << 0; - template static jsonifier_constexpr value_type digiTypeNonZero = 1 << 1; - template static jsonifier_constexpr value_type digiTypePos = 1 << 2; - template static jsonifier_constexpr value_type digiTypeNeg = 1 << 3; - template static jsonifier_constexpr value_type digiTypeDot = 1 << 4; - template static jsonifier_constexpr value_type digiTypeExp = 1 << 5; - - template jsonifier_inline static bool digiIsType(value_type d, value_type type) { - return (digiTable[d] & type) != 0; - } - - template jsonifier_inline static bool digiIsFp(value_type d) { - return digiIsType(d, uint8_t(digiTypeDot | digiTypeExp)); - } - template jsonifier_inline static bool digiIsDigitOrFp(value_type d) { - return digiIsType(d, uint8_t(digiTypeZero | digiTypeNonZero | digiTypeDot | digiTypeExp)); - } - -#define repeatIIn_1_18(x) \ - { x(1) x(2) x(3) x(4) x(5) x(6) x(7) x(8) x(9) x(10) x(11) x(12) x(13) x(14) x(15) x(16) x(17) x(18) } - - static jsonifier_constexpr auto eBit = static_cast('E' ^ 'e'); - static jsonifier_constexpr auto f64MaxDecExp = 308; - static jsonifier_constexpr auto f64MinDecExp = (-324); - - jsonifier_inline static consteval uint32_t ceillog2(uint32_t x) { - return x < 2 ? x : 1 + ceillog2(x >> 1); - } - - struct big_int_t { - jsonifier::vector data = {}; - - jsonifier_inline big_int_t(uint64_t num) { - uint32_t lowerWord = uint32_t(num); - uint32_t upperWord = uint32_t(num >> 32); - if (upperWord > 0) { - data = { lowerWord, upperWord }; - } else { - data = { lowerWord }; - } - } - - jsonifier_inline void mulU32(uint32_t num) { - uint32_t carry = 0; - for (uint64_t x = 0; x < data.size(); x++) { - uint64_t res = uint64_t(data[x]) * uint64_t(num) + uint64_t(carry); - uint32_t lowerWord = uint32_t(res); - uint32_t upperWord = uint32_t(res >> 32); - data[x] = lowerWord; - carry = upperWord; - } - if (carry != 0) { - data.emplace_back(carry); - } - } - - jsonifier_inline void mulPow10(uint32_t pow10) { - for (; pow10 >= 9; pow10 -= 9) { - mulU32(static_cast(powersOfTenInt[9])); - } - if (pow10) { - mulU32(static_cast(powersOfTenInt[pow10])); - } - } - - jsonifier_inline void mulPow2(uint32_t exp) { - uint32_t shft = exp % 32; - uint32_t move = exp / 32; - uint32_t idx = static_cast(data.size()) - 1; - 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]; - } - while (move) - data[--move] = 0; - } else { - data.resize(data.size() + move + 1); - ++idx; - for (; idx > 0; idx--) { - uint32_t num = data[idx] << shft; - num |= data[idx - 1ULL] >> (32 - shft); - data[static_cast(idx) + static_cast(move)] = num; - } - data[move] = data[0] << shft; - if (data.back() == 0) - data.resize(data.size() - 1); - while (move) - data[--move] = 0; - } - } - - jsonifier_inline auto operator<=>(const big_int_t& rhs) const { - if (data.size() < rhs.data.size()) - return -1; - if (data.size() > rhs.data.size()) - return 1; - for (auto x = data.size() - 1; x > 0; --x) { - ; - if (data[x] < rhs.data[x]) - return -1; - if (data[x] > rhs.data[x]) - return 1; - } - return 0; - } - }; - - // Source: https://github.com/ibireme/yyjson/blob/master/src/yyjson.c - - jsonifier_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__) || defined(__GNUG__) - #pragma GCC diagnostic pop - #endif - *hi = uint64_t(m >> 64); - *lo = uint64_t(m); -#elif defined(_M_X64) - *lo = _umul128(a, b, hi); -#elif defined(_M_ARM64) - *hi = __umulh(a, b); - *lo = a * b; -#else - uint32_t a0 = ( uint32_t )(a), array01 = ( uint32_t )(a >> 32); - uint32_t b0 = ( uint32_t )(b), b1 = ( uint32_t )(b >> 32); - uint64_t p00 = ( uint64_t )a0 * b0, p01 = ( uint64_t )a0 * b1; - uint64_t p10 = ( uint64_t )array01 * b0, p11 = ( uint64_t )array01 * b1; - uint64_t m0 = p01 + (p00 >> 32); - uint32_t m00 = ( uint32_t )(m0), m01 = ( uint32_t )(m0 >> 32); - uint64_t m1 = p10 + m00; - uint32_t m10 = ( uint32_t )(m1), m11 = ( uint32_t )(m1 >> 32); - *hi = p11 + m01 + m11; - *lo = (( uint64_t )m10 << 32) | ( uint32_t )p00; -#endif - } - - jsonifier_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__) || defined(__GNUG__) - #pragma GCC diagnostic pop - #endif - *hi = uint64_t(m >> 64); - *lo = uint64_t(m); -#else - uint64_t h, l, t; - u128Mul(a, b, &h, &l); - t = l + c; - h += ((t < l) | (t < c)); - *hi = h; - *lo = t; -#endif - } - - jsonifier_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 jsonifier_inline static bool parseNumber(value_type& value, value_type02* cur) { - [[maybe_unused]] value_type02* sigEnd{}; - value_type02* sigCut{}; - value_type02* dotPos{}; - uint32_t fracZeroes{}; - uint64_t sig{}; - int32_t exp{}; - bool expSign{}; - int32_t expSig{}; - int32_t expLit{}; - uint64_t numTmp{}; - value_type02* tmp{}; - value_type02* hdr = cur; - bool sign{}; - sign = (*hdr == '-'); - cur += sign; - auto applySign = [&](auto&& value) -> value_type { - return static_cast(value); - }; - sig = static_cast(*cur) - static_cast('0'); - if (sig > 9) { - return false; - } - static jsonifier_constexpr auto zero = static_cast('0'); -#define expr_intg(x) \ - if ((numTmp = static_cast(cur[x] - static_cast(zero))) <= 9) [[likely]] \ - sig = static_cast(numTmp) + sig * 10ULL; \ - else { \ - goto digi_sepr_##x; \ - } - repeatIIn_1_18(expr_intg); -#undef expr_intg - cur += 19; - if (!digiIsDigitOrFp(*cur)) { - value = static_cast(sig); - return true; - } - goto digi_intg_more; -#define expr_sepr(x) \ - digi_sepr_##x : if ((!digiIsFp(cur[x]))) [[likely]] { \ - cur += x; \ - value = static_cast(applySign(sig)); \ - return true; \ - } \ - dotPos = cur + x; \ - if ((cur[x] == '.')) [[likely]] { \ - if (sig == 0) \ - while (cur[fracZeroes + x + 1] == static_cast(zero)) \ - ++fracZeroes; \ - goto digi_frac_##x; \ - } \ - cur += x; \ - sigEnd = cur; \ - goto digi_exp_more; - repeatIIn_1_18(expr_sepr) -#undef expr_sepr -#define expr_frac(x) \ - digi_frac_##x : if (((numTmp = static_cast(cur[x + 1 + fracZeroes] - static_cast(zero))) <= 9)) [[likely]] sig = numTmp + sig * 10; \ - else { \ - goto digi_stop_##x; \ - } - repeatIIn_1_18(expr_frac) -#undef expr_frac - 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; \ - goto digi_frac_end; - repeatIIn_1_18(expr_stop) -#undef expr_stop - digi_intg_more : static jsonifier_constexpr uint64_t u64Max = std::numeric_limits::max(); - if ((numTmp = static_cast(*cur - static_cast(zero))) < 10) { - if (!digiIsDigitOrFp(cur[1])) { - if ((sig < (u64Max / 10)) || (sig == (u64Max / 10) && numTmp <= (u64Max % 10))) { - sig = numTmp + sig * 10; - ++cur; - value = static_cast(sig); - return true; - } - } - } - if ((eBit | *cur) == 'e') { - dotPos = cur; - goto digi_exp_more; - } - if (*cur == '.') { - dotPos = cur++; - if (uint8_t(*cur - static_cast(zero)) > 9) { - return false; - } - } - digi_frac_more: - sigCut = cur; - sig += (*cur >= '5'); - while (uint8_t(*++cur - static_cast(zero)) < 10) { - } - if (!dotPos) { - dotPos = cur; - if (*cur == '.') { - if (uint8_t(*++cur - static_cast(zero)) > 9) { - return false; - } - while (uint8_t(*++cur - static_cast(zero)) < 10) { - } - } - } - expSig = static_cast(dotPos - sigCut); - expSig += (dotPos < sigCut); - tmp = cur - 1; - while (*tmp == '0' || *tmp == '.') - tmp--; - if (tmp < sigCut) { - sigCut = nullptr; - } - if ((eBit | *cur) == 'e') - goto digi_exp_more; - goto digi_exp_finish; - digi_frac_end: - expSig = -int32_t((cur - dotPos) - 1); - if ((eBit | *cur) != 'e') [[likely]] { - if ((expSig < f64MinDecExp - 19)) [[unlikely]] { - value = static_cast(applySign(0)); - return true; - } - exp = expSig; - goto digi_finish; - } else { - goto digi_exp_more; - } - digi_exp_more: - expSign = (*++cur == '-'); - cur += (*cur == '+' || *cur == '-'); - if (uint8_t(*cur - zero) > 9) [[unlikely]] { - goto digi_finish; - } - while (*cur == '0') - ++cur; - tmp = cur; - uint8_t c; - while (uint8_t(c = static_cast(*cur - zero)) < 10) { - ++cur; - expLit = c + int32_t(expLit) * 10; - } - if ((cur - tmp >= 6)) [[unlikely]] { - if (sig == 0 || expSign) { - value = static_cast(applySign(0)); - value = static_cast(sig); - return true; - } else { - value = static_cast(applySign(std::numeric_limits::infinity())); - return true; - } - } - expSig += expSign ? -expLit : expLit; - digi_exp_finish: - if (sig == 0) { - value = static_cast((!sign) ? -0 : 0); - return true; - } - if (expSig < -20) { - value = static_cast(applySign(0)); - return true; - } else if (expSig > 20) { - value = static_cast(applySign(std::numeric_limits::infinity())); - return true; - } - exp = expSig; - digi_finish: - - value = static_cast(sig); - if (exp >= 0 && exp < 20) { - value *= static_cast(powersOfTenInt[exp]); - } else if (exp > -20 && exp < 0) { - value /= static_cast(powersOfTenInt[-exp]); - } - return true; - } - - template jsonifier_inline static bool parseNumber(value_type& value, value_type02* cur) { - [[maybe_unused]] value_type02* sigEnd{}; - value_type02* sigCut{}; - value_type02* dotPos{}; - uint32_t fracZeroes{}; - uint64_t sig{}; - int32_t exp{}; - bool expSign{}; - int32_t expSig{}; - int32_t expLit{}; - uint64_t numTmp{}; - value_type02* tmp{}; - value_type02* hdr = cur; - bool sign{}; - sign = (*hdr == '-'); - cur += sign; - auto applySign = [&](auto&& value) -> value_type { - return sign ? -static_cast(value) : static_cast(value); - }; - sig = static_cast(*cur) - static_cast('0'); - if (sig > 9) { - if (*cur == 'n' && cur[1] == 'u' && cur[2] == 'l' && cur[3] == 'l') { - cur += 4; - value = static_cast(std::numeric_limits::quiet_NaN()); - return true; - } else if ((*cur | eBit) == 'n' && (cur[1] | eBit) == 'a' && (cur[2] | eBit) == 'n') { - cur += 3; - value = static_cast(sign ? -std::numeric_limits::quiet_NaN() : std::numeric_limits::quiet_NaN()); - return true; - } else { - return false; - } - } - static jsonifier_constexpr auto zero = static_cast('0'); -#define expr_intg(x) \ - if ((numTmp = static_cast(cur[x] - static_cast(zero))) <= 9) [[likely]] \ - sig = static_cast(numTmp) + sig * 10ULL; \ - else { \ - goto digi_sepr_##x; \ - } - repeatIIn_1_18(expr_intg); -#undef expr_intg - cur += 19; - if (!digiIsDigitOrFp(*cur)) { - value = static_cast(sig); - value *= sign ? -1 : 1; - return true; - } - goto digi_intg_more; -#define expr_sepr(x) \ - digi_sepr_##x : if ((!digiIsFp(cur[x]))) [[likely]] { \ - cur += x; \ - value = static_cast(applySign(sig)); \ - return true; \ - } \ - dotPos = cur + x; \ - if ((cur[x] == '.')) [[likely]] { \ - if (sig == 0) \ - while (cur[fracZeroes + x + 1] == zero) \ - ++fracZeroes; \ - goto digi_frac_##x; \ - } \ - cur += x; \ - sigEnd = cur; \ - goto digi_exp_more; - repeatIIn_1_18(expr_sepr) -#undef expr_sepr -#define expr_frac(x) \ - digi_frac_##x : if (((numTmp = static_cast(cur[x + 1 + fracZeroes] - static_cast(zero))) <= 9)) [[likely]] sig = numTmp + sig * 10; \ - else { \ - goto digi_stop_##x; \ - } - repeatIIn_1_18(expr_frac) -#undef expr_frac - cur += 20ULL + fracZeroes; - if (uint8_t(*cur - static_cast(zero)) > 9) - goto digi_frac_end; - goto digi_frac_more; -#define expr_stop(x) \ - digi_stop_##x : cur += x##ULL + 1ULL + fracZeroes; \ - goto digi_frac_end; - repeatIIn_1_18(expr_stop) -#undef expr_stop - digi_intg_more : static jsonifier_constexpr uint64_t u64Max = std::numeric_limits::max(); - if ((numTmp = static_cast(*cur - static_cast(zero))) < 10) { - if (!digiIsDigitOrFp(cur[1])) { - if ((sig < (u64Max / 10)) || (sig == (u64Max / 10) && numTmp <= (u64Max % 10))) { - sig = numTmp + sig * 10; - ++cur; - value = static_cast(sig); - value *= sign ? -1 : 1; - return true; - } - } - } - if ((eBit | *cur) == 'e') { - dotPos = cur; - goto digi_exp_more; - } - if (*cur == '.') { - dotPos = cur++; - if (uint8_t(*cur - zero) > 9) { - return false; - } - } - digi_frac_more: - sigCut = cur; - sig += (*cur >= '5'); - while (uint8_t(*++cur - zero) < 10) { - } - if (!dotPos) { - dotPos = cur; - if (*cur == '.') { - if (uint8_t(*++cur - zero) > 9) { - return false; - } - while (uint8_t(*++cur - zero) < 10) { - } - } - } - expSig = static_cast(dotPos - sigCut); - expSig += (dotPos < sigCut); - tmp = cur - 1; - while (*tmp == '0' || *tmp == '.') - tmp--; - if (tmp < sigCut) { - sigCut = nullptr; - } - if ((eBit | *cur) == 'e') - goto digi_exp_more; - goto digi_exp_finish; - digi_frac_end: - expSig = -int32_t((cur - dotPos) - 1); - if ((eBit | *cur) != 'e') [[likely]] { - if ((expSig < f64MinDecExp - 19)) [[unlikely]] { - value = static_cast(applySign(0)); - return true; - } - exp = expSig; - goto digi_finish; - } else { - goto digi_exp_more; - } - digi_exp_more: - expSign = (*++cur == '-'); - cur += (*cur == '+' || *cur == '-'); - if (uint8_t(*cur - zero) > 9) [[unlikely]] { - goto digi_finish; - } - while (*cur == '0') - ++cur; - tmp = cur; - uint8_t c; - while (uint8_t(c = static_cast(*cur - zero)) < 10) { - ++cur; - expLit = c + int32_t(expLit) * 10; - } - if ((cur - tmp >= 6)) [[unlikely]] { - if (sig == 0 || expSign) { - value = static_cast(applySign(0)); - value = static_cast(sig); - return true; - } else { - value = static_cast(applySign(std::numeric_limits::infinity())); - return true; - } - } - expSig += expSign ? -expLit : expLit; - digi_exp_finish: - if (sig == 0) { - value = static_cast((sign) ? -0 : 0); - return true; - } - if (expSig < -20) { - value = static_cast(applySign(0)); - return true; - } else if (expSig > 20) { - value = static_cast(applySign(std::numeric_limits::infinity())); - return true; - } - exp = expSig; - digi_finish: - - value = static_cast(sig); - value *= sign ? -1 : 1; - if (exp >= 0 && exp < 20) { - value *= static_cast(powersOfTenInt[exp]); - } else if (exp > -20 && exp < 0) { - value /= static_cast(powersOfTenInt[-exp]); - } - return true; - } - - template jsonifier_inline static bool parseNumber(value_type& value, value_type02* cur) { - [[maybe_unused]] value_type02* sigEnd{}; - value_type02* sigCut{}; - value_type02* dotPos{}; - uint32_t fracZeroes{}; - uint64_t sig{}; - int32_t exp{}; - bool expSign{}; - int32_t expSig{}; - int32_t expLit{}; - uint64_t numTmp{}; - value_type02* tmp{}; - value_type02* hdr = cur; - bool sign{}; - sign = (*hdr == '-'); - cur += sign; - auto applySign = [&](auto&& value) -> value_type { - if jsonifier_constexpr (std::is_unsigned_v) { - return static_cast(value); - } else { - return sign ? -static_cast(value) : static_cast(value); - } - }; - sig = static_cast(*cur) - '0'; - if (sig > 9) { - if (*cur == 'n' && cur[1] == 'u' && cur[2] == 'l' && cur[3] == 'l') { - cur += 4; - value = static_cast(std::numeric_limits::quiet_NaN()); - return true; - } else if ((*cur | eBit) == 'n' && (cur[1] | eBit) == 'a' && (cur[2] | eBit) == 'n') { - cur += 3; - value = static_cast(sign ? -std::numeric_limits::quiet_NaN() : std::numeric_limits::quiet_NaN()); - return true; - } else { - return false; - } - } - static jsonifier_constexpr auto zero = static_cast('0'); -#define expr_intg(x) \ - if ((numTmp = static_cast(cur[x] - static_cast(zero))) <= 9) [[likely]] \ - sig = static_cast(numTmp) + sig * 10ULL; \ - else { \ - goto digi_sepr_##x; \ - } - repeatIIn_1_18(expr_intg); -#undef expr_intg - cur += 19; - if (!digiIsDigitOrFp(*cur)) { - value = static_cast(sig); - if jsonifier_constexpr (!std::is_unsigned_v) { - value *= sign ? -1 : 1; - } - return true; - } - goto digi_intg_more; -#define expr_sepr(x) \ - digi_sepr_##x : if ((!digiIsFp(cur[x]))) [[likely]] { \ - cur += x; \ - value = static_cast(applySign(sig)); \ - return true; \ - } \ - dotPos = cur + x; \ - if ((cur[x] == '.')) [[likely]] { \ - if (sig == 0) \ - while (cur[fracZeroes + x + 1] == zero) \ - ++fracZeroes; \ - goto digi_frac_##x; \ - } \ - cur += x; \ - sigEnd = cur; \ - goto digi_exp_more; - repeatIIn_1_18(expr_sepr) -#undef expr_sepr -#define expr_frac(x) \ - digi_frac_##x : if (((numTmp = static_cast(cur[x + 1 + fracZeroes] - static_cast(zero))) <= 9)) [[likely]] sig = numTmp + sig * 10; \ - else { \ - goto digi_stop_##x; \ - } - repeatIIn_1_18(expr_frac) -#undef expr_frac - 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; \ - goto digi_frac_end; - repeatIIn_1_18(expr_stop) -#undef expr_stop - digi_intg_more : static jsonifier_constexpr uint64_t u64Max = std::numeric_limits::max(); - if ((numTmp = static_cast(*cur - static_cast(zero))) < 10) { - if (!digiIsDigitOrFp(cur[1])) { - if ((sig < (u64Max / 10)) || (sig == (u64Max / 10) && numTmp <= (u64Max % 10))) { - sig = numTmp + sig * 10; - ++cur; - value = static_cast(sig); - if jsonifier_constexpr (!std::is_unsigned_v) { - value *= sign ? -1 : 1; - } - return true; - } - } - } - if ((eBit | *cur) == 'e') { - dotPos = cur; - goto digi_exp_more; - } - if (*cur == '.') { - dotPos = cur++; - if (uint8_t(*cur - zero) > 9) { - return false; - } - } - digi_frac_more: - sigCut = cur; - sig += (*cur >= '5'); - while (uint8_t(*++cur - zero) < 10) { - } - if (!dotPos) { - dotPos = cur; - if (*cur == '.') { - if (uint8_t(*++cur - zero) > 9) { - return false; - } - while (uint8_t(*++cur - zero) < 10) { - } - } - } - expSig = static_cast(dotPos - sigCut); - expSig += (dotPos < sigCut); - tmp = cur - 1; - while (*tmp == '0' || *tmp == '.') - tmp--; - if (tmp < sigCut) { - sigCut = nullptr; - } - if ((eBit | *cur) == 'e') - goto digi_exp_more; - goto digi_exp_finish; - digi_frac_end: - expSig = -int32_t((cur - dotPos) - 1); - if ((eBit | *cur) != 'e') [[likely]] { - if ((expSig < f64MinDecExp - 19)) [[unlikely]] { - value = static_cast(applySign(0)); - return true; - } - exp = expSig; - goto digi_finish; - } else { - goto digi_exp_more; - } - digi_exp_more: - expSign = (*++cur == '-'); - cur += (*cur == '+' || *cur == '-'); - if (uint8_t(*cur - zero) > 9) [[unlikely]] { - goto digi_finish; - } - while (*cur == '0') - ++cur; - tmp = cur; - uint8_t c; - while (uint8_t(c = static_cast(*cur - zero)) < 10) { - ++cur; - expLit = c + int32_t(expLit) * 10; - } - if ((cur - tmp >= 6)) [[unlikely]] { - if (sig == 0 || expSign) { - value = static_cast(applySign(0)); - value = static_cast(sig); - return true; - } else { - value = static_cast(applySign(std::numeric_limits::infinity())); - return true; - } - } - expSig += expSign ? -expLit : expLit; - digi_exp_finish: - if (sig == 0) { - value = static_cast(sign ? -value_type{ 0 } : value_type{ 0 }); - return true; - } - if ((expSig < f64MinDecExp - 19)) [[unlikely]] { - value = static_cast(sign ? -value_type{ 0 } : value_type{ 0 }); - return true; - } else if ((expSig > f64MaxDecExp)) [[unlikely]] { - value = static_cast(sign ? -std::numeric_limits::infinity() : std::numeric_limits::infinity()); - return true; - } - exp = expSig; - digi_finish: - - if jsonifier_constexpr (std::floating_point) { - if (sig < (uint64_t(1) << 53) && std::abs(exp) <= 22) { - value = static_cast(sig); - if jsonifier_constexpr (!std::is_unsigned_v) { - value *= sign ? -1 : 1; - } - if (exp >= 0 && exp < 23) { - value *= static_cast(powersOfTenFloat[exp]); - } else if (exp > -23 && exp < 0) { - value /= static_cast(powersOfTenFloat[-exp]); - } - return true; - } - } else { - if (sig < (uint64_t(1) << 24) && std::abs(exp) <= 8) { - value = static_cast(sig); - if jsonifier_constexpr (!std::is_unsigned_v) { - value *= sign ? -1 : 1; - } - if (exp >= 0 && exp < 23) { - value *= static_cast(powersOfTenFloat[exp]); - } else if (exp > -23 && exp < 0) { - value /= 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(sizeof(float) == 4 && sizeof(double) == 8); - - 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 jsonifier_constexpr uint64_t roundMask = uint64_t(1) << 63 >> (std::numeric_limits::digits - 1); - static jsonifier_constexpr uint32_t exponentBits = ceillog2(std::numeric_limits::max_exponent - std::numeric_limits::min_exponent + 1); - static jsonifier_constexpr uint32_t mantissaShift = exponentBits + 1 + 64 - 8 * sizeof(raw_t); - int32_t exp2 = static_cast(exp2FromExp10(exp) + static_cast(-sigLeadingZeroes + sigProductStartsWith1)); - - if (exp2 < std::numeric_limits::min_exponent - 1) [[unlikely]] { - value = static_cast(sign ? -value_type(0) : value_type(0)); - return true; - } else if (exp2 > std::numeric_limits::max_exponent - 1) [[unlikely]] { - value = 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) { - auto sigUpper = (mantisa >> (mantissaShift - 1)) | (uint64_t(1) << 63 >> (mantissaShift - 2)) | 1; - int32_t exp2Upper = exp2 - std::numeric_limits::digits; - - big_int_t bigComp{ sigUpper }; - big_int_t bigFull{ sig }; - if (exp >= 0) { - bigFull.mulPow10(static_cast(exp)); - } else { - bigComp.mulPow10(static_cast(-exp)); - } - if (exp2Upper >= 0) { - bigComp.mulPow2(static_cast(exp2Upper)); - } else { - bigFull.mulPow2(static_cast(-exp2Upper)); - } - auto cmp = bigFull <=> bigComp; - if (cmp != 0) [[likely]] { - round = (cmp > 0); - } else { - round = (mantisa & (roundMask << 1)) != 0; - } - } 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))) { - 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)); - num += raw_t(round); - std::memcpy(&value, &num, sizeof(value_type)); - return true; - } - - template jsonifier_inline static value_type* toChars(value_type* buf, value_type02 value) { - uint32_t aa, bb, cc, dd, ee, aabb, bbcc, ccdd, ddee, aabbcc; - uint32_t lz; - - if (value < 100) { - lz = value < 10; - std::memcpy(&buf[0], &charTable[value * 2ULL + lz], 2); - buf -= lz; - return buf + 2ULL; - } else if (value < 10000) { - aa = (value * 5243u) >> 19; - bb = value - aa * 100; - lz = aa < 10; - std::memcpy(&buf[0], &charTable[aa * 2ULL + lz], 2); - buf -= lz; - std::memcpy(&buf[2], &charTable[2ULL * bb], 2); - - return buf + 4ULL; - } else if (value < 1000000) { - aa = uint32_t((uint64_t(value) * 429497) >> 32); - bbcc = value - aa * 10000; - bb = (bbcc * 5243) >> 19; - cc = bbcc - bb * 100; - lz = aa < 10; - std::memcpy(buf, charTable + aa * 2ULL + lz, 2); - buf -= lz; - std::memcpy(buf + 2ULL, charTable + bb * 2ULL, 2); - std::memcpy(buf + 4ULL, charTable + cc * 2ULL, 2); - return buf + 6ULL; - } else if (value < 100000000) { - aabb = uint32_t((uint64_t(value) * 109951163) >> 40); - ccdd = value - aabb * 10000; - aa = (aabb * 5243) >> 19; - cc = (ccdd * 5243) >> 19; - bb = aabb - aa * 100; - dd = ccdd - cc * 100; - lz = aa < 10; - std::memcpy(buf, charTable + aa * 2ULL + lz, 2); - buf -= lz; - 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(value) * 3518437209ul) >> 45); - aa = uint32_t((uint64_t(aabbcc) * 429497) >> 32); - ddee = value - aabbcc * 10000; - bbcc = aabbcc - aa * 10000; - bb = (bbcc * 5243) >> 19; - dd = (ddee * 5243) >> 19; - cc = bbcc - bb * 100; - ee = ddee - dd * 100; - lz = aa < 10; - std::memcpy(buf, charTable + aa * 2ULL + lz, 2); - buf -= lz; - 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 jsonifier_inline static value_type* toChars(value_type* buf, value_type02 value) { - uint32_t neg = uint32_t(-value); - uint64_t sign = value < 0; - *buf = '-'; - return toChars(buf + sign, sign ? uint32_t(neg) : uint32_t(value)); - } - - template jsonifier_inline static value_type* toCharsU64Len8(value_type* buf, uint32_t value) { - uint32_t aa, bb, cc, dd, aabb, ccdd; - aabb = uint32_t((uint64_t(value) * 109951163) >> 40); - ccdd = value - aabb * 10000; - aa = (aabb * 5243) >> 19; - cc = (ccdd * 5243) >> 19; - bb = aabb - aa * 100; - dd = ccdd - cc * 100; - 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; - } - - template jsonifier_inline static value_type* toCharsU64Len4(value_type* buf, uint32_t value) { - uint32_t aa, bb; - aa = (value * 5243) >> 19; - bb = value - aa * 100; - std::memcpy(buf, charTable + aa * 2ULL, 2); - std::memcpy(buf + 2ULL, charTable + bb * 2ULL, 2); - return buf + 4ULL; - } - - template jsonifier_inline static value_type* toCharsU64Len18(value_type* buf, uint32_t value) { - uint32_t aa, bb, cc, dd, aabb, bbcc, ccdd, lz; - - if (value < 100) { - lz = value < 10; - std::memcpy(buf, charTable + value * 2ULL + lz, 2); - buf -= lz; - return buf + 2ULL; - } else if (value < 10000) { - aa = (value * 5243) >> 19; - bb = value - aa * 100; - lz = aa < 10; - std::memcpy(buf, charTable + aa * 2ULL + lz, 2); - buf -= lz; - std::memcpy(buf + 2ULL, charTable + bb * 2ULL, 2); - return buf + 4ULL; - } else if (value < 1000000) { - aa = uint32_t((uint64_t(value) * 429497) >> 32); - bbcc = value - aa * 10000; - bb = (bbcc * 5243) >> 19; - cc = bbcc - bb * 100; - lz = aa < 10; - std::memcpy(buf, charTable + aa * 2ULL + lz, 2); - buf -= lz; - 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(value) * 109951163) >> 40); - ccdd = value - aabb * 10000; - aa = (aabb * 5243) >> 19; - cc = (ccdd * 5243) >> 19; - bb = aabb - aa * 100; - dd = ccdd - cc * 100; - lz = aa < 10; - std::memcpy(buf, charTable + aa * 2ULL + lz, 2); - buf -= lz; - 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 jsonifier_inline static value_type* toCharsU64Len58(value_type* buf, uint32_t value) { - uint32_t aa, bb, cc, dd, aabb, bbcc, ccdd, lz; - - if (value < 1000000) { - aa = uint32_t((uint64_t(value) * 429497) >> 32); - bbcc = value - aa * 10000; - bb = (bbcc * 5243) >> 19; - cc = bbcc - bb * 100; - lz = aa < 10; - std::memcpy(buf, charTable + aa * 2ULL + lz, 2); - buf -= lz; - 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(value) * 109951163) >> 40); - ccdd = value - aabb * 10000; - aa = (aabb * 5243) >> 19; - cc = (ccdd * 5243) >> 19; - bb = aabb - aa * 100; - dd = ccdd - cc * 100; - lz = aa < 10; - std::memcpy(buf, charTable + aa * 2ULL + lz, 2); - buf -= lz; - 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 jsonifier_inline static char_type* toChars(char_type* buf, value_type value) { - uint64_t tmp, hgh; - uint32_t mid, low; - - if (value < 100000000) { - buf = toCharsU64Len18(buf, uint32_t(value)); - return buf; - } else if (value < 100000000ULL * 100000000ULL) { - hgh = value / 100000000; - low = uint32_t(value - hgh * 100000000); - buf = toCharsU64Len18(buf, uint32_t(hgh)); - buf = toCharsU64Len8(buf, low); - return buf; - } else { - tmp = value / 100000000; - low = uint32_t(value - tmp * 100000000); - hgh = uint32_t(tmp / 10000); - mid = uint32_t(tmp - hgh * 10000); - buf = toCharsU64Len58(buf, uint32_t(hgh)); - buf = toCharsU64Len4(buf, mid); - buf = toCharsU64Len8(buf, low); - return buf; - } - } - - template jsonifier_inline static char_type* toChars(char_type* buf, value_type value) { - uint64_t neg = uint64_t(-value); - uint64_t sign = value < 0; - *buf = '-'; - return toChars(buf + sign, sign ? uint64_t(neg) : uint64_t(value)); - } - - /** - This function use the Schubfach algorithm: - Raffaello Giulietti, The Schubfach way to render doubles, 2020. - https://drive.google.com/open?id=1luHhyQF9zKlM8yJ1nebU0OgVYhfC6CBN - https://github.com/abolz/Drachennest - - See also: - Dragonbox: A New Floating-Point Binary-to-Decimal Conversion Algorithm, 2020. - https://github.com/jk-jeon/dragonbox/blob/master/other_files/Dragonbox.pdf - https://github.com/jk-jeon/dragonbox - */ - jsonifier_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; - - isEven = !(sigBin & 1); - lowerBoundCloser = (sigRaw == 0 && expRaw > 1); - - cbl = 4 * sigBin - 2 + lowerBoundCloser; - cb = 4 * sigBin; - cbr = 4 * sigBin + 2ULL; - - k = (expBin * 315653 - (lowerBoundCloser ? 131237 : 0)) >> 20; - - exp10 = -k; - h = expBin + ((exp10 * 217707) >> 16) + 1; - - pow10TableGetSig128(exp10, &pow10hi, &pow10lo); - pow10lo += (exp10 < pow10SigTable128MinExactExp || exp10 > pow10SigTable128MaxExactExp); - vbl = roundToOdd(pow10hi, pow10lo, cbl << h); - vb = roundToOdd(pow10hi, pow10lo, cb << h); - vbr = roundToOdd(pow10hi, pow10lo, cbr << h); - - lower = vbl + !isEven; - upper = vbr - !isEven; - - s = vb / 4; - if (s >= 10) { - sp = s / 10; - uInside = (lower <= 40 * sp); - wInside = (upper >= 40 * sp + 40); - if (uInside != wInside) { - *sigDec = sp + wInside; - *expDec = k + 1; - return; - } - } - - uInside = (lower <= 4 * s); - wInside = (upper >= 4 * s + 4ULL); - - mid = 4 * s + 2ULL; - round_up = (vb > mid) || (vb == mid && (s & 1) != 0); - - *sigDec = s + ((uInside != wInside) ? wInside : round_up); - *expDec = k; - } - - template jsonifier_inline static value_type* writeU64Len15To17Trim(value_type* buf, uint64_t sig) { - bool lz; - uint32_t tz1, tz2, tz; - - uint32_t abbccddee = uint32_t(sig / 100000000); - uint32_t ffgghhii = uint32_t(sig - uint64_t(abbccddee) * 100000000); - uint32_t abbcc = abbccddee / 10000; - uint32_t ddee = abbccddee - abbcc * 10000; - uint32_t abb = uint32_t((uint64_t(abbcc) * 167773) >> 24); - uint32_t a = (abb * 41) >> 12; - uint32_t bb = abb - a * 100; - uint32_t cc = abbcc - abb * 100; - - buf[0] = static_cast(a + static_cast('0')); - buf += a > 0; - lz = bb < 10 && a == 0; - std::memcpy(buf, charTable + (bb * 2ULL + lz), 2ULL); - buf -= lz; - std::memcpy(buf + 2ULL, charTable + 2ULL * cc, 2ULL); - - if (ffgghhii) { - uint32_t dd = (ddee * 5243) >> 19; - uint32_t ee = ddee - dd * 100; - uint32_t ffgg = uint32_t((uint64_t(ffgghhii) * 109951163) >> 40); - uint32_t hhii = ffgghhii - ffgg * 10000; - uint32_t ff = (ffgg * 5243) >> 19; - uint32_t gg = ffgg - ff * 100; - 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 + 2ULL * hh, 2ULL); - std::memcpy(buf + 14ULL, charTable + 2ULL * ii, 2ULL); - tz1 = static_cast(decTrailingZeroTable[hh]); - tz2 = static_cast(decTrailingZeroTable[ii]); - tz = ii ? tz2 : (tz1 + 2ULL); - buf += 16 - tz; - return buf; - } else { - tz1 = static_cast(decTrailingZeroTable[ff]); - tz2 = static_cast(decTrailingZeroTable[gg]); - tz = gg ? tz2 : (tz1 + 2ULL); - buf += 12 - tz; - return buf; - } - } else { - if (ddee) { - uint32_t dd = (ddee * 5243) >> 19; - uint32_t ee = ddee - dd * 100; - std::memcpy(buf + 4ULL, charTable + 2ULL * dd, 2ULL); - std::memcpy(buf + 6ULL, charTable + 2ULL * ee, 2ULL); - tz1 = static_cast(decTrailingZeroTable[dd]); - tz2 = static_cast(decTrailingZeroTable[ee]); - tz = ee ? tz2 : (tz1 + 2ULL); - buf += 8 - tz; - return buf; - } else { - tz1 = static_cast(decTrailingZeroTable[bb]); - tz2 = static_cast(decTrailingZeroTable[cc]); - tz = cc ? tz2 : (tz1 + tz2); - buf += 4 - tz; - return buf; - } - } - } - - static jsonifier_constexpr uint32_t numbits(uint32_t x) { - return x < 2 ? x : 1 + numbits(x >> 1); - } - - template jsonifier_inline static value_type01* toChars(value_type01* buffer, value_type value) { - 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>; - - raw_t raw{}; - std::memcpy(&raw, &value, sizeof(value_type)); - - static jsonifier_constexpr uint32_t exponentBits = numbits(std::numeric_limits::max_exponent - std::numeric_limits::min_exponent + 1); - static jsonifier_constexpr raw_t sigMask = raw_t(-1) >> (exponentBits + 1); - bool sign = (raw >> (sizeof(value_type) * 8 - 1)); - uint64_t sigRaw = raw & sigMask; - 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; - } - if (sign) { - *buffer = '-'; - ++buffer; - } - if ((raw << 1) != 0) [[likely]] { - uint64_t sigBin; - int32_t expBin; - if (expRaw == 0) [[unlikely]] { - sigBin = sigRaw; - 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); - } - - uint64_t sigDec; - int32_t expDec; - f64BinToDec(sigRaw, expRaw, sigBin, expBin, &sigDec, &expDec); - if jsonifier_constexpr (std::same_as) { - sigDec *= 100000000; - expDec -= 8; - } - - int32_t sigLen = 17; - 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 numEnd = writeU64Len15To17Trim(numHdr, sigDec); - buffer[0] = '0'; - buffer[1] = '.'; - 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; - auto numEnd = writeU64Len15To17Trim(numHdr, sigDec); - for (int32_t x = 0; x < dotPos; x++) - 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); - expDec += sigLen - 1; - buffer[0] = buffer[1]; - buffer[1] = '.'; - end[0] = 'E'; - buffer = end + 1; - buffer[0] = '-'; - buffer += expDec < 0; - expDec = std::abs(expDec); - if (expDec < 100) { - uint32_t lz = expDec < 10; - 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 + (lo * 2ULL), 2ULL); - return buffer + 3ULL; - } - } - } else [[unlikely]] { - *buffer = '0'; - return buffer + 1; - } - } - - - -}// namespace jsonifier_internal +#include +#include +#include +#include namespace jsonifier { - template jsonifier_inline jsonifier::string_base toString(const value_type01& value) { + template JSONIFIER_INLINE jsonifier::string_base toString(const value_type01& value) { string_base returnstring{}; returnstring.resize(64); auto newPtr = jsonifier_internal::toChars(returnstring.data(), value); @@ -1366,7 +42,7 @@ namespace jsonifier { return returnstring; } - template jsonifier_inline double strToDouble(const jsonifier::string& string) { + template JSONIFIER_INLINE double strToDouble(const jsonifier::string& string) { double newValue{}; if (string.size() > 0) { jsonifier_internal::parseNumber(newValue, string.data()); @@ -1374,7 +50,7 @@ namespace jsonifier { return newValue; } - template<> jsonifier_inline double strToDouble<16>(const jsonifier::string& string) { + template<> JSONIFIER_INLINE double strToDouble<16>(const jsonifier::string& string) { double newValue{}; if (string.size() > 0) { newValue = std::strtod(string.data(), nullptr); @@ -1382,7 +58,7 @@ namespace jsonifier { return newValue; } - template jsonifier_inline int64_t strToInt64(const jsonifier::string& string) { + template JSONIFIER_INLINE int64_t strToInt64(const jsonifier::string& string) { int64_t newValue{}; if (string.size() > 0) { jsonifier_internal::parseNumber(newValue, string.data()); @@ -1390,7 +66,7 @@ namespace jsonifier { return newValue; } - template<> jsonifier_inline int64_t strToInt64<16>(const jsonifier::string& string) { + template<> JSONIFIER_INLINE int64_t strToInt64<16>(const jsonifier::string& string) { int64_t newValue{}; if (string.size() > 0) { newValue = std::strtoll(string.data(), nullptr, 16); @@ -1398,7 +74,7 @@ namespace jsonifier { return newValue; } - template jsonifier_inline uint64_t strToUint64(const jsonifier::string& string) { + template JSONIFIER_INLINE uint64_t strToUint64(const jsonifier::string& string) { uint64_t newValue{}; if (string.size() > 0) { jsonifier_internal::parseNumber(newValue, string.data()); @@ -1406,7 +82,7 @@ namespace jsonifier { return newValue; } - template<> jsonifier_inline uint64_t strToUint64<16>(const jsonifier::string& string) { + template<> JSONIFIER_INLINE uint64_t strToUint64<16>(const jsonifier::string& string) { uint64_t newValue{}; if (string.size() > 0) { newValue = std::strtoull(string.data(), nullptr, 16); diff --git a/Include/jsonifier/Pair.hpp b/Include/jsonifier/Pair.hpp deleted file mode 100644 index 25d33fa39..000000000 --- a/Include/jsonifier/Pair.hpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - 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 20, 2023 -#pragma once - -namespace jsonifier_internal { - - template class pair { - public: - using first_type = FirstType; - using second_type = SecondType; - - first_type first; - second_type second; - - jsonifier_constexpr pair() = default; - - template jsonifier_constexpr pair(FirstTypeNew&& firstNew, SecondTypeNew&& secondNew) - : first{ std::forward(firstNew) }, second{ std::forward(secondNew) } { - } - - template - requires(std::same_as) - jsonifier_constexpr pair(FirstTypeNew&& firstNew) : first{ std::forward(firstNew) } { - } - - template - requires(std::same_as) - jsonifier_constexpr pair(SecondTypeNew&& firstNew) : second{ std::forward(firstNew) } { - } - - jsonifier_constexpr bool operator==(const pair& other) const { - return first == other.first && second == other.second; - } - }; - - template pair(a, b) -> pair, std::unwrap_ref_decay>; -} diff --git a/Include/jsonifier/Parse_Impl.hpp b/Include/jsonifier/Parse_Impl.hpp index 6053608c7..a09903587 100644 --- a/Include/jsonifier/Parse_Impl.hpp +++ b/Include/jsonifier/Parse_Impl.hpp @@ -32,11 +32,12 @@ namespace jsonifier_internal { - template struct parse_impl { - jsonifier_inline static void op(value_type& value, structural_iterator& iter, parser& parserNew) { + template struct parse_impl { + template + JSONIFIER_INLINE static void op(value_type&& value, iterator_type&& iter) { auto newPtr = iter.operator->(); - if (!derailleur::template checkForMatchClosed(iter)) { - parserNew.errors.emplace_back(createError(iter)); + if (!derailleur::template checkForMatchClosed(iter)) [[unlikely]] { + iter.template createError(); derailleur::skipValue(iter); return; } @@ -44,54 +45,71 @@ namespace jsonifier_internal { } }; - template struct parse_impl { - jsonifier_inline static void op(value_type& value, structural_iterator& iter, parser& parserNew) { + template struct parse_impl { + template + JSONIFIER_INLINE static void op(value_type&& value, iterator_type&& iter) { auto newPtr = iter.operator->(); - if (!derailleur::template checkForMatchClosed(iter)) { - parserNew.errors.emplace_back(createError(iter)); + if (!derailleur::template checkForMatchClosed(iter)) [[unlikely]] { + iter.template createError(); derailleur::skipValue(iter); return; } - parseNumber(value, newPtr); + if (!parseNumber(value, newPtr)) { + iter.template createError(); + } } }; - template struct parse_impl { - jsonifier_inline static void op(value_type& value, structural_iterator& iter, parser& parserNew) { + template struct parse_impl { + template + JSONIFIER_INLINE static void op(value_type&& value, iterator_type&& iter) { uint64_t newValue{}; auto newValueOld = static_cast(value); - parse::op(newValue, iter, parserNew); + parse::template op(newValue, std::forward(iter)); newValue |= newValueOld; - value = static_cast(newValue); + value = static_cast(newValue); + } + }; + + template struct parse_impl { + template + JSONIFIER_INLINE static void op(value_type&& value, iterator_type&& iter) { + if (!derailleur::template checkForMatchClosed(iter)) [[unlikely]] { + iter.template createError(); + derailleur::skipValue(iter); + return; + } } }; - template struct parse_impl { - jsonifier_inline static void op(value_type& value, structural_iterator& iter, parser& parserNew) { - value = std::make_unique(); - parse::op(*value, iter, parserNew); + template struct parse_impl { + template + JSONIFIER_INLINE static void op(value_type&& value, iterator_type&& iter) { + value = std::make_unique(); + parse::template op(*value, std::forward(iter)); } }; - template struct parse_impl { - jsonifier_inline static void op(value_type& value, structural_iterator& iter, parser&) { + template struct parse_impl { + template + JSONIFIER_INLINE static void op(value_type&& value, iterator_type&& iter) { auto newPtr = iter.operator->(); switch (*iter) { case 0x22u: { derailleur::skipValue(iter); - int64_t sizeNew = (iter.operator->() - newPtr) - 1; - if (sizeNew > 0) { - value.resize(static_cast(sizeNew)); - std::memcpy(value.data(), newPtr, static_cast(sizeNew)); + int64_t newSize = (iter.operator->() - newPtr) - 1; + if (newSize > 0) { + value.resize(static_cast(newSize)); + std::memcpy(value.data(), newPtr, static_cast(newSize)); } break; } default: { derailleur::skipValue(iter); - int64_t sizeNew = iter.operator->() - newPtr; - if (sizeNew > 0) { - value.resize(static_cast(sizeNew)); - std::memcpy(value.data(), newPtr, static_cast(sizeNew)); + int64_t newSize = iter.operator->() - newPtr; + if (newSize > 0) { + value.resize(static_cast(newSize)); + std::memcpy(value.data(), newPtr, static_cast(newSize)); } break; } @@ -100,52 +118,53 @@ namespace jsonifier_internal { } }; - template struct parse_impl { - jsonifier_inline static void op(value_type& value, structural_iterator& iter, parser& parserNew) { + template struct parse_impl { + template + JSONIFIER_INLINE static void op(value_type&& value, iterator_type&& iter) { auto newPtr = iter.operator->(); - if (!derailleur::template checkForMatchClosed(iter)) { - parserNew.errors.emplace_back(createError(iter)); + if (!derailleur::template checkForMatchClosed(iter)) [[unlikely]] { + iter.template createError(); derailleur::skipValue(iter); return; } - auto sizeNew = static_cast(roundUpToMultiple(static_cast(iter.operator->() - newPtr)) * 2ULL); - if (sizeNew > static_cast(parserNew.currentStringBuffer.size())) { - parserNew.currentStringBuffer.resize(static_cast(sizeNew)); + auto newSize = static_cast(roundUpToMultiple(static_cast(iter.operator->() - newPtr))); + if (newSize * 2 > static_cast(iter.size())) { + iter.resize(static_cast(newSize * 2)); } - sizeNew = parseString(newPtr + 1, parserNew.currentStringBuffer.data(), static_cast(sizeNew)) - parserNew.currentStringBuffer.data(); - if (sizeNew > 0) { - value.resize(static_cast(sizeNew)); - std::memcpy(value.data(), parserNew.currentStringBuffer.data(), static_cast(sizeNew)); + newSize = parseString(newPtr + 1, iter.data(), static_cast(newSize)) - iter.data(); + if (newSize > 0) { + value.resize(static_cast(newSize)); + std::memcpy(value.data(), iter.data(), static_cast(newSize)); } } }; - template struct parse_impl { - jsonifier_inline static void op(value_type& value, structural_iterator& iter, parser&) { - value = *static_cast(iter.operator->() + 1); + template struct parse_impl { + template + JSONIFIER_INLINE static void op(value_type&& value, iterator_type&& iter) { + value = static_cast(*iter.operator->() + 1); ++iter; } }; - template struct parse_impl { - jsonifier_inline static void op(value_type& value, structural_iterator& iter, parser& parserNew) { - if (!derailleur::template checkForMatchClosed(iter)) { - parserNew.errors.emplace_back(createError(iter)); + template struct parse_impl { + template + JSONIFIER_INLINE static void op(value_type&& value, iterator_type&& iter) { + if (!derailleur::template checkForMatchClosed(iter)) [[unlikely]] { + iter.template createError(); derailleur::skipValue(iter); return; } if (derailleur::template checkForMatchOpen(iter)) [[unlikely]] { return; } - const auto n = std::size(value); + static constexpr auto n = std::size(value); - auto valueIter = value; - - for (uint64_t i = 0; i < n; ++i) { - parse::op(*valueIter++, iter, parserNew); + for (uint64_t x = 0; x < n; ++x) { + parse::template op(value[x], std::forward(iter)); if (!derailleur::template checkForMatchOpen(iter)) [[likely]] { - if (!derailleur::template checkForMatchClosed(iter)) { - parserNew.errors.emplace_back(createError(iter)); + if (!derailleur::template checkForMatchClosed(iter)) [[unlikely]] { + iter.template createError(); derailleur::skipValue(iter); } return; @@ -154,10 +173,11 @@ namespace jsonifier_internal { } }; - template struct parse_impl { - jsonifier_inline static void op(value_type& value, structural_iterator& iter, parser& parserNew) { - if (!derailleur::template checkForMatchClosed(iter)) { - parserNew.errors.emplace_back(createError(iter)); + template struct parse_impl { + template + JSONIFIER_INLINE static void op(value_type&& value, iterator_type&& iter) { + if (!derailleur::template checkForMatchClosed(iter)) [[unlikely]] { + iter.template createError(); derailleur::skipValue(iter); return; } @@ -166,23 +186,22 @@ namespace jsonifier_internal { } const auto m = value.size(); - auto valueIter = value.begin(); - for (uint64_t i = 0; i < m; ++i) { - parse::op(*valueIter++, iter, parserNew); + for (uint64_t x = 0; x < m; ++x) { + parse::template op(value[x], iter); if (!derailleur::template checkForMatchOpen(iter)) [[likely]] { - if (!derailleur::template checkForMatchClosed(iter)) { - parserNew.errors.emplace_back(createError(iter)); + if (!derailleur::template checkForMatchClosed(iter)) [[unlikely]] { + iter.template createError(); derailleur::skipValue(iter); } return; } } - if jsonifier_constexpr (jsonifier::concepts::has_emplace_back) { + if constexpr (jsonifier::concepts::has_emplace_back) { while (iter != iter) { - parse::op(value.emplace_back(), iter, parserNew); + parse::template op(value.emplace_back(), iter); if (!derailleur::template checkForMatchOpen(iter)) [[likely]] { - if (!derailleur::template checkForMatchClosed(iter)) { - parserNew.errors.emplace_back(createError(iter)); + if (!derailleur::template checkForMatchClosed(iter)) [[unlikely]] { + iter.template createError(); derailleur::skipValue(iter); } return; @@ -192,10 +211,11 @@ namespace jsonifier_internal { } }; - template struct parse_impl { - jsonifier_inline static void op(value_type& value, structural_iterator& iter, parser& parserNew) { - if (!derailleur::template checkForMatchClosed(iter)) { - parserNew.errors.emplace_back(createError(iter)); + template struct parse_impl { + template + JSONIFIER_INLINE static void op(value_type&& value, iterator_type&& iter) { + if (!derailleur::template checkForMatchClosed(iter)) [[unlikely]] { + iter.template createError(); derailleur::skipToEndOfObject(iter); return; } @@ -206,8 +226,8 @@ namespace jsonifier_internal { } else if (first) [[unlikely]] { first = false; } else [[likely]] { - if (!derailleur::template checkForMatchClosed(iter)) { - parserNew.errors.emplace_back(createError(iter)); + if (!derailleur::template checkForMatchClosed(iter)) [[unlikely]] { + iter.template createError(); derailleur::skipToEndOfObject(iter); return; } @@ -216,76 +236,37 @@ namespace jsonifier_internal { continue; } - if jsonifier_constexpr (jsonifier::concepts::string_t) { - parse::op(parserNew.currentStringBuffer, iter, parserNew); - if (!derailleur::template checkForMatchClosed(iter)) { - parserNew.errors.emplace_back(createError(iter)); - derailleur::skipToEndOfObject(iter); - return; - } - parse::op(value[static_cast(parserNew.currentStringBuffer)], iter, parserNew); - } else { - parse::op(parserNew.currentKeyBuffer, iter, parserNew); - if (!derailleur::template checkForMatchClosed(iter)) { - parserNew.errors.emplace_back(createError(iter)); - derailleur::skipToEndOfObject(iter); - return; - } - parse::op(value[parserNew.currentKeyBuffer], iter, parserNew); - } - } - } - }; - - template struct parse_impl { - jsonifier_inline static void op(value_type& value, structural_iterator& iter, parser& parserNew) { - if (!derailleur::template checkForMatchClosed(iter)) { - parserNew.errors.emplace_back(createError(iter)); - derailleur::skipToEndOfArray(iter); - return; - } - static jsonifier_constexpr auto size{ std::tuple_size_v>> }; - - forEach([&](auto I) { - auto& newMember = getMember(value, get(jsonifier::concepts::coreV)); - parse::op(newMember, iter, parserNew); - if (iter == iter) { - return; - } - if (!derailleur::template checkForMatchOpen(iter)) [[likely]] { - if (!derailleur::template checkForMatchClosed(iter)) { - parserNew.errors.emplace_back(createError(iter)); - derailleur::skipToEndOfArray(iter); - } + static thread_local typename value_type_new::key_type keyNew{}; + parse::template op(keyNew, iter); + if (!derailleur::template checkForMatchClosed(iter)) [[unlikely]] { + iter.template createError(); + derailleur::skipToEndOfObject(iter); return; } - }); + parse::template op(value[keyNew], iter); + } } }; - template struct parse_impl { - jsonifier_inline static void op(value_type& value, structural_iterator& iter, parser& parserNew) { - if (!derailleur::template checkForMatchClosed(iter)) { - parserNew.errors.emplace_back(createError(iter)); + template struct parse_impl { + template + JSONIFIER_INLINE static void op(value_type&& value, iterator_type&& iter) { + if (!derailleur::template checkForMatchClosed(iter)) [[unlikely]] { + iter.template createError(); derailleur::skipToEndOfArray(iter); return; } - static jsonifier_constexpr auto size{ std::tuple_size_v>> }; + static constexpr auto size{ std::tuple_size_v> }; forEach([&](auto I) { - auto& newMember = getMember(value, get(jsonifier::concepts::coreV)); - using member_type = jsonifier::concepts::unwrap; - if jsonifier_constexpr (jsonifier::concepts::has_excluded_keys) { - parse::op(newMember, iter, newMember.excludedKeys, parserNew); - } else { - parse::op(newMember, iter, parserNew); - } + auto& newMember = getMember(value, get(jsonifier::concepts::coreV)); + parse::template op(newMember, std::forward(iter)); if (iter == iter) { return; } if (!derailleur::template checkForMatchOpen(iter)) [[likely]] { - if (!derailleur::template checkForMatchClosed(iter)) { - parserNew.errors.emplace_back(createError(iter)); + if (!derailleur::template checkForMatchClosed(iter)) [[unlikely]] { + iter.template createError(); derailleur::skipToEndOfArray(iter); } return; @@ -294,10 +275,12 @@ namespace jsonifier_internal { } }; - template struct parse_impl { - jsonifier_inline static void op(value_type& value, structural_iterator& iter, parser& parserNew) { - if (!derailleur::template checkForMatchClosed(iter)) { - parserNew.errors.emplace_back(createError(iter)); + template struct parse_impl { + template + JSONIFIER_INLINE static void op(value_type&& value, iterator_type&& iter, key_type&&... excludedKeys) { + if (!derailleur::template checkForMatchClosed(iter)) [[unlikely]] { + iter.template createError(); derailleur::skipToEndOfObject(iter); return; } @@ -307,160 +290,48 @@ namespace jsonifier_internal { return; } else if (first) [[unlikely]] { first = false; - } else [[likely]] { - if (!derailleur::template checkForMatchClosed(iter)) { - parserNew.errors.emplace_back(createError(iter)); - derailleur::skipToEndOfObject(iter); - return; - } - } - - auto start = iter.operator->(); - if (!derailleur::template checkForMatchClosed(iter)) { - parserNew.errors.emplace_back(createError(iter)); - derailleur::skipToEndOfObject(iter); - return; - } - const jsonifier::string_view_base key{ start + 1, static_cast(iter.operator->() - (start + 2)) }; - if (!derailleur::template checkForMatchClosed(iter)) { - parserNew.errors.emplace_back(createError(iter)); + } else if (!derailleur::template checkForMatchClosed(iter)) [[unlikely]] { + iter.template createError(); derailleur::skipToEndOfObject(iter); return; } - static jsonifier_constexpr auto frozenMap = makeMap(); - const auto& memberIt = frozenMap.find(key); - if (derailleur::template checkForMatchOpen(iter)) [[unlikely]] { - continue; - } else if (memberIt != frozenMap.end()) [[likely]] { - std::visit( - [&](auto& memberPtr) { - auto& newMember = getMember(value, memberPtr); - parse::op(newMember, iter, parserNew); - }, - memberIt->second); - } else [[unlikely]] { - derailleur::skipValue(iter); - } - } - } - }; - - template struct parse_impl { - jsonifier_inline static void op(value_type& value, structural_iterator& iter, parser& parserNew) { - if (!derailleur::template checkForMatchClosed(iter)) { - parserNew.errors.emplace_back(createError(iter)); - derailleur::skipToEndOfObject(iter); - return; - } - bool first{ true }; - while (iter != iter) { - if (derailleur::template checkForMatchOpen(iter)) [[unlikely]] { - return; - } else if (first) [[unlikely]] { - first = false; - } else [[likely]] { - if (!derailleur::template checkForMatchClosed(iter)) { - parserNew.errors.emplace_back(createError(iter)); - derailleur::skipToEndOfObject(iter); - return; - } - } auto start = iter.operator->(); - if (!derailleur::template checkForMatchClosed(iter)) { - parserNew.errors.emplace_back(createError(iter)); + if (!derailleur::template checkForMatchClosed(iter)) [[unlikely]] { + iter.template createError(); derailleur::skipToEndOfObject(iter); return; } const jsonifier::string_view_base key{ start + 1, static_cast(iter.operator->() - (start + 2)) }; - if (!derailleur::template checkForMatchClosed(iter)) { - parserNew.errors.emplace_back(createError(iter)); - derailleur::skipToEndOfObject(iter); - return; - } - static jsonifier_constexpr auto frozenMap = makeMap(); - const auto& memberIt = frozenMap.find(key); - if (derailleur::template checkForMatchOpen(iter)) [[unlikely]] { - continue; - } else if (memberIt != frozenMap.end()) [[likely]] { - std::visit( - [&](auto& memberPtr) { - auto& newMember = getMember(value, memberPtr); - using member_type = jsonifier::concepts::unwrap; - if jsonifier_constexpr (jsonifier::concepts::has_excluded_keys) { - parse::op(newMember, iter, parserNew, newMember.excludedKeys); - } else { - parse::op(newMember, iter, parserNew); - } - }, - memberIt->second); - } else [[unlikely]] { - derailleur::skipValue(iter); - } - } - }; - - template - jsonifier_inline static void op(value_type& value, structural_iterator& iter, parser& parserNew, const KeyType& excludedKeys) { - if (!derailleur::template checkForMatchClosed(iter)) { - parserNew.errors.emplace_back(createError(iter)); - derailleur::skipToEndOfObject(iter); - return; - } - bool first{ true }; - while (iter != iter) { - if (derailleur::template checkForMatchOpen(iter)) [[unlikely]] { - return; - } else if (first) [[unlikely]] { - first = false; - } else [[likely]] { - if (!derailleur::template checkForMatchClosed(iter)) { - parserNew.errors.emplace_back(createError(iter)); - derailleur::skipToEndOfObject(iter); - return; + if constexpr ((( !std::is_void_v ) || ...)) { + if (((excludedKeys.find(static_cast::key_type>(key)) != excludedKeys.end()) && ...)) { + derailleur::skipToNextValue(iter); + continue; } } - - auto start = iter.operator->(); - if (!derailleur::template checkForMatchClosed(iter)) { - parserNew.errors.emplace_back(createError(iter)); - derailleur::skipToEndOfObject(iter); - return; - } - auto keySize = static_cast(iter.operator->() - start); - if (keySize > 2) { - parserNew.currentKeyBuffer.resize(keySize - 2); - } - std::memcpy(parserNew.currentKeyBuffer.data(), start + 1, keySize - 2); - if (excludedKeys.find(static_cast(parserNew.currentKeyBuffer)) != excludedKeys.end()) { - derailleur::skipToNextValue(iter); - continue; - } - if (!derailleur::template checkForMatchClosed(iter)) { - parserNew.errors.emplace_back(createError(iter)); + if (!derailleur::template checkForMatchClosed(iter)) [[unlikely]] { + iter.template createError(); derailleur::skipToEndOfObject(iter); return; } - static jsonifier_constexpr auto frozenMap = makeMap(); - const auto& memberIt = frozenMap.find(parserNew.currentKeyBuffer); + static constexpr auto frozenMap = makeMap(); + const auto& memberIt = frozenMap.find(key); if (derailleur::template checkForMatchOpen(iter)) [[unlikely]] { continue; } else if (memberIt != frozenMap.end()) [[likely]] { - std::visit( - [&](auto& memberPtr) { - auto& newMember = getMember(value, memberPtr); - using member_type = jsonifier::concepts::unwrap; - if jsonifier_constexpr (jsonifier::concepts::has_excluded_keys) { - parse::op(newMember, iter, parserNew, newMember.excludedKeys); - } else { - parse::op(newMember, iter, parserNew); - } - }, - memberIt->second); + if constexpr (std::variant_size_vsecond)> > 0) { + std::visit( + [&](auto& memberPtr) { + auto& newMember = getMember(value, memberPtr); + parse::template op(newMember, iter); + }, + memberIt->second); + } } else [[unlikely]] { derailleur::skipValue(iter); } } } }; + } \ No newline at end of file diff --git a/Include/jsonifier/Parser.hpp b/Include/jsonifier/Parser.hpp index 7bf71374a..c8ec7a898 100644 --- a/Include/jsonifier/Parser.hpp +++ b/Include/jsonifier/Parser.hpp @@ -23,7 +23,7 @@ /// Feb 3, 2023 #pragma once -#include +#include #include #include #include @@ -31,56 +31,50 @@ namespace jsonifier_internal { - class parser; + template struct parse_impl; - template struct parse_impl {}; - - template struct parse { - template jsonifier_inline static void op(value_type& value, structural_iterator& iter, parser& parserNew) { - parse_impl::op(value, iter, parserNew); - } - - template - jsonifier_inline static void op(value_type& value, structural_iterator& iter, parser& parserNew, const KeyType& keys) { - parse_impl::op(value, iter, parserNew, keys); + struct parse { + template + JSONIFIER_INLINE static void op(value_type&& value, iterator_type&& iter) { + if constexpr (jsonifier::concepts::has_excluded_keys) { + parse_impl>::template op(std::forward(value), std::forward(iter), + value.jsonifierExcludedKeys); + } else { + parse_impl>::template op(std::forward(value), std::forward(iter)); + } } }; - class parser { + template class parser : protected simd_structural_iterator, derived_type> { public: - template friend struct parse_impl; - template friend struct parse; + using iterator_type = simd_structural_iterator, derived_type>; - template - jsonifier_inline void parseJson(value_type&& data, buffer_type& stringNew) { - if (stringNew.empty()) { - return; - } - section.reset(std::forward(stringNew)); - errors.clear(); - auto newIter = section.begin(); - if (!*newIter) { + template friend struct parse_impl; + + JSONIFIER_INLINE parser& operator=(const parser& other) = delete; + JSONIFIER_INLINE parser(const parser& other) = delete; + + template + JSONIFIER_INLINE void parseJson(value_type&& data, buffer_type&& stringNew) { + derivedRef.errors.clear(); + section.reset(stringNew.data(), stringNew.size()); + iterator_type::reset(section.begin()); + if (!iterator_type::operator->()) { return; } - if jsonifier_constexpr (excludeKeys) { - if jsonifier_constexpr (jsonifier::concepts::has_excluded_keys>) { - parse::op(data, newIter, *this, data.excludedKeys); - } else { - parse::op(data, newIter, *this); - } - } else { - parse::op(data, newIter, *this); - } - } - - jsonifier_inline jsonifier::vector& getErrors() { - return errors; + parse::template op(std::forward(data), std::forward(*this)); } protected: - buffer_string currentStringBuffer{}; - buffer_string currentKeyBuffer{}; - jsonifier::vector errors{}; + derived_type& derivedRef{ initializeSelfRef() }; simd_string_reader section{}; + + JSONIFIER_INLINE parser() noexcept : derivedRef{ initializeSelfRef() } {}; + + JSONIFIER_INLINE ~parser() noexcept = default; + + JSONIFIER_INLINE derived_type& initializeSelfRef() { + return *static_cast(this); + } }; }; diff --git a/Include/jsonifier/RawJsonData.hpp b/Include/jsonifier/RawJsonData.hpp index 820de9051..c4700738d 100644 --- a/Include/jsonifier/RawJsonData.hpp +++ b/Include/jsonifier/RawJsonData.hpp @@ -30,28 +30,32 @@ namespace std { template<> struct hash { - jsonifier_inline uint64_t operator()(const jsonifier::string& string) const { + JSONIFIER_INLINE uint64_t operator()(const jsonifier::string& string) const { return jsonifier_internal::fnv1aHash(string); } }; } -namespace jsonifier { +namespace jsonifier_internal { enum class json_type : uint8_t { Unset = 0, Object = 0x7Bu, Array = 0x5Bu, String = 0x22u, Number = 0x2Du, Bool = 0x74u, Null = 0x6Eu }; - jsonifier_inline static std::unordered_map typeMap{ { "", json_type::Unset }, { "Object", json_type::Object }, { "Array", json_type::Array }, + inline std::unordered_map typeMap{ { "", json_type::Unset }, { "Object", json_type::Object }, { "Array", json_type::Array }, { "String", json_type::String }, { "Number", json_type::Number }, { "Bool", json_type::Bool }, { "Null", json_type::Null } }; +} + +namespace jsonifier { + class raw_json_data { public: using object_type = std::unordered_map; using array_type = jsonifier::vector; - jsonifier_inline raw_json_data() = default; + JSONIFIER_INLINE raw_json_data() = default; - jsonifier_inline raw_json_data& operator=(bool value) { + JSONIFIER_INLINE raw_json_data& operator=(bool value) { if (value) { jsonData = "true"; } else { @@ -60,58 +64,58 @@ namespace jsonifier { return *this; } - jsonifier_inline raw_json_data(bool value) { + JSONIFIER_INLINE raw_json_data(bool value) { *this = value; } - jsonifier_inline raw_json_data& operator=(double value) { + JSONIFIER_INLINE raw_json_data& operator=(double value) { jsonData = toString(value); return *this; } - jsonifier_inline raw_json_data(double value) { + JSONIFIER_INLINE raw_json_data(double value) { *this = value; } - jsonifier_inline raw_json_data& operator=(int64_t value) { + JSONIFIER_INLINE raw_json_data& operator=(int64_t value) { jsonData = toString(value); return *this; } - jsonifier_inline raw_json_data(int64_t value) { + JSONIFIER_INLINE raw_json_data(int64_t value) { *this = value; } - jsonifier_inline raw_json_data& operator=(const jsonifier::string& value) { + JSONIFIER_INLINE raw_json_data& operator=(const jsonifier::string& value) { jsonData = value; return *this; } - jsonifier_inline raw_json_data(const jsonifier::string& value) { + JSONIFIER_INLINE raw_json_data(const jsonifier::string& value) { *this = value; } - jsonifier_inline const char* data() const { + JSONIFIER_INLINE const char* data() const { return jsonData.data(); } - jsonifier_inline char* data() { + JSONIFIER_INLINE char* data() { return jsonData.data(); } - jsonifier_inline json_type getType() { + JSONIFIER_INLINE jsonifier_internal::json_type getType() { if (jsonData.size() > 0) { - return typeMap[jsonifier_internal::getValueType(static_cast(jsonData[0]))]; + return jsonifier_internal::typeMap[jsonifier_internal::getValueType(static_cast(jsonData[0]))]; } else { - return typeMap[""]; + return jsonifier_internal::typeMap[""]; } } - jsonifier_inline void resize(uint64_t sizeNew) { - jsonData.resize(sizeNew); + JSONIFIER_INLINE void resize(uint64_t newSize) { + jsonData.resize(newSize); } - jsonifier_inline explicit operator object_type() { + JSONIFIER_INLINE explicit operator object_type() { object_type results{}; if (jsonData.size() > 0) { jsonifier::string::iterator newIter01 = jsonData.begin(); @@ -157,7 +161,7 @@ namespace jsonifier { return {}; } - jsonifier_inline explicit operator array_type() { + JSONIFIER_INLINE explicit operator array_type() { array_type results{}; if (jsonData.size() > 0) { jsonifier::string::iterator newIter01 = jsonData.begin(); @@ -182,7 +186,7 @@ namespace jsonifier { return {}; } - jsonifier_inline explicit operator string_view() { + JSONIFIER_INLINE explicit operator string_view() { if (jsonData.size() > 0) { return { jsonData.data() + 1, jsonData.size() - 1 }; } else { @@ -190,7 +194,7 @@ namespace jsonifier { } } - jsonifier_inline explicit operator string() const { + JSONIFIER_INLINE explicit operator string() const { if (jsonData.size() > 0) { return { jsonData.data() + 1, jsonData.size() - 1 }; } else { @@ -198,7 +202,7 @@ namespace jsonifier { } } - jsonifier_inline explicit operator double() const { + JSONIFIER_INLINE explicit operator double() const { if (jsonData.size() > 0) { return strToDouble(jsonData); } else { @@ -206,7 +210,7 @@ namespace jsonifier { } } - jsonifier_inline explicit operator uint64_t() const { + JSONIFIER_INLINE explicit operator uint64_t() const { if (jsonData.size() > 0) { return strToUint64(jsonData); } else { @@ -214,7 +218,7 @@ namespace jsonifier { } } - jsonifier_inline explicit operator int64_t() const { + JSONIFIER_INLINE explicit operator int64_t() const { if (jsonData.size() > 0) { return strToInt64(jsonData); } else { @@ -222,7 +226,7 @@ namespace jsonifier { } } - jsonifier_inline explicit operator bool() const { + JSONIFIER_INLINE explicit operator bool() const { if (jsonData == "true") { return true; } else { @@ -230,11 +234,11 @@ namespace jsonifier { } } - jsonifier_inline jsonifier::string_view rawJson() { + JSONIFIER_INLINE jsonifier::string_view rawJson() { return jsonData; } - jsonifier_inline bool operator==(const raw_json_data& other) const { + JSONIFIER_INLINE bool operator==(const raw_json_data& other) const { return jsonData == other.jsonData; } @@ -242,7 +246,7 @@ namespace jsonifier { string jsonData{}; }; - jsonifier_inline std::ostream& operator<<(std::ostream& os, raw_json_data& jsonValue) { + JSONIFIER_INLINE std::ostream& operator<<(std::ostream& os, raw_json_data& jsonValue) { os << jsonValue.rawJson(); return os; } diff --git a/Include/jsonifier/SerializationIterator.hpp b/Include/jsonifier/SerializationIterator.hpp new file mode 100644 index 000000000..1ba17ec23 --- /dev/null +++ b/Include/jsonifier/SerializationIterator.hpp @@ -0,0 +1,163 @@ +/* + 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 +#include + +namespace jsonifier_internal { + + template class serialization_iterator { + public: + friend class derailleur; + + using iterator_concept = std::forward_iterator_tag; + using iterator_category = std::forward_iterator_tag; + using value_type = uint64_t; + using pointer = uint8_t*; + using difference_type = std::ptrdiff_t; + using size_type = uint64_t; + + size_type currentSize{}; + + JSONIFIER_INLINE serialization_iterator() noexcept : selfRef{ initializeSelfRef() } {}; + + JSONIFIER_INLINE serialization_iterator& operator=(const serialization_iterator& other) noexcept { + if (this != &other) { + serialization_iterator{ other }.swap(*this); + } + return *this; + }; + + JSONIFIER_INLINE serialization_iterator(const serialization_iterator& other) noexcept : selfRef{ initializeSelfRef() }, currentSize{ other.currentSize } {}; + + JSONIFIER_INLINE value_type operator*() const { + return 0; + } + + JSONIFIER_INLINE pointer operator->() const { + return &selfRef.stringBuffer[currentSize]; + } + + JSONIFIER_INLINE void potentiallyResize(size_type sizeNew) { + if (currentSize + sizeNew >= selfRef.stringBuffer.size()) { + selfRef.stringBuffer.resize((currentSize + sizeNew) * 2); + } + } + + template JSONIFIER_INLINE void writeCharacter() { + if (currentSize + 1 >= selfRef.stringBuffer.size()) { + selfRef.stringBuffer.resize((currentSize + 1) * 2); + } + selfRef.stringBuffer[currentSize++] = static_cast(c); + } + + template JSONIFIER_INLINE void writeCharacter(char_type c) { + if (currentSize + 1 >= selfRef.stringBuffer.size()) { + selfRef.stringBuffer.resize((currentSize + 1) * 2); + } + selfRef.stringBuffer[currentSize++] = static_cast(c); + } + + template JSONIFIER_INLINE void writeCharacterUnchecked(char_type c) { + selfRef.stringBuffer[currentSize++] = static_cast(c); + } + + template JSONIFIER_INLINE void writeCharacters() { + constexpr auto n = str.size(); + if (currentSize + n >= selfRef.stringBuffer.size()) { + selfRef.stringBuffer.resize((currentSize + n) * 2); + } + std::memcpy(selfRef.stringBuffer.data() + currentSize, str.data(), n); + currentSize += n; + } + + template JSONIFIER_INLINE void writeCharacters(const char (&str)[size]) { + constexpr auto n = size - 1; + if (currentSize + n >= selfRef.stringBuffer.size()) { + selfRef.stringBuffer.resize((currentSize + n) * 2); + } + std::memcpy(selfRef.stringBuffer.data() + currentSize, str, n); + currentSize += n; + } + + template JSONIFIER_INLINE void writeCharacterUnchecked() { + selfRef.stringBuffer[currentSize++] = static_cast(c); + } + + template JSONIFIER_INLINE void writeCharactersUnchecked(const char (&str)[size]) { + std::memcpy(selfRef.stringBuffer.data() + currentSize, str, size - 1); + currentSize += size - 1; + } + + JSONIFIER_INLINE void resize(size_type sizeNew) { + selfRef.stringBuffer.resize(sizeNew); + } + + JSONIFIER_INLINE pointer data() const { + return selfRef.stringBuffer.data(); + } + + JSONIFIER_INLINE void reset() { + currentSize = 0; + } + + JSONIFIER_INLINE serialization_iterator& operator++() { + ++currentSize; + return *this; + } + + JSONIFIER_INLINE serialization_iterator operator++(int32_t) { + serialization_iterator temp{ *this }; + ++(*this); + return temp; + } + + JSONIFIER_INLINE uint8_t& operator[](uint64_t index) const { + return selfRef.stringBuffer[index]; + } + + JSONIFIER_INLINE bool operator==(const serialization_iterator& other) const { + return currentSize == other.currentSize; + } + + JSONIFIER_INLINE size_type size() const { + return selfRef.stringBuffer.size(); + } + + JSONIFIER_INLINE void swap(serialization_iterator& other) { + std::swap(currentSize, other.currentSize); + } + + protected: + second_derived_type& selfRef{ initializeSelfRef() }; + + second_derived_type& initializeSelfRef() { + return *static_cast(this); + } + }; +} \ No newline at end of file diff --git a/Include/jsonifier/Serialize_Impl.hpp b/Include/jsonifier/Serialize_Impl.hpp index a924cf533..4cedac5f7 100644 --- a/Include/jsonifier/Serialize_Impl.hpp +++ b/Include/jsonifier/Serialize_Impl.hpp @@ -30,415 +30,250 @@ namespace jsonifier_internal { - template jsonifier_inline void writeCharacter(char c, buffer_type& buffer, uint64_t& index) { - if (index + 1 >= buffer.size()) { - buffer.resize(buffer.size() == 0 ? index + 1 : (buffer.size() + index) * 2); - } - - buffer[index++] = c; - buffer[index] = '\0'; - } - - template jsonifier_inline void writeCharacter(buffer_type& buffer, uint64_t& index) { - if (index + 1 >= buffer.size()) { - buffer.resize(buffer.size() == 0 ? index + 1 : (buffer.size() + index) * 2); - } - - buffer[index++] = static_cast::value_type>(c); - buffer[index] = '\0'; - } - - template jsonifier_inline void writeCharacterUnChecked(buffer_type& buffer, uint64_t& index) { - buffer[index++] = static_cast::value_type>(c); - buffer[index] = '\0'; - } - - template jsonifier_inline void writeCharacters(buffer_type& buffer, uint64_t& index) { - static jsonifier_constexpr uint64_t n = str.size(); - if (index + n >= buffer.size()) { - buffer.resize((std::max)(buffer.size() * 2, index + n)); - } - - std::memcpy(buffer.data() + index, str.data(), n); - index += n; - } - - template jsonifier_inline void writeCharacters(const jsonifier::string_view str, buffer_type& buffer, uint64_t& index) { - const auto n = str.size(); - if (index + n >= buffer.size()) { - buffer.resize((std::max)(buffer.size() * 2, index + n)); - } - - std::memcpy(buffer.data() + index, str.data(), n); - index += n; - } - - template struct serialize_impl { - template jsonifier_inline static void op(const value_type&, buffer_type& buffer, uint64_t& index) { - static jsonifier_constexpr jsonifier::string_view stringViewNew{ "null" }; - writeCharacters(buffer, index); + template struct serialize_impl { + template + JSONIFIER_INLINE static void op(value_type&&, iterator_type&& buffer) { + buffer.writeCharacters("null"); } }; - template struct serialize_impl { - template jsonifier_inline static void op(const value_type& value, buffer_type& buffer, uint64_t& index) { - if (value) { - static jsonifier_constexpr jsonifier::string_view stringViewNew{ "true" }; - writeCharacters(buffer, index); - } else { - static jsonifier_constexpr jsonifier::string_view stringViewNew{ "false" }; - writeCharacters(buffer, index); - } + template struct serialize_impl { + template + JSONIFIER_INLINE static void op(value_type&& value, iterator_type&& buffer) { + value ? buffer.writeCharacters("true") : buffer.writeCharacters("false"); } }; - template struct serialize_impl { - template jsonifier_inline static void op(const value_type& value, buffer_type& buffer, uint64_t& index) { - if (index + 32 >= buffer.size()) { - buffer.resize((buffer.size() + index + 32) * 4); - } - auto start = buffer.data() + index; - auto end = toChars(start, value); - index += std::distance(start, end); + template struct serialize_impl { + template + JSONIFIER_INLINE static void op(value_type&& value, iterator_type&& buffer) { + buffer.potentiallyResize(32); + auto end = toChars(buffer.data() + buffer.currentSize, value); + buffer.currentSize += end - (buffer.data() + buffer.currentSize); } }; - template struct serialize_impl { - template jsonifier_inline static void op(const value_type& value, buffer_type& buffer, uint64_t& index) { - if (index + 32 >= buffer.size()) { - buffer.resize((buffer.size() + index + 32) * 4); - } - auto start = buffer.data() + index; - auto end = toChars(start, static_cast(value)); - index += std::distance(start, end); + template struct serialize_impl { + template + JSONIFIER_INLINE static void op(value_type&& value, iterator_type&& buffer) { + buffer.potentiallyResize(32); + auto end = toChars(buffer.data() + buffer.currentSize, static_cast(value)); + buffer.currentSize += end - (buffer.data() + buffer.currentSize); } }; - template struct serialize_impl { - template jsonifier_inline static void op(const value_type& value, buffer_type& buffer, uint64_t& index) { - writeCharacter(buffer, index); + template struct serialize_impl { + template + JSONIFIER_INLINE static void op(value_type&& value, iterator_type&& buffer) { + buffer.template writeCharacter(); switch (value) { - case 0x22u: { - static jsonifier_constexpr jsonifier::string_view stringViewNew{ "\\\"" }; - writeCharacters(buffer, index); + case 0x08u: { + buffer.writeCharacters("\\b"); break; } - case 0x5Cu: { - static jsonifier_constexpr jsonifier::string_view stringViewNew{ "\\\\" }; - writeCharacters(buffer, index); + case 0x09u: { + buffer.writeCharacters("\\t"); break; } - case 0x08u: { - static jsonifier_constexpr jsonifier::string_view stringViewNew{ "\\b" }; - writeCharacters(buffer, index); + case 0x0Au: { + buffer.writeCharacters("\\n"); break; } case 0x0Cu: { - static jsonifier_constexpr jsonifier::string_view stringViewNew{ "\\f" }; - writeCharacters(buffer, index); + buffer.writeCharacters("\\f"); break; } - case 0x0Au: { - static jsonifier_constexpr jsonifier::string_view stringViewNew{ "\\n" }; - writeCharacters(buffer, index); + case 0x0Du: { + buffer.writeCharacters("\\r"); break; } - case 0x0Du: { - static jsonifier_constexpr jsonifier::string_view stringViewNew{ "\\r" }; - writeCharacters(buffer, index); + case 0x22u: { + buffer.writeCharacters("\\\""); break; } - case 0x09u: { - static jsonifier_constexpr jsonifier::string_view stringViewNew{ "\\t" }; - writeCharacters(buffer, index); + case 0x5CU: { + buffer.writeCharacters("\\\\"); break; } - default: - writeCharacter(value, buffer, index); + default: { + buffer.writeCharacter(value); + } } - writeCharacter(buffer, index); + buffer.template writeCharacter(); } }; - template struct serialize_impl { - template jsonifier_inline static void op(const value_type& value, buffer_type& buffer, uint64_t& index) { - const auto n = value.size(); + template struct serialize_impl { + template + JSONIFIER_INLINE static void op(value_type&& value, iterator_type&& buffer) { + auto n = static_cast(value.size()); - if jsonifier_constexpr (jsonifier::concepts::has_resize) { - const auto k = index + (4 * n); - if (k >= buffer.size()) [[unlikely]] { - buffer.resize((std::max)(buffer.size() * 2, k)); - } - } - writeCharacterUnChecked(buffer, index); - uint64_t indexNew{}; + buffer.potentiallyResize(buffer.currentSize + (4 * n)); + buffer.template writeCharacterUnchecked(); - auto newPtr = serializeString(value.data(), buffer.data() + index, value.size(), indexNew); + n = 0; - index += indexNew; + auto newPtr = serializeString(value.data(), buffer.data() + buffer.currentSize, value.size(), n); - indexNew = static_cast(newPtr - value.data()); - for (auto iterBegin = value.begin() + static_cast(indexNew); iterBegin < value.end(); ++iterBegin) { - switch (*iterBegin) { - case 0x22u: - std::memcpy(buffer.data() + index, R"(\")", 2); - index += 2; + buffer.currentSize += n; + + n = static_cast(newPtr - value.data()); + for (; n < value.size(); ++n) { + switch (value[n]) { + case 0x08u: { + buffer.writeCharactersUnchecked("\\b"); break; - case 0x5CU: - std::memcpy(buffer.data() + index, R"(\\)", 2); - index += 2; + } + case 0x09u: { + buffer.writeCharactersUnchecked("\\t"); break; - case 0x08u: - std::memcpy(buffer.data() + index, R"(\b)", 2); - index += 2; + } + case 0x0Au: { + buffer.writeCharactersUnchecked("\\n"); break; - case 0x0Cu: - std::memcpy(buffer.data() + index, R"(\f)", 2); - index += 2; + } + case 0x0Cu: { + buffer.writeCharactersUnchecked("\\f"); break; - case 0x0Au: - std::memcpy(buffer.data() + index, R"(\n)", 2); - index += 2; + } + case 0x0Du: { + buffer.writeCharactersUnchecked("\\r"); break; - case 0x0Du: - std::memcpy(buffer.data() + index, R"(\r)", 2); - index += 2; + } + case 0x22u: { + buffer.writeCharactersUnchecked("\\\""); break; - case 0x09u: - std::memcpy(buffer.data() + index, R"(\t)", 2); - index += 2; + } + case 0x5CU: { + buffer.writeCharactersUnchecked("\\\\"); break; - default: - buffer[index++] = static_cast(*iterBegin); + } + default: { + buffer.writeCharacterUnchecked(value[n]); + } } } - writeCharacterUnChecked(buffer, index); + buffer.template writeCharacterUnchecked(); } }; - template struct serialize_impl { - template jsonifier_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 serialize_impl { + template + JSONIFIER_INLINE static void op(value_type&& value, iterator_type&& buffer) { + serialize::template op(static_cast(value), buffer); } }; - template struct serialize_impl { - template jsonifier_inline static void op(const value_type& value, buffer_type& buffer, uint64_t& index) { - const auto n = std::size(value); - 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); + template struct serialize_impl { + template + JSONIFIER_INLINE static void op(value_type& value, iterator_type&& buffer) { + static constexpr auto n = std::size(value); + buffer.template writeCharacter(); + if constexpr (n > 0) { + serialize::template op(value[0], buffer); + for (uint64_t x = 0; x < n; ++x) { + buffer.template writeCharacter(); + serialize::template op(value[x], buffer); } } - writeCharacter(buffer, index); + + buffer.template writeCharacter(); } }; - template struct serialize_impl { - template jsonifier_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); - } - serialize::op(*iter, buffer, index); + template struct serialize_impl { + template + JSONIFIER_INLINE static void op(value_type&& value, iterator_type&& buffer) { + buffer.template writeCharacter(); + + if (value.size() > 0) { + auto iter = value.begin(); + serialize::template op(*iter, buffer); + ++iter; + for (; iter != value.end(); ++iter) { + buffer.template writeCharacter(); + serialize::template op(*iter, buffer); } } - writeCharacter(buffer, index); - } - }; - template struct serialize_impl { - template jsonifier_inline static void op(const value_type& value, buffer_type& buffer, uint64_t& index) { - writeCharacter(buffer, index); - uint64_t currentIndex{}; - for (auto& [key, valueNew]: value) { - serialize::op(key, buffer, index); - writeCharacter(buffer, index); - serialize::op(valueNew, buffer, index); - const bool needsComma = currentIndex < value.size() - 1; - if (needsComma) { - writeCharacter(buffer, index); - } - ++currentIndex; - }; - writeCharacter(buffer, index); + buffer.template writeCharacter(); } }; - template struct serialize_impl { - template jsonifier_inline static void op(const value_type& value, buffer_type& buffer, uint64_t& index) { - static jsonifier_constexpr auto size{ std::tuple_size_v> }; - - writeCharacter(buffer, index); - forEach([&](auto I) { - auto& newMember = getMember(value, get(jsonifier::concepts::coreV)); - serialize::op(newMember, buffer, index); - jsonifier_constexpr bool needsComma = I < size - 1; - if jsonifier_constexpr (needsComma) { - writeCharacter(buffer, index); + template struct serialize_impl { + template + JSONIFIER_INLINE static void op(value_type&& value, iterator_type&& buffer) { + buffer.template writeCharacter(); + bool first{ true }; + auto setToFalseLambda = [&]() { + first = false; + }; + if (value.size() > 0) { + for (auto& [key, valueNew]: value) { + first ? setToFalseLambda() : buffer.template writeCharacter(); + serialize::template op(key, buffer); + buffer.template writeCharacter(); + serialize::template op(valueNew, buffer); } - }); - writeCharacter(buffer, index); - } - }; - - jsonifier_constexpr bool needsEscaping(auto& S) { - for (auto& c: S) { - if (c == 0x22u) { - return true; } - } - return false; - } - - template struct serialize_impl { - template jsonifier_inline static void op(const value_type& value, buffer_type& buffer, uint64_t& index) { - writeCharacter(buffer, index); - static jsonifier_constexpr auto n = std::tuple_size_v>; - - bool first = true; - forEach([&](auto x) { - static jsonifier_constexpr auto item = get(jsonifier::concepts::coreV); - using item_type = decltype(item); - using member_ptr_t = std::tuple_element_t<1, item_type>; - using value_type_new = member_t; - - if jsonifier_constexpr (jsonifier::concepts::null_t) { - auto isNull = [&]() { - if jsonifier_constexpr (std::is_member_pointer_v>) { - return !bool(value.*get<1>(item)); - } else { - return !bool(get<1>(item)(value)); - } - }(); - if (isNull()) { - return; - } - } - - if (first) { - first = false; - } else { - writeCharacter(buffer, index); - } - static jsonifier_constexpr jsonifier::string_view key = get<0>(item); - static jsonifier_constexpr jsonifier::string_view string01{ R"(")" }; - static jsonifier_constexpr jsonifier::string_view string02{ R"(":)" }; - static jsonifier_constexpr auto quoted = JoinV; - writeCharacters(buffer, index); - auto& newMember = getMember(value, get<1>(item)); - serialize::op(newMember, buffer, index); - }); - writeCharacter(buffer, index); + buffer.template writeCharacter(); } }; - template struct serialize_impl { - template jsonifier_inline static void op(const value_type& value, buffer_type& buffer, uint64_t& index) { - writeCharacter(buffer, index); - static jsonifier_constexpr auto n = std::tuple_size_v>; - - bool first = true; - forEach([&](auto x) { - static jsonifier_constexpr auto item = get(jsonifier::concepts::coreV); - using item_type = decltype(item); - using member_ptr_t = std::tuple_element_t<1, item_type>; - using value_type_new = member_t; - - if jsonifier_constexpr (jsonifier::concepts::null_t) { - auto isNull = [&]() { - if jsonifier_constexpr (std::is_member_pointer_v>) { - return !bool(value.*get<1>(item)); - } else { - return !bool(get<1>(item)(value)); - } - }(); - if (isNull()) { - return; - } - } + template struct serialize_impl { + template + JSONIFIER_INLINE static void op(value_type&& value, iterator_type&& buffer) { + static constexpr auto size{ std::tuple_size_v> }; + + buffer.template writeCharacter(); + if constexpr (size > 0) { + auto& newMember = getMember(value, get<0>(jsonifier::concepts::coreV)); + serialize::template op(newMember, buffer); + forEach([&](auto x) { + buffer.template writeCharacter(); + auto& newMember = getMember(value, get(jsonifier::concepts::coreV)); + serialize::template op(newMember, buffer); + }); + } - if (first) { - first = false; - } else { - writeCharacter(buffer, index); - } - static jsonifier_constexpr jsonifier::string_view key = get<0>(item); - static jsonifier_constexpr jsonifier::string_view string01{ R"(")" }; - static jsonifier_constexpr jsonifier::string_view string02{ R"(":)" }; - static jsonifier_constexpr auto quoted = JoinV; - writeCharacters(buffer, index); - auto& newMember = getMember(value, get<1>(item)); - using MemberType = decltype(newMember); - if jsonifier_constexpr (jsonifier::concepts::has_excluded_keys) { - serialize::op(newMember, buffer, index, newMember.excludedKeys); - } else { - serialize::op(newMember, buffer, index); - } - }); - writeCharacter(buffer, index); + buffer.template writeCharacter(); } + }; - template - jsonifier_inline static void op(const value_type& value, buffer_type& buffer, uint64_t& index, const KeyType& excludedKeys) { - writeCharacter(buffer, index); - static jsonifier_constexpr auto n = std::tuple_size_v>; - - bool first = true; + template struct serialize_impl { + template + JSONIFIER_INLINE static void op(value_type&& value, iterator_type&& buffer, key_type&&... excludedKeys) { + buffer.template writeCharacter(); + static constexpr auto n = std::tuple_size_v>; + bool first{ true }; + auto setToFalseLambda = [&]() { + first = false; + }; forEach([&](auto x) { - static jsonifier_constexpr auto item = get(jsonifier::concepts::coreV); - using item_type = decltype(item); - using member_ptr_t = std::tuple_element_t<1, item_type>; - using value_type_new = member_t; - - if jsonifier_constexpr (jsonifier::concepts::null_t) { - auto isNull = [&]() { - if jsonifier_constexpr (std::is_member_pointer_v>) { - return !bool(value.*get<1>(item)); - } else { - return !bool(get<1>(item)(value)); - } - }(); - if (isNull()) { + static constexpr auto& item = get(jsonifier::concepts::coreV); + using item_type = jsonifier::concepts::unwrap; + using member_ptr_t = std::tuple_element_t<1, item_type>; + using value_type_newer = member_t; + + static constexpr jsonifier::string_view key = get<0>(item); + if constexpr ((( !std::is_void_v ) || ...)) { + constexpr jsonifier::string_view keyNew{ key }; + if (((excludedKeys.find(static_cast::key_type>(keyNew)) != excludedKeys.end()) && ...)) { return; } } + first ? setToFalseLambda() : buffer.template writeCharacter(); + buffer.writeCharacters("\""); + buffer.template writeCharacters(); + buffer.writeCharacters("\":"); - static jsonifier_constexpr jsonifier::string_view key = get<0>(item); - if (excludedKeys.find(static_cast(key)) != excludedKeys.end()) { - return; - } - if (first) { - first = false; - } else { - writeCharacter(buffer, index); - } - static jsonifier_constexpr jsonifier::string_view string01{ R"(")" }; - static jsonifier_constexpr jsonifier::string_view string02{ R"(":)" }; - static jsonifier_constexpr auto quoted = JoinV; - writeCharacters(buffer, index); - - auto& newMember = getMember(value, get<1>(item)); - using MemberType = decltype(newMember); - if jsonifier_constexpr (jsonifier::concepts::has_excluded_keys) { - serialize::op(newMember, buffer, index, newMember.excludedKeys); - } else { - serialize::op(newMember, buffer, index); - } + auto& newMember = getMember(value, get<1>(item)); + serialize::template op(newMember, buffer); }); - writeCharacter(buffer, index); + buffer.template writeCharacter(); } }; } \ No newline at end of file diff --git a/Include/jsonifier/Serializer.hpp b/Include/jsonifier/Serializer.hpp index 6544a2e66..db67abfd5 100644 --- a/Include/jsonifier/Serializer.hpp +++ b/Include/jsonifier/Serializer.hpp @@ -23,46 +23,57 @@ /// Feb 20, 2023 #pragma once +#include #include #include +#include namespace jsonifier_internal { - template struct serialize_impl; + template struct serialize_impl; - template struct serialize { - template jsonifier_inline static void op(const value_type& value, buffer_type& buffer, uint64_t& index) { - serialize_impl>::op(value, buffer, index); - } - - template - jsonifier_inline static void op(const value_type& value, buffer_type& buffer, uint64_t& index, const KeyType& keys) { - serialize_impl>::op(value, buffer, index, keys); + struct serialize { + template + JSONIFIER_INLINE static void op(value_type&& value, iterator_type&& iter) { + if constexpr (jsonifier::concepts::has_excluded_keys) { + serialize_impl>::template op(std::forward(value), std::forward(iter), + value.jsonifierExcludedKeys); + } else { + serialize_impl>::template op(std::forward(value), std::forward(iter)); + } } }; - class serializer { + template class serializer : protected serialization_iterator, derived_type> { public: - template - jsonifier_inline void serializeJson(value_type&& data, buffer_type& buffer) { - uint64_t index{}; - if jsonifier_constexpr (excludeKeys) { - if jsonifier_constexpr (jsonifier::concepts::has_excluded_keys) { - serialize::op(std::forward(data), stringBuffer, index, data.excludedKeys); - } else { - serialize::op(std::forward(data), stringBuffer, index); - } - } else { - serialize::op(std::forward(data), stringBuffer, index); - } - if (buffer.size() != index) [[unlikely]] { - buffer.resize(index); + using iterator_type = serialization_iterator, derived_type>; + + template friend struct serialize_impl; + + JSONIFIER_INLINE serializer& operator=(const serializer& other) = delete; + JSONIFIER_INLINE serializer(const serializer& other) = delete; + + template + JSONIFIER_INLINE void serializeJson(value_type&& data, buffer_type&& iter) { + iterator_type::reset(); + derivedRef.errors.clear(); + serialize::template op(std::forward(data), std::forward(*this)); + if (iter.size() != iterator_type::currentSize) [[unlikely]] { + iter.resize(iterator_type::currentSize); } - std::memcpy(buffer.data(), stringBuffer.data(), index); + std::memcpy(iter.data(), iterator_type::data(), iterator_type::currentSize); } protected: - buffer_string stringBuffer{}; + derived_type& derivedRef{ initializeSelfRef() }; + + JSONIFIER_INLINE serializer() noexcept : derivedRef{ initializeSelfRef() } {}; + + JSONIFIER_INLINE ~serializer() noexcept = default; + + JSONIFIER_INLINE derived_type& initializeSelfRef() { + return *static_cast(this); + } }; -} +} \ No newline at end of file diff --git a/Include/jsonifier/Simd.hpp b/Include/jsonifier/Simd.hpp index 571b76f22..ae5c6a541 100644 --- a/Include/jsonifier/Simd.hpp +++ b/Include/jsonifier/Simd.hpp @@ -23,23 +23,24 @@ /// Feb 3, 2023 #pragma once -#include +#include #include #include +#include #include namespace jsonifier_internal { class string_block_reader { public: - jsonifier_inline void reset(const uint8_t* stringViewNew, uint64_t lengthNew) noexcept { + JSONIFIER_INLINE void reset(string_view_ptr stringViewNew, uint64_t lengthNew) noexcept { lengthMinusStep = lengthNew < BitsPerStep ? 0 : lengthNew - BitsPerStep; inString = stringViewNew; length = lengthNew; index = 0; } - jsonifier_inline uint64_t getRemainder(string_buffer_ptr dest) const noexcept { + JSONIFIER_INLINE uint64_t getRemainder(string_buffer_ptr dest) const noexcept { if (length == index) { return 0; } @@ -48,18 +49,18 @@ namespace jsonifier_internal { return length - index; } - jsonifier_inline string_view_ptr fullBlock() noexcept { - const uint8_t* newPtr = inString + index; + JSONIFIER_INLINE string_view_ptr fullBlock() noexcept { + string_view_ptr newPtr = inString + index; index += BitsPerStep; return newPtr; } - jsonifier_inline bool hasFullBlock() const noexcept { + JSONIFIER_INLINE bool hasFullBlock() const noexcept { return index < lengthMinusStep; } protected: - const uint8_t* inString{}; + string_view_ptr inString{}; uint64_t lengthMinusStep{}; uint64_t length{}; uint64_t index{}; @@ -69,68 +70,58 @@ namespace jsonifier_internal { public: using size_type = uint64_t; using allocator = alloc_wrapper; + static constexpr double multiplier{ 4.5f / 5.0f }; - template jsonifier_inline void reset(string_type&& stringViewNew) { - if jsonifier_constexpr (refreshString) { - stringView = reinterpret_cast(stringViewNew.data()); - stringLength = stringViewNew.size(); - structuralIndices.resize(roundUpToMultiple<8>(static_cast(static_cast(stringLength) * 4.5f / 5.0f))); + template JSONIFIER_INLINE void reset(char_type* stringViewNew, size_type size) { + if constexpr (refreshString) { + currentParseBuffer = jsonifier::string_view_base{ reinterpret_cast(stringViewNew), size }; + structuralIndices.resize(roundUpToMultiple<8>(static_cast(static_cast(currentParseBuffer.size()) * multiplier))); resetInternal(); - } else if (jsonifier::string_view_base{ stringView, stringLength } != stringViewNew) { - stringView = reinterpret_cast(stringViewNew.data()); - stringLength = stringViewNew.size(); - structuralIndices.resize(roundUpToMultiple<8>(static_cast(static_cast(stringLength) * 4.5f / 5.0f))); + } else if (currentParseBuffer != stringViewNew) { + currentParseBuffer = jsonifier::string_view_base{ reinterpret_cast(stringViewNew), size }; + structuralIndices.resize(roundUpToMultiple<8>(static_cast(static_cast(currentParseBuffer.size()) * multiplier))); resetInternal(); } } - template - jsonifier_inline std::string resetWithErrorPrintOut(string_type&& stringViewNew, size_type errorIndex) { + template JSONIFIER_INLINE std::string resetWithErrorPrintOut(char_type* stringViewNew, size_type size, size_type errorIndex) { std::string returnValue{ "For the following string values: " }; if (errorIndex < std::string{}.max_size()) { - returnValue += std::string_view{ reinterpret_cast(stringViewNew.data() + errorIndex), BitsPerStep }; + returnValue += std::string_view{ reinterpret_cast(stringViewNew + errorIndex), BitsPerStep }; returnValue += "\n"; } - if jsonifier_constexpr (refreshString) { - stringView = reinterpret_cast(stringViewNew.data()); - stringLength = stringViewNew.size(); - structuralIndices.resize(roundUpToMultiple<8>(static_cast(static_cast(stringLength) * 4.5f / 5.0f))); + if constexpr (refreshString) { + currentParseBuffer = { reinterpret_cast(stringViewNew), size }; + structuralIndices.resize(roundUpToMultiple<8>(static_cast(static_cast(currentParseBuffer.size()) * multiplier))); return returnValue + resetInternalWithErrorPrintOut(errorIndex); - } else if (jsonifier::string_view_base{ stringView, stringLength } != stringViewNew) { - stringView = reinterpret_cast(stringViewNew.data()); - stringLength = stringViewNew.size(); - structuralIndices.resize(roundUpToMultiple<8>(static_cast(static_cast(stringLength) * 4.5f / 5.0f))); + } else if (currentParseBuffer != stringViewNew) { + currentParseBuffer = { reinterpret_cast(stringViewNew), size }; + structuralIndices.resize(roundUpToMultiple<8>(static_cast(static_cast(currentParseBuffer.size()) * multiplier))); return returnValue + resetInternalWithErrorPrintOut(errorIndex); } } - jsonifier_inline void resetInternal() { - stringBlockReader.reset(stringView, stringLength); + JSONIFIER_INLINE void resetInternal() { + stringBlockReader.reset(currentParseBuffer.data(), currentParseBuffer.size()); stringIndex = 0; tapeIndex = 0; generateJsonIndices(); } - jsonifier_inline std::string resetInternalWithErrorPrintOut(size_type errorIndex) { - stringBlockReader.reset(stringView, stringLength); + JSONIFIER_INLINE std::string resetInternalWithErrorPrintOut(size_type errorIndex) { + stringBlockReader.reset(currentParseBuffer.data(), currentParseBuffer.size()); stringIndex = 0; tapeIndex = 0; return generateJsonIndicesWithErrorPrintOut(errorIndex); } - jsonifier_inline structural_iterator begin() { - return structural_iterator{ getStructurals() }; - } - - jsonifier_inline structural_index* getStructurals() { + JSONIFIER_INLINE auto begin() { structuralIndices[tapeIndex] = nullptr; return structuralIndices.data(); } - jsonifier_inline ~simd_string_reader(){}; - protected: - static jsonifier_constexpr simd_int_t oddBitsVal{ simdFromValue(0xAA) }; + static constexpr simd_int_t oddBitsVal{ simdFromValue(0xAA) }; simd_int_t newPtr[StridesPerStep]{}; simd_int_t nextIsEscaped{}; simd_int_t backslashes{}; @@ -140,17 +131,15 @@ namespace jsonifier_internal { simd_int_t quotes{}; simd_int_t op{}; alignas(BytesPerStep) size_type newBits[SixtyFourBitsPerStep]{}; - bool prevInString{}; - bool overflow{}; + jsonifier::string_view_base currentParseBuffer{}; + int64_t prevInString{}; structural_index_vector structuralIndices{}; string_block_reader stringBlockReader{}; - string_view_ptr stringView{}; - size_type stringLength{}; size_type stringIndex{}; size_type tapeIndex{}; + bool overflow{}; - - jsonifier_inline void generateJsonIndices() { + JSONIFIER_INLINE void generateJsonIndices() { while (stringBlockReader.hasFullBlock()) { generateStructurals(stringBlockReader.fullBlock()); } @@ -160,100 +149,84 @@ namespace jsonifier_internal { } } - jsonifier_inline size_type getTapeLength() { + JSONIFIER_INLINE size_type getTapeLength() { return tapeIndex - 1; } - template jsonifier_inline size_type rollValuesIntoTape(size_type currentIndex, size_type newBits) { - if jsonifier_constexpr (index < StridesPerStep) { - structuralIndices[index + (currentIndex * 8) + tapeIndex] = stringView + static_cast(tzcnt(newBits) + (index02 * 64ull) + stringIndex); - newBits = blsr(newBits); - return (newBits == 0) ? newBits : rollValuesIntoTape(currentIndex, newBits); - } else { - return newBits; - } - } - template jsonifier_inline void collectStringValuesHelper(string_view_ptr valuesNew) { - newPtr[index] = gatherValuesU(valuesNew + (BytesPerStep * index)); + template JSONIFIER_INLINE size_type rollValuesIntoTape(size_type currentIndex, size_type newBits, std::index_sequence) { + static constexpr uint64_t bitTotal{ index * 64ull }; + ((structuralIndices[indices + (currentIndex * 8) + tapeIndex] = currentParseBuffer.data() + static_cast(tzcnt(newBits) + bitTotal + stringIndex), + newBits = blsr(newBits)), + ...); + return newBits; } - jsonifier_inline void collectStringValues(string_view_ptr valuesNew) { - collectStringValuesHelper<0>(valuesNew); - collectStringValuesHelper<1>(valuesNew); - collectStringValuesHelper<2>(valuesNew); - collectStringValuesHelper<3>(valuesNew); - collectStringValuesHelper<4>(valuesNew); - collectStringValuesHelper<5>(valuesNew); - collectStringValuesHelper<6>(valuesNew); - collectStringValuesHelper<7>(valuesNew); + template void collectStringValues(string_view_ptr values, std::index_sequence) { + ((newPtr[indices] = gatherValuesU(values + (BytesPerStep * indices))), ...); } - jsonifier_inline void generateStructurals(string_view_ptr valueNew) { - collectStringValues(valueNew); - collectWhitespaceAsSimdBase(whitespace, newPtr); - collectBackslashesAsSimdBase(backslashes, newPtr); - collectStructuralsAsSimdBase(op, newPtr); - collectQuotesAsSimdBase(quotes, newPtr); + JSONIFIER_INLINE void generateStructurals(string_view_ptr values) { + collectStringValues(values, std::make_index_sequence{}); + whitespace = collectWhitespaceAsSimdBase(newPtr, std::make_index_sequence{}); + backslashes = collectBackslashesAsSimdBase(newPtr, std::make_index_sequence{}); + op = collectStructuralsAsSimdBase(newPtr, std::make_index_sequence{}); + quotes = collectQuotesAsSimdBase(newPtr, std::make_index_sequence{}); collectStructurals(); - addTapeValues(); + addTapeValues(std::make_index_sequence{}); stringIndex += BitsPerStep; } - jsonifier_inline void addTapeValues() { + template JSONIFIER_INLINE void addTapeValues(std::index_sequence) { store(structurals, newBits); - addTapeValuesHelper<0>(); + (addTapeValuesHelper(), ...); } - template jsonifier_inline void addTapeValuesHelper() { - if jsonifier_constexpr (index < SixtyFourBitsPerStep) { - if (!newBits[index]) { - addTapeValuesHelper(); - return; - } - 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; - addTapeValuesHelper(); + template JSONIFIER_INLINE void addTapeValuesHelper() { + if (!newBits[index]) { + return; + } + 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(y, newBits[index], std::make_index_sequence{}); } + tapeIndex += cnt; } - jsonifier_inline void collectNonEmptyEscaped() noexcept { - simd_int_t potentialEscape = bitAndNot(backslashes, nextIsEscaped); - simd_int_t maybeEscaped = shl<1>(potentialEscape); + JSONIFIER_INLINE void collectNonEmptyEscaped() noexcept { + simd_int_t potentialEscape = opAndNot(backslashes, nextIsEscaped); + simd_int_t maybeEscaped = shl<1>(potentialEscape, std::make_index_sequence{}); simd_int_t maybeEscapedAndOddBits = opOr(maybeEscaped, oddBitsVal); - simd_int_t evenSeriesCodesAndOddBits = opSub(maybeEscapedAndOddBits, potentialEscape); + simd_int_t evenSeriesCodesAndOddBits = opSub(maybeEscapedAndOddBits, potentialEscape, std::make_index_sequence{}); simd_int_t escapeAndTerminalCode = opXor(evenSeriesCodesAndOddBits, oddBitsVal); escaped = opXor(escapeAndTerminalCode, opOr(backslashes, nextIsEscaped)); nextIsEscaped = setLSB(nextIsEscaped, getMSB(opAnd(escapeAndTerminalCode, backslashes))); } - jsonifier_inline void collectEmptyEscaped() { + JSONIFIER_INLINE void collectEmptyEscaped() { auto escapedNew = nextIsEscaped; nextIsEscaped = simd_base::reset(); escaped = escapedNew; } - jsonifier_inline void collectEscapedCharacters() { + JSONIFIER_INLINE void collectEscapedCharacters() { return opBool(backslashes) ? collectNonEmptyEscaped() : collectEmptyEscaped(); } - jsonifier_inline void collectStructurals() { + JSONIFIER_INLINE void collectStructurals() { collectEscapedCharacters(); - quotes = bitAndNot(quotes, escaped); - simd_int_t inString = carrylessMultiplication(quotes, prevInString); + quotes = opAndNot(quotes, escaped); + simd_int_t inString = carrylessMultiplication(quotes, prevInString, std::make_index_sequence{}); simd_int_t stringTail = opXor(inString, quotes); simd_int_t scalar = opNot(opOr(op, whitespace)); - simd_int_t nonQuoteScalar = bitAndNot(scalar, quotes); + simd_int_t nonQuoteScalar = opAndNot(scalar, quotes); simd_int_t followsNonQuoteScalar = follows(nonQuoteScalar, overflow); - simd_int_t potentialScalarStart = bitAndNot(scalar, followsNonQuoteScalar); + simd_int_t potentialScalarStart = opAndNot(scalar, followsNonQuoteScalar); simd_int_t porentialStructuralStart = opOr(op, potentialScalarStart); - structurals = bitAndNot(porentialStructuralStart, stringTail); + structurals = opAndNot(porentialStructuralStart, stringTail); } - jsonifier_inline std::string collectEscapedCharactersWithErrorPrintOut(size_type errorIndex) { + JSONIFIER_INLINE std::string collectEscapedCharactersWithErrorPrintOut(size_type errorIndex) { if (opBool(backslashes)) { return collectNonEmptyEscapedWithErrorPrintOut(errorIndex); } else { @@ -262,7 +235,7 @@ namespace jsonifier_internal { } } - jsonifier_inline std::string generateJsonIndicesWithErrorPrintOut(size_type errorIndex) { + JSONIFIER_INLINE std::string generateJsonIndicesWithErrorPrintOut(size_type errorIndex) { std::string returnValue{}; while (stringBlockReader.hasFullBlock()) { returnValue += generateStructuralsWithErrorPrintOut(stringBlockReader.fullBlock(), errorIndex); @@ -274,13 +247,13 @@ namespace jsonifier_internal { return returnValue; } - jsonifier_inline std::string generateStructuralsWithErrorPrintOut(string_view_ptr valueNew, size_type errorIndex) { + JSONIFIER_INLINE std::string generateStructuralsWithErrorPrintOut(string_view_ptr values, size_type errorIndex) { std::stringstream returnValue{}; - collectStringValues(valueNew); - collectWhitespaceAsSimdBase(whitespace, newPtr); - collectBackslashesAsSimdBase(backslashes, newPtr); - collectStructuralsAsSimdBase(op, newPtr); - collectQuotesAsSimdBase(quotes, newPtr); + collectStringValues(values, std::make_index_sequence{}); + whitespace = collectWhitespaceAsSimdBase(newPtr, std::make_index_sequence{}); + backslashes = collectBackslashesAsSimdBase(newPtr, std::make_index_sequence{}); + op = collectStructuralsAsSimdBase(newPtr, std::make_index_sequence{}); + quotes = collectQuotesAsSimdBase(newPtr, std::make_index_sequence{}); if (stringIndex == errorIndex) { returnValue << "Whitespace Bits, for Index: " + std::to_string(stringIndex) + ": "; returnValue << printBits(whitespace).data(); @@ -295,17 +268,17 @@ namespace jsonifier_internal { if (stringIndex == errorIndex) { returnValue << returnValueNew; } - addTapeValues(); + addTapeValues(std::make_index_sequence{}); stringIndex += BitsPerStep; return returnValue.str(); } - jsonifier_inline std::string collectNonEmptyEscapedWithErrorPrintOut(size_type errorIndex) noexcept { + JSONIFIER_INLINE std::string collectNonEmptyEscapedWithErrorPrintOut(size_type errorIndex) noexcept { std::stringstream returnValue{}; - simd_int_t potentialEscape = bitAndNot(backslashes, nextIsEscaped); - simd_int_t maybeEscaped = shl<1>(potentialEscape); + simd_int_t potentialEscape = opAndNot(backslashes, nextIsEscaped); + simd_int_t maybeEscaped = shl<1>(potentialEscape, std::make_index_sequence{}); simd_int_t maybeEscapedAndOddBits = opOr(maybeEscaped, oddBitsVal); - simd_int_t evenSeriesCodesAndOddBits = opSub(maybeEscapedAndOddBits, potentialEscape); + simd_int_t evenSeriesCodesAndOddBits = opSub(maybeEscapedAndOddBits, potentialEscape, std::make_index_sequence{}); simd_int_t escapeAndTerminalCode = opXor(evenSeriesCodesAndOddBits, oddBitsVal); escaped = opXor(escapeAndTerminalCode, opOr(backslashes, nextIsEscaped)); nextIsEscaped = setLSB(nextIsEscaped, getMSB(opAnd(escapeAndTerminalCode, backslashes))); @@ -320,24 +293,24 @@ namespace jsonifier_internal { returnValue << printBits(evenSeriesCodesAndOddBits).data(); returnValue << "Escape And Terminal Code Bits, for Index: " + std::to_string(stringIndex) + ": "; returnValue << printBits(escapeAndTerminalCode).data(); - returnValue << "Next Is Escaped Bits, for Index: " + std::to_string(stringIndex) + ": "; + returnValue << "Next indices Escaped Bits, for Index: " + std::to_string(stringIndex) + ": "; returnValue << printBits(nextIsEscaped).data(); } return returnValue.str(); } - jsonifier_inline std::string collectStructuralsWithErrorPrintOut(size_type errorIndex) { + JSONIFIER_INLINE std::string collectStructuralsWithErrorPrintOut(size_type errorIndex) { std::stringstream returnValue{}; std::string returnValueNew = collectEscapedCharactersWithErrorPrintOut(errorIndex); - quotes = bitAndNot(quotes, escaped); - simd_int_t inString = carrylessMultiplication(quotes, prevInString); + quotes = opAndNot(quotes, escaped); + simd_int_t inString = carrylessMultiplication(quotes, prevInString, std::make_index_sequence{}); simd_int_t stringTail = opXor(inString, quotes); simd_int_t scalar = opNot(opOr(op, whitespace)); - simd_int_t nonQuoteScalar = bitAndNot(scalar, quotes); + simd_int_t nonQuoteScalar = opAndNot(scalar, quotes); simd_int_t followsNonQuoteScalar = follows(nonQuoteScalar, overflow); - simd_int_t potentialScalarStart = bitAndNot(scalar, followsNonQuoteScalar); + simd_int_t potentialScalarStart = opAndNot(scalar, followsNonQuoteScalar); simd_int_t porentialStructuralStart = opOr(op, potentialScalarStart); - structurals = bitAndNot(porentialStructuralStart, stringTail); + structurals = opAndNot(porentialStructuralStart, stringTail); if (stringIndex == errorIndex) { returnValue << returnValueNew; returnValue << "Escaped Bits, for Index: " + std::to_string(stringIndex) + ": "; @@ -356,9 +329,9 @@ namespace jsonifier_internal { returnValue << printBits(nonQuoteScalar).data(); returnValue << "Follows NonQuote Scalar Bits, for Index: " + std::to_string(stringIndex) + ": "; returnValue << printBits(followsNonQuoteScalar).data(); - returnValue << "Potential Scalar Start Bits, for Index: " + std::to_string(stringIndex) + ": "; + returnValue << "Potential Scalar start Bits, for Index: " + std::to_string(stringIndex) + ": "; returnValue << printBits(potentialScalarStart).data(); - returnValue << "Potential Structural Start Bits, for Index: " + std::to_string(stringIndex) + ": "; + returnValue << "Potential Structural start Bits, for Index: " + std::to_string(stringIndex) + ": "; returnValue << printBits(porentialStructuralStart).data(); returnValue << "Final Bits, for Index: " + std::to_string(stringIndex) + ": "; returnValue << printBits(structurals).data(); diff --git a/Include/jsonifier/SimdStructuralIterator.hpp b/Include/jsonifier/SimdStructuralIterator.hpp new file mode 100644 index 000000000..1a112d7ac --- /dev/null +++ b/Include/jsonifier/SimdStructuralIterator.hpp @@ -0,0 +1,136 @@ +/* + 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 + +namespace jsonifier_internal { + + template class simd_structural_iterator { + public: + friend class derailleur; + + using iterator_concept = std::forward_iterator_tag; + using iterator_category = std::forward_iterator_tag; + using value_type = uint8_t; + using pointer_internal = string_view_ptr*; + using pointer = string_view_ptr; + using difference_type = std::ptrdiff_t; + using size_type = uint64_t; + + JSONIFIER_INLINE simd_structural_iterator() noexcept : selfRef{ initializeSelfRef() } {}; + + JSONIFIER_INLINE simd_structural_iterator& operator=(const simd_structural_iterator& other) noexcept { + if (this != &other) { + simd_structural_iterator{ other }.swap(*this); + } + return *this; + }; + + JSONIFIER_INLINE simd_structural_iterator(const simd_structural_iterator& other) noexcept + : selfRef{ initializeSelfRef() }, currentIndex(other.currentIndex), rootIndex(other.rootIndex) { + selfRef = *static_cast(this); + } + + JSONIFIER_INLINE value_type operator*() const { + return (*currentIndex) ? **currentIndex : defaultValue; + } + + JSONIFIER_INLINE pointer operator->() const { + return *currentIndex; + } + + JSONIFIER_INLINE simd_structural_iterator& operator++() { + ++currentIndex; + return *this; + } + + template JSONIFIER_INLINE void createError(std::source_location location = std::source_location::current()) { + selfRef.errors.emplace_back(jsonifier_internal::createError(*this, location)); + } + + JSONIFIER_INLINE simd_structural_iterator operator++(int32_t) { + simd_structural_iterator temp{ *this }; + ++(*this); + return temp; + } + + JSONIFIER_INLINE pointer getEndPtr() const { + auto newIndex = currentIndex; + while (*(newIndex + 1) != nullptr) { + ++newIndex; + } + return *newIndex; + } + + JSONIFIER_INLINE void reset(structural_index* rootIndexNew) { + currentIndex = rootIndexNew; + rootIndex = rootIndexNew; + } + + JSONIFIER_INLINE pointer getRootPtr() const { + return *rootIndex; + } + + JSONIFIER_INLINE typename jsonifier::string_base::pointer data() const { + return selfRef.stringBuffer.data(); + } + + JSONIFIER_INLINE void resize(size_type newSize) { + selfRef.stringBuffer.resize(newSize); + } + + JSONIFIER_INLINE size_type size() const { + return selfRef.stringBuffer.size(); + } + + JSONIFIER_INLINE buffer_string& getCurrentString() { + return selfRef.stringBuffer; + } + + JSONIFIER_INLINE size_type getCurrentStringIndex() const { + return static_cast((*currentIndex) - (*rootIndex)); + } + + JSONIFIER_INLINE bool operator==(const simd_structural_iterator&) const { + return !(*currentIndex); + } + + JSONIFIER_INLINE void swap(simd_structural_iterator& other) { + std::swap(currentIndex, other.currentIndex); + std::swap(rootIndex, other.rootIndex); + } + + protected: + second_derived_type& selfRef{ *static_cast(this) }; + static constexpr value_type defaultValue{ 0x00ll }; + pointer_internal currentIndex{}; + pointer_internal rootIndex{}; + + second_derived_type& initializeSelfRef() { + return *static_cast(this); + } + }; +} \ No newline at end of file diff --git a/Include/jsonifier/StrToD.hpp b/Include/jsonifier/StrToD.hpp new file mode 100644 index 000000000..5aa6f4974 --- /dev/null +++ b/Include/jsonifier/StrToD.hpp @@ -0,0 +1,481 @@ +/* + 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. +*/ +/// Note: Most of the code in this header was sampled from Glaze library: https://github.com/stephenberry/glaze +/// https://github.com/RealTimeChris/jsonifier +/// Nov 13, 2023 +#pragma once + +#include +#include + +#include +#include +#include +#include + +#if defined(_M_X64) || defined(_M_ARM64) + #include +#endif + +namespace jsonifier_internal { + +// https://stackoverflow.com/questions/28868367/getting-the-high-part-of-64-bit-integer-multiplication +#if defined(__SIZEOF_INT128__) + JSONIFIER_INLINE 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); + #pragma GCC diagnostic pop + #else + unsigned __int128 prod = a * static_cast(b); + #endif + return prod >> 64; + } +#elif defined(_M_X64) || defined(_M_ARM64) + #define mulhi64 __umulh +#else + JSONIFIER_INLINE uint64_t mulhi64(uint64_t a, uint64_t b) noexcept { + uint64_t aLo = a; + uint64_t aHi = a >> 32; + uint64_t bLo = b; + uint64_t bHi = b >> 32; + uint64_t axbHi = aHi * bHi; + uint64_t axbMid = aHi * bLo; + uint64_t bxaMid = bHi * aLo; + uint64_t axbLo = aLo * bLo; + uint64_t carryBit = axbMid + bxaMid + (axbLo >> 32) >> 32; + uint64_t multhi = axbHi + (axbMid >> 32) + (bxaMid >> 32) + carryBit; + return multhi; + } +#endif + + constexpr int64_t pow10SigTableMinExp = -343; + constexpr int64_t pow10SigTableMaxExp = 324; + constexpr int64_t pow10SigTableMinExact = 0; + constexpr int64_t pow10SigTableMaxExact = 27; + + JSONIFIER_INLINE uint64_t sig2FromExp10(uint64_t exp10) noexcept { + return pow10SigTable[exp10 - pow10SigTableMinExp]; + } + + JSONIFIER_INLINE int64_t exp2FromExp10(int64_t exp10) noexcept { + return (((exp10 * 217706 - 4128768) >> 16) + 126); + } + + constexpr uint8_t digiTypeZero = 1 << 0; + constexpr uint8_t digiTypeNonZero = 1 << 1; + constexpr uint8_t digiTypeNeg = 1 << 3; + constexpr uint8_t digiTypeDot = 1 << 4; + constexpr uint8_t digiTypeExp = 1 << 5; + + JSONIFIER_INLINE bool digiIsType(uint8_t d, uint8_t type) noexcept { + return (digiTable[d] & type) != 0; + } + + JSONIFIER_INLINE bool digiIsFp(uint8_t d) noexcept { + return digiIsType(d, uint8_t(digiTypeDot | digiTypeExp)); + } + + JSONIFIER_INLINE bool digiIsDigitOrFp(uint8_t d) noexcept { + return digiIsType(d, uint8_t(digiTypeZero | digiTypeNonZero | digiTypeDot | digiTypeExp)); + } + +#define repeat_in_1_18(x) \ + { x(1) x(2) x(3) x(4) x(5) x(6) x(7) x(8) x(9) x(10) x(11) x(12) x(13) x(14) x(15) x(16) x(17) x(18) } + + constexpr uint8_t eBit = static_cast(0x45u ^ 0x65u); + constexpr int64_t f64MaxDecExp = 308; + constexpr int64_t f64MinDecExp = (-324); + + consteval uint64_t ceillog2(uint64_t x) { + return x < 2 ? x : 1 + ceillog2(x >> 1); + } + + struct big_int_t final { + std::vector data = {}; + + big_int_t(uint64_t num) noexcept { + uint64_t lowerWord = num; + uint64_t upperWord = num >> 32; + if (upperWord > 0) { + data = { lowerWord, upperWord }; + } else { + data = { lowerWord }; + } + } + + void mulU32(uint64_t num) noexcept { + uint64_t carry = 0; + for (std::size_t x = 0; x < data.size(); x++) { + uint64_t res = data[x] * num + carry; + uint64_t lowerWord = res; + uint64_t upperWord = res >> 32; + data[x] = lowerWord; + carry = upperWord; + } + if (carry != 0) { + data.emplace_back(carry); + } + } + + void mulPow10(uint64_t pow10) noexcept { + for (; pow10 >= 9; pow10 -= 9) { + mulU32(static_cast(powersOfTenInt[9])); + } + if (pow10) { + mulU32(static_cast(powersOfTenInt[pow10])); + } + } + + void mulPow2(uint64_t exp) noexcept { + uint64_t shft = exp % 32; + uint64_t move = exp / 32; + uint64_t idx = static_cast(data.size()) - 1; + if (shft == 0) { + data.resize(data.size() + move); + for (; idx > 0; idx--) { + data[idx + move - 1] = data[idx - 1]; + } + while (move) + data[--move] = 0; + } else { + data.resize(data.size() + move + 1); + ++idx; + for (; idx > 0; idx--) { + uint64_t num = data[idx] << shft; + num |= data[idx - 1] >> (32 - shft); + data[idx + move] = num; + } + data[move] = data[0] << shft; + if (data.back() == 0) + data.pop_back(); + while (move) + data[--move] = 0; + } + } + + auto operator<=>(const big_int_t& rhs) const noexcept { + if (data.size() < rhs.data.size()) + return -1; + if (data.size() > rhs.data.size()) + return 1; + for (auto x = data.size() - 1; x > 0; --x) { + ; + if (data[x] < rhs.data[x]) + return -1; + if (data[x] > rhs.data[x]) + return 1; + } + return 0; + } + }; + + template JSONIFIER_INLINE bool parseNumber(value_type01& value, char_type* cur) noexcept { + [[maybe_unused]] const char_type* sigEnd{}; + const char_type *tmp{}, *sigCut{}, *dotPos{}, *hdr{ cur }; + uint64_t fracZeros{}, numTmp{}, sig{}; + int64_t exp{}, expSig{}, expLit{}; + bool sign{ (*hdr == 0x2Du) }, expSign{}; + cur += sign; + auto applySign = [&](auto&& value) -> value_type01 { + return sign ? -static_cast(value) : static_cast(value); + }; + + sig = static_cast(asciiToValueTable[static_cast(*cur)]); + if (sig > 9) { + if (*cur == 0x6Eu && cur[1] == 0x75u && cur[2] == 0x6Cu && cur[3] == 0x6Cu) { + cur += 4; + value = 0; + return true; + } else if ((*cur | eBit) == 0x6Eu && (cur[1] | eBit) == 0x61u && (cur[2] | eBit) == 0x6Eu) { + cur += 3; + value = sign ? -std::numeric_limits::quiet_NaN() : std::numeric_limits::quiet_NaN(); + return true; + } else { + return false; + } + } + constexpr auto zero = static_cast(0x30u); +#define expr_intg(x) \ + if ((numTmp = static_cast(asciiToValueTable[static_cast(cur[x])])) <= 9) [[likely]] \ + sig = numTmp + sig * 10; \ + else { \ + if (*cur == zero) \ + return false; \ + goto digi_sepr_##x; \ + } + repeat_in_1_18(expr_intg); +#undef expr_intg + if (*cur == zero) [[unlikely]] { + return false; + } + cur += 19; + if (!digiIsDigitOrFp(static_cast(*cur))) { + value = static_cast(sig); + if constexpr (!std::unsigned_integral) { + value *= sign ? -1 : 1; + } + return true; + } + goto digi_intg_more; +#define expr_sepr(x) \ + digi_sepr_##x : if ((!digiIsFp(static_cast(cur[x])))) [[likely]] { \ + cur += x; \ + value = applySign(sig); \ + return true; \ + } \ + dotPos = cur + x; \ + if ((cur[x] == 0x2Eu)) [[likely]] { \ + if (sig == 0) \ + while (cur[fracZeros + x + 1] == zero) \ + ++fracZeros; \ + goto digi_frac_##x; \ + } \ + cur += x; \ + sigEnd = cur; \ + goto digi_exp_more; + repeat_in_1_18(expr_sepr) +#undef expr_sepr +#define expr_frac(x) \ + digi_frac_##x : if (numTmp = static_cast(asciiToValueTable[cur[x + 1 + fracZeros]]); numTmp <= 9) [[likely]] sig = numTmp + sig * 10; \ + else { \ + goto digi_stop_##x; \ + } + repeat_in_1_18(expr_frac) +#undef expr_frac + cur += 20ull + fracZeros; + if (asciiToValueTable[static_cast(*cur)] > 9) + goto digi_frac_end; + goto digi_frac_more; +#define expr_stop(x) \ + digi_stop_##x : cur += x + 1 + fracZeros; \ + goto digi_frac_end; + repeat_in_1_18(expr_stop) +#undef expr_stop + digi_intg_more : static constexpr uint64_t u64Max = (std::numeric_limits::max)(); + if (numTmp = static_cast(asciiToValueTable[static_cast(*cur)]); numTmp < 10) { + if (!digiIsDigitOrFp(static_cast(cur[1]))) { + if ((sig < (u64Max / 10)) || (sig == (u64Max / 10) && numTmp <= (u64Max % 10))) { + sig = numTmp + sig * 10; + cur++; + value = static_cast(sig); + if constexpr (!std::unsigned_integral) { + value *= sign ? -1 : 1; + } + return true; + } + } + } + if ((eBit | *cur) == 0x65u) { + dotPos = cur; + goto digi_exp_more; + } + if (*cur == 0x2Eu) { + dotPos = cur++; + if (asciiToValueTable[static_cast(*cur)] > 9) { + return false; + } + } + digi_frac_more: + sigCut = cur; + sig += (*cur >= 0x35u); + while (asciiToValueTable[*++cur] < 10) { + } + if (!dotPos) { + dotPos = cur; + if (*cur == 0x2Eu) { + if (asciiToValueTable[*++cur] > 9) { + return false; + } + while (asciiToValueTable[*++cur] < 10) { + } + } + } + expSig = static_cast(dotPos - sigCut); + expSig += (dotPos < sigCut); + tmp = cur - 1; + while (*tmp == 0x30u || *tmp == 0x2Eu) { + --tmp; + } + if (tmp < sigCut) { + sigCut = nullptr; + } else { + sigEnd = cur; + } + if ((eBit | *cur) == 0x65u) + goto digi_exp_more; + goto digi_exp_finish; + digi_frac_end: + sigEnd = cur; + expSig = -int64_t((cur - dotPos) - 1); + if (expSig == 0) { + return false; + } + if ((eBit | *cur) != 0x65u) [[likely]] { + if (expSig < f64MinDecExp - 19) [[unlikely]] { + value = applySign(0); + return true; + } + exp = expSig; + goto digi_finish; + } else { + goto digi_exp_more; + } + digi_exp_more : { + expSign = (*++cur == 0x2Du); + cur += (*cur == 0x2Bu || *cur == 0x2Du); + if (asciiToValueTable[static_cast(*cur)] > 9) [[unlikely]] { + return false; + } + while (*cur == 0x30u) { + ++cur; + } + tmp = cur; + uint8_t c{}; + while (c < 10) { + c = static_cast(asciiToValueTable[static_cast(*cur)]); + ++cur; + expLit = c + int64_t(expLit) * 10; + } + if (cur - tmp >= 6) [[unlikely]] { + if (sig == 0 || expSign) { + value = applySign(0); + value = static_cast(sig); + return true; + } else { + value = applySign(std::numeric_limits::infinity()); + return true; + } + } + expSig += expSign ? -expLit : expLit; + } + digi_exp_finish: + if (sig == 0) { + value = (sign ? -value_type01{ 0 } : value_type01{ 0 }); + return true; + } + if (expSig < f64MinDecExp - 19) [[unlikely]] { + value = (sign ? -value_type01{ 0 } : value_type01{ 0 }); + return true; + } else if (expSig > f64MaxDecExp) [[unlikely]] { + value = sign ? -std::numeric_limits::infinity() : std::numeric_limits::infinity(); + return true; + } + exp = expSig; + digi_finish: + + if constexpr (std::same_as) { + if (sig < (uint64_t(1) << 53) && std::abs(exp) <= 22) { + value = static_cast(sig); + if constexpr (!std::unsigned_integral) { + value *= sign ? -1 : 1; + } + if (exp >= 0 && exp < 23) { + value *= static_cast(powersOfTenFloat[exp]); + } else if (-exp < 23) { + value /= static_cast(powersOfTenFloat[-exp]); + } + return true; + } + } else { + if (sig < (uint64_t(1) << 24) && std::abs(exp) <= 8) { + value = static_cast(sig); + if constexpr (!std::unsigned_integral) { + value *= sign ? -1 : 1; + } + if (exp >= 0 && exp < 23) { + value *= static_cast(powersOfTenFloat[exp]); + } else if (-exp < 23) { + value /= static_cast(powersOfTenFloat[-exp]); + } + return true; + } + } + + if (sig == 0) [[unlikely]] { + value = value_type01(0); + 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(sizeof(float) == 4 && sizeof(double) == 8); + + const auto sigLeadingZeros = std::countl_zero(sig); + const auto sigNorm = sig << sigLeadingZeros; + const auto sig2Norm = sig2FromExp10(static_cast(exp)); + const auto sigProduct = mulhi64(sigNorm, sig2Norm) + 1; + const auto sigProductStartsWith1 = sigProduct >> 63; + auto mantisa = sigProduct << (2 - sigProductStartsWith1); + constexpr uint64_t roundMask = uint64_t(1) << 63 >> (std::numeric_limits::digits - 1); + constexpr uint64_t exponentBits = ceillog2(std::numeric_limits::max_exponent - std::numeric_limits::min_exponent + 1); + constexpr uint64_t mantissaShift = exponentBits + 1 + 64 - 8 * sizeof(uint64_t); + int64_t exp2 = static_cast(exp2FromExp10(exp) + static_cast(-sigLeadingZeros + sigProductStartsWith1)); + + if (exp2 < std::numeric_limits::min_exponent - 1) [[unlikely]] { + value = sign ? -value_type01(0) : value_type01(0); + return true; + } else if (exp2 > std::numeric_limits::max_exponent - 1) [[unlikely]] { + value = 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) { + auto sig_upper = (mantisa >> (mantissaShift - 1)) | (uint64_t(1) << 63 >> (mantissaShift - 2)) | 1; + int64_t exp2_upper = exp2 - std::numeric_limits::digits; + + big_int_t big_comp{ sig_upper }; + big_int_t big_full{ sig }; + if (exp >= 0) { + big_full.mulPow10(static_cast(exp)); + } else { + big_comp.mulPow10(static_cast(-exp)); + } + if (exp2_upper >= 0) { + big_comp.mulPow2(static_cast(exp2_upper)); + } else { + big_full.mulPow2(static_cast(-exp2_upper)); + } + auto cmp = big_full <=> big_comp; + if (cmp != 0) [[likely]] { + round = (cmp > 0); + } else { + round = (mantisa & (roundMask << 1)) != 0; + } + } else if ((exp < pow10SigTableMinExact || exp > pow10SigTableMaxExact) || (mantisa & (roundMask << 1)) || + (static_cast(std::countr_zero(sigNorm)) + static_cast(std::countr_zero(sig2Norm)) < + 128 - std::numeric_limits::digits - (2 - sigProductStartsWith1))) { + round = 1; + } + } + + auto num = uint64_t(sign) << (sizeof(uint64_t) * 8 - 1) | uint64_t(mantisa >> mantissaShift) | + (uint64_t(exp2 + std::numeric_limits::max_exponent - 1) << (std::numeric_limits::digits - 1)); + num += uint64_t(round); + std::memcpy(&value, &num, sizeof(value_type01)); + return true; + } +} \ No newline at end of file diff --git a/Include/jsonifier/StrToI.hpp b/Include/jsonifier/StrToI.hpp new file mode 100644 index 000000000..e5230e840 --- /dev/null +++ b/Include/jsonifier/StrToI.hpp @@ -0,0 +1,392 @@ +/* + 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. +*/ +/// Note: Most of the code in this header was sampled from Glaze library: https://github.com/stephenberry/glaze +/// https://github.com/RealTimeChris/jsonifier +/// Nov 13, 2023 +#pragma once + +#include +#include + +#include +#include +#include +#include + +namespace jsonifier_internal { + + template JSONIFIER_INLINE bool parseNumber(value_type01& value, char_type* cur) { + [[maybe_unused]] const char_type* sigEnd{}; + const char_type *tmp{}, *sigCut{}, *dotPos{}, *hdr{ cur }; + uint64_t fracZeros{}, numTmp{}, sig{}; + int64_t exp{}, expSig{}, expLit{}; + bool sign{ (*hdr == 0x2Du) }, expSign{}; + auto applySign = [&](auto&& value) -> value_type01 { + return sign ? -static_cast(value) : static_cast(value); + }; + cur += sign; + sig = static_cast(asciiToValueTable[static_cast(*cur)]); + if (sig > 9) { + if (*cur == 0x6Eu && cur[1] == 0x75u && cur[2] == 0x6Cu && cur[3] == 0x6Cu) { + value = applySign(0); + return true; + } else if ((*cur | eBit) == 0x6Eu && (cur[1] | eBit) == 0x61u && (cur[2] | eBit) == 0x6Eu) { + value = applySign(std::numeric_limits::quiet_NaN()); + return true; + } else { + return false; + } + } + static constexpr auto zero = static_cast(0x30u); +#define expr_intg(x) \ + if (numTmp = static_cast(asciiToValueTable[static_cast(cur[x])]); numTmp <= 9) [[likely]] \ + sig = static_cast(numTmp) + sig * 10ull; \ + else { \ + goto digi_sepr_##x; \ + } + repeat_in_1_18(expr_intg); +#undef expr_intg + cur += 19; + if (!digiIsDigitOrFp(static_cast(*cur))) { + value = applySign(static_cast(sig)); + return true; + } + goto digi_intg_more; +#define expr_sepr(x) \ + digi_sepr_##x : if (!digiIsFp(static_cast(cur[x]))) [[likely]] { \ + cur += x; \ + value = applySign(static_cast(sig)); \ + return true; \ + } \ + dotPos = cur + x; \ + if (cur[x] == 0x2Eu) [[likely]] { \ + if (sig == 0) \ + while (cur[fracZeros + x + 1] == static_cast(zero)) \ + ++fracZeros; \ + goto digi_frac_##x; \ + } \ + cur += x; \ + sigEnd = cur; \ + goto digi_exp_more; + repeat_in_1_18(expr_sepr) +#undef expr_sepr +#define expr_frac(x) \ + digi_frac_##x : if (numTmp = static_cast(asciiToValueTable[cur[x + 1 + fracZeros]]); numTmp <= 9) [[likely]] sig = numTmp + sig * 10; \ + else { \ + goto digi_stop_##x; \ + } + repeat_in_1_18(expr_frac) +#undef expr_frac + cur += 20ull + fracZeros; + if (asciiToValueTable[static_cast(*cur)] > 9) + goto digi_frac_end; + goto digi_frac_more; +#define expr_stop(x) \ + digi_stop_##x : cur += x##ull + 1ull + fracZeros; \ + goto digi_frac_end; + repeat_in_1_18(expr_stop) +#undef expr_stop + digi_intg_more : static constexpr uint64_t uint64_tMax = std::numeric_limits::max(); + if (numTmp = static_cast(asciiToValueTable[static_cast(*cur)]); numTmp < 10) { + if (!digiIsDigitOrFp(static_cast(cur[1]))) { + if ((sig < (uint64_tMax / 10)) || (sig == (uint64_tMax / 10) && numTmp <= (uint64_tMax % 10))) { + sig = numTmp + sig * 10; + ++cur; + value = applySign(static_cast(sig)); + return true; + } + } + } + if ((eBit | *cur) == 0x65u) { + dotPos = cur; + goto digi_exp_more; + } + if (*cur == 0x2Eu) { + dotPos = cur++; + if (asciiToValueTable[static_cast(*cur)] > 9) { + return false; + } + } + digi_frac_more: + sigCut = cur; + sig += (*cur >= 0x35u); + while (asciiToValueTable[*++cur] < 10) { + } + if (!dotPos) { + dotPos = cur; + if (*cur == 0x2Eu) { + if (asciiToValueTable[*++cur] > 9) { + return false; + } + while (asciiToValueTable[*++cur] < 10) { + } + } + } + expSig = static_cast(dotPos - sigCut); + expSig += (dotPos < sigCut); + tmp = cur - 1; + while (*tmp == 0x30u || *tmp == 0x2Eu) + tmp--; + if (tmp < sigCut) { + sigCut = nullptr; + } + if ((eBit | *cur) == 0x65u) + goto digi_exp_more; + goto digi_exp_finish; + digi_frac_end: + expSig = -int64_t((cur - dotPos) - 1); + if ((eBit | *cur) != 0x65u) [[likely]] { + if (expSig < f64MinDecExp - 19) [[unlikely]] { + value = applySign(0); + return true; + } + exp = expSig; + goto digi_finish; + } else { + goto digi_exp_more; + } + digi_exp_more : { + expSign = (*++cur == 0x2Du); + cur += (*cur == 0x2Bu || *cur == 0x2Du); + if (asciiToValueTable[static_cast(*cur)] > 9) [[unlikely]] { + goto digi_finish; + } + while (*cur == 0x30u) + ++cur; + tmp = cur; + uint8_t c{}; + while (c < 10) { + c = static_cast(asciiToValueTable[static_cast(*cur)]); + ++cur; + expLit = c + int64_t(expLit) * 10; + } + if (cur - tmp >= 6) [[unlikely]] { + if (sig == 0 || expSign) { + value = applySign(sig); + return true; + } else { + value = applySign(std::numeric_limits::infinity()); + return true; + } + } + expSig += expSign ? -expLit : expLit; + } + + digi_exp_finish: + if (sig == 0) { + value = applySign(!sign ? -0 : 0); + return true; + } + if (expSig < -20) { + value = applySign(0); + return true; + } else if (expSig > 20) { + value = applySign(std::numeric_limits::infinity()); + return true; + } + exp = expSig; + digi_finish: + + value = applySign(sig); + if (exp >= 0 && exp < 20) { + value *= applySign(powersOfTenInt[exp]); + } else if (exp > -20 && exp < 0) { + value /= applySign(powersOfTenInt[-exp]); + } + return true; + } + + template JSONIFIER_INLINE bool parseNumber(value_type01& value, char_type* cur) { + [[maybe_unused]] const char_type* sigEnd{}; + const char_type *tmp{}, *sigCut{}, *dotPos{}; + uint64_t fracZeros{}, numTmp{}, sig{}; + int64_t exp{}, expSig{}, expLit{}; + sig = static_cast(asciiToValueTable[static_cast(*cur)]); + if (sig > 9) { + if (*cur == 0x6Eu && cur[1] == 0x75u && cur[2] == 0x6Cu && cur[3] == 0x6Cu) { + value = static_cast(0); + return true; + } else if ((*cur | eBit) == 0x6Eu && (cur[1] | eBit) == 0x61u && (cur[2] | eBit) == 0x6Eu) { + value = static_cast(std::numeric_limits::quiet_NaN()); + return true; + } else { + return false; + } + } + static constexpr auto zero = static_cast(0x30u); +#define expr_intg(x) \ + if (numTmp = static_cast(asciiToValueTable[static_cast(cur[x])]); numTmp <= 9) [[likely]] \ + sig = static_cast(numTmp) + sig * 10ull; \ + else { \ + goto digi_sepr_##x; \ + } + repeat_in_1_18(expr_intg); +#undef expr_intg + cur += 19; + if (!digiIsDigitOrFp(static_cast(*cur))) { + value = static_cast(static_cast(sig)); + return true; + } + goto digi_intg_more; +#define expr_sepr(x) \ + digi_sepr_##x : if (!digiIsFp(static_cast(cur[x]))) [[likely]] { \ + cur += x; \ + value = static_cast(static_cast(sig)); \ + return true; \ + } \ + dotPos = cur + x; \ + if (cur[x] == 0x2Eu) [[likely]] { \ + if (sig == 0) \ + while (cur[fracZeros + x + 1] == static_cast(zero)) \ + ++fracZeros; \ + goto digi_frac_##x; \ + } \ + cur += x; \ + sigEnd = cur; \ + goto digi_exp_more; + repeat_in_1_18(expr_sepr) +#undef expr_sepr +#define expr_frac(x) \ + digi_frac_##x : if (numTmp = static_cast(asciiToValueTable[cur[x + 1 + fracZeros]]); numTmp <= 9) [[likely]] sig = numTmp + sig * 10; \ + else { \ + goto digi_stop_##x; \ + } + repeat_in_1_18(expr_frac) +#undef expr_frac + cur += 20ull + fracZeros; + if (asciiToValueTable[static_cast(*cur)] > 9) + goto digi_frac_end; + goto digi_frac_more; +#define expr_stop(x) \ + digi_stop_##x : cur += x##ull + 1ull + fracZeros; \ + goto digi_frac_end; + repeat_in_1_18(expr_stop) +#undef expr_stop + digi_intg_more : static constexpr uint64_t uint64_tMax = std::numeric_limits::max(); + if (numTmp = static_cast(asciiToValueTable[static_cast(*cur)]); numTmp < 10) { + if (!digiIsDigitOrFp(static_cast(cur[1]))) { + if ((sig < (uint64_tMax / 10)) || (sig == (uint64_tMax / 10) && numTmp <= (uint64_tMax % 10))) { + sig = numTmp + sig * 10; + ++cur; + value = static_cast(static_cast(sig)); + return true; + } + } + } + if ((eBit | *cur) == 0x65u) { + dotPos = cur; + goto digi_exp_more; + } + if (*cur == 0x2Eu) { + dotPos = cur++; + if (asciiToValueTable[static_cast(*cur)] > 9) { + return false; + } + } + digi_frac_more: + sigCut = cur; + sig += (*cur >= 0x35u); + while (asciiToValueTable[*++cur] < 10) { + } + if (!dotPos) { + dotPos = cur; + if (*cur == 0x2Eu) { + if (asciiToValueTable[*++cur] > 9) { + return false; + } + while (asciiToValueTable[*++cur] < 10) { + } + } + } + expSig = static_cast(dotPos - sigCut); + expSig += (dotPos < sigCut); + tmp = cur - 1; + while (*tmp == 0x30u || *tmp == 0x2Eu) + tmp--; + if (tmp < sigCut) { + sigCut = nullptr; + } + if ((eBit | *cur) == 0x65u) + goto digi_exp_more; + goto digi_exp_finish; + digi_frac_end: + expSig = -int64_t((cur - dotPos) - 1); + if ((eBit | *cur) != 0x65u) [[likely]] { + if (expSig < f64MinDecExp - 19) [[unlikely]] { + value = static_cast(0); + return true; + } + exp = expSig; + goto digi_finish; + } else { + goto digi_exp_more; + } + digi_exp_more : { + cur += (*cur == 0x2Bu || *cur == 0x2Du); + if (asciiToValueTable[static_cast(*cur)] > 9) [[unlikely]] { + goto digi_finish; + } + while (*cur == 0x30u) + ++cur; + tmp = cur; + uint8_t c{}; + while (c < 10) { + c = static_cast(asciiToValueTable[static_cast(*cur)]); + ++cur; + expLit = c + int64_t(expLit) * 10; + } + if (cur - tmp >= 6) [[unlikely]] { + if (sig == 0) { + value = static_cast(sig); + return true; + } else { + value = static_cast(std::numeric_limits::infinity()); + return true; + } + } + expSig += expLit; + } + + digi_exp_finish: + if (sig == 0) { + value = 0; + return true; + } + if (expSig < -20) { + value = static_cast(0); + return true; + } else if (expSig > 20) { + value = static_cast(std::numeric_limits::infinity()); + return true; + } + exp = expSig; + digi_finish: + + value = static_cast(sig); + if (exp >= 0 && exp < 20) { + value *= static_cast(powersOfTenInt[exp]); + } else if (exp > -20 && exp < 0) { + value /= static_cast(powersOfTenInt[-exp]); + } + return true; + } +} \ No newline at end of file diff --git a/Include/jsonifier/String.hpp b/Include/jsonifier/String.hpp index c83a0370e..cd90e39f5 100644 --- a/Include/jsonifier/String.hpp +++ b/Include/jsonifier/String.hpp @@ -28,7 +28,7 @@ namespace jsonifier_internal { - template jsonifier_constexpr bool stringConstCompare(const value_type01& string01, const value_type02& string02) { + template constexpr bool stringConstCompare(const value_type01& string01, const value_type02& string02) { if (string01.size() != string02.size()) [[unlikely]] { return false; } @@ -50,7 +50,7 @@ namespace jsonifier_internal { using const_pointer = const value_type*; using size_type = uint64_t; - static jsonifier_constexpr void move(pointer firstNew, pointer first2, size_type count) { + static constexpr void move(pointer firstNew, pointer first2, size_type count) { if (std::is_constant_evaluated()) { bool loopForward = true; @@ -75,10 +75,10 @@ namespace jsonifier_internal { std::memmove(firstNew, first2, count * sizeof(value_type)); } - static jsonifier_constexpr size_type length(const_pointer first) { + static constexpr size_type length(const_pointer first) { const_pointer newPtr = first; size_type count = 0; - while (newPtr && *newPtr != static_cast('\0')) { + while (newPtr && *newPtr != static_cast(0x00u)) { ++count; ++newPtr; } @@ -109,102 +109,89 @@ namespace jsonifier { using allocator = jsonifier_internal::alloc_wrapper; using traits_type = jsonifier_internal::char_traits; - jsonifier_inline string_base() : capacityVal{}, sizeVal{}, dataVal{} {}; + JSONIFIER_INLINE string_base() : capacityVal{}, sizeVal{}, dataVal{} {}; - static jsonifier_constexpr size_type bufSize = 16 / sizeof(value_type) < 1 ? 1 : 16 / sizeof(value_type); - static jsonifier_constexpr size_type npos{ std::numeric_limits::max() }; + static constexpr size_type bufSize = 16 / sizeof(value_type) < 1 ? 1 : 16 / sizeof(value_type); + static constexpr size_type npos{ std::numeric_limits::max() }; - jsonifier_inline string_base& operator=(string_base&& other) noexcept { + JSONIFIER_INLINE string_base& operator=(string_base&& other) noexcept { if (this != &other) { - reset(); - swap(other); + string_base{ other }.swap(*this); } return *this; } - jsonifier_inline explicit string_base(string_base&& other) noexcept : capacityVal{}, sizeVal{}, dataVal{} { - *this = std::move(other); - } + JSONIFIER_INLINE explicit string_base(string_base&& other) noexcept : capacityVal{}, sizeVal{}, dataVal{} { + swap(other); + }; - jsonifier_inline string_base& operator=(const string_base& other) { + JSONIFIER_INLINE string_base& operator=(const string_base& other) { if (this != &other) { - size_type sizeNew = other.size(); - if (sizeNew > 0 && sizeNew < maxSize()) { - reset(); - string_base temp{}; - temp.reserve(sizeNew); - temp.sizeVal = sizeNew; - std::uninitialized_copy(other.data(), other.data() + sizeNew, temp.dataVal); - getAlloc().construct(&temp[sizeNew], static_cast(0x00)); - swap(temp); - } + string_base{ other }.swap(*this); } return *this; } - jsonifier_inline string_base(const string_base& other) : capacityVal{}, sizeVal{}, dataVal{} { - *this = other; + JSONIFIER_INLINE string_base(const string_base& other) : capacityVal{}, sizeVal{}, dataVal{} { + size_type newSize = other.size(); + if (newSize > 0 && newSize < maxSize()) [[likely]] { + reserve(newSize); + sizeVal = newSize; + std::uninitialized_copy(other.data(), other.data() + newSize, dataVal); + allocator::construct(&(*this)[newSize], static_cast(0x00)); + } } - template jsonifier_inline string_base& operator=(value_type_newer&& other) { - size_type sizeNew = other.size() * (sizeof(typename jsonifier::concepts::unwrap::value_type) / sizeof(value_type)); - if (sizeNew > 0) { - reset(); - string_base temp{}; - temp.reserve(sizeNew); - temp.sizeVal = sizeNew; - std::uninitialized_copy(other.data(), other.data() + sizeNew, temp.dataVal); - getAlloc().construct(&temp[sizeNew], static_cast(0x00)); - swap(temp); - } + template JSONIFIER_INLINE string_base& operator=(const value_type_newer& other) { + string_base{ other }.swap(*this); return *this; } - template jsonifier_inline explicit string_base(value_type_newer&& other) : capacityVal{}, sizeVal{}, dataVal{} { - *this = std::forward(other); + template JSONIFIER_INLINE explicit string_base(const value_type_newer& other) : capacityVal{}, sizeVal{}, dataVal{} { + size_type newSize = other.size() * (sizeof(typename jsonifier::concepts::unwrap::value_type) / sizeof(value_type)); + if (newSize > 0 && newSize < maxSize()) [[likely]] { + reserve(newSize); + sizeVal = newSize; + std::uninitialized_copy(other.data(), other.data() + newSize, dataVal); + allocator::construct(&(*this)[newSize], static_cast(0x00)); + } } - template jsonifier_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(); - string_base temp{}; - temp.reserve(sizeNew); - temp.sizeVal = sizeNew; - std::uninitialized_copy(other, other + sizeNew, temp.dataVal); - getAlloc().construct(&temp[sizeNew], static_cast(0x00)); - swap(temp); - } + template JSONIFIER_INLINE string_base& operator=(value_type_newer other) { + string_base{ std::forward(other) }.swap(*this); return *this; } - template jsonifier_inline string_base(value_type_newer other) : capacityVal{}, sizeVal{}, dataVal{} { - *this = std::forward(other); + template JSONIFIER_INLINE string_base(value_type_newer other) : capacityVal{}, sizeVal{}, dataVal{} { + auto newSize = + jsonifier_internal::char_traits>::length(other) * (sizeof(std::remove_pointer_t) / sizeof(value_type)); + if (newSize > 0 && newSize < maxSize()) [[likely]] { + reserve(newSize); + sizeVal = newSize; + std::uninitialized_copy(other, other + newSize, dataVal); + allocator::construct(&(*this)[newSize], static_cast(0x00)); + } } - template jsonifier_inline string_base& operator=(value_type_newer other) { - push_back(static_cast(other)); + template JSONIFIER_INLINE string_base& operator=(value_type_newer other) { + pushBack(static_cast(other)); return *this; } - template jsonifier_inline string_base(value_type_newer other) : capacityVal{}, sizeVal{}, dataVal{} { + template JSONIFIER_INLINE string_base(value_type_newer other) : capacityVal{}, sizeVal{}, dataVal{} { *this = other; } - jsonifier_inline string_base(const_pointer other, uint64_t sizeNew) : capacityVal{}, sizeVal{}, dataVal{} { - if (sizeNew && sizeNew < maxSize()) [[likely]] { - reset(); - string_base temp{}; - temp.reserve(sizeNew); - temp.sizeVal = sizeNew; - std::uninitialized_copy(other, other + sizeNew, temp.dataVal); - getAlloc().construct(&temp[sizeNew], static_cast(0x00)); - swap(temp); + JSONIFIER_INLINE string_base(const_pointer other, uint64_t newSize) : capacityVal{}, sizeVal{}, dataVal{} { + if (newSize > 0 && newSize < maxSize()) [[likely]] { + reserve(newSize); + sizeVal = newSize; + std::uninitialized_copy(other, other + newSize, dataVal); + allocator::construct(&(*this)[newSize], static_cast(0x00)); } } - jsonifier_inline string_base substr(size_type position, size_type count = std::numeric_limits::max()) const { + JSONIFIER_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."); } @@ -219,45 +206,45 @@ namespace jsonifier { return result; } - jsonifier_constexpr static size_type maxSize() { + constexpr size_type maxSize() { const size_type allocMax = allocator::maxSize(); const size_type storageMax = std::max(allocMax, static_cast(bufSize)); return std::min(static_cast((std::numeric_limits::max)()), storageMax - 1); } - jsonifier_constexpr iterator begin() noexcept { + constexpr iterator begin() noexcept { return iterator{ dataVal }; } - jsonifier_constexpr iterator end() noexcept { + constexpr iterator end() noexcept { return iterator{ dataVal + sizeVal }; } - jsonifier_constexpr reverse_iterator rbegin() noexcept { + constexpr reverse_iterator rbegin() noexcept { return reverse_iterator{ end() }; } - jsonifier_constexpr reverse_iterator rend() noexcept { + constexpr reverse_iterator rend() noexcept { return reverse_iterator{ begin() }; } - jsonifier_constexpr const_iterator begin() const noexcept { + constexpr const_iterator begin() const noexcept { return const_iterator{ dataVal }; } - jsonifier_constexpr const_iterator end() const noexcept { + constexpr const_iterator end() const noexcept { return const_iterator{ dataVal + sizeVal }; } - jsonifier_constexpr const_reverse_iterator rbegin() const noexcept { + constexpr const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator{ end() }; } - jsonifier_constexpr const_reverse_iterator rend() const noexcept { + constexpr const_reverse_iterator rend() const noexcept { return const_reverse_iterator{ begin() }; } - jsonifier_inline size_type find(const_pointer args, size_type position = 0) const { + JSONIFIER_INLINE size_type find(const_pointer args, size_type position = 0) const { auto newSize = traits_type::length(args); if (position + newSize > sizeVal) { return npos; @@ -266,7 +253,7 @@ namespace jsonifier { return foundValue == npos ? npos : foundValue + position; } - template jsonifier_inline size_type find(value_type_newer args, size_type position = 0) const { + template JSONIFIER_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; @@ -275,7 +262,7 @@ namespace jsonifier { return foundValue == npos ? npos : foundValue + position; } - template jsonifier_inline size_type find(const value_type_newer& args, size_type position = 0) const { + template JSONIFIER_INLINE size_type find(const value_type_newer& args, size_type position = 0) const { if (position + args.size() > sizeVal) { return npos; } @@ -283,72 +270,72 @@ namespace jsonifier { return foundValue == npos ? npos : foundValue + position; } - template jsonifier_inline size_type findFirstOf(ArgTypes&&... args) const { - return operator std::basic_string_view().find_first_of(std::forward(args)...); + template JSONIFIER_INLINE size_type findFirstOf(arg_types&&... args) const { + return operator std::basic_string_view().find_first_of(std::forward(args)...); } - template jsonifier_inline size_type findLastOf(ArgTypes&&... args) const { - return operator std::basic_string_view().find_last_of(std::forward(args)...); + template JSONIFIER_INLINE size_type findLastOf(arg_types&&... args) const { + return operator std::basic_string_view().find_last_of(std::forward(args)...); } - template jsonifier_inline size_type findFirstNotOf(ArgTypes&&... args) const { - return operator std::basic_string_view().find_first_not_of(std::forward(args)...); + template JSONIFIER_INLINE size_type findFirstNotOf(arg_types&&... args) const { + return operator std::basic_string_view().find_first_not_of(std::forward(args)...); } - template jsonifier_inline size_type findLastNotOf(ArgTypes&&... args) const { - return operator std::basic_string_view().find_last_not_of(std::forward(args)...); + template JSONIFIER_INLINE size_type findLastNotOf(arg_types&&... args) const { + return operator std::basic_string_view().find_last_not_of(std::forward(args)...); } - jsonifier_inline void append(const string_base& sizeNew) { - if (sizeVal + sizeNew.size() >= capacityVal) { - reserve(sizeVal + sizeNew.size()); + JSONIFIER_INLINE void append(const string_base& newSize) { + if (sizeVal + newSize.size() >= capacityVal) { + reserve(sizeVal + newSize.size()); } - std::memcpy(dataVal + sizeVal, sizeNew.data(), sizeNew.size()); - sizeVal += sizeNew.size(); - getAlloc().construct(&dataVal[sizeVal], static_cast(0x00)); + std::memcpy(dataVal + sizeVal, newSize.data(), newSize.size()); + sizeVal += newSize.size(); + allocator::construct(&dataVal[sizeVal], static_cast(0x00)); } - template jsonifier_inline void append(value_type_newer* valuesNew, uint64_t sizeNew) { - if (sizeVal + sizeNew >= capacityVal) { - resize(sizeVal + sizeNew); + template JSONIFIER_INLINE void append(value_type_newer* values, uint64_t newSize) { + if (sizeVal + newSize >= capacityVal) { + resize(sizeVal + newSize); } - if (sizeNew > 0 && valuesNew) { - std::memcpy(dataVal + sizeVal, valuesNew, sizeNew); - sizeVal += sizeNew; - getAlloc().construct(&dataVal[sizeVal], static_cast(0x00)); + if (newSize > 0 && values) { + std::memcpy(dataVal + sizeVal, values, newSize); + sizeVal += newSize; + allocator::construct(&dataVal[sizeVal], static_cast(0x00)); } } - template jsonifier_inline void insert(Iterator01 where, Iterator02 start, Iterator02 end) { - int64_t sizeNew = end - start; + template JSONIFIER_INLINE void insert(Iterator01 where, Iterator02 start, Iterator02 end) { + int64_t newSize = end - start; auto posNew = where.operator->() - dataVal; - if (sizeNew <= 0) { + if (newSize <= 0) { return; } - if (sizeVal + sizeNew >= capacityVal) { - reserve(sizeVal + sizeNew); + if (sizeVal + newSize >= capacityVal) { + reserve(sizeVal + newSize); } - 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], static_cast(0x00)); + std::memmove(dataVal + posNew + newSize, dataVal + posNew, (sizeVal - posNew) * sizeof(value_type)); + std::memcpy(dataVal + posNew, start.operator->(), newSize * sizeof(value_type)); + sizeVal += newSize; + allocator::construct(&dataVal[sizeVal], static_cast(0x00)); } - jsonifier_inline void insert(iterator valuesNew, value_type toInsert) { - auto positionNew = valuesNew - begin(); + JSONIFIER_INLINE void insert(iterator values, value_type toInsert) { + auto positionNew = values - begin(); if (sizeVal + 1 >= capacityVal) { reserve((sizeVal + 1) * 2); } - auto sizeNew = sizeVal - positionNew; - std::memmove(dataVal + positionNew + 1, dataVal + positionNew, sizeNew * sizeof(value_type)); - getAlloc().construct(&dataVal[positionNew], toInsert); + auto newSize = sizeVal - positionNew; + std::memmove(dataVal + positionNew + 1, dataVal + positionNew, newSize * sizeof(value_type)); + allocator::construct(&dataVal[positionNew], toInsert); ++sizeVal; } - jsonifier_inline void erase(size_type count) { + JSONIFIER_INLINE void erase(size_type count) { if (count == 0) { return; } else if (count > sizeVal) { @@ -356,56 +343,56 @@ namespace jsonifier { } traits_type::move(dataVal, dataVal + count, sizeVal - count); sizeVal -= count; - getAlloc().construct(&dataVal[sizeVal], static_cast('\0')); + allocator::construct(&dataVal[sizeVal], static_cast(0x00u)); } - jsonifier_inline void erase(iterator count) { - auto sizeNew = count - dataVal; - if (sizeNew == 0) { + JSONIFIER_INLINE void erase(iterator count) { + auto newSize = count - dataVal; + if (newSize == 0) { return; - } else if (sizeNew > static_cast(sizeVal)) { - sizeNew = static_cast(sizeVal); + } else if (newSize > static_cast(sizeVal)) { + newSize = static_cast(sizeVal); } - traits_type::move(dataVal, dataVal + sizeNew, sizeVal - sizeNew); - sizeVal -= sizeNew; - getAlloc().construct(&dataVal[sizeVal], static_cast('\0')); + traits_type::move(dataVal, dataVal + newSize, sizeVal - newSize); + sizeVal -= newSize; + allocator::construct(&dataVal[sizeVal], static_cast(0x00u)); } - jsonifier_inline void push_back(value_type value) { + JSONIFIER_INLINE void pushBack(value_type value) { if (sizeVal + 1 >= capacityVal) { reserve((sizeVal + 2) * 4); } - getAlloc().construct(&dataVal[sizeVal++], value); - getAlloc().construct(&dataVal[sizeVal], static_cast(0x00)); + allocator::construct(&dataVal[sizeVal++], value); + allocator::construct(&dataVal[sizeVal], static_cast(0x00)); } - jsonifier_inline const_reference at(size_type index) const { + JSONIFIER_INLINE const_reference at(size_type index) const { if (index >= sizeVal) { throw std::runtime_error{ "Sorry, but that index is beyond the end of this string." }; } return dataVal[index]; } - jsonifier_inline reference at(size_type index) { + JSONIFIER_INLINE reference at(size_type index) { if (index >= sizeVal) { throw std::runtime_error{ "Sorry, but that index is beyond the end of this string." }; } return dataVal[index]; } - jsonifier_inline const_reference operator[](size_type index) const { + JSONIFIER_INLINE const_reference operator[](size_type index) const { return dataVal[index]; } - jsonifier_inline reference operator[](size_type index) { + JSONIFIER_INLINE reference operator[](size_type index) { return dataVal[index]; } - jsonifier_inline operator std::basic_string_view() const { + JSONIFIER_INLINE operator std::basic_string_view() const { return { dataVal, sizeVal }; } - template jsonifier_inline explicit operator std::basic_string() const { + template JSONIFIER_INLINE explicit operator std::basic_string() const { std::basic_string returnValue{}; if (sizeVal > 0) { returnValue.resize(sizeVal); @@ -414,82 +401,99 @@ namespace jsonifier { return returnValue; } - jsonifier_inline void clear() { + template JSONIFIER_INLINE explicit operator string_base() const { + string_base returnValue{}; + if (sizeVal > 0) { + returnValue.resize(sizeVal); + std::memcpy(returnValue.data(), data(), returnValue.size()); + } + return returnValue; + } + + virtual JSONIFIER_INLINE void clear() { + if (sizeVal > 0) { + allocator::construct(dataVal, static_cast(0x00u)); + } sizeVal = 0; } - jsonifier_inline void resize(size_type sizeNew) { - if (sizeNew > 0) [[likely]] { - auto sizeNewer = jsonifier_internal::roundUpToMultiple(sizeNew); - if (sizeNewer > capacityVal) [[likely]] { - pointer newPtr = getAlloc().allocate(sizeNewer + 1); + JSONIFIER_INLINE void resize(size_type newSize) { + if (newSize > 0) [[likely]] { + if (newSize > capacityVal) { + pointer newPtr = allocator::allocate(newSize + 1); try { if (dataVal) [[likely]] { if (sizeVal > 0) { std::uninitialized_move(dataVal, dataVal + sizeVal, newPtr); } - getAlloc().deallocate(dataVal, capacityVal + 1); + allocator::deallocate(dataVal, capacityVal + 1); } } catch (...) { - getAlloc().deallocate(newPtr, sizeNewer + 1); + allocator::deallocate(newPtr, newSize + 1); throw; } - capacityVal = sizeNewer; + capacityVal = newSize; dataVal = newPtr; - std::uninitialized_fill(dataVal + sizeVal, dataVal + capacityVal, value_type{}); - } else if (sizeNewer > sizeVal) [[unlikely]] { - std::uninitialized_fill(dataVal + sizeVal, dataVal + capacityVal, value_type{}); + allocator::construct(newPtr + newSize, value_type{}); + sizeVal = newSize; + } else if (newSize > sizeVal) { + std::fill(dataVal + sizeVal, dataVal + newSize, value_type{}); + allocator::construct(dataVal + newSize, value_type{}); + sizeVal = newSize; + + } else if (newSize < sizeVal) { + std::destroy(dataVal + newSize, dataVal + sizeVal); + allocator::construct(dataVal + newSize, value_type{}); + sizeVal = newSize; } - sizeVal = sizeNew; - getAlloc().construct(&dataVal[sizeVal], static_cast(0x00)); } else { + std::destroy(dataVal, dataVal + sizeVal); sizeVal = 0; } } - jsonifier_inline void reserve(size_type capacityNew) { - size_type capacityNewer = jsonifier_internal::roundUpToMultiple(capacityNew); - if (capacityNewer > capacityVal) [[likely]] { - pointer newPtr = getAlloc().allocate(capacityNewer + 1); + JSONIFIER_INLINE void reserve(size_type capacityNew) { + if (capacityNew > capacityVal) [[likely]] { + pointer newPtr = allocator::allocate(capacityNew + 1); try { if (dataVal) [[likely]] { if (sizeVal > 0) { std::uninitialized_move(dataVal, dataVal + sizeVal, newPtr); } - getAlloc().deallocate(dataVal, capacityVal + 1); + allocator::deallocate(dataVal, capacityVal + 1); } } catch (...) { - getAlloc().deallocate(newPtr, capacityNewer + 1); + allocator::deallocate(newPtr, capacityNew + 1); throw; } - capacityVal = capacityNewer; + capacityVal = capacityNew; dataVal = newPtr; - getAlloc().construct(&dataVal[sizeVal], static_cast(0x00)); + allocator::construct(&dataVal[sizeVal], static_cast(0x00)); } } - jsonifier_inline size_type capacity() const { + constexpr size_type capacity() const { return capacityVal; } - jsonifier_inline size_type size() const { + constexpr size_type size() const { return sizeVal; } - jsonifier_inline bool empty() const { + constexpr bool empty() const { return sizeVal == 0; } - jsonifier_inline pointer data() const { + constexpr pointer data() const { return dataVal; } - jsonifier_inline pointer data() { + constexpr pointer data() { return dataVal; } template - jsonifier_inline friend std::enable_if_t, bool> operator==(const string_base& lhs, const value_type_newer& rhs) { + JSONIFIER_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; @@ -497,90 +501,90 @@ namespace jsonifier { return jsonifier_internal::jsonifier_core_internal::compare(rhs, lhs.data(), rhsLength); } - template jsonifier_inline friend bool operator==(const string_base& lhs, const value_type_newer& rhs) { + template JSONIFIER_INLINE friend bool operator==(const string_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()); } - jsonifier_inline void swap(string_base& other) { + template JSONIFIER_INLINE void swap(string_base_new&& other) { std::swap(capacityVal, other.capacityVal); std::swap(sizeVal, other.sizeVal); std::swap(dataVal, other.dataVal); } - template jsonifier_inline friend string_base operator+(const value_type_newer (&lhs)[size], const string_base& rhs) { + template JSONIFIER_INLINE friend string_base operator+(const value_type_newer (&lhs)[size], const string_base& rhs) { string_base newLhs{ lhs }; newLhs += rhs; return newLhs; } - template jsonifier_inline friend string_base operator+=(const value_type_newer (&lhs)[size], const string_base& rhs) { + template JSONIFIER_INLINE friend string_base operator+=(const value_type_newer (&lhs)[size], const string_base& rhs) { string_base newLhs{ lhs }; newLhs += rhs; return newLhs; } - template jsonifier_inline friend string_base operator+(string_type_new&& lhs, const string_base& rhs) { + template JSONIFIER_INLINE friend string_base operator+(string_type_new&& lhs, const string_base& rhs) { string_base newLhs{ lhs }; newLhs += rhs; return newLhs; } - template jsonifier_inline friend string_base operator+=(string_type_new&& lhs, const string_base& rhs) { + template JSONIFIER_INLINE friend string_base operator+=(string_type_new&& lhs, const string_base& rhs) { string_base newLhs{ lhs }; newLhs += rhs; return newLhs; } - jsonifier_inline string_base operator+(const value_type& rhs) { + JSONIFIER_INLINE string_base operator+(const value_type& rhs) { string_base newLhs{ *this }; - newLhs.push_back(rhs); + newLhs.pushBack(rhs); return newLhs; } - jsonifier_inline string_base& operator+=(const value_type& rhs) { - push_back(rhs); + JSONIFIER_INLINE string_base& operator+=(const value_type& rhs) { + pushBack(rhs); return *this; } - template jsonifier_inline string_base operator+(const string_type_new& rhs) const { + template JSONIFIER_INLINE string_base operator+(const string_type_new& rhs) const { string_base newLhs{ *this }; newLhs += rhs; return newLhs; } - template jsonifier_inline string_base& operator+=(const string_type_new& rhs) { + template JSONIFIER_INLINE string_base& operator+=(const string_type_new& rhs) { append(static_cast(rhs)); return *this; } - template jsonifier_inline string_base operator+(string_type_new&& rhs) { + template JSONIFIER_INLINE string_base operator+(string_type_new&& rhs) { string_base newLhs{ *this }; newLhs += rhs; return newLhs; } - template jsonifier_inline string_base& operator+=(string_type_new&& rhs) { + template JSONIFIER_INLINE string_base& operator+=(string_type_new&& rhs) { string_base newRhs{ rhs }; *this += newRhs; return *this; } - template jsonifier_inline string_base operator+(const value_type_newer (&rhs)[size]) const { + template JSONIFIER_INLINE string_base operator+(const value_type_newer (&rhs)[size]) const { string_base newLhs{ *this }; newLhs += rhs; return newLhs; } - template jsonifier_inline string_base& operator+=(const value_type_newer (&rhs)[size]) { + template JSONIFIER_INLINE string_base& operator+=(const value_type_newer (&rhs)[size]) { string_base newRhs{ rhs }; *this += newRhs; return *this; } - jsonifier_inline ~string_base() { + virtual JSONIFIER_INLINE ~string_base() { reset(); } @@ -589,17 +593,13 @@ namespace jsonifier { size_type sizeVal{}; pointer dataVal{}; - jsonifier_inline allocator& getAlloc() { - return *this; - } - - jsonifier_inline void reset() { + JSONIFIER_INLINE void reset() { if (dataVal && capacityVal) { if (sizeVal) { std::destroy(dataVal, dataVal + sizeVal); sizeVal = 0; } - getAlloc().deallocate(dataVal, capacityVal + 1); + allocator::deallocate(dataVal, capacityVal + 1); dataVal = nullptr; capacityVal = 0; } @@ -608,7 +608,7 @@ namespace jsonifier { using string = string_base; - template jsonifier_inline std::ostream& operator<<(std::ostream& os, const string_base& string) { + template JSONIFIER_INLINE std::ostream& operator<<(std::ostream& os, const string_base& string) { os << string.operator typename std::string(); return os; } @@ -618,9 +618,37 @@ namespace jsonifier_internal { template class buffer_string : public jsonifier::string_base { public: - jsonifier_inline buffer_string() { - jsonifier::string_base::resize(16384); + using base = jsonifier::string_base; + using value_type = base::value_type; + using pointer = base::pointer; + using const_pointer = base::const_pointer; + using reference = base::reference; + using const_reference = base::const_reference; + using difference_type = base::difference_type; + using iterator = base::iterator; + using const_iterator = base::const_iterator; + using reverse_iterator = base::reverse_iterator; + using const_reverse_iterator = base::const_reverse_iterator; + using size_type = base::size_type; + using allocator = base::allocator; + using traits_type = base::traits_type; + + JSONIFIER_INLINE buffer_string() { + base::resize(16384); + }; + + JSONIFIER_INLINE void clear() override { + base::sizeVal = 0; } }; + template struct hash> { + JSONIFIER_INLINE uint64_t operator()(const buffer_string& value, uint64_t seed) const { + return fnv1aHash(value, seed); + } + + JSONIFIER_INLINE uint64_t operator()(const buffer_string& value, uint64_t seed) const { + return fnv1aHash(value, seed); + } + }; } \ No newline at end of file diff --git a/Include/jsonifier/StringUtils.hpp b/Include/jsonifier/StringUtils.hpp index b8933b0d6..28fbc93c6 100644 --- a/Include/jsonifier/StringUtils.hpp +++ b/Include/jsonifier/StringUtils.hpp @@ -21,7 +21,7 @@ */ /// https://github.com/RealTimeChris/jsonifier /// Feb 3, 2023 -/// Most of the code in this header was sampled from simdjson - https://github.com/simdjson +/// A lot of the code in this header was sampled from simdjson - https://github.com/simdjson #pragma once #include @@ -31,183 +31,210 @@ namespace jsonifier_internal { - class backslash_and_quote { + template class backslash_and_quote; + + template<> class backslash_and_quote { public: - template jsonifier_inline static backslash_and_quote copyAndFind(const source_type* source, dest_type* destString) { - auto values = gatherValuesU(source); - storeu(values, destString); - backslash_and_quote returnData{}; - returnData.bsOrQuoteBits = simd_base::cmpeq(values, backslashes128); - returnData.bsOrQuoteBits |= simd_base::cmpeq(values, quotes128); - return returnData; + template JSONIFIER_INLINE static string_parsing_type copyAndFind(const char_type01* source, char_type02* dest) { + simd_int_t values(gatherValuesU(source)); + storeu(values, dest); + return static_cast(simd_base::cmpeq(values, simd_base::backslashes) | simd_base::cmpeq(values, simd_base::quotes)); } + }; - jsonifier_inline bool hasBackslashOrQuote() { - return bsOrQuoteBits != 0; + template<> class backslash_and_quote { + public: + template JSONIFIER_INLINE static uint16_t copyAndFind(const char_type01* source, char_type02* dest) { + simd_int_128 values(gatherValuesU(source)); + storeu(values, dest); + return static_cast(simd_base::cmpeq(values, backslashes128) | simd_base::cmpeq(values, quotes128)); } - jsonifier_inline uint16_t backslashOrQuoteIndex() { - return tzcnt(bsOrQuoteBits); + protected: + static constexpr simd_int_128 backslashes128{ simdFromValue(0x5Cu) }; + static constexpr simd_int_128 quotes128{ simdFromValue(0x22u) }; + }; + + template class escapeable; + + template<> class escapeable { + public: + template JSONIFIER_INLINE static string_parsing_type copyAndFind(const char_type01* source, char_type02* dest) { + simd_int_t values(gatherValuesU(source)); + storeu(values, dest); + return static_cast( + simd_base::cmpeq(simd_base::opShuffle(escapeableChars01, values), values) | simd_base::cmpeq(simd_base::opShuffle(escapeableChars03, values), values)); } protected: - static jsonifier_constexpr simd_int_128 backslashes128{ simdFromValue(0x5Cu) }; - static jsonifier_constexpr simd_int_128 quotes128{ simdFromValue(0x22u) }; - uint16_t bsOrQuoteBits{}; + static constexpr uint8_t escapeableChars00[]{ 0x00u, 0x00u, 0x22u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x0Du, 0x00u, 0x00u }; + static constexpr uint8_t escapeableChars02[]{ 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x09u, 0x0Au, 0x00u, 0x5Cu, 0x00u, 0x00u, 0x00u }; + static constexpr simd_int_t escapeableChars01{ simdFromTable(escapeableChars00) }; + static constexpr simd_int_t escapeableChars03{ simdFromTable(escapeableChars02) }; }; - class escapeable { + template<> class escapeable { public: - template jsonifier_inline static escapeable copyAndFind(const source_type* source, dest_type* dest) { + template JSONIFIER_INLINE static uint16_t copyAndFind(const char_type01* source, char_type02* dest) { simd_int_128 values(gatherValuesU(source)); storeu(values, dest); - escapeable returnData{}; - returnData.nextEscapeableVal = simd_base::cmpeq(simd_base::shuffle(escapeableChars02, values), values); - returnData.nextEscapeableVal |= simd_base::cmpeq(simd_base::shuffle(escapeableChars03, values), values); - return returnData; - } - - jsonifier_inline uint16_t nextEscapeable() { - return tzcnt(nextEscapeableVal); + return static_cast( + simd_base::cmpeq(simd_base::opShuffle(escapeableChars01, values), values) | simd_base::cmpeq(simd_base::opShuffle(escapeableChars03, values), values)); } protected: - static jsonifier_constexpr std::array escapeableChars00{ 0x00u, 0x00u, 0x22u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x0Du, - 0x00u, 0x00u }; - static jsonifier_constexpr std::array escapeableChars01{ 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x09u, 0x0Au, 0x00u, 0x5Cu, 0x00u, - 0x00u, 0x00u }; - static jsonifier_constexpr simd_int_128 escapeableChars02{ simdFromTable(escapeableChars00) }; - static jsonifier_constexpr simd_int_128 escapeableChars03{ simdFromTable(escapeableChars01) }; - uint16_t nextEscapeableVal{}; + static constexpr uint8_t escapeableChars00[]{ 0x00u, 0x00u, 0x22u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x00u, 0x00u, 0x0Cu, 0x0Du, 0x00u, 0x00u }; + static constexpr uint8_t escapeableChars02[]{ 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x09u, 0x0Au, 0x00u, 0x5Cu, 0x00u, 0x00u, 0x00u }; + static constexpr simd_int_128 escapeableChars01{ simdFromTable(escapeableChars00) }; + static constexpr simd_int_128 escapeableChars03{ simdFromTable(escapeableChars02) }; }; - template jsonifier_inline static uint32_t hexToU32NoCheck(const value_type* source) { - uint32_t v1 = digitToVal32[630 + source[0]]; - uint32_t v2 = digitToVal32[420 + source[1]]; - uint32_t v3 = digitToVal32[210 + source[2]]; - uint32_t v4 = digitToVal32[0 + source[3]]; + template JSONIFIER_INLINE uint32_t hexToU32NoCheck(const char_type* source) { + uint32_t v1 = digitToVal32[630 + source[0]]; + uint32_t v2 = digitToVal32[420 + source[1]]; + uint32_t v3 = digitToVal32[210 + source[2]]; + uint32_t v4 = digitToVal32[0 + source[3]]; return v1 | v2 | v3 | v4; } - template jsonifier_inline static uint32_t codePointToUtf8(uint32_t codePoint, value_type* c) { + template JSONIFIER_INLINE uint32_t codePointToUtf8(uint32_t codePoint, char_type* c) { if (codePoint <= 0x7F) { - c[0] = value_type(codePoint); + c[0] = static_cast(codePoint); return 1; } - uint32_t leading_zeros = lzcnt(codePoint); + uint32_t leadingZeros = lzcnt(codePoint); - if (leading_zeros >= 11) { - uint32_t pattern = pdep(0x3F00U, codePoint); + if (leadingZeros >= 11) { + uint32_t pattern = pdep(0x3F00u, codePoint); pattern |= 0xC0ull; - c[0] = static_cast(pattern >> 8); - c[1] = static_cast(pattern & 0xFFu); + c[0] = static_cast(pattern >> 8); + c[1] = static_cast(pattern & 0xFFu); return 2; - } else if (leading_zeros >= 16) { - uint32_t pattern = pdep(0x0F0800U, codePoint); + } else if (leadingZeros >= 16) { + uint32_t pattern = pdep(0x0F0800u, codePoint); pattern |= 0xE0ull; - c[0] = static_cast(pattern >> 16); - c[1] = static_cast(pattern >> 8); - c[2] = static_cast(pattern & 0xFFu); + c[0] = static_cast(pattern >> 16); + c[1] = static_cast(pattern >> 8); + c[2] = static_cast(pattern & 0xFFu); return 3; - } else if (leading_zeros >= 21) { - uint32_t pattern = pdep(0x01020400U, codePoint); + } else if (leadingZeros >= 21) { + uint32_t pattern = pdep(0x01020400u, codePoint); pattern |= 0xF0ull; - c[0] = static_cast(pattern >> 24); - c[1] = static_cast(pattern >> 16); - c[2] = static_cast(pattern >> 8); - c[3] = static_cast(pattern & 0xFFu); + c[0] = static_cast(pattern >> 24); + c[1] = static_cast(pattern >> 16); + c[2] = static_cast(pattern >> 8); + c[3] = static_cast(pattern & 0xFFu); return 4; } return 0; } - template jsonifier_inline bool handleUnicodeCodePoint(value_type01* srcPtr, value_type02* dstPtr) { - static jsonifier_constexpr uint32_t subCodePoint = 0xfffd; - static jsonifier_constexpr uint8_t backslash{ '\\' }; - static jsonifier_constexpr uint8_t u{ 'u' }; + template JSONIFIER_INLINE bool handleUnicodeCodePoint(char_type01* srcPtr, char_type02* dstPtr) { uint32_t codePoint = hexToU32NoCheck(*srcPtr + 2); *srcPtr += 6; - if (codePoint >= 0xd800 && codePoint < 0xdc00) { - value_type01 srcData = *srcPtr; - if (((srcData[0] << 8) | srcData[1]) != ((static_cast>(backslash) << 8) | static_cast>(u))) { - codePoint = subCodePoint; + if (codePoint >= 0xD800 && codePoint < 0xDC00) { + char_type01 srcData = *srcPtr; + if (((srcData[0] << 8) | srcData[1]) != ((static_cast>(0x5Cu) << 8) | static_cast>(0x75u))) { + codePoint = 0xFFFD; } else { uint32_t codePoint02 = hexToU32NoCheck(srcData + 2); - uint32_t lowBit = codePoint02 - 0xdc00; + uint32_t lowBit = codePoint02 - 0xDC00; if (lowBit >> 10) { - codePoint = subCodePoint; + codePoint = 0xFFFD; } else { - codePoint = (((codePoint - 0xd800) << 10) | lowBit) + 0x10000; + codePoint = (((codePoint - 0xD800) << 10) | lowBit) + 0x10000; *srcPtr += 6; } } - } else if (codePoint >= 0xdc00 && codePoint <= 0xdfff) { - codePoint = subCodePoint; + } else if (codePoint >= 0xdc00 && codePoint <= 0xdFFF) { + codePoint = 0xFFFD; } - size_t offset = codePointToUtf8(codePoint, *dstPtr); + uint64_t offset = codePointToUtf8(codePoint, *dstPtr); *dstPtr += offset; return offset > 0; } - template jsonifier_inline static dest_type* parseString(const source_type* source, dest_type* destString, uint64_t lengthNew) { + template constexpr uint64_t getStringLength() { + return shortStringsSupport ? 16 : BytesPerStep; + } + + template + JSONIFIER_INLINE char_type02* parseString(const char_type01* source, char_type02* dest, uint64_t lengthNew) { while (static_cast(lengthNew) >= static_cast(0)) { - backslash_and_quote bsQuote = backslash_and_quote::copyAndFind(source, destString); - if (bsQuote.hasBackslashOrQuote()) { - auto bsDist = bsQuote.backslashOrQuoteIndex(); - source_type escapeChar = source[bsDist]; - if (escapeChar == '"') { - return destString + bsDist; + string_parsing_type nextBackslashOrQuote = backslash_and_quote::copyAndFind(source, dest); + if (nextBackslashOrQuote != 0) { + nextBackslashOrQuote = tzcnt(nextBackslashOrQuote); + auto escapeChar = source[nextBackslashOrQuote]; + if (escapeChar == 0x22u) { + return dest + nextBackslashOrQuote; } - escapeChar = source[bsDist + 1]; - if (escapeChar == 'u') { - source += bsDist; - destString += bsDist; - handleUnicodeCodePoint(&source, &destString); + escapeChar = source[nextBackslashOrQuote + 1]; + if (escapeChar == 0x75u) { + source += nextBackslashOrQuote; + dest += nextBackslashOrQuote; + handleUnicodeCodePoint(&source, &dest); } else { - uint8_t escapeResult = escapeMap[escapeChar]; + char_type01 escapeResult = escapeMap[escapeChar]; if (escapeResult == 0u) { - return nullptr; + return static_cast(nullptr); } - destString[bsDist] = escapeResult; - destString += bsDist + 1ULL; - source += bsDist + 2ULL; + dest[nextBackslashOrQuote] = escapeResult; + dest += nextBackslashOrQuote + 1ull; + source += nextBackslashOrQuote + 2ull; + lengthNew -= nextBackslashOrQuote + 2ull; } } else { - source += 16; - destString += 16; + dest += getStringLength(); + source += getStringLength(); + lengthNew -= getStringLength(); } } - return nullptr; + return static_cast(nullptr); } - template - jsonifier_inline value_type01* serializeString(value_type01* source, value_type02* dest, uint64_t lengthNew, uint64_t& indexNew) { - while (static_cast(lengthNew) >= static_cast(16)) { - escapeable bsQuote = escapeable::copyAndFind(source, dest); - auto nextEscapeable = bsQuote.nextEscapeable(); - if (nextEscapeable != 16) { - uint8_t escapeResult = escapeableChars[source[nextEscapeable]]; - if (escapeResult == 0u) { - return source; + template + JSONIFIER_INLINE char_type01* serializeString(char_type01* source, char_type02* dest, uint64_t lengthNew, uint64_t& indexNew) { +#if JSONIFIER_CHECK_FOR_INSTRUCTION(JSONIFIER_ANY_AVX) + auto serializationLambda = [&](char_type01* source, char_type02*& dest, uint64_t remainingLength, auto&& comparitor) -> char_type01* { + while (comparitor(static_cast(lengthNew), static_cast(remainingLength))) { + string_parsing_type nextEscapeable = escapeable::copyAndFind(source, dest); + if (nextEscapeable != 0) { + nextEscapeable = tzcnt(nextEscapeable); + char_type01 escapeResult = static_cast(escapeableChars[static_cast(source[nextEscapeable])]); + if (escapeResult == 0u) { + lengthNew -= nextEscapeable; + indexNew += nextEscapeable; + source += nextEscapeable; + dest += nextEscapeable; + return source; + } + dest[nextEscapeable] = 0x5Cu; + dest[static_cast(nextEscapeable) + 1ull] = static_cast(escapeResult); + dest += static_cast(nextEscapeable) + 2ull; + indexNew += static_cast(nextEscapeable) + 2ull; + lengthNew -= (nextEscapeable + 1ull); + source += nextEscapeable + 1ull; + } else { + lengthNew -= remainingLength > 0 ? remainingLength : 1; + indexNew += remainingLength > 0 ? remainingLength : 1; + source += remainingLength > 0 ? remainingLength : 1; + dest += remainingLength > 0 ? remainingLength : 1; } - dest[nextEscapeable] = '\\'; - dest[static_cast(nextEscapeable) + 1ULL] = escapeResult; - dest += static_cast(nextEscapeable) + 2ULL; - indexNew += static_cast(nextEscapeable) + 2ULL; - lengthNew -= (nextEscapeable + 1ULL); - source += nextEscapeable + 1ULL; - } else { - lengthNew -= 16ULL; - indexNew += 16ULL; - source += 16ULL; - dest += 16ULL; } - } + return source; + }; + + source = serializationLambda(source, dest, getStringLength(), std::greater_equal{}); + std::remove_const_t newValues[getStringLength()]{}; + std::memcpy(newValues, source, lengthNew); + return serializationLambda(newValues, dest, 0, std::greater{}); +#else return source; +#endif } - jsonifier_inline bool parseBool(string_view_ptr json) { - uint8_t valueNew[5]{ "true" }; - return std::memcmp(valueNew, json, 4) == 0; + template JSONIFIER_INLINE bool parseBool(char_type* json) { + char_type values[5]{ "true" }; + return std::memcmp(values, json, 4) == 0; } }// namespace jsonifier_internal diff --git a/Include/jsonifier/StringView.hpp b/Include/jsonifier/StringView.hpp index 7015bf012..e6ac6b649 100644 --- a/Include/jsonifier/StringView.hpp +++ b/Include/jsonifier/StringView.hpp @@ -37,106 +37,108 @@ namespace jsonifier { using size_type = uint64_t; using traits_type = jsonifier_internal::char_traits; - const_pointer dataVal{}; - size_type sizeVal{}; + static constexpr size_type npos{ std::numeric_limits::max() }; - static jsonifier_constexpr size_type npos{ std::numeric_limits::max() }; - - jsonifier_constexpr string_view_base() : dataVal(), sizeVal(0) { + constexpr string_view_base() : dataVal(), sizeVal(0) { } - template jsonifier_constexpr string_view_base& operator=(const value_type_newer& stringNew) { + template constexpr string_view_base& operator=(const string_base& stringNew) { dataVal = stringNew.data(); sizeVal = stringNew.size(); return *this; } - template jsonifier_constexpr string_view_base(const value_type_newer& stringNew) { + template constexpr string_view_base(const string_base& stringNew) { *this = stringNew; } - template jsonifier_constexpr string_view_base(const value_type (&other)[strLength]) { - dataVal = other; - sizeVal = strLength; + template> constexpr string_view_base& operator=(const value_type_newer& stringNew) { + dataVal = stringNew.data(); + sizeVal = stringNew.size(); + return *this; + } + + template> constexpr string_view_base(const value_type_newer& stringNew) { + *this = stringNew; } - jsonifier_constexpr string_view_base(const_pointer pointerNew) : dataVal(pointerNew), sizeVal(traits_type::length(pointerNew)) { + constexpr string_view_base(const_pointer pointerNew) : dataVal(pointerNew), sizeVal(traits_type::length(pointerNew)) { } - jsonifier_constexpr string_view_base(const_pointer pointerNew, const size_type countNew) : dataVal(pointerNew), sizeVal(countNew){}; + constexpr string_view_base(const_pointer pointerNew, const size_type countNew) : dataVal(pointerNew), sizeVal(countNew){}; - jsonifier_constexpr const_iterator begin() noexcept { + constexpr const_iterator begin() noexcept { return const_iterator{ dataVal }; } - jsonifier_constexpr const_iterator end() noexcept { + constexpr const_iterator end() noexcept { return const_iterator{ dataVal + sizeVal }; } - jsonifier_constexpr const_reverse_iterator rbegin() noexcept { + constexpr const_reverse_iterator rbegin() noexcept { return const_reverse_iterator{ end() }; } - jsonifier_constexpr const_reverse_iterator rend() noexcept { + constexpr const_reverse_iterator rend() noexcept { return const_reverse_iterator{ begin() }; } - jsonifier_constexpr const_iterator begin() const noexcept { + constexpr const_iterator begin() const noexcept { return const_iterator{ dataVal }; } - jsonifier_constexpr const_iterator end() const noexcept { + constexpr const_iterator end() const noexcept { return const_iterator{ dataVal + sizeVal }; } - jsonifier_constexpr const_reverse_iterator rbegin() const noexcept { + constexpr const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator{ end() }; } - jsonifier_constexpr const_reverse_iterator rend() const noexcept { + constexpr const_reverse_iterator rend() const noexcept { return const_reverse_iterator{ begin() }; } - jsonifier_constexpr size_type size() const { + constexpr size_type size() const { return sizeVal; } - jsonifier_constexpr size_type length() const { + constexpr size_type length() const { return sizeVal; } - jsonifier_constexpr bool empty() const { + constexpr bool empty() const { return sizeVal == 0; } - jsonifier_constexpr const_pointer data() const { + constexpr const_pointer data() const { return dataVal; } - jsonifier_constexpr size_type max_size() const { + constexpr size_type max_size() const { return std::min(static_cast(std::numeric_limits::max()), static_cast(-1) / sizeof(value_type)); } - jsonifier_constexpr const_reference at(const size_type offsetNew) const { + 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 string_view instance." }; } return dataVal[offsetNew]; } - jsonifier_constexpr const_reference operator[](const size_type offsetNew) const { + constexpr const_reference operator[](const size_type offsetNew) const { return dataVal[offsetNew]; } - jsonifier_constexpr const_reference front() const { + constexpr const_reference front() const { return dataVal[0]; } - jsonifier_constexpr const_reference back() const { + constexpr const_reference back() const { return dataVal[sizeVal - 1]; } - jsonifier_inline size_type find(const_pointer args, size_type position = 0) const { + JSONIFIER_INLINE size_type find(const_pointer args, size_type position = 0) const { auto newSize = traits_type::length(args); if (position + newSize > sizeVal) { return npos; @@ -145,7 +147,7 @@ namespace jsonifier { return foundValue == npos ? npos : foundValue + position; } - template jsonifier_inline size_type find(value_type_newer args, size_type position = 0) const { + template JSONIFIER_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; @@ -154,7 +156,7 @@ namespace jsonifier { return foundValue == npos ? npos : foundValue + position; } - template jsonifier_inline size_type find(const value_type_newer& args, size_type position = 0) const { + template JSONIFIER_INLINE size_type find(const value_type_newer& args, size_type position = 0) const { if (position + args.size() > sizeVal) { return npos; } @@ -162,29 +164,29 @@ namespace jsonifier { return foundValue == npos ? npos : foundValue + position; } - template jsonifier_constexpr size_type findFirstOf(ArgTypes&&... args) const { - return operator std::basic_string_view().find_first_of(std::forward(args)...); + template constexpr size_type findFirstOf(arg_types&&... args) const { + return operator std::basic_string_view().find_first_of(std::forward(args)...); } - template jsonifier_constexpr size_type findLastOf(ArgTypes&&... args) const { - return operator std::basic_string_view().find_last_of(std::forward(args)...); + template constexpr size_type findLastOf(arg_types&&... args) const { + return operator std::basic_string_view().find_last_of(std::forward(args)...); } - template jsonifier_constexpr size_type findFirstNotOf(ArgTypes&&... args) const { - return operator std::basic_string_view().find_first_not_of(std::forward(args)...); + template constexpr size_type findFirstNotOf(arg_types&&... args) const { + return operator std::basic_string_view().find_first_not_of(std::forward(args)...); } - template jsonifier_constexpr size_type findLastNotOf(ArgTypes&&... args) const { - return operator std::basic_string_view().find_last_not_of(std::forward(args)...); + template constexpr size_type findLastNotOf(arg_types&&... args) const { + return operator std::basic_string_view().find_last_not_of(std::forward(args)...); } - jsonifier_constexpr void swap(string_view_base& other) { + constexpr void swap(string_view_base& other) { const string_view_base temp{ other }; other = *this; *this = temp; } - jsonifier_constexpr string_view_base substr(const size_type offsetNew = 0, size_type countNew = npos) const { + 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."); } @@ -193,7 +195,7 @@ namespace jsonifier { return string_view_base(dataVal + offsetNew, countNew); } - template jsonifier_inline explicit operator std::basic_string() const { + template JSONIFIER_INLINE explicit operator std::basic_string() const { std::basic_string returnValue{}; returnValue.resize(sizeVal); if (sizeVal > 0) { @@ -202,7 +204,7 @@ namespace jsonifier { return returnValue; } - template jsonifier_inline explicit operator string_base() const { + template JSONIFIER_INLINE explicit operator string_base() const { string_base returnValue{}; returnValue.resize(sizeVal); if (sizeVal > 0) { @@ -211,12 +213,12 @@ namespace jsonifier { return returnValue; } - jsonifier_constexpr explicit operator std::basic_string_view() const { + constexpr explicit operator std::basic_string_view() const { return { data(), size() }; } template - jsonifier_inline friend std::enable_if_t, bool> operator==(const string_view_base& lhs, const value_type_newer& rhs) { + JSONIFIER_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; @@ -224,7 +226,7 @@ namespace jsonifier { return jsonifier_internal::jsonifier_core_internal::compare(rhs, lhs.data(), rhsLength); } - template jsonifier_inline friend bool operator==(const string_view_base& lhs, const value_type_newer& rhs) { + template JSONIFIER_INLINE friend bool operator==(const string_view_base& lhs, const value_type_newer& rhs) { if (rhs.size() != lhs.size()) { return false; } @@ -232,73 +234,77 @@ namespace jsonifier { } template - jsonifier_inline friend string_base operator+(const value_type_newer (&lhs)[size], const string_view_base& rhs) { + JSONIFIER_INLINE friend string_base operator+(const value_type_newer (&lhs)[size], const string_view_base& rhs) { string_base newLhs{ lhs }; newLhs += rhs; return newLhs; } template - jsonifier_inline friend string_base operator+=(const value_type_newer (&lhs)[size], const string_view_base& rhs) { + JSONIFIER_INLINE friend string_base operator+=(const value_type_newer (&lhs)[size], const string_view_base& rhs) { string_base newLhs{ lhs }; newLhs += rhs; return newLhs; } template - jsonifier_inline friend string_base operator+(string_type_newer&& lhs, const string_view_base& rhs) { + JSONIFIER_INLINE friend string_base operator+(string_type_newer&& lhs, const string_view_base& rhs) { string_base> newLhs{ lhs }; newLhs += rhs; return newLhs; } template - jsonifier_inline friend string_base operator+=(string_type_newer&& lhs, const string_view_base& rhs) { + JSONIFIER_INLINE friend string_base operator+=(string_type_newer&& lhs, const string_view_base& rhs) { string_base> newLhs{ lhs }; newLhs += rhs; return newLhs; } - jsonifier_inline string_base operator+(const value_type& rhs) { + JSONIFIER_INLINE string_base operator+(const value_type& rhs) { string_base newLhs{ *this }; - newLhs.push_back(rhs); + newLhs.pushBack(rhs); return newLhs; } - jsonifier_inline string_base operator+=(const value_type& rhs) { + JSONIFIER_INLINE string_base operator+=(const value_type& rhs) { string_base newLhs{ *this }; - newLhs.push_back(rhs); + newLhs.pushBack(rhs); return newLhs; } - template jsonifier_inline string_base operator+(const string_type_new& rhs) const { + template JSONIFIER_INLINE string_base operator+(const string_type_new& rhs) const { string_base newLhs{ *this }; newLhs += rhs; return newLhs; } - template jsonifier_inline string_base operator+=(const string_type_new& rhs) { + template JSONIFIER_INLINE string_base operator+=(const string_type_new& rhs) { string_base newLhs{ *this }; newLhs.append(rhs.data(), rhs.size()); return newLhs; } - template jsonifier_inline string_base operator+(const value_type_newer (&rhs)[size]) const { + template JSONIFIER_INLINE string_base operator+(const value_type_newer (&rhs)[size]) const { string_base newLhs{ *this }; newLhs += rhs; return newLhs; } - template jsonifier_inline string_base operator+=(const value_type_newer (&rhs)[size]) { + template JSONIFIER_INLINE string_base operator+=(const value_type_newer (&rhs)[size]) { string_base newLhs{ *this }; newLhs += rhs; return newLhs; } + + protected: + const_pointer dataVal{}; + size_type sizeVal{}; }; using string_view = string_view_base; - jsonifier_inline std::ostream& operator<<(std::ostream& oStream, const jsonifier::string_view_base& string) { + JSONIFIER_INLINE std::ostream& operator<<(std::ostream& oStream, const jsonifier::string_view_base& string) { oStream << string.operator jsonifier::string(); return oStream; } @@ -308,19 +314,11 @@ namespace jsonifier { namespace jsonifier_internal { template struct hash> { - jsonifier_constexpr uint64_t operator()(jsonifier::string_view_base value) const { - return fnv1aHash(value); - } - - jsonifier_constexpr uint64_t operator()(jsonifier::string_view_base value, uint64_t seed) const { + constexpr uint64_t operator()(jsonifier::string_view_base value, uint64_t seed) const { return fnv1aHash(value, seed); } - jsonifier_constexpr uint64_t operator()(jsonifier::string_view_base value) const { - return fnv1aHash(value); - } - - jsonifier_constexpr uint64_t operator()(jsonifier::string_view_base value, uint64_t seed) const { + constexpr uint64_t operator()(jsonifier::string_view_base value, uint64_t seed) const { return fnv1aHash(value, seed); } }; @@ -329,8 +327,8 @@ namespace jsonifier_internal { namespace std { template<> struct hash { - jsonifier_inline size_t operator()(jsonifier ::string_view lhs) const { - return jsonifier_internal::hash{}.operator()(lhs); + JSONIFIER_INLINE size_t operator()(jsonifier ::string_view lhs) const { + return jsonifier_internal::fnv1aHash(lhs); } }; } diff --git a/Include/jsonifier/StructuralIterator.hpp b/Include/jsonifier/StructuralIterator.hpp deleted file mode 100644 index a34a4010c..000000000 --- a/Include/jsonifier/StructuralIterator.hpp +++ /dev/null @@ -1,92 +0,0 @@ -/* - 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 { - - class structural_iterator { - public: - friend class derailleur; - - using iterator_category = std::forward_iterator_tag; - using value_type = uint8_t; - using difference_type = std::ptrdiff_t; - using pointer = string_view_ptr*; - using reference = value_type&; - using size_type = int64_t; - - jsonifier_inline structural_iterator() noexcept = default; - - jsonifier_inline structural_iterator(structural_index* rootIndexNew) { - currentIndex = rootIndexNew; - rootIndex = rootIndexNew; - } - - jsonifier_inline value_type operator*() const { - return (*currentIndex) ? **currentIndex : defaultValue; - } - - jsonifier_inline string_view_ptr operator->() const { - return *currentIndex; - } - - jsonifier_inline structural_iterator& operator++() { - ++currentIndex; - return *this; - } - - jsonifier_inline structural_iterator operator++(int32_t) { - structural_iterator oldIter{ *this }; - ++(*this); - return oldIter; - } - - jsonifier_inline string_view_ptr getEndPtr() { - auto newIndex = currentIndex; - while (*(newIndex + 1) != nullptr) { - ++newIndex; - } - return *newIndex; - } - - jsonifier_inline string_view_ptr getRootPtr() { - return *rootIndex; - } - - jsonifier_inline size_type getCurrentStringIndex() const { - return (*currentIndex) - (*rootIndex); - } - - jsonifier_inline bool operator==(const structural_iterator&) const { - return !(*currentIndex); - } - - protected: - static jsonifier_constexpr uint8_t defaultValue{ 0x00 }; - pointer currentIndex{}; - pointer rootIndex{}; - }; -} \ No newline at end of file diff --git a/Include/jsonifier/Tables.hpp b/Include/jsonifier/Tables.hpp index 41553602a..30e34ccfb 100644 --- a/Include/jsonifier/Tables.hpp +++ b/Include/jsonifier/Tables.hpp @@ -13,7 +13,7 @@ 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 PARTICuAR 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 @@ -27,610 +27,423 @@ namespace jsonifier_internal { - jsonifier_constexpr double powersOfTenFloat[]{ 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22 }; - - jsonifier_constexpr uint64_t powersOfTenInt[]{ 1ull, 10ull, 100ull, 1000ull, 10000ull, 100000ull, 1000000ull, 10000000ull, 100000000ull, 1000000000ull, 10000000000ull, - 100000000000ull, 1000000000000ull, 10000000000000ull, 100000000000000ull, 1000000000000000ull, 10000000000000000ull, 100000000000000000ull, 1000000000000000000ull, + constexpr uint64_t powersOfTenInt[]{ 1ull, 10ull, 100ull, 1000ull, 10000ull, 100000ull, 1000000ull, 10000000ull, 100000000ull, 1000000000ull, 10000000000ull, 100000000000ull, + 1000000000000ull, 10000000000000ull, 100000000000000ull, 1000000000000000ull, 10000000000000000ull, 100000000000000000ull, 1000000000000000000ull, 10000000000000000000ull }; - template jsonifier_constexpr value_type decTrailingZeroTable[]{ static_cast(0x02u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x01u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x01u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x01u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x01u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x01u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x01u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x01u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x01u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x01u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u) }; + constexpr double powersOfTenFloat[]{ 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22 }; - template jsonifier_constexpr value_type digiTable[]{ static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x04u), static_cast(0x00u), static_cast(0x08u), static_cast(0x10u), static_cast(0x00u), - static_cast(0x01u), static_cast(0x02u), static_cast(0x02u), static_cast(0x02u), static_cast(0x02u), - static_cast(0x02u), static_cast(0x02u), static_cast(0x02u), static_cast(0x02u), static_cast(0x02u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x20u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x20u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u) }; + constexpr uint8_t decTrailingZeroTable[]{ 2u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 1u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 1u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 1u, 0u, 0u, + 0u, 0u, 0u, 0u, 0u, 0u, 0u, 1u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 1u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 1u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 1u, 0u, 0u, 0u, 0u, 0u, + 0u, 0u, 0u, 0u, 1u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 1u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u }; - template jsonifier_constexpr value_type escapeMap[]{ static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x08u), static_cast(0x09u), static_cast(0x0Au), static_cast(0x00u), static_cast(0x0Cu), - static_cast(0x0Du), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x22u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x2fu), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x5cu), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x08u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x0cu), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x0au), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x0du), static_cast(0x00u), static_cast(0x09u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u) }; + constexpr uint8_t digiTable[]{ 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, + 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x04u, + 0x00u, 0x08u, 0x10u, 0x00u, 0x01u, 0x02u, 0x02u, 0x02u, 0x02u, 0x02u, 0x02u, 0x02u, 0x02u, 0x02u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, + 0x00u, 0x20u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, + 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x20u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, + 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u }; - template jsonifier_constexpr value_type escapeableChars[]{ static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x62u), static_cast(0x74u), static_cast(0x6Eu), static_cast(0x00u), static_cast(0x66u), - static_cast(0x72u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x22u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x5Cu), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), static_cast(0x00u), - static_cast(0x00u), static_cast(0x00u) }; + constexpr bool structuralTable[]{ false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, true, + true, false, false, true, true, true, true, true, true, true, true, true, true, true, false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, true, false, false, + false, false, false, false, false, false, true, false, false, false, false, false, false, false, true, false, false, false, false, false, true, false, false, false, false, + false, false, true, false, true, false, false }; - template jsonifier_constexpr value_type charTable[]{ static_cast(0x30u), static_cast(0x30u), static_cast(0x30u), - static_cast(0x31u), static_cast(0x30u), static_cast(0x32u), static_cast(0x30u), static_cast(0x33u), - static_cast(0x30u), static_cast(0x34u), static_cast(0x30u), static_cast(0x35u), static_cast(0x30u), - static_cast(0x36u), static_cast(0x30u), static_cast(0x37u), static_cast(0x30u), static_cast(0x38u), - static_cast(0x30u), static_cast(0x39u), static_cast(0x31u), static_cast(0x30u), static_cast(0x31u), - static_cast(0x31u), static_cast(0x31u), static_cast(0x32u), static_cast(0x31u), static_cast(0x33u), - static_cast(0x31u), static_cast(0x34u), static_cast(0x31u), static_cast(0x35u), static_cast(0x31u), - static_cast(0x36u), static_cast(0x31u), static_cast(0x37u), static_cast(0x31u), static_cast(0x38u), - static_cast(0x31u), static_cast(0x39u), static_cast(0x32u), static_cast(0x30u), static_cast(0x32u), - static_cast(0x31u), static_cast(0x32u), static_cast(0x32u), static_cast(0x32u), static_cast(0x33u), - static_cast(0x32u), static_cast(0x34u), static_cast(0x32u), static_cast(0x35u), static_cast(0x32u), - static_cast(0x36u), static_cast(0x32u), static_cast(0x37u), static_cast(0x32u), static_cast(0x38u), - static_cast(0x32u), static_cast(0x39u), static_cast(0x33u), static_cast(0x30u), static_cast(0x33u), - static_cast(0x31u), static_cast(0x33u), static_cast(0x32u), static_cast(0x33u), static_cast(0x33u), - static_cast(0x33u), static_cast(0x34u), static_cast(0x33u), static_cast(0x35u), static_cast(0x33u), - static_cast(0x36u), static_cast(0x33u), static_cast(0x37u), static_cast(0x33u), static_cast(0x38u), - static_cast(0x33u), static_cast(0x39u), static_cast(0x34u), static_cast(0x30u), static_cast(0x34u), - static_cast(0x31u), static_cast(0x34u), static_cast(0x32u), static_cast(0x34u), static_cast(0x33u), - static_cast(0x34u), static_cast(0x34u), static_cast(0x34u), static_cast(0x35u), static_cast(0x34u), - static_cast(0x36u), static_cast(0x34u), static_cast(0x37u), static_cast(0x34u), static_cast(0x38u), - static_cast(0x34u), static_cast(0x39u), static_cast(0x35u), static_cast(0x30u), static_cast(0x35u), - static_cast(0x31u), static_cast(0x35u), static_cast(0x32u), static_cast(0x35u), static_cast(0x33u), - static_cast(0x35u), static_cast(0x34u), static_cast(0x35u), static_cast(0x35u), static_cast(0x35u), - static_cast(0x36u), static_cast(0x35u), static_cast(0x37u), static_cast(0x35u), static_cast(0x38u), - static_cast(0x35u), static_cast(0x39u), static_cast(0x36u), static_cast(0x30u), static_cast(0x36u), - static_cast(0x31u), static_cast(0x36u), static_cast(0x32u), static_cast(0x36u), static_cast(0x33u), - static_cast(0x36u), static_cast(0x34u), static_cast(0x36u), static_cast(0x35u), static_cast(0x36u), - static_cast(0x36u), static_cast(0x36u), static_cast(0x37u), static_cast(0x36u), static_cast(0x38u), - static_cast(0x36u), static_cast(0x39u), static_cast(0x37u), static_cast(0x30u), static_cast(0x37u), - static_cast(0x31u), static_cast(0x37u), static_cast(0x32u), static_cast(0x37u), static_cast(0x33u), - static_cast(0x37u), static_cast(0x34u), static_cast(0x37u), static_cast(0x35u), static_cast(0x37u), - static_cast(0x36u), static_cast(0x37u), static_cast(0x37u), static_cast(0x37u), static_cast(0x38u), - static_cast(0x37u), static_cast(0x39u), static_cast(0x38u), static_cast(0x30u), static_cast(0x38u), - static_cast(0x31u), static_cast(0x38u), static_cast(0x32u), static_cast(0x38u), static_cast(0x33u), - static_cast(0x38u), static_cast(0x34u), static_cast(0x38u), static_cast(0x35u), static_cast(0x38u), - static_cast(0x36u), static_cast(0x38u), static_cast(0x37u), static_cast(0x38u), static_cast(0x38u), - static_cast(0x38u), static_cast(0x39u), static_cast(0x39u), static_cast(0x30u), static_cast(0x39u), - static_cast(0x31u), static_cast(0x39u), static_cast(0x32u), static_cast(0x39u), static_cast(0x33u), - static_cast(0x39u), static_cast(0x34u), static_cast(0x39u), static_cast(0x35u), static_cast(0x39u), - static_cast(0x36u), static_cast(0x39u), static_cast(0x37u), static_cast(0x39u), static_cast(0x38u), - static_cast(0x39u), static_cast(0x39u) }; + constexpr int16_t asciiToValueTable[]{ -48, -47, -46, -45, -44, -43, -42, -41, -40, -39, -38, -37, -36, -35, -34, -33, -32, -31, -30, -29, -28, -27, -26, -25, -24, -23, -22, + -21, -20, -19, -18, -17, -16, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79 }; - jsonifier_constexpr bool numberTable[]{ false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, - false, false, true, false, false, true, true, true, true, true, true, true, true, true, true, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, - false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, + constexpr bool numberTable[]{ false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, + true, false, false, true, true, true, true, true, true, true, true, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false }; + true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false }; + + constexpr uint8_t escapeMap[]{ 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x08u, 0x09u, 0x0Au, 0x00u, 0x0Cu, 0x0Du, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, + 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x22u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, + 0x00u, 0x00u, 0x00u, 0x2fu, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, + 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, + 0x5cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x08u, 0x00u, 0x00u, 0x00u, 0x0cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x0au, 0x00u, 0x00u, 0x00u, 0x0du, 0x00u, + 0x09u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u }; + + constexpr uint8_t escapeableChars[]{ 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x62u, 0x74u, 0x6Eu, 0x00u, 0x66u, 0x72u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, + 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x22u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, + 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, + 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, + 0x5Cu, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, + 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u }; + + constexpr uint8_t charTable[]{ 0x30u, 0x30u, 0x30u, 0x31u, 0x30u, 0x32u, 0x30u, 0x33u, 0x30u, 0x34u, 0x30u, 0x35u, 0x30u, 0x36u, 0x30u, 0x37u, 0x30u, 0x38u, 0x30u, 0x39u, + 0x31u, 0x30u, 0x31u, 0x31u, 0x31u, 0x32u, 0x31u, 0x33u, 0x31u, 0x34u, 0x31u, 0x35u, 0x31u, 0x36u, 0x31u, 0x37u, 0x31u, 0x38u, 0x31u, 0x39u, 0x32u, 0x30u, 0x32u, 0x31u, + 0x32u, 0x32u, 0x32u, 0x33u, 0x32u, 0x34u, 0x32u, 0x35u, 0x32u, 0x36u, 0x32u, 0x37u, 0x32u, 0x38u, 0x32u, 0x39u, 0x33u, 0x30u, 0x33u, 0x31u, 0x33u, 0x32u, 0x33u, 0x33u, + 0x33u, 0x34u, 0x33u, 0x35u, 0x33u, 0x36u, 0x33u, 0x37u, 0x33u, 0x38u, 0x33u, 0x39u, 0x34u, 0x30u, 0x34u, 0x31u, 0x34u, 0x32u, 0x34u, 0x33u, 0x34u, 0x34u, 0x34u, 0x35u, + 0x34u, 0x36u, 0x34u, 0x37u, 0x34u, 0x38u, 0x34u, 0x39u, 0x35u, 0x30u, 0x35u, 0x31u, 0x35u, 0x32u, 0x35u, 0x33u, 0x35u, 0x34u, 0x35u, 0x35u, 0x35u, 0x36u, 0x35u, 0x37u, + 0x35u, 0x38u, 0x35u, 0x39u, 0x36u, 0x30u, 0x36u, 0x31u, 0x36u, 0x32u, 0x36u, 0x33u, 0x36u, 0x34u, 0x36u, 0x35u, 0x36u, 0x36u, 0x36u, 0x37u, 0x36u, 0x38u, 0x36u, 0x39u, + 0x37u, 0x30u, 0x37u, 0x31u, 0x37u, 0x32u, 0x37u, 0x33u, 0x37u, 0x34u, 0x37u, 0x35u, 0x37u, 0x36u, 0x37u, 0x37u, 0x37u, 0x38u, 0x37u, 0x39u, 0x38u, 0x30u, 0x38u, 0x31u, + 0x38u, 0x32u, 0x38u, 0x33u, 0x38u, 0x34u, 0x38u, 0x35u, 0x38u, 0x36u, 0x38u, 0x37u, 0x38u, 0x38u, 0x38u, 0x39u, 0x39u, 0x30u, 0x39u, 0x31u, 0x39u, 0x32u, 0x39u, 0x33u, + 0x39u, 0x34u, 0x39u, 0x35u, 0x39u, 0x36u, 0x39u, 0x37u, 0x39u, 0x38u, 0x39u, 0x39u }; + + constexpr uint32_t digitToVal32[]{ 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0x00000000u, + 0x00000001u, 0x00000002u, 0x00000003u, 0x00000004u, 0x00000005u, 0x00000006u, 0x00000007u, 0x00000008u, 0x00000009u, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0x0000000au, 0x0000000bu, 0x0000000cu, 0x0000000du, 0x0000000eu, 0x0000000fu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0x0000000au, 0x0000000bu, 0x0000000cu, 0x0000000du, + 0x0000000eu, 0x0000000fu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0x00000000u, 0x00000010u, 0x00000020u, 0x00000030u, 0x00000040u, 0x00000050u, 0x00000060u, 0x00000070u, 0x00000080u, 0x00000090u, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0x000000a0u, 0x000000b0u, 0x000000c0u, 0x000000d0u, 0x000000e0u, 0x000000f0u, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0x000000a0u, 0x000000b0u, + 0x000000c0u, 0x000000d0u, 0x000000e0u, 0x000000f0u, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0x00000000u, 0x00000100u, 0x00000200u, 0x00000300u, 0x00000400u, 0x00000500u, 0x00000600u, 0x00000700u, 0x00000800u, 0x00000900u, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0x00000a00u, 0x00000b00u, 0x00000c00u, 0x00000d00u, 0x00000e00u, 0x00000f00u, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0x00000a00u, 0x00000b00u, 0x00000c00u, 0x00000d00u, 0x00000e00u, 0x00000f00u, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0x00000000u, 0x00001000u, 0x00002000u, 0x00003000u, 0x00004000u, 0x00005000u, 0x00006000u, 0x00007000u, + 0x00008000u, 0x00009000u, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0x0000a000u, 0x0000b000u, 0xc0000000u, 0x0000d000u, + 0x0000e000u, 0x0000f000u, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0x0000a000u, 0x0000b000u, 0x0000c000u, 0x0000d000u, 0x0000e000u, 0x0000f000u, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, + 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu }; + + constexpr uint64_t pow10SigTable[]{ 0xBF29DCABA82FDEAEull, 0xEEF453D6923BD65Aull, 0x9558B4661B6565F8ull, 0xBAAEE17FA23EBF76ull, 0xE95A99DF8ACE6F53ull, 0x91D8A02BB6C10594ull, + 0xB64EC836A47146F9ull, 0xE3E27A444D8D98B7ull, 0x8E6D8C6AB0787F72ull, 0xB208EF855C969F4Full, 0xDE8B2B66B3BC4723ull, 0x8B16FB203055AC76ull, 0xADDCB9E83C6B1793ull, + 0xD953E8624B85DD78ull, 0x87D4713D6F33AA6Bull, 0xA9C98D8CCB009506ull, 0xD43BF0EFFDC0BA48ull, 0x84A57695FE98746Dull, 0xA5CED43B7E3E9188ull, 0xCF42894A5DCE35EAull, + 0x818995CE7AA0E1B2ull, 0xA1EBFB4219491A1Full, 0xCA66FA129F9B60A6ull, 0xFD00B897478238D0ull, 0x9E20735E8CB16382ull, 0xC5A890362FDDBC62ull, 0xF712B443BBD52B7Bull, + 0x9A6BB0AA55653B2Dull, 0xC1069CD4EABE89F8ull, 0xF148440A256E2C76ull, 0x96CD2A865764DBCAull, 0xBC807527ED3E12BCull, 0xEBA09271E88D976Bull, 0x93445B8731587EA3ull, + 0xB8157268FDAE9E4Cull, 0xE61ACF033D1A45DFull, 0x8FD0C16206306BABull, 0xB3C4F1BA87BC8696ull, 0xE0B62E2929ABA83Cull, 0x8C71DCD9BA0B4925ull, 0xAF8E5410288E1B6Full, + 0xDB71E91432B1A24Aull, 0x892731AC9FAF056Eull, 0xAB70FE17C79AC6CAull, 0xD64D3D9DB981787Dull, 0x85F0468293F0EB4Eull, 0xA76C582338ED2621ull, 0xD1476E2C07286FAAull, + 0x82CCA4DB847945CAull, 0xA37FCE126597973Cull, 0xCC5FC196FEFD7D0Cull, 0xFF77B1FCBEBCDC4Full, 0x9FAACF3DF73609B1ull, 0xC795830D75038C1Dull, 0xF97AE3D0D2446F25ull, + 0x9BECCE62836AC577ull, 0xC2E801FB244576D5ull, 0xF3A20279ED56D48Aull, 0x9845418C345644D6ull, 0xBE5691EF416BD60Cull, 0xEDEC366B11C6CB8Full, 0x94B3A202EB1C3F39ull, + 0xB9E08A83A5E34F07ull, 0xE858AD248F5C22C9ull, 0x91376C36D99995BEull, 0xB58547448FFFFB2Dull, 0xE2E69915B3FFF9F9ull, 0x8DD01FAD907FFC3Bull, 0xB1442798F49FFB4Aull, + 0xDD95317F31C7FA1Dull, 0x8A7D3EEF7F1CFC52ull, 0xAD1C8EAB5EE43B66ull, 0xD863B256369D4A40ull, 0x873E4F75E2224E68ull, 0xA90DE3535AAAE202ull, 0xD3515C2831559A83ull, + 0x8412D9991ED58091ull, 0xA5178FFF668AE0B6ull, 0xCE5D73FF402D98E3ull, 0x80FA687F881C7F8Eull, 0xA139029F6A239F72ull, 0xC987434744AC874Eull, 0xFBE9141915D7A922ull, + 0x9D71AC8FADA6C9B5ull, 0xC4CE17B399107C22ull, 0xF6019DA07F549B2Bull, 0x99C102844F94E0FBull, 0xC0314325637A1939ull, 0xF03D93EEBC589F88ull, 0x96267C7535B763B5ull, + 0xBBB01B9283253CA2ull, 0xEA9C227723EE8BCBull, 0x92A1958A7675175Full, 0xB749FAED14125D36ull, 0xE51C79A85916F484ull, 0x8F31CC0937AE58D2ull, 0xB2FE3F0B8599EF07ull, + 0xDFBDCECE67006AC9ull, 0x8BD6A141006042BDull, 0xAECC49914078536Dull, 0xDA7F5BF590966848ull, 0x888F99797A5E012Dull, 0xAAB37FD7D8F58178ull, 0xD5605FCDCF32E1D6ull, + 0x855C3BE0A17FCD26ull, 0xA6B34AD8C9DFC06Full, 0xD0601D8EFC57B08Bull, 0x823C12795DB6CE57ull, 0xA2CB1717B52481EDull, 0xCB7DDCDDA26DA268ull, 0xFE5D54150B090B02ull, + 0x9EFA548D26E5A6E1ull, 0xC6B8E9B0709F109Aull, 0xF867241C8CC6D4C0ull, 0x9B407691D7FC44F8ull, 0xC21094364DFB5636ull, 0xF294B943E17A2BC4ull, 0x979CF3CA6CEC5B5Aull, + 0xBD8430BD08277231ull, 0xECE53CEC4A314EBDull, 0x940F4613AE5ED136ull, 0xB913179899F68584ull, 0xE757DD7EC07426E5ull, 0x9096EA6F3848984Full, 0xB4BCA50B065ABE63ull, + 0xE1EBCE4DC7F16DFBull, 0x8D3360F09CF6E4BDull, 0xB080392CC4349DECull, 0xDCA04777F541C567ull, 0x89E42CAAF9491B60ull, 0xAC5D37D5B79B6239ull, 0xD77485CB25823AC7ull, + 0x86A8D39EF77164BCull, 0xA8530886B54DBDEBull, 0xD267CAA862A12D66ull, 0x8380DEA93DA4BC60ull, 0xA46116538D0DEB78ull, 0xCD795BE870516656ull, 0x806BD9714632DFF6ull, + 0xA086CFCD97BF97F3ull, 0xC8A883C0FDAF7DF0ull, 0xFAD2A4B13D1B5D6Cull, 0x9CC3A6EEC6311A63ull, 0xC3F490AA77BD60FCull, 0xF4F1B4D515ACB93Bull, 0x991711052D8BF3C5ull, + 0xBF5CD54678EEF0B6ull, 0xEF340A98172AACE4ull, 0x9580869F0E7AAC0Eull, 0xBAE0A846D2195712ull, 0xE998D258869FACD7ull, 0x91FF83775423CC06ull, 0xB67F6455292CBF08ull, + 0xE41F3D6A7377EECAull, 0x8E938662882AF53Eull, 0xB23867FB2A35B28Dull, 0xDEC681F9F4C31F31ull, 0x8B3C113C38F9F37Eull, 0xAE0B158B4738705Eull, 0xD98DDAEE19068C76ull, + 0x87F8A8D4CFA417C9ull, 0xA9F6D30A038D1DBCull, 0xD47487CC8470652Bull, 0x84C8D4DFD2C63F3Bull, 0xA5FB0A17C777CF09ull, 0xCF79CC9DB955C2CCull, 0x81AC1FE293D599BFull, + 0xA21727DB38CB002Full, 0xCA9CF1D206FDC03Bull, 0xFD442E4688BD304Aull, 0x9E4A9CEC15763E2Eull, 0xC5DD44271AD3CDBAull, 0xF7549530E188C128ull, 0x9A94DD3E8CF578B9ull, + 0xC13A148E3032D6E7ull, 0xF18899B1BC3F8CA1ull, 0x96F5600F15A7B7E5ull, 0xBCB2B812DB11A5DEull, 0xEBDF661791D60F56ull, 0x936B9FCEBB25C995ull, 0xB84687C269EF3BFBull, + 0xE65829B3046B0AFAull, 0x8FF71A0FE2C2E6DCull, 0xB3F4E093DB73A093ull, 0xE0F218B8D25088B8ull, 0x8C974F7383725573ull, 0xAFBD2350644EEACFull, 0xDBAC6C247D62A583ull, + 0x894BC396CE5DA772ull, 0xAB9EB47C81F5114Full, 0xD686619BA27255A2ull, 0x8613FD0145877585ull, 0xA798FC4196E952E7ull, 0xD17F3B51FCA3A7A0ull, 0x82EF85133DE648C4ull, + 0xA3AB66580D5FDAF5ull, 0xCC963FEE10B7D1B3ull, 0xFFBBCFE994E5C61Full, 0x9FD561F1FD0F9BD3ull, 0xC7CABA6E7C5382C8ull, 0xF9BD690A1B68637Bull, 0x9C1661A651213E2Dull, + 0xC31BFA0FE5698DB8ull, 0xF3E2F893DEC3F126ull, 0x986DDB5C6B3A76B7ull, 0xBE89523386091465ull, 0xEE2BA6C0678B597Full, 0x94DB483840B717EFull, 0xBA121A4650E4DDEBull, + 0xE896A0D7E51E1566ull, 0x915E2486EF32CD60ull, 0xB5B5ADA8AAFF80B8ull, 0xE3231912D5BF60E6ull, 0x8DF5EFABC5979C8Full, 0xB1736B96B6FD83B3ull, 0xDDD0467C64BCE4A0ull, + 0x8AA22C0DBEF60EE4ull, 0xAD4AB7112EB3929Dull, 0xD89D64D57A607744ull, 0x87625F056C7C4A8Bull, 0xA93AF6C6C79B5D2Dull, 0xD389B47879823479ull, 0x843610CB4BF160CBull, + 0xA54394FE1EEDB8FEull, 0xCE947A3DA6A9273Eull, 0x811CCC668829B887ull, 0xA163FF802A3426A8ull, 0xC9BCFF6034C13052ull, 0xFC2C3F3841F17C67ull, 0x9D9BA7832936EDC0ull, + 0xC5029163F384A931ull, 0xF64335BCF065D37Dull, 0x99EA0196163FA42Eull, 0xC06481FB9BCF8D39ull, 0xF07DA27A82C37088ull, 0x964E858C91BA2655ull, 0xBBE226EFB628AFEAull, + 0xEADAB0ABA3B2DBE5ull, 0x92C8AE6B464FC96Full, 0xB77ADA0617E3BBCBull, 0xE55990879DDCAABDull, 0x8F57FA54C2A9EAB6ull, 0xB32DF8E9F3546564ull, 0xDFF9772470297EBDull, + 0x8BFBEA76C619EF36ull, 0xAEFAE51477A06B03ull, 0xDAB99E59958885C4ull, 0x88B402F7FD75539Bull, 0xAAE103B5FCD2A881ull, 0xD59944A37C0752A2ull, 0x857FCAE62D8493A5ull, + 0xA6DFBD9FB8E5B88Eull, 0xD097AD07A71F26B2ull, 0x825ECC24C873782Full, 0xA2F67F2DFA90563Bull, 0xCBB41EF979346BCAull, 0xFEA126B7D78186BCull, 0x9F24B832E6B0F436ull, + 0xC6EDE63FA05D3143ull, 0xF8A95FCF88747D94ull, 0x9B69DBE1B548CE7Cull, 0xC24452DA229B021Bull, 0xF2D56790AB41C2A2ull, 0x97C560BA6B0919A5ull, 0xBDB6B8E905CB600Full, + 0xED246723473E3813ull, 0x9436C0760C86E30Bull, 0xB94470938FA89BCEull, 0xE7958CB87392C2C2ull, 0x90BD77F3483BB9B9ull, 0xB4ECD5F01A4AA828ull, 0xE2280B6C20DD5232ull, + 0x8D590723948A535Full, 0xB0AF48EC79ACE837ull, 0xDCDB1B2798182244ull, 0x8A08F0F8BF0F156Bull, 0xAC8B2D36EED2DAC5ull, 0xD7ADF884AA879177ull, 0x86CCBB52EA94BAEAull, + 0xA87FEA27A539E9A5ull, 0xD29FE4B18E88640Eull, 0x83A3EEEEF9153E89ull, 0xA48CEAAAB75A8E2Bull, 0xCDB02555653131B6ull, 0x808E17555F3EBF11ull, 0xA0B19D2AB70E6ED6ull, + 0xC8DE047564D20A8Bull, 0xFB158592BE068D2Eull, 0x9CED737BB6C4183Dull, 0xC428D05AA4751E4Cull, 0xF53304714D9265DFull, 0x993FE2C6D07B7FABull, 0xBF8FDB78849A5F96ull, + 0xEF73D256A5C0F77Cull, 0x95A8637627989AADull, 0xBB127C53B17EC159ull, 0xE9D71B689DDE71AFull, 0x9226712162AB070Dull, 0xB6B00D69BB55C8D1ull, 0xE45C10C42A2B3B05ull, + 0x8EB98A7A9A5B04E3ull, 0xB267ED1940F1C61Cull, 0xDF01E85F912E37A3ull, 0x8B61313BBABCE2C6ull, 0xAE397D8AA96C1B77ull, 0xD9C7DCED53C72255ull, 0x881CEA14545C7575ull, + 0xAA242499697392D2ull, 0xD4AD2DBFC3D07787ull, 0x84EC3C97DA624AB4ull, 0xA6274BBDD0FADD61ull, 0xCFB11EAD453994BAull, 0x81CEB32C4B43FCF4ull, 0xA2425FF75E14FC31ull, + 0xCAD2F7F5359A3B3Eull, 0xFD87B5F28300CA0Dull, 0x9E74D1B791E07E48ull, 0xC612062576589DDAull, 0xF79687AED3EEC551ull, 0x9ABE14CD44753B52ull, 0xC16D9A0095928A27ull, + 0xF1C90080BAF72CB1ull, 0x971DA05074DA7BEEull, 0xBCE5086492111AEAull, 0xEC1E4A7DB69561A5ull, 0x9392EE8E921D5D07ull, 0xB877AA3236A4B449ull, 0xE69594BEC44DE15Bull, + 0x901D7CF73AB0ACD9ull, 0xB424DC35095CD80Full, 0xE12E13424BB40E13ull, 0x8CBCCC096F5088CBull, 0xAFEBFF0BCB24AAFEull, 0xDBE6FECEBDEDD5BEull, 0x89705F4136B4A597ull, + 0xABCC77118461CEFCull, 0xD6BF94D5E57A42BCull, 0x8637BD05AF6C69B5ull, 0xA7C5AC471B478423ull, 0xD1B71758E219652Bull, 0x83126E978D4FDF3Bull, 0xA3D70A3D70A3D70Aull, + 0xCCCCCCCCCCCCCCCCull, 0x8000000000000000ull, 0xA000000000000000ull, 0xC800000000000000ull, 0xFA00000000000000ull, 0x9C40000000000000ull, 0xC350000000000000ull, + 0xF424000000000000ull, 0x9896800000000000ull, 0xBEBC200000000000ull, 0xEE6B280000000000ull, 0x9502F90000000000ull, 0xBA43B74000000000ull, 0xE8D4A51000000000ull, + 0x9184E72A00000000ull, 0xB5E620F480000000ull, 0xE35FA931A0000000ull, 0x8E1BC9BF04000000ull, 0xB1A2BC2EC5000000ull, 0xDE0B6B3A76400000ull, 0x8AC7230489E80000ull, + 0xAD78EBC5AC620000ull, 0xD8D726B7177A8000ull, 0x878678326EAC9000ull, 0xA968163F0A57B400ull, 0xD3C21BCECCEDA100ull, 0x84595161401484A0ull, 0xA56FA5B99019A5C8ull, + 0xCECB8F27F4200F3Aull, 0x813F3978F8940984ull, 0xA18F07D736B90BE5ull, 0xC9F2C9CD04674EDEull, 0xFC6F7C4045812296ull, 0x9DC5ADA82B70B59Dull, 0xC5371912364CE305ull, + 0xF684DF56C3E01BC6ull, 0x9A130B963A6C115Cull, 0xC097CE7BC90715B3ull, 0xF0BDC21ABB48DB20ull, 0x96769950B50D88F4ull, 0xBC143FA4E250EB31ull, 0xEB194F8E1AE525FDull, + 0x92EFD1B8D0CF37BEull, 0xB7ABC627050305ADull, 0xE596B7B0C643C719ull, 0x8F7E32CE7BEA5C6Full, 0xB35DBF821AE4F38Bull, 0xE0352F62A19E306Eull, 0x8C213D9DA502DE45ull, + 0xAF298D050E4395D6ull, 0xDAF3F04651D47B4Cull, 0x88D8762BF324CD0Full, 0xAB0E93B6EFEE0053ull, 0xD5D238A4ABE98068ull, 0x85A36366EB71F041ull, 0xA70C3C40A64E6C51ull, + 0xD0CF4B50CFE20765ull, 0x82818F1281ED449Full, 0xA321F2D7226895C7ull, 0xCBEA6F8CEB02BB39ull, 0xFEE50B7025C36A08ull, 0x9F4F2726179A2245ull, 0xC722F0EF9D80AAD6ull, + 0xF8EBAD2B84E0D58Bull, 0x9B934C3B330C8577ull, 0xC2781F49FFCFA6D5ull, 0xF316271C7FC3908Aull, 0x97EDD871CFDA3A56ull, 0xBDE94E8E43D0C8ECull, 0xED63A231D4C4FB27ull, + 0x945E455F24FB1CF8ull, 0xB975D6B6EE39E436ull, 0xE7D34C64A9C85D44ull, 0x90E40FBEEA1D3A4Aull, 0xB51D13AEA4A488DDull, 0xE264589A4DCDAB14ull, 0x8D7EB76070A08AECull, + 0xB0DE65388CC8ADA8ull, 0xDD15FE86AFFAD912ull, 0x8A2DBF142DFCC7ABull, 0xACB92ED9397BF996ull, 0xD7E77A8F87DAF7FBull, 0x86F0AC99B4E8DAFDull, 0xA8ACD7C0222311BCull, + 0xD2D80DB02AABD62Bull, 0x83C7088E1AAB65DBull, 0xA4B8CAB1A1563F52ull, 0xCDE6FD5E09ABCF26ull, 0x80B05E5AC60B6178ull, 0xA0DC75F1778E39D6ull, 0xC913936DD571C84Cull, + 0xFB5878494ACE3A5Full, 0x9D174B2DCEC0E47Bull, 0xC45D1DF942711D9Aull, 0xF5746577930D6500ull, 0x9968BF6ABBE85F20ull, 0xBFC2EF456AE276E8ull, 0xEFB3AB16C59B14A2ull, + 0x95D04AEE3B80ECE5ull, 0xBB445DA9CA61281Full, 0xEA1575143CF97226ull, 0x924D692CA61BE758ull, 0xB6E0C377CFA2E12Eull, 0xE498F455C38B997Aull, 0x8EDF98B59A373FECull, + 0xB2977EE300C50FE7ull, 0xDF3D5E9BC0F653E1ull, 0x8B865B215899F46Cull, 0xAE67F1E9AEC07187ull, 0xDA01EE641A708DE9ull, 0x884134FE908658B2ull, 0xAA51823E34A7EEDEull, + 0xD4E5E2CDC1D1EA96ull, 0x850FADC09923329Eull, 0xA6539930BF6BFF45ull, 0xCFE87F7CEF46FF16ull, 0x81F14FAE158C5F6Eull, 0xA26DA3999AEF7749ull, 0xCB090C8001AB551Cull, + 0xFDCB4FA002162A63ull, 0x9E9F11C4014DDA7Eull, 0xC646D63501A1511Dull, 0xF7D88BC24209A565ull, 0x9AE757596946075Full, 0xC1A12D2FC3978937ull, 0xF209787BB47D6B84ull, + 0x9745EB4D50CE6332ull, 0xBD176620A501FBFFull, 0xEC5D3FA8CE427AFFull, 0x93BA47C980E98CDFull, 0xB8A8D9BBE123F017ull, 0xE6D3102AD96CEC1Dull, 0x9043EA1AC7E41392ull, + 0xB454E4A179DD1877ull, 0xE16A1DC9D8545E94ull, 0x8CE2529E2734BB1Dull, 0xB01AE745B101E9E4ull, 0xDC21A1171D42645Dull, 0x899504AE72497EBAull, 0xABFA45DA0EDBDE69ull, + 0xD6F8D7509292D603ull, 0x865B86925B9BC5C2ull, 0xA7F26836F282B732ull, 0xD1EF0244AF2364FFull, 0x8335616AED761F1Full, 0xA402B9C5A8D3A6E7ull, 0xCD036837130890A1ull, + 0x802221226BE55A64ull, 0xA02AA96B06DEB0FDull, 0xC83553C5C8965D3Dull, 0xFA42A8B73ABBF48Cull, 0x9C69A97284B578D7ull, 0xC38413CF25E2D70Dull, 0xF46518C2EF5B8CD1ull, + 0x98BF2F79D5993802ull, 0xBEEEFB584AFF8603ull, 0xEEAABA2E5DBF6784ull, 0x952AB45CFA97A0B2ull, 0xBA756174393D88DFull, 0xE912B9D1478CEB17ull, 0x91ABB422CCB812EEull, + 0xB616A12B7FE617AAull, 0xE39C49765FDF9D94ull, 0x8E41ADE9FBEBC27Dull, 0xB1D219647AE6B31Cull, 0xDE469FBD99A05FE3ull, 0x8AEC23D680043BEEull, 0xADA72CCC20054AE9ull, + 0xD910F7FF28069DA4ull, 0x87AA9AFF79042286ull, 0xA99541BF57452B28ull, 0xD3FA922F2D1675F2ull, 0x847C9B5D7C2E09B7ull, 0xA59BC234DB398C25ull, 0xCF02B2C21207EF2Eull, + 0x8161AFB94B44F57Dull, 0xA1BA1BA79E1632DCull, 0xCA28A291859BBF93ull, 0xFCB2CB35E702AF78ull, 0x9DEFBF01B061ADABull, 0xC56BAEC21C7A1916ull, 0xF6C69A72A3989F5Bull, + 0x9A3C2087A63F6399ull, 0xC0CB28A98FCF3C7Full, 0xF0FDF2D3F3C30B9Full, 0x969EB7C47859E743ull, 0xBC4665B596706114ull, 0xEB57FF22FC0C7959ull, 0x9316FF75DD87CBD8ull, + 0xB7DCBF5354E9BECEull, 0xE5D3EF282A242E81ull, 0x8FA475791A569D10ull, 0xB38D92D760EC4455ull, 0xE070F78D3927556Aull, 0x8C469AB843B89562ull, 0xAF58416654A6BABBull, + 0xDB2E51BFE9D0696Aull, 0x88FCF317F22241E2ull, 0xAB3C2FDDEEAAD25Aull, 0xD60B3BD56A5586F1ull, 0x85C7056562757456ull, 0xA738C6BEBB12D16Cull, 0xD106F86E69D785C7ull, + 0x82A45B450226B39Cull, 0xA34D721642B06084ull, 0xCC20CE9BD35C78A5ull, 0xFF290242C83396CEull, 0x9F79A169BD203E41ull, 0xC75809C42C684DD1ull, 0xF92E0C3537826145ull, + 0x9BBCC7A142B17CCBull, 0xC2ABF989935DDBFEull, 0xF356F7EBF83552FEull, 0x98165AF37B2153DEull, 0xBE1BF1B059E9A8D6ull, 0xEDA2EE1C7064130Cull, 0x9485D4D1C63E8BE7ull, + 0xB9A74A0637CE2EE1ull, 0xE8111C87C5C1BA99ull, 0x910AB1D4DB9914A0ull, 0xB54D5E4A127F59C8ull, 0xE2A0B5DC971F303Aull, 0x8DA471A9DE737E24ull, 0xB10D8E1456105DADull, + 0xDD50F1996B947518ull, 0x8A5296FFE33CC92Full, 0xACE73CBFDC0BFB7Bull, 0xD8210BEFD30EFA5Aull, 0x8714A775E3E95C78ull, 0xA8D9D1535CE3B396ull, 0xD31045A8341CA07Cull, + 0x83EA2B892091E44Dull, 0xA4E4B66B68B65D60ull, 0xCE1DE40642E3F4B9ull, 0x80D2AE83E9CE78F3ull, 0xA1075A24E4421730ull, 0xC94930AE1D529CFCull, 0xFB9B7CD9A4A7443Cull, + 0x9D412E0806E88AA5ull, 0xC491798A08A2AD4Eull, 0xF5B5D7EC8ACB58A2ull, 0x9991A6F3D6BF1765ull, 0xBFF610B0CC6EDD3Full, 0xEFF394DCFF8A948Eull, 0x95F83D0A1FB69CD9ull, + 0xBB764C4CA7A4440Full, 0xEA53DF5FD18D5513ull, 0x92746B9BE2F8552Cull, 0xB7118682DBB66A77ull, 0xE4D5E82392A40515ull, 0x8F05B1163BA6832Dull, 0xB2C71D5BCA9023F8ull, + 0xDF78E4B2BD342CF6ull, 0x8BAB8EEFB6409C1Aull, 0xAE9672ABA3D0C320ull, 0xDA3C0F568CC4F3E8ull, 0x8865899617FB1871ull, 0xAA7EEBFB9DF9DE8Dull, 0xD51EA6FA85785631ull, + 0x8533285C936B35DEull, 0xA67FF273B8460356ull, 0xD01FEF10A657842Cull, 0x8213F56A67F6B29Bull, 0xA298F2C501F45F42ull, 0xCB3F2F7642717713ull, 0xFE0EFB53D30DD4D7ull, + 0x9EC95D1463E8A506ull, 0xC67BB4597CE2CE48ull, 0xF81AA16FDC1B81DAull, 0x9B10A4E5E9913128ull, 0xC1D4CE1F63F57D72ull, 0xF24A01A73CF2DCCFull, 0x976E41088617CA01ull, + 0xBD49D14AA79DBC82ull, 0xEC9C459D51852BA2ull, 0x93E1AB8252F33B45ull, 0xB8DA1662E7B00A17ull, 0xE7109BFBA19C0C9Dull, 0x906A617D450187E2ull, 0xB484F9DC9641E9DAull, + 0xE1A63853BBD26451ull, 0x8D07E33455637EB2ull, 0xB049DC016ABC5E5Full, 0xDC5C5301C56B75F7ull, 0x89B9B3E11B6329BAull, 0xAC2820D9623BF429ull, 0xD732290FBACAF133ull, + 0x867F59A9D4BED6C0ull, 0xA81F301449EE8C70ull, 0xD226FC195C6A2F8Cull, 0x83585D8FD9C25DB7ull, 0xA42E74F3D032F525ull, 0xCD3A1230C43FB26Full, 0x80444B5E7AA7CF85ull, + 0xA0555E361951C366ull, 0xC86AB5C39FA63440ull, 0xFA856334878FC150ull, 0x9C935E00D4B9D8D2ull, 0xC3B8358109E84F07ull, 0xF4A642E14C6262C8ull, 0x98E7E9CCCFBD7DBDull, + 0xBF21E44003ACDD2Cull, 0xEEEA5D5004981478ull, 0x95527A5202DF0CCBull, 0xBAA718E68396CFFDull, 0xE950DF20247C83FDull, 0x91D28B7416CDD27Eull, 0xB6472E511C81471Dull, + 0xE3D8F9E563A198E5ull, 0x8E679C2F5E44FF8Full, 0xB201833B35D63F73ull, 0xDE81E40A034BCF4Full, 0x8B112E86420F6191ull, 0xADD57A27D29339F6ull, 0xD94AD8B1C7380874ull, + 0x87CEC76F1C830548ull, 0xA9C2794AE3A3C69Aull, 0xD433179D9C8CB841ull, 0x849FEEC281D7F328ull, 0xA5C7EA73224DEFF3ull, 0xCF39E50FEAE16BEFull, 0x81842F29F2CCE375ull, + 0xA1E53AF46F801C53ull, 0xCA5E89B18B602368ull, 0xFCF62C1DEE382C42ull, 0x9E19DB92B4E31BA9ull }; - template jsonifier_constexpr value_type digitToVal32[]{ static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0x00000000u), static_cast(0x00000001u), - static_cast(0x00000002u), static_cast(0x00000003u), static_cast(0x00000004u), static_cast(0x00000005u), - static_cast(0x00000006u), static_cast(0x00000007u), static_cast(0x00000008u), static_cast(0x00000009u), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0x0000000au), - static_cast(0x0000000bu), static_cast(0x0000000cu), static_cast(0x0000000du), static_cast(0x0000000eu), - static_cast(0x0000000fu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0x0000000au), - static_cast(0x0000000bu), static_cast(0x0000000cu), static_cast(0x0000000du), static_cast(0x0000000eu), - static_cast(0x0000000fu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0x00000000u), static_cast(0x00000010u), static_cast(0x00000020u), static_cast(0x00000030u), - static_cast(0x00000040u), static_cast(0x00000050u), static_cast(0x00000060u), static_cast(0x00000070u), - static_cast(0x00000080u), static_cast(0x00000090u), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0x000000a0u), static_cast(0x000000b0u), static_cast(0x000000c0u), - static_cast(0x000000d0u), static_cast(0x000000e0u), static_cast(0x000000f0u), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0x000000a0u), static_cast(0x000000b0u), static_cast(0x000000c0u), - static_cast(0x000000d0u), static_cast(0x000000e0u), static_cast(0x000000f0u), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0x00000000u), static_cast(0x00000100u), - static_cast(0x00000200u), static_cast(0x00000300u), static_cast(0x00000400u), static_cast(0x00000500u), - static_cast(0x00000600u), static_cast(0x00000700u), static_cast(0x00000800u), static_cast(0x00000900u), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0x00000a00u), - static_cast(0x00000b00u), static_cast(0x00000c00u), static_cast(0x00000d00u), static_cast(0x00000e00u), - static_cast(0x00000f00u), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0x00000a00u), - static_cast(0x00000b00u), static_cast(0x00000c00u), static_cast(0x00000d00u), static_cast(0x00000e00u), - static_cast(0x00000f00u), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0x00000000u), static_cast(0x00001000u), static_cast(0x00002000u), static_cast(0x00003000u), - static_cast(0x00004000u), static_cast(0x00005000u), static_cast(0x00006000u), static_cast(0x00007000u), - static_cast(0x00008000u), static_cast(0x00009000u), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0x0000a000u), static_cast(0x0000b000u), static_cast(0x0000c000u), - static_cast(0x0000d000u), static_cast(0x0000e000u), static_cast(0x0000f000u), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0x0000a000u), static_cast(0x0000b000u), static_cast(0x0000c000u), - static_cast(0x0000d000u), static_cast(0x0000e000u), static_cast(0x0000f000u), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), - static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu), static_cast(0xffffffffu) }; + constexpr uint64_t pow10SigTable128[]{ 0xBF29DCABA82FDEAEull, 0x7432EE873880FC33ull, 0xEEF453D6923BD65Aull, 0x113FAA2906A13B3Full, 0x9558B4661B6565F8ull, 0x4AC7CA59A424C507ull, + 0xBAAEE17FA23EBF76ull, 0x5D79BCF00D2DF649ull, 0xE95A99DF8ACE6F53ull, 0xF4D82C2C107973DCull, 0x91D8A02BB6C10594ull, 0x79071B9B8A4BE869ull, 0xB64EC836A47146F9ull, + 0x9748E2826CDEE284ull, 0xE3E27A444D8D98B7ull, 0xFD1B1B2308169B25ull, 0x8E6D8C6AB0787F72ull, 0xFE30F0F5E50E20F7ull, 0xB208EF855C969F4Full, 0xBDBD2D335E51A935ull, + 0xDE8B2B66B3BC4723ull, 0xAD2C788035E61382ull, 0x8B16FB203055AC76ull, 0x4C3BCB5021AFCC31ull, 0xADDCB9E83C6B1793ull, 0xDF4ABE242A1BBF3Dull, 0xD953E8624B85DD78ull, + 0xD71D6DAD34A2AF0Dull, 0x87D4713D6F33AA6Bull, 0x8672648C40E5AD68ull, 0xA9C98D8CCB009506ull, 0x680EFDAF511F18C2ull, 0xD43BF0EFFDC0BA48ull, 0x0212BD1B2566DEF2ull, + 0x84A57695FE98746Dull, 0x014BB630F7604B57ull, 0xA5CED43B7E3E9188ull, 0x419EA3BD35385E2Dull, 0xCF42894A5DCE35EAull, 0x52064CAC828675B9ull, 0x818995CE7AA0E1B2ull, + 0x7343EFEBD1940993ull, 0xA1EBFB4219491A1Full, 0x1014EBE6C5F90BF8ull, 0xCA66FA129F9B60A6ull, 0xD41A26E077774EF6ull, 0xFD00B897478238D0ull, 0x8920B098955522B4ull, + 0x9E20735E8CB16382ull, 0x55B46E5F5D5535B0ull, 0xC5A890362FDDBC62ull, 0xEB2189F734AA831Dull, 0xF712B443BBD52B7Bull, 0xA5E9EC7501D523E4ull, 0x9A6BB0AA55653B2Dull, + 0x47B233C92125366Eull, 0xC1069CD4EABE89F8ull, 0x999EC0BB696E840Aull, 0xF148440A256E2C76ull, 0xC00670EA43CA250Dull, 0x96CD2A865764DBCAull, 0x380406926A5E5728ull, + 0xBC807527ED3E12BCull, 0xC605083704F5ECF2ull, 0xEBA09271E88D976Bull, 0xF7864A44C633682Eull, 0x93445B8731587EA3ull, 0x7AB3EE6AFBE0211Dull, 0xB8157268FDAE9E4Cull, + 0x5960EA05BAD82964ull, 0xE61ACF033D1A45DFull, 0x6FB92487298E33BDull, 0x8FD0C16206306BABull, 0xA5D3B6D479F8E056ull, 0xB3C4F1BA87BC8696ull, 0x8F48A4899877186Cull, + 0xE0B62E2929ABA83Cull, 0x331ACDABFE94DE87ull, 0x8C71DCD9BA0B4925ull, 0x9FF0C08B7F1D0B14ull, 0xAF8E5410288E1B6Full, 0x07ECF0AE5EE44DD9ull, 0xDB71E91432B1A24Aull, + 0xC9E82CD9F69D6150ull, 0x892731AC9FAF056Eull, 0xBE311C083A225CD2ull, 0xAB70FE17C79AC6CAull, 0x6DBD630A48AAF406ull, 0xD64D3D9DB981787Dull, 0x092CBBCCDAD5B108ull, + 0x85F0468293F0EB4Eull, 0x25BBF56008C58EA5ull, 0xA76C582338ED2621ull, 0xAF2AF2B80AF6F24Eull, 0xD1476E2C07286FAAull, 0x1AF5AF660DB4AEE1ull, 0x82CCA4DB847945CAull, + 0x50D98D9FC890ED4Dull, 0xA37FCE126597973Cull, 0xE50FF107BAB528A0ull, 0xCC5FC196FEFD7D0Cull, 0x1E53ED49A96272C8ull, 0xFF77B1FCBEBCDC4Full, 0x25E8E89C13BB0F7Aull, + 0x9FAACF3DF73609B1ull, 0x77B191618C54E9ACull, 0xC795830D75038C1Dull, 0xD59DF5B9EF6A2417ull, 0xF97AE3D0D2446F25ull, 0x4B0573286B44AD1Dull, 0x9BECCE62836AC577ull, + 0x4EE367F9430AEC32ull, 0xC2E801FB244576D5ull, 0x229C41F793CDA73Full, 0xF3A20279ED56D48Aull, 0x6B43527578C1110Full, 0x9845418C345644D6ull, 0x830A13896B78AAA9ull, + 0xBE5691EF416BD60Cull, 0x23CC986BC656D553ull, 0xEDEC366B11C6CB8Full, 0x2CBFBE86B7EC8AA8ull, 0x94B3A202EB1C3F39ull, 0x7BF7D71432F3D6A9ull, 0xB9E08A83A5E34F07ull, + 0xDAF5CCD93FB0CC53ull, 0xE858AD248F5C22C9ull, 0xD1B3400F8F9CFF68ull, 0x91376C36D99995BEull, 0x23100809B9C21FA1ull, 0xB58547448FFFFB2Dull, 0xABD40A0C2832A78Aull, + 0xE2E69915B3FFF9F9ull, 0x16C90C8F323F516Cull, 0x8DD01FAD907FFC3Bull, 0xAE3DA7D97F6792E3ull, 0xB1442798F49FFB4Aull, 0x99CD11CFDF41779Cull, 0xDD95317F31C7FA1Dull, + 0x40405643D711D583ull, 0x8A7D3EEF7F1CFC52ull, 0x482835EA666B2572ull, 0xAD1C8EAB5EE43B66ull, 0xDA3243650005EECFull, 0xD863B256369D4A40ull, 0x90BED43E40076A82ull, + 0x873E4F75E2224E68ull, 0x5A7744A6E804A291ull, 0xA90DE3535AAAE202ull, 0x711515D0A205CB36ull, 0xD3515C2831559A83ull, 0x0D5A5B44CA873E03ull, 0x8412D9991ED58091ull, + 0xE858790AFE9486C2ull, 0xA5178FFF668AE0B6ull, 0x626E974DBE39A872ull, 0xCE5D73FF402D98E3ull, 0xFB0A3D212DC8128Full, 0x80FA687F881C7F8Eull, 0x7CE66634BC9D0B99ull, + 0xA139029F6A239F72ull, 0x1C1FFFC1EBC44E80ull, 0xC987434744AC874Eull, 0xA327FFB266B56220ull, 0xFBE9141915D7A922ull, 0x4BF1FF9F0062BAA8ull, 0x9D71AC8FADA6C9B5ull, + 0x6F773FC3603DB4A9ull, 0xC4CE17B399107C22ull, 0xCB550FB4384D21D3ull, 0xF6019DA07F549B2Bull, 0x7E2A53A146606A48ull, 0x99C102844F94E0FBull, 0x2EDA7444CBFC426Dull, + 0xC0314325637A1939ull, 0xFA911155FEFB5308ull, 0xF03D93EEBC589F88ull, 0x793555AB7EBA27CAull, 0x96267C7535B763B5ull, 0x4BC1558B2F3458DEull, 0xBBB01B9283253CA2ull, + 0x9EB1AAEDFB016F16ull, 0xEA9C227723EE8BCBull, 0x465E15A979C1CADCull, 0x92A1958A7675175Full, 0x0BFACD89EC191EC9ull, 0xB749FAED14125D36ull, 0xCEF980EC671F667Bull, + 0xE51C79A85916F484ull, 0x82B7E12780E7401Aull, 0x8F31CC0937AE58D2ull, 0xD1B2ECB8B0908810ull, 0xB2FE3F0B8599EF07ull, 0x861FA7E6DCB4AA15ull, 0xDFBDCECE67006AC9ull, + 0x67A791E093E1D49Aull, 0x8BD6A141006042BDull, 0xE0C8BB2C5C6D24E0ull, 0xAECC49914078536Dull, 0x58FAE9F773886E18ull, 0xDA7F5BF590966848ull, 0xAF39A475506A899Eull, + 0x888F99797A5E012Dull, 0x6D8406C952429603ull, 0xAAB37FD7D8F58178ull, 0xC8E5087BA6D33B83ull, 0xD5605FCDCF32E1D6ull, 0xFB1E4A9A90880A64ull, 0x855C3BE0A17FCD26ull, + 0x5CF2EEA09A55067Full, 0xA6B34AD8C9DFC06Full, 0xF42FAA48C0EA481Eull, 0xD0601D8EFC57B08Bull, 0xF13B94DAF124DA26ull, 0x823C12795DB6CE57ull, 0x76C53D08D6B70858ull, + 0xA2CB1717B52481EDull, 0x54768C4B0C64CA6Eull, 0xCB7DDCDDA26DA268ull, 0xA9942F5DCF7DFD09ull, 0xFE5D54150B090B02ull, 0xD3F93B35435D7C4Cull, 0x9EFA548D26E5A6E1ull, + 0xC47BC5014A1A6DAFull, 0xC6B8E9B0709F109Aull, 0x359AB6419CA1091Bull, 0xF867241C8CC6D4C0ull, 0xC30163D203C94B62ull, 0x9B407691D7FC44F8ull, 0x79E0DE63425DCF1Dull, + 0xC21094364DFB5636ull, 0x985915FC12F542E4ull, 0xF294B943E17A2BC4ull, 0x3E6F5B7B17B2939Dull, 0x979CF3CA6CEC5B5Aull, 0xA705992CEECF9C42ull, 0xBD8430BD08277231ull, + 0x50C6FF782A838353ull, 0xECE53CEC4A314EBDull, 0xA4F8BF5635246428ull, 0x940F4613AE5ED136ull, 0x871B7795E136BE99ull, 0xB913179899F68584ull, 0x28E2557B59846E3Full, + 0xE757DD7EC07426E5ull, 0x331AEADA2FE589CFull, 0x9096EA6F3848984Full, 0x3FF0D2C85DEF7621ull, 0xB4BCA50B065ABE63ull, 0x0FED077A756B53A9ull, 0xE1EBCE4DC7F16DFBull, + 0xD3E8495912C62894ull, 0x8D3360F09CF6E4BDull, 0x64712DD7ABBBD95Cull, 0xB080392CC4349DECull, 0xBD8D794D96AACFB3ull, 0xDCA04777F541C567ull, 0xECF0D7A0FC5583A0ull, + 0x89E42CAAF9491B60ull, 0xF41686C49DB57244ull, 0xAC5D37D5B79B6239ull, 0x311C2875C522CED5ull, 0xD77485CB25823AC7ull, 0x7D633293366B828Bull, 0x86A8D39EF77164BCull, + 0xAE5DFF9C02033197ull, 0xA8530886B54DBDEBull, 0xD9F57F830283FDFCull, 0xD267CAA862A12D66ull, 0xD072DF63C324FD7Bull, 0x8380DEA93DA4BC60ull, 0x4247CB9E59F71E6Dull, + 0xA46116538D0DEB78ull, 0x52D9BE85F074E608ull, 0xCD795BE870516656ull, 0x67902E276C921F8Bull, 0x806BD9714632DFF6ull, 0x00BA1CD8A3DB53B6ull, 0xA086CFCD97BF97F3ull, + 0x80E8A40ECCD228A4ull, 0xC8A883C0FDAF7DF0ull, 0x6122CD128006B2CDull, 0xFAD2A4B13D1B5D6Cull, 0x796B805720085F81ull, 0x9CC3A6EEC6311A63ull, 0xCBE3303674053BB0ull, + 0xC3F490AA77BD60FCull, 0xBEDBFC4411068A9Cull, 0xF4F1B4D515ACB93Bull, 0xEE92FB5515482D44ull, 0x991711052D8BF3C5ull, 0x751BDD152D4D1C4Aull, 0xBF5CD54678EEF0B6ull, + 0xD262D45A78A0635Dull, 0xEF340A98172AACE4ull, 0x86FB897116C87C34ull, 0x9580869F0E7AAC0Eull, 0xD45D35E6AE3D4DA0ull, 0xBAE0A846D2195712ull, 0x8974836059CCA109ull, + 0xE998D258869FACD7ull, 0x2BD1A438703FC94Bull, 0x91FF83775423CC06ull, 0x7B6306A34627DDCFull, 0xB67F6455292CBF08ull, 0x1A3BC84C17B1D542ull, 0xE41F3D6A7377EECAull, + 0x20CABA5F1D9E4A93ull, 0x8E938662882AF53Eull, 0x547EB47B7282EE9Cull, 0xB23867FB2A35B28Dull, 0xE99E619A4F23AA43ull, 0xDEC681F9F4C31F31ull, 0x6405FA00E2EC94D4ull, + 0x8B3C113C38F9F37Eull, 0xDE83BC408DD3DD04ull, 0xAE0B158B4738705Eull, 0x9624AB50B148D445ull, 0xD98DDAEE19068C76ull, 0x3BADD624DD9B0957ull, 0x87F8A8D4CFA417C9ull, + 0xE54CA5D70A80E5D6ull, 0xA9F6D30A038D1DBCull, 0x5E9FCF4CCD211F4Cull, 0xD47487CC8470652Bull, 0x7647C3200069671Full, 0x84C8D4DFD2C63F3Bull, 0x29ECD9F40041E073ull, + 0xA5FB0A17C777CF09ull, 0xF468107100525890ull, 0xCF79CC9DB955C2CCull, 0x7182148D4066EEB4ull, 0x81AC1FE293D599BFull, 0xC6F14CD848405530ull, 0xA21727DB38CB002Full, + 0xB8ADA00E5A506A7Cull, 0xCA9CF1D206FDC03Bull, 0xA6D90811F0E4851Cull, 0xFD442E4688BD304Aull, 0x908F4A166D1DA663ull, 0x9E4A9CEC15763E2Eull, 0x9A598E4E043287FEull, + 0xC5DD44271AD3CDBAull, 0x40EFF1E1853F29FDull, 0xF7549530E188C128ull, 0xD12BEE59E68EF47Cull, 0x9A94DD3E8CF578B9ull, 0x82BB74F8301958CEull, 0xC13A148E3032D6E7ull, + 0xE36A52363C1FAF01ull, 0xF18899B1BC3F8CA1ull, 0xDC44E6C3CB279AC1ull, 0x96F5600F15A7B7E5ull, 0x29AB103A5EF8C0B9ull, 0xBCB2B812DB11A5DEull, 0x7415D448F6B6F0E7ull, + 0xEBDF661791D60F56ull, 0x111B495B3464AD21ull, 0x936B9FCEBB25C995ull, 0xCAB10DD900BEEC34ull, 0xB84687C269EF3BFBull, 0x3D5D514F40EEA742ull, 0xE65829B3046B0AFAull, + 0x0CB4A5A3112A5112ull, 0x8FF71A0FE2C2E6DCull, 0x47F0E785EABA72ABull, 0xB3F4E093DB73A093ull, 0x59ED216765690F56ull, 0xE0F218B8D25088B8ull, 0x306869C13EC3532Cull, + 0x8C974F7383725573ull, 0x1E414218C73A13FBull, 0xAFBD2350644EEACFull, 0xE5D1929EF90898FAull, 0xDBAC6C247D62A583ull, 0xDF45F746B74ABF39ull, 0x894BC396CE5DA772ull, + 0x6B8BBA8C328EB783ull, 0xAB9EB47C81F5114Full, 0x066EA92F3F326564ull, 0xD686619BA27255A2ull, 0xC80A537B0EFEFEBDull, 0x8613FD0145877585ull, 0xBD06742CE95F5F36ull, + 0xA798FC4196E952E7ull, 0x2C48113823B73704ull, 0xD17F3B51FCA3A7A0ull, 0xF75A15862CA504C5ull, 0x82EF85133DE648C4ull, 0x9A984D73DBE722FBull, 0xA3AB66580D5FDAF5ull, + 0xC13E60D0D2E0EBBAull, 0xCC963FEE10B7D1B3ull, 0x318DF905079926A8ull, 0xFFBBCFE994E5C61Full, 0xFDF17746497F7052ull, 0x9FD561F1FD0F9BD3ull, 0xFEB6EA8BEDEFA633ull, + 0xC7CABA6E7C5382C8ull, 0xFE64A52EE96B8FC0ull, 0xF9BD690A1B68637Bull, 0x3DFDCE7AA3C673B0ull, 0x9C1661A651213E2Dull, 0x06BEA10CA65C084Eull, 0xC31BFA0FE5698DB8ull, + 0x486E494FCFF30A62ull, 0xF3E2F893DEC3F126ull, 0x5A89DBA3C3EFCCFAull, 0x986DDB5C6B3A76B7ull, 0xF89629465A75E01Cull, 0xBE89523386091465ull, 0xF6BBB397F1135823ull, + 0xEE2BA6C0678B597Full, 0x746AA07DED582E2Cull, 0x94DB483840B717EFull, 0xA8C2A44EB4571CDCull, 0xBA121A4650E4DDEBull, 0x92F34D62616CE413ull, 0xE896A0D7E51E1566ull, + 0x77B020BAF9C81D17ull, 0x915E2486EF32CD60ull, 0x0ACE1474DC1D122Eull, 0xB5B5ADA8AAFF80B8ull, 0x0D819992132456BAull, 0xE3231912D5BF60E6ull, 0x10E1FFF697ED6C69ull, + 0x8DF5EFABC5979C8Full, 0xCA8D3FFA1EF463C1ull, 0xB1736B96B6FD83B3ull, 0xBD308FF8A6B17CB2ull, 0xDDD0467C64BCE4A0ull, 0xAC7CB3F6D05DDBDEull, 0x8AA22C0DBEF60EE4ull, + 0x6BCDF07A423AA96Bull, 0xAD4AB7112EB3929Dull, 0x86C16C98D2C953C6ull, 0xD89D64D57A607744ull, 0xE871C7BF077BA8B7ull, 0x87625F056C7C4A8Bull, 0x11471CD764AD4972ull, + 0xA93AF6C6C79B5D2Dull, 0xD598E40D3DD89BCFull, 0xD389B47879823479ull, 0x4AFF1D108D4EC2C3ull, 0x843610CB4BF160CBull, 0xCEDF722A585139BAull, 0xA54394FE1EEDB8FEull, + 0xC2974EB4EE658828ull, 0xCE947A3DA6A9273Eull, 0x733D226229FEEA32ull, 0x811CCC668829B887ull, 0x0806357D5A3F525Full, 0xA163FF802A3426A8ull, 0xCA07C2DCB0CF26F7ull, + 0xC9BCFF6034C13052ull, 0xFC89B393DD02F0B5ull, 0xFC2C3F3841F17C67ull, 0xBBAC2078D443ACE2ull, 0x9D9BA7832936EDC0ull, 0xD54B944B84AA4C0Dull, 0xC5029163F384A931ull, + 0x0A9E795E65D4DF11ull, 0xF64335BCF065D37Dull, 0x4D4617B5FF4A16D5ull, 0x99EA0196163FA42Eull, 0x504BCED1BF8E4E45ull, 0xC06481FB9BCF8D39ull, 0xE45EC2862F71E1D6ull, + 0xF07DA27A82C37088ull, 0x5D767327BB4E5A4Cull, 0x964E858C91BA2655ull, 0x3A6A07F8D510F86Full, 0xBBE226EFB628AFEAull, 0x890489F70A55368Bull, 0xEADAB0ABA3B2DBE5ull, + 0x2B45AC74CCEA842Eull, 0x92C8AE6B464FC96Full, 0x3B0B8BC90012929Dull, 0xB77ADA0617E3BBCBull, 0x09CE6EBB40173744ull, 0xE55990879DDCAABDull, 0xCC420A6A101D0515ull, + 0x8F57FA54C2A9EAB6ull, 0x9FA946824A12232Dull, 0xB32DF8E9F3546564ull, 0x47939822DC96ABF9ull, 0xDFF9772470297EBDull, 0x59787E2B93BC56F7ull, 0x8BFBEA76C619EF36ull, + 0x57EB4EDB3C55B65Aull, 0xAEFAE51477A06B03ull, 0xEDE622920B6B23F1ull, 0xDAB99E59958885C4ull, 0xE95FAB368E45ECEDull, 0x88B402F7FD75539Bull, 0x11DBCB0218EBB414ull, + 0xAAE103B5FCD2A881ull, 0xD652BDC29F26A119ull, 0xD59944A37C0752A2ull, 0x4BE76D3346F0495Full, 0x857FCAE62D8493A5ull, 0x6F70A4400C562DDBull, 0xA6DFBD9FB8E5B88Eull, + 0xCB4CCD500F6BB952ull, 0xD097AD07A71F26B2ull, 0x7E2000A41346A7A7ull, 0x825ECC24C873782Full, 0x8ED400668C0C28C8ull, 0xA2F67F2DFA90563Bull, 0x728900802F0F32FAull, + 0xCBB41EF979346BCAull, 0x4F2B40A03AD2FFB9ull, 0xFEA126B7D78186BCull, 0xE2F610C84987BFA8ull, 0x9F24B832E6B0F436ull, 0x0DD9CA7D2DF4D7C9ull, 0xC6EDE63FA05D3143ull, + 0x91503D1C79720DBBull, 0xF8A95FCF88747D94ull, 0x75A44C6397CE912Aull, 0x9B69DBE1B548CE7Cull, 0xC986AFBE3EE11ABAull, 0xC24452DA229B021Bull, 0xFBE85BADCE996168ull, + 0xF2D56790AB41C2A2ull, 0xFAE27299423FB9C3ull, 0x97C560BA6B0919A5ull, 0xDCCD879FC967D41Aull, 0xBDB6B8E905CB600Full, 0x5400E987BBC1C920ull, 0xED246723473E3813ull, + 0x290123E9AAB23B68ull, 0x9436C0760C86E30Bull, 0xF9A0B6720AAF6521ull, 0xB94470938FA89BCEull, 0xF808E40E8D5B3E69ull, 0xE7958CB87392C2C2ull, 0xB60B1D1230B20E04ull, + 0x90BD77F3483BB9B9ull, 0xB1C6F22B5E6F48C2ull, 0xB4ECD5F01A4AA828ull, 0x1E38AEB6360B1AF3ull, 0xE2280B6C20DD5232ull, 0x25C6DA63C38DE1B0ull, 0x8D590723948A535Full, + 0x579C487E5A38AD0Eull, 0xB0AF48EC79ACE837ull, 0x2D835A9DF0C6D851ull, 0xDCDB1B2798182244ull, 0xF8E431456CF88E65ull, 0x8A08F0F8BF0F156Bull, 0x1B8E9ECB641B58FFull, + 0xAC8B2D36EED2DAC5ull, 0xE272467E3D222F3Full, 0xD7ADF884AA879177ull, 0x5B0ED81DCC6ABB0Full, 0x86CCBB52EA94BAEAull, 0x98E947129FC2B4E9ull, 0xA87FEA27A539E9A5ull, + 0x3F2398D747B36224ull, 0xD29FE4B18E88640Eull, 0x8EEC7F0D19A03AADull, 0x83A3EEEEF9153E89ull, 0x1953CF68300424ACull, 0xA48CEAAAB75A8E2Bull, 0x5FA8C3423C052DD7ull, + 0xCDB02555653131B6ull, 0x3792F412CB06794Dull, 0x808E17555F3EBF11ull, 0xE2BBD88BBEE40BD0ull, 0xA0B19D2AB70E6ED6ull, 0x5B6ACEAEAE9D0EC4ull, 0xC8DE047564D20A8Bull, + 0xF245825A5A445275ull, 0xFB158592BE068D2Eull, 0xEED6E2F0F0D56712ull, 0x9CED737BB6C4183Dull, 0x55464DD69685606Bull, 0xC428D05AA4751E4Cull, 0xAA97E14C3C26B886ull, + 0xF53304714D9265DFull, 0xD53DD99F4B3066A8ull, 0x993FE2C6D07B7FABull, 0xE546A8038EFE4029ull, 0xBF8FDB78849A5F96ull, 0xDE98520472BDD033ull, 0xEF73D256A5C0F77Cull, + 0x963E66858F6D4440ull, 0x95A8637627989AADull, 0xDDE7001379A44AA8ull, 0xBB127C53B17EC159ull, 0x5560C018580D5D52ull, 0xE9D71B689DDE71AFull, 0xAAB8F01E6E10B4A6ull, + 0x9226712162AB070Dull, 0xCAB3961304CA70E8ull, 0xB6B00D69BB55C8D1ull, 0x3D607B97C5FD0D22ull, 0xE45C10C42A2B3B05ull, 0x8CB89A7DB77C506Aull, 0x8EB98A7A9A5B04E3ull, + 0x77F3608E92ADB242ull, 0xB267ED1940F1C61Cull, 0x55F038B237591ED3ull, 0xDF01E85F912E37A3ull, 0x6B6C46DEC52F6688ull, 0x8B61313BBABCE2C6ull, 0x2323AC4B3B3DA015ull, + 0xAE397D8AA96C1B77ull, 0xABEC975E0A0D081Aull, 0xD9C7DCED53C72255ull, 0x96E7BD358C904A21ull, 0x881CEA14545C7575ull, 0x7E50D64177DA2E54ull, 0xAA242499697392D2ull, + 0xDDE50BD1D5D0B9E9ull, 0xD4AD2DBFC3D07787ull, 0x955E4EC64B44E864ull, 0x84EC3C97DA624AB4ull, 0xBD5AF13BEF0B113Eull, 0xA6274BBDD0FADD61ull, 0xECB1AD8AEACDD58Eull, + 0xCFB11EAD453994BAull, 0x67DE18EDA5814AF2ull, 0x81CEB32C4B43FCF4ull, 0x80EACF948770CED7ull, 0xA2425FF75E14FC31ull, 0xA1258379A94D028Dull, 0xCAD2F7F5359A3B3Eull, + 0x096EE45813A04330ull, 0xFD87B5F28300CA0Dull, 0x8BCA9D6E188853FCull, 0x9E74D1B791E07E48ull, 0x775EA264CF55347Dull, 0xC612062576589DDAull, 0x95364AFE032A819Dull, + 0xF79687AED3EEC551ull, 0x3A83DDBD83F52204ull, 0x9ABE14CD44753B52ull, 0xC4926A9672793542ull, 0xC16D9A0095928A27ull, 0x75B7053C0F178293ull, 0xF1C90080BAF72CB1ull, + 0x5324C68B12DD6338ull, 0x971DA05074DA7BEEull, 0xD3F6FC16EBCA5E03ull, 0xBCE5086492111AEAull, 0x88F4BB1CA6BCF584ull, 0xEC1E4A7DB69561A5ull, 0x2B31E9E3D06C32E5ull, + 0x9392EE8E921D5D07ull, 0x3AFF322E62439FCFull, 0xB877AA3236A4B449ull, 0x09BEFEB9FAD487C2ull, 0xE69594BEC44DE15Bull, 0x4C2EBE687989A9B3ull, 0x901D7CF73AB0ACD9ull, + 0x0F9D37014BF60A10ull, 0xB424DC35095CD80Full, 0x538484C19EF38C94ull, 0xE12E13424BB40E13ull, 0x2865A5F206B06FB9ull, 0x8CBCCC096F5088CBull, 0xF93F87B7442E45D3ull, + 0xAFEBFF0BCB24AAFEull, 0xF78F69A51539D748ull, 0xDBE6FECEBDEDD5BEull, 0xB573440E5A884D1Bull, 0x89705F4136B4A597ull, 0x31680A88F8953030ull, 0xABCC77118461CEFCull, + 0xFDC20D2B36BA7C3Dull, 0xD6BF94D5E57A42BCull, 0x3D32907604691B4Cull, 0x8637BD05AF6C69B5ull, 0xA63F9A49C2C1B10Full, 0xA7C5AC471B478423ull, 0x0FCF80DC33721D53ull, + 0xD1B71758E219652Bull, 0xD3C36113404EA4A8ull, 0x83126E978D4FDF3Bull, 0x645A1CAC083126E9ull, 0xA3D70A3D70A3D70Aull, 0x3D70A3D70A3D70A3ull, 0xCCCCCCCCCCCCCCCCull, + 0xCCCCCCCCCCCCCCCCull, 0x8000000000000000ull, 0x0000000000000000ull, 0xA000000000000000ull, 0x0000000000000000ull, 0xC800000000000000ull, 0x0000000000000000ull, + 0xFA00000000000000ull, 0x0000000000000000ull, 0x9C40000000000000ull, 0x0000000000000000ull, 0xC350000000000000ull, 0x0000000000000000ull, 0xF424000000000000ull, + 0x0000000000000000ull, 0x9896800000000000ull, 0x0000000000000000ull, 0xBEBC200000000000ull, 0x0000000000000000ull, 0xEE6B280000000000ull, 0x0000000000000000ull, + 0x9502F90000000000ull, 0x0000000000000000ull, 0xBA43B74000000000ull, 0x0000000000000000ull, 0xE8D4A51000000000ull, 0x0000000000000000ull, 0x9184E72A00000000ull, + 0x0000000000000000ull, 0xB5E620F480000000ull, 0x0000000000000000ull, 0xE35FA931A0000000ull, 0x0000000000000000ull, 0x8E1BC9BF04000000ull, 0x0000000000000000ull, + 0xB1A2BC2EC5000000ull, 0x0000000000000000ull, 0xDE0B6B3A76400000ull, 0x0000000000000000ull, 0x8AC7230489E80000ull, 0x0000000000000000ull, 0xAD78EBC5AC620000ull, + 0x0000000000000000ull, 0xD8D726B7177A8000ull, 0x0000000000000000ull, 0x878678326EAC9000ull, 0x0000000000000000ull, 0xA968163F0A57B400ull, 0x0000000000000000ull, + 0xD3C21BCECCEDA100ull, 0x0000000000000000ull, 0x84595161401484A0ull, 0x0000000000000000ull, 0xA56FA5B99019A5C8ull, 0x0000000000000000ull, 0xCECB8F27F4200F3Aull, + 0x0000000000000000ull, 0x813F3978F8940984ull, 0x4000000000000000ull, 0xA18F07D736B90BE5ull, 0x5000000000000000ull, 0xC9F2C9CD04674EDEull, 0xA400000000000000ull, + 0xFC6F7C4045812296ull, 0x4D00000000000000ull, 0x9DC5ADA82B70B59Dull, 0xF020000000000000ull, 0xC5371912364CE305ull, 0x6C28000000000000ull, 0xF684DF56C3E01BC6ull, + 0xC732000000000000ull, 0x9A130B963A6C115Cull, 0x3C7F400000000000ull, 0xC097CE7BC90715B3ull, 0x4B9F100000000000ull, 0xF0BDC21ABB48DB20ull, 0x1E86D40000000000ull, + 0x96769950B50D88F4ull, 0x1314448000000000ull, 0xBC143FA4E250EB31ull, 0x17D955A000000000ull, 0xEB194F8E1AE525FDull, 0x5DCFAB0800000000ull, 0x92EFD1B8D0CF37BEull, + 0x5AA1CAE500000000ull, 0xB7ABC627050305ADull, 0xF14A3D9E40000000ull, 0xE596B7B0C643C719ull, 0x6D9CCD05D0000000ull, 0x8F7E32CE7BEA5C6Full, 0xE4820023A2000000ull, + 0xB35DBF821AE4F38Bull, 0xDDA2802C8A800000ull, 0xE0352F62A19E306Eull, 0xD50B2037AD200000ull, 0x8C213D9DA502DE45ull, 0x4526F422CC340000ull, 0xAF298D050E4395D6ull, + 0x9670B12B7F410000ull, 0xDAF3F04651D47B4Cull, 0x3C0CDD765F114000ull, 0x88D8762BF324CD0Full, 0xA5880A69FB6AC800ull, 0xAB0E93B6EFEE0053ull, 0x8EEA0D047A457A00ull, + 0xD5D238A4ABE98068ull, 0x72A4904598D6D880ull, 0x85A36366EB71F041ull, 0x47A6DA2B7F864750ull, 0xA70C3C40A64E6C51ull, 0x999090B65F67D924ull, 0xD0CF4B50CFE20765ull, + 0xFFF4B4E3F741CF6Dull, 0x82818F1281ED449Full, 0xBFF8F10E7A8921A4ull, 0xA321F2D7226895C7ull, 0xAFF72D52192B6A0Dull, 0xCBEA6F8CEB02BB39ull, 0x9BF4F8A69F764490ull, + 0xFEE50B7025C36A08ull, 0x02F236D04753D5B4ull, 0x9F4F2726179A2245ull, 0x01D762422C946590ull, 0xC722F0EF9D80AAD6ull, 0x424D3AD2B7B97EF5ull, 0xF8EBAD2B84E0D58Bull, + 0xD2E0898765A7DEB2ull, 0x9B934C3B330C8577ull, 0x63CC55F49F88EB2Full, 0xC2781F49FFCFA6D5ull, 0x3CBF6B71C76B25FBull, 0xF316271C7FC3908Aull, 0x8BEF464E3945EF7Aull, + 0x97EDD871CFDA3A56ull, 0x97758BF0E3CBB5ACull, 0xBDE94E8E43D0C8ECull, 0x3D52EEED1CBEA317ull, 0xED63A231D4C4FB27ull, 0x4CA7AAA863EE4BDDull, 0x945E455F24FB1CF8ull, + 0x8FE8CAA93E74EF6Aull, 0xB975D6B6EE39E436ull, 0xB3E2FD538E122B44ull, 0xE7D34C64A9C85D44ull, 0x60DBBCA87196B616ull, 0x90E40FBEEA1D3A4Aull, 0xBC8955E946FE31CDull, + 0xB51D13AEA4A488DDull, 0x6BABAB6398BDBE41ull, 0xE264589A4DCDAB14ull, 0xC696963C7EED2DD1ull, 0x8D7EB76070A08AECull, 0xFC1E1DE5CF543CA2ull, 0xB0DE65388CC8ADA8ull, + 0x3B25A55F43294BCBull, 0xDD15FE86AFFAD912ull, 0x49EF0EB713F39EBEull, 0x8A2DBF142DFCC7ABull, 0x6E3569326C784337ull, 0xACB92ED9397BF996ull, 0x49C2C37F07965404ull, + 0xD7E77A8F87DAF7FBull, 0xDC33745EC97BE906ull, 0x86F0AC99B4E8DAFDull, 0x69A028BB3DED71A3ull, 0xA8ACD7C0222311BCull, 0xC40832EA0D68CE0Cull, 0xD2D80DB02AABD62Bull, + 0xF50A3FA490C30190ull, 0x83C7088E1AAB65DBull, 0x792667C6DA79E0FAull, 0xA4B8CAB1A1563F52ull, 0x577001B891185938ull, 0xCDE6FD5E09ABCF26ull, 0xED4C0226B55E6F86ull, + 0x80B05E5AC60B6178ull, 0x544F8158315B05B4ull, 0xA0DC75F1778E39D6ull, 0x696361AE3DB1C721ull, 0xC913936DD571C84Cull, 0x03BC3A19CD1E38E9ull, 0xFB5878494ACE3A5Full, + 0x04AB48A04065C723ull, 0x9D174B2DCEC0E47Bull, 0x62EB0D64283F9C76ull, 0xC45D1DF942711D9Aull, 0x3BA5D0BD324F8394ull, 0xF5746577930D6500ull, 0xCA8F44EC7EE36479ull, + 0x9968BF6ABBE85F20ull, 0x7E998B13CF4E1ECBull, 0xBFC2EF456AE276E8ull, 0x9E3FEDD8C321A67Eull, 0xEFB3AB16C59B14A2ull, 0xC5CFE94EF3EA101Eull, 0x95D04AEE3B80ECE5ull, + 0xBBA1F1D158724A12ull, 0xBB445DA9CA61281Full, 0x2A8A6E45AE8EDC97ull, 0xEA1575143CF97226ull, 0xF52D09D71A3293BDull, 0x924D692CA61BE758ull, 0x593C2626705F9C56ull, + 0xB6E0C377CFA2E12Eull, 0x6F8B2FB00C77836Cull, 0xE498F455C38B997Aull, 0x0B6DFB9C0F956447ull, 0x8EDF98B59A373FECull, 0x4724BD4189BD5EACull, 0xB2977EE300C50FE7ull, + 0x58EDEC91EC2CB657ull, 0xDF3D5E9BC0F653E1ull, 0x2F2967B66737E3EDull, 0x8B865B215899F46Cull, 0xBD79E0D20082EE74ull, 0xAE67F1E9AEC07187ull, 0xECD8590680A3AA11ull, + 0xDA01EE641A708DE9ull, 0xE80E6F4820CC9495ull, 0x884134FE908658B2ull, 0x3109058D147FDCDDull, 0xAA51823E34A7EEDEull, 0xBD4B46F0599FD415ull, 0xD4E5E2CDC1D1EA96ull, + 0x6C9E18AC7007C91Aull, 0x850FADC09923329Eull, 0x03E2CF6BC604DDB0ull, 0xA6539930BF6BFF45ull, 0x84DB8346B786151Cull, 0xCFE87F7CEF46FF16ull, 0xE612641865679A63ull, + 0x81F14FAE158C5F6Eull, 0x4FCB7E8F3F60C07Eull, 0xA26DA3999AEF7749ull, 0xE3BE5E330F38F09Dull, 0xCB090C8001AB551Cull, 0x5CADF5BFD3072CC5ull, 0xFDCB4FA002162A63ull, + 0x73D9732FC7C8F7F6ull, 0x9E9F11C4014DDA7Eull, 0x2867E7FDDCDD9AFAull, 0xC646D63501A1511Dull, 0xB281E1FD541501B8ull, 0xF7D88BC24209A565ull, 0x1F225A7CA91A4226ull, + 0x9AE757596946075Full, 0x3375788DE9B06958ull, 0xC1A12D2FC3978937ull, 0x0052D6B1641C83AEull, 0xF209787BB47D6B84ull, 0xC0678C5DBD23A49Aull, 0x9745EB4D50CE6332ull, + 0xF840B7BA963646E0ull, 0xBD176620A501FBFFull, 0xB650E5A93BC3D898ull, 0xEC5D3FA8CE427AFFull, 0xA3E51F138AB4CEBEull, 0x93BA47C980E98CDFull, 0xC66F336C36B10137ull, + 0xB8A8D9BBE123F017ull, 0xB80B0047445D4184ull, 0xE6D3102AD96CEC1Dull, 0xA60DC059157491E5ull, 0x9043EA1AC7E41392ull, 0x87C89837AD68DB2Full, 0xB454E4A179DD1877ull, + 0x29BABE4598C311FBull, 0xE16A1DC9D8545E94ull, 0xF4296DD6FEF3D67Aull, 0x8CE2529E2734BB1Dull, 0x1899E4A65F58660Cull, 0xB01AE745B101E9E4ull, 0x5EC05DCFF72E7F8Full, + 0xDC21A1171D42645Dull, 0x76707543F4FA1F73ull, 0x899504AE72497EBAull, 0x6A06494A791C53A8ull, 0xABFA45DA0EDBDE69ull, 0x0487DB9D17636892ull, 0xD6F8D7509292D603ull, + 0x45A9D2845D3C42B6ull, 0x865B86925B9BC5C2ull, 0x0B8A2392BA45A9B2ull, 0xA7F26836F282B732ull, 0x8E6CAC7768D7141Eull, 0xD1EF0244AF2364FFull, 0x3207D795430CD926ull, + 0x8335616AED761F1Full, 0x7F44E6BD49E807B8ull, 0xA402B9C5A8D3A6E7ull, 0x5F16206C9C6209A6ull, 0xCD036837130890A1ull, 0x36DBA887C37A8C0Full, 0x802221226BE55A64ull, + 0xC2494954DA2C9789ull, 0xA02AA96B06DEB0FDull, 0xF2DB9BAA10B7BD6Cull, 0xC83553C5C8965D3Dull, 0x6F92829494E5ACC7ull, 0xFA42A8B73ABBF48Cull, 0xCB772339BA1F17F9ull, + 0x9C69A97284B578D7ull, 0xFF2A760414536EFBull, 0xC38413CF25E2D70Dull, 0xFEF5138519684ABAull, 0xF46518C2EF5B8CD1ull, 0x7EB258665FC25D69ull, 0x98BF2F79D5993802ull, + 0xEF2F773FFBD97A61ull, 0xBEEEFB584AFF8603ull, 0xAAFB550FFACFD8FAull, 0xEEAABA2E5DBF6784ull, 0x95BA2A53F983CF38ull, 0x952AB45CFA97A0B2ull, 0xDD945A747BF26183ull, + 0xBA756174393D88DFull, 0x94F971119AEEF9E4ull, 0xE912B9D1478CEB17ull, 0x7A37CD5601AAB85Dull, 0x91ABB422CCB812EEull, 0xAC62E055C10AB33Aull, 0xB616A12B7FE617AAull, + 0x577B986B314D6009ull, 0xE39C49765FDF9D94ull, 0xED5A7E85FDA0B80Bull, 0x8E41ADE9FBEBC27Dull, 0x14588F13BE847307ull, 0xB1D219647AE6B31Cull, 0x596EB2D8AE258FC8ull, + 0xDE469FBD99A05FE3ull, 0x6FCA5F8ED9AEF3BBull, 0x8AEC23D680043BEEull, 0x25DE7BB9480D5854ull, 0xADA72CCC20054AE9ull, 0xAF561AA79A10AE6Aull, 0xD910F7FF28069DA4ull, + 0x1B2BA1518094DA04ull, 0x87AA9AFF79042286ull, 0x90FB44D2F05D0842ull, 0xA99541BF57452B28ull, 0x353A1607AC744A53ull, 0xD3FA922F2D1675F2ull, 0x42889B8997915CE8ull, + 0x847C9B5D7C2E09B7ull, 0x69956135FEBADA11ull, 0xA59BC234DB398C25ull, 0x43FAB9837E699095ull, 0xCF02B2C21207EF2Eull, 0x94F967E45E03F4BBull, 0x8161AFB94B44F57Dull, + 0x1D1BE0EEBAC278F5ull, 0xA1BA1BA79E1632DCull, 0x6462D92A69731732ull, 0xCA28A291859BBF93ull, 0x7D7B8F7503CFDCFEull, 0xFCB2CB35E702AF78ull, 0x5CDA735244C3D43Eull, + 0x9DEFBF01B061ADABull, 0x3A0888136AFA64A7ull, 0xC56BAEC21C7A1916ull, 0x088AAA1845B8FDD0ull, 0xF6C69A72A3989F5Bull, 0x8AAD549E57273D45ull, 0x9A3C2087A63F6399ull, + 0x36AC54E2F678864Bull, 0xC0CB28A98FCF3C7Full, 0x84576A1BB416A7DDull, 0xF0FDF2D3F3C30B9Full, 0x656D44A2A11C51D5ull, 0x969EB7C47859E743ull, 0x9F644AE5A4B1B325ull, + 0xBC4665B596706114ull, 0x873D5D9F0DDE1FEEull, 0xEB57FF22FC0C7959ull, 0xA90CB506D155A7EAull, 0x9316FF75DD87CBD8ull, 0x09A7F12442D588F2ull, 0xB7DCBF5354E9BECEull, + 0x0C11ED6D538AEB2Full, 0xE5D3EF282A242E81ull, 0x8F1668C8A86DA5FAull, 0x8FA475791A569D10ull, 0xF96E017D694487BCull, 0xB38D92D760EC4455ull, 0x37C981DCC395A9ACull, + 0xE070F78D3927556Aull, 0x85BBE253F47B1417ull, 0x8C469AB843B89562ull, 0x93956D7478CCEC8Eull, 0xAF58416654A6BABBull, 0x387AC8D1970027B2ull, 0xDB2E51BFE9D0696Aull, + 0x06997B05FCC0319Eull, 0x88FCF317F22241E2ull, 0x441FECE3BDF81F03ull, 0xAB3C2FDDEEAAD25Aull, 0xD527E81CAD7626C3ull, 0xD60B3BD56A5586F1ull, 0x8A71E223D8D3B074ull, + 0x85C7056562757456ull, 0xF6872D5667844E49ull, 0xA738C6BEBB12D16Cull, 0xB428F8AC016561DBull, 0xD106F86E69D785C7ull, 0xE13336D701BEBA52ull, 0x82A45B450226B39Cull, + 0xECC0024661173473ull, 0xA34D721642B06084ull, 0x27F002D7F95D0190ull, 0xCC20CE9BD35C78A5ull, 0x31EC038DF7B441F4ull, 0xFF290242C83396CEull, 0x7E67047175A15271ull, + 0x9F79A169BD203E41ull, 0x0F0062C6E984D386ull, 0xC75809C42C684DD1ull, 0x52C07B78A3E60868ull, 0xF92E0C3537826145ull, 0xA7709A56CCDF8A82ull, 0x9BBCC7A142B17CCBull, + 0x88A66076400BB691ull, 0xC2ABF989935DDBFEull, 0x6ACFF893D00EA435ull, 0xF356F7EBF83552FEull, 0x0583F6B8C4124D43ull, 0x98165AF37B2153DEull, 0xC3727A337A8B704Aull, + 0xBE1BF1B059E9A8D6ull, 0x744F18C0592E4C5Cull, 0xEDA2EE1C7064130Cull, 0x1162DEF06F79DF73ull, 0x9485D4D1C63E8BE7ull, 0x8ADDCB5645AC2BA8ull, 0xB9A74A0637CE2EE1ull, + 0x6D953E2BD7173692ull, 0xE8111C87C5C1BA99ull, 0xC8FA8DB6CCDD0437ull, 0x910AB1D4DB9914A0ull, 0x1D9C9892400A22A2ull, 0xB54D5E4A127F59C8ull, 0x2503BEB6D00CAB4Bull, + 0xE2A0B5DC971F303Aull, 0x2E44AE64840FD61Dull, 0x8DA471A9DE737E24ull, 0x5CEAECFED289E5D2ull, 0xB10D8E1456105DADull, 0x7425A83E872C5F47ull, 0xDD50F1996B947518ull, + 0xD12F124E28F77719ull, 0x8A5296FFE33CC92Full, 0x82BD6B70D99AAA6Full, 0xACE73CBFDC0BFB7Bull, 0x636CC64D1001550Bull, 0xD8210BEFD30EFA5Aull, 0x3C47F7E05401AA4Eull, + 0x8714A775E3E95C78ull, 0x65ACFAEC34810A71ull, 0xA8D9D1535CE3B396ull, 0x7F1839A741A14D0Dull, 0xD31045A8341CA07Cull, 0x1EDE48111209A050ull, 0x83EA2B892091E44Dull, + 0x934AED0AAB460432ull, 0xA4E4B66B68B65D60ull, 0xF81DA84D5617853Full, 0xCE1DE40642E3F4B9ull, 0x36251260AB9D668Eull, 0x80D2AE83E9CE78F3ull, 0xC1D72B7C6B426019ull, + 0xA1075A24E4421730ull, 0xB24CF65B8612F81Full, 0xC94930AE1D529CFCull, 0xDEE033F26797B627ull, 0xFB9B7CD9A4A7443Cull, 0x169840EF017DA3B1ull, 0x9D412E0806E88AA5ull, + 0x8E1F289560EE864Eull, 0xC491798A08A2AD4Eull, 0xF1A6F2BAB92A27E2ull, 0xF5B5D7EC8ACB58A2ull, 0xAE10AF696774B1DBull, 0x9991A6F3D6BF1765ull, 0xACCA6DA1E0A8EF29ull, + 0xBFF610B0CC6EDD3Full, 0x17FD090A58D32AF3ull, 0xEFF394DCFF8A948Eull, 0xDDFC4B4CEF07F5B0ull, 0x95F83D0A1FB69CD9ull, 0x4ABDAF101564F98Eull, 0xBB764C4CA7A4440Full, + 0x9D6D1AD41ABE37F1ull, 0xEA53DF5FD18D5513ull, 0x84C86189216DC5EDull, 0x92746B9BE2F8552Cull, 0x32FD3CF5B4E49BB4ull, 0xB7118682DBB66A77ull, 0x3FBC8C33221DC2A1ull, + 0xE4D5E82392A40515ull, 0x0FABAF3FEAA5334Aull, 0x8F05B1163BA6832Dull, 0x29CB4D87F2A7400Eull, 0xB2C71D5BCA9023F8ull, 0x743E20E9EF511012ull, 0xDF78E4B2BD342CF6ull, + 0x914DA9246B255416ull, 0x8BAB8EEFB6409C1Aull, 0x1AD089B6C2F7548Eull, 0xAE9672ABA3D0C320ull, 0xA184AC2473B529B1ull, 0xDA3C0F568CC4F3E8ull, 0xC9E5D72D90A2741Eull, + 0x8865899617FB1871ull, 0x7E2FA67C7A658892ull, 0xAA7EEBFB9DF9DE8Dull, 0xDDBB901B98FEEAB7ull, 0xD51EA6FA85785631ull, 0x552A74227F3EA565ull, 0x8533285C936B35DEull, + 0xD53A88958F87275Full, 0xA67FF273B8460356ull, 0x8A892ABAF368F137ull, 0xD01FEF10A657842Cull, 0x2D2B7569B0432D85ull, 0x8213F56A67F6B29Bull, 0x9C3B29620E29FC73ull, + 0xA298F2C501F45F42ull, 0x8349F3BA91B47B8Full, 0xCB3F2F7642717713ull, 0x241C70A936219A73ull, 0xFE0EFB53D30DD4D7ull, 0xED238CD383AA0110ull, 0x9EC95D1463E8A506ull, + 0xF4363804324A40AAull, 0xC67BB4597CE2CE48ull, 0xB143C6053EDCD0D5ull, 0xF81AA16FDC1B81DAull, 0xDD94B7868E94050Aull, 0x9B10A4E5E9913128ull, 0xCA7CF2B4191C8326ull, + 0xC1D4CE1F63F57D72ull, 0xFD1C2F611F63A3F0ull, 0xF24A01A73CF2DCCFull, 0xBC633B39673C8CECull, 0x976E41088617CA01ull, 0xD5BE0503E085D813ull, 0xBD49D14AA79DBC82ull, + 0x4B2D8644D8A74E18ull, 0xEC9C459D51852BA2ull, 0xDDF8E7D60ED1219Eull, 0x93E1AB8252F33B45ull, 0xCABB90E5C942B503ull, 0xB8DA1662E7B00A17ull, 0x3D6A751F3B936243ull, + 0xE7109BFBA19C0C9Dull, 0x0CC512670A783AD4ull, 0x906A617D450187E2ull, 0x27FB2B80668B24C5ull, 0xB484F9DC9641E9DAull, 0xB1F9F660802DEDF6ull, 0xE1A63853BBD26451ull, + 0x5E7873F8A0396973ull, 0x8D07E33455637EB2ull, 0xDB0B487B6423E1E8ull, 0xB049DC016ABC5E5Full, 0x91CE1A9A3D2CDA62ull, 0xDC5C5301C56B75F7ull, 0x7641A140CC7810FBull, + 0x89B9B3E11B6329BAull, 0xA9E904C87FCB0A9Dull, 0xAC2820D9623BF429ull, 0x546345FA9FBDCD44ull, 0xD732290FBACAF133ull, 0xA97C177947AD4095ull, 0x867F59A9D4BED6C0ull, + 0x49ED8EABCCCC485Dull, 0xA81F301449EE8C70ull, 0x5C68F256BFFF5A74ull, 0xD226FC195C6A2F8Cull, 0x73832EEC6FFF3111ull, 0x83585D8FD9C25DB7ull, 0xC831FD53C5FF7EABull, + 0xA42E74F3D032F525ull, 0xBA3E7CA8B77F5E55ull, 0xCD3A1230C43FB26Full, 0x28CE1BD2E55F35EBull, 0x80444B5E7AA7CF85ull, 0x7980D163CF5B81B3ull, 0xA0555E361951C366ull, + 0xD7E105BCC332621Full, 0xC86AB5C39FA63440ull, 0x8DD9472BF3FEFAA7ull, 0xFA856334878FC150ull, 0xB14F98F6F0FEB951ull, 0x9C935E00D4B9D8D2ull, 0x6ED1BF9A569F33D3ull, + 0xC3B8358109E84F07ull, 0x0A862F80EC4700C8ull, 0xF4A642E14C6262C8ull, 0xCD27BB612758C0FAull, 0x98E7E9CCCFBD7DBDull, 0x8038D51CB897789Cull, 0xBF21E44003ACDD2Cull, + 0xE0470A63E6BD56C3ull, 0xEEEA5D5004981478ull, 0x1858CCFCE06CAC74ull, 0x95527A5202DF0CCBull, 0x0F37801E0C43EBC8ull, 0xBAA718E68396CFFDull, 0xD30560258F54E6BAull, + 0xE950DF20247C83FDull, 0x47C6B82EF32A2069ull, 0x91D28B7416CDD27Eull, 0x4CDC331D57FA5441ull, 0xB6472E511C81471Dull, 0xE0133FE4ADF8E952ull, 0xE3D8F9E563A198E5ull, + 0x58180FDDD97723A6ull, 0x8E679C2F5E44FF8Full, 0x570F09EAA7EA7648ull, 0xB201833B35D63F73ull, 0x2CD2CC6551E513DAull, 0xDE81E40A034BCF4Full, 0xF8077F7EA65E58D1ull, + 0x8B112E86420F6191ull, 0xFB04AFAF27FAF782ull, 0xADD57A27D29339F6ull, 0x79C5DB9AF1F9B563ull, 0xD94AD8B1C7380874ull, 0x18375281AE7822BCull, 0x87CEC76F1C830548ull, + 0x8F2293910D0B15B5ull, 0xA9C2794AE3A3C69Aull, 0xB2EB3875504DDB22ull, 0xD433179D9C8CB841ull, 0x5FA60692A46151EBull, 0x849FEEC281D7F328ull, 0xDBC7C41BA6BCD333ull, + 0xA5C7EA73224DEFF3ull, 0x12B9B522906C0800ull, 0xCF39E50FEAE16BEFull, 0xD768226B34870A00ull, 0x81842F29F2CCE375ull, 0xE6A1158300D46640ull, 0xA1E53AF46F801C53ull, + 0x60495AE3C1097FD0ull, 0xCA5E89B18B602368ull, 0x385BB19CB14BDFC4ull, 0xFCF62C1DEE382C42ull, 0x46729E03DD9ED7B5ull, 0x9E19DB92B4E31BA9ull, 0x6C07A2C26A8346D1ull }; - jsonifier_constexpr uint64_t pow10SigTable128[]{ 0xBF29DCABA82FDEAEu, 0x7432EE873880FC33u, 0xEEF453D6923BD65Au, 0x113FAA2906A13B3Fu, 0x9558B4661B6565F8u, 0x4AC7CA59A424C507, - 0xBAAEE17FA23EBF76u, 0x5D79BCF00D2DF649u, 0xE95A99DF8ACE6F53u, 0xF4D82C2C107973DCu, 0x91D8A02BB6C10594u, 0x79071B9B8A4BE869u, 0xB64EC836A47146F9u, 0x9748E2826CDEE284, - 0xE3E27A444D8D98B7u, 0xFD1B1B2308169B25u, 0x8E6D8C6AB0787F72u, 0xFE30F0F5E50E20F7u, 0xB208EF855C969F4Fu, 0xBDBD2D335E51A935u, 0xDE8B2B66B3BC4723u, 0xAD2C788035E61382, - 0x8B16FB203055AC76u, 0x4C3BCB5021AFCC31u, 0xADDCB9E83C6B1793u, 0xDF4ABE242A1BBF3Du, 0xD953E8624B85DD78u, 0xD71D6DAD34A2AF0Du, 0x87D4713D6F33AA6Bu, 0x8672648C40E5AD68, - 0xA9C98D8CCB009506u, 0x680EFDAF511F18C2u, 0xD43BF0EFFDC0BA48u, 0x0212BD1B2566DEF2u, 0x84A57695FE98746Du, 0x014BB630F7604B57u, 0xA5CED43B7E3E9188u, 0x419EA3BD35385E2D, - 0xCF42894A5DCE35EAu, 0x52064CAC828675B9u, 0x818995CE7AA0E1B2u, 0x7343EFEBD1940993u, 0xA1EBFB4219491A1Fu, 0x1014EBE6C5F90BF8u, 0xCA66FA129F9B60A6u, 0xD41A26E077774EF6, - 0xFD00B897478238D0u, 0x8920B098955522B4u, 0x9E20735E8CB16382u, 0x55B46E5F5D5535B0u, 0xC5A890362FDDBC62u, 0xEB2189F734AA831Du, 0xF712B443BBD52B7Bu, 0xA5E9EC7501D523E4, - 0x9A6BB0AA55653B2Du, 0x47B233C92125366Eu, 0xC1069CD4EABE89F8u, 0x999EC0BB696E840Au, 0xF148440A256E2C76u, 0xC00670EA43CA250Du, 0x96CD2A865764DBCAu, 0x380406926A5E5728, - 0xBC807527ED3E12BCu, 0xC605083704F5ECF2u, 0xEBA09271E88D976Bu, 0xF7864A44C633682Eu, 0x93445B8731587EA3u, 0x7AB3EE6AFBE0211Du, 0xB8157268FDAE9E4Cu, 0x5960EA05BAD82964, - 0xE61ACF033D1A45DFu, 0x6FB92487298E33BDu, 0x8FD0C16206306BABu, 0xA5D3B6D479F8E056u, 0xB3C4F1BA87BC8696u, 0x8F48A4899877186Cu, 0xE0B62E2929ABA83Cu, 0x331ACDABFE94DE87, - 0x8C71DCD9BA0B4925u, 0x9FF0C08B7F1D0B14u, 0xAF8E5410288E1B6Fu, 0x07ECF0AE5EE44DD9u, 0xDB71E91432B1A24Au, 0xC9E82CD9F69D6150u, 0x892731AC9FAF056Eu, 0xBE311C083A225CD2, - 0xAB70FE17C79AC6CAu, 0x6DBD630A48AAF406u, 0xD64D3D9DB981787Du, 0x092CBBCCDAD5B108u, 0x85F0468293F0EB4Eu, 0x25BBF56008C58EA5u, 0xA76C582338ED2621u, 0xAF2AF2B80AF6F24E, - 0xD1476E2C07286FAAu, 0x1AF5AF660DB4AEE1u, 0x82CCA4DB847945CAu, 0x50D98D9FC890ED4Du, 0xA37FCE126597973Cu, 0xE50FF107BAB528A0u, 0xCC5FC196FEFD7D0Cu, 0x1E53ED49A96272C8, - 0xFF77B1FCBEBCDC4Fu, 0x25E8E89C13BB0F7Au, 0x9FAACF3DF73609B1u, 0x77B191618C54E9ACu, 0xC795830D75038C1Du, 0xD59DF5B9EF6A2417u, 0xF97AE3D0D2446F25u, 0x4B0573286B44AD1D, - 0x9BECCE62836AC577u, 0x4EE367F9430AEC32u, 0xC2E801FB244576D5u, 0x229C41F793CDA73Fu, 0xF3A20279ED56D48Au, 0x6B43527578C1110Fu, 0x9845418C345644D6u, 0x830A13896B78AAA9, - 0xBE5691EF416BD60Cu, 0x23CC986BC656D553u, 0xEDEC366B11C6CB8Fu, 0x2CBFBE86B7EC8AA8u, 0x94B3A202EB1C3F39u, 0x7BF7D71432F3D6A9u, 0xB9E08A83A5E34F07u, 0xDAF5CCD93FB0CC53, - 0xE858AD248F5C22C9u, 0xD1B3400F8F9CFF68u, 0x91376C36D99995BEu, 0x23100809B9C21FA1u, 0xB58547448FFFFB2Du, 0xABD40A0C2832A78Au, 0xE2E69915B3FFF9F9u, 0x16C90C8F323F516C, - 0x8DD01FAD907FFC3Bu, 0xAE3DA7D97F6792E3u, 0xB1442798F49FFB4Au, 0x99CD11CFDF41779Cu, 0xDD95317F31C7FA1Du, 0x40405643D711D583u, 0x8A7D3EEF7F1CFC52u, 0x482835EA666B2572, - 0xAD1C8EAB5EE43B66u, 0xDA3243650005EECFu, 0xD863B256369D4A40u, 0x90BED43E40076A82u, 0x873E4F75E2224E68u, 0x5A7744A6E804A291u, 0xA90DE3535AAAE202u, 0x711515D0A205CB36, - 0xD3515C2831559A83u, 0x0D5A5B44CA873E03u, 0x8412D9991ED58091u, 0xE858790AFE9486C2u, 0xA5178FFF668AE0B6u, 0x626E974DBE39A872u, 0xCE5D73FF402D98E3u, 0xFB0A3D212DC8128F, - 0x80FA687F881C7F8Eu, 0x7CE66634BC9D0B99u, 0xA139029F6A239F72u, 0x1C1FFFC1EBC44E80u, 0xC987434744AC874Eu, 0xA327FFB266B56220u, 0xFBE9141915D7A922u, 0x4BF1FF9F0062BAA8, - 0x9D71AC8FADA6C9B5u, 0x6F773FC3603DB4A9u, 0xC4CE17B399107C22u, 0xCB550FB4384D21D3u, 0xF6019DA07F549B2Bu, 0x7E2A53A146606A48u, 0x99C102844F94E0FBu, 0x2EDA7444CBFC426D, - 0xC0314325637A1939u, 0xFA911155FEFB5308u, 0xF03D93EEBC589F88u, 0x793555AB7EBA27CAu, 0x96267C7535B763B5u, 0x4BC1558B2F3458DEu, 0xBBB01B9283253CA2u, 0x9EB1AAEDFB016F16, - 0xEA9C227723EE8BCBu, 0x465E15A979C1CADCu, 0x92A1958A7675175Fu, 0x0BFACD89EC191EC9u, 0xB749FAED14125D36u, 0xCEF980EC671F667Bu, 0xE51C79A85916F484u, 0x82B7E12780E7401A, - 0x8F31CC0937AE58D2u, 0xD1B2ECB8B0908810u, 0xB2FE3F0B8599EF07u, 0x861FA7E6DCB4AA15u, 0xDFBDCECE67006AC9u, 0x67A791E093E1D49Au, 0x8BD6A141006042BDu, 0xE0C8BB2C5C6D24E0, - 0xAECC49914078536Du, 0x58FAE9F773886E18u, 0xDA7F5BF590966848u, 0xAF39A475506A899Eu, 0x888F99797A5E012Du, 0x6D8406C952429603u, 0xAAB37FD7D8F58178u, 0xC8E5087BA6D33B83, - 0xD5605FCDCF32E1D6u, 0xFB1E4A9A90880A64u, 0x855C3BE0A17FCD26u, 0x5CF2EEA09A55067Fu, 0xA6B34AD8C9DFC06Fu, 0xF42FAA48C0EA481Eu, 0xD0601D8EFC57B08Bu, 0xF13B94DAF124DA26, - 0x823C12795DB6CE57u, 0x76C53D08D6B70858u, 0xA2CB1717B52481EDu, 0x54768C4B0C64CA6Eu, 0xCB7DDCDDA26DA268u, 0xA9942F5DCF7DFD09u, 0xFE5D54150B090B02u, 0xD3F93B35435D7C4C, - 0x9EFA548D26E5A6E1u, 0xC47BC5014A1A6DAFu, 0xC6B8E9B0709F109Au, 0x359AB6419CA1091Bu, 0xF867241C8CC6D4C0u, 0xC30163D203C94B62u, 0x9B407691D7FC44F8u, 0x79E0DE63425DCF1D, - 0xC21094364DFB5636u, 0x985915FC12F542E4u, 0xF294B943E17A2BC4u, 0x3E6F5B7B17B2939Du, 0x979CF3CA6CEC5B5Au, 0xA705992CEECF9C42u, 0xBD8430BD08277231u, 0x50C6FF782A838353, - 0xECE53CEC4A314EBDu, 0xA4F8BF5635246428u, 0x940F4613AE5ED136u, 0x871B7795E136BE99u, 0xB913179899F68584u, 0x28E2557B59846E3Fu, 0xE757DD7EC07426E5u, 0x331AEADA2FE589CF, - 0x9096EA6F3848984Fu, 0x3FF0D2C85DEF7621u, 0xB4BCA50B065ABE63u, 0x0FED077A756B53A9u, 0xE1EBCE4DC7F16DFBu, 0xD3E8495912C62894u, 0x8D3360F09CF6E4BDu, 0x64712DD7ABBBD95C, - 0xB080392CC4349DECu, 0xBD8D794D96AACFB3u, 0xDCA04777F541C567u, 0xECF0D7A0FC5583A0u, 0x89E42CAAF9491B60u, 0xF41686C49DB57244u, 0xAC5D37D5B79B6239u, 0x311C2875C522CED5, - 0xD77485CB25823AC7u, 0x7D633293366B828Bu, 0x86A8D39EF77164BCu, 0xAE5DFF9C02033197u, 0xA8530886B54DBDEBu, 0xD9F57F830283FDFCu, 0xD267CAA862A12D66u, 0xD072DF63C324FD7B, - 0x8380DEA93DA4BC60u, 0x4247CB9E59F71E6Du, 0xA46116538D0DEB78u, 0x52D9BE85F074E608u, 0xCD795BE870516656u, 0x67902E276C921F8Bu, 0x806BD9714632DFF6u, 0x00BA1CD8A3DB53B6, - 0xA086CFCD97BF97F3u, 0x80E8A40ECCD228A4u, 0xC8A883C0FDAF7DF0u, 0x6122CD128006B2CDu, 0xFAD2A4B13D1B5D6Cu, 0x796B805720085F81u, 0x9CC3A6EEC6311A63u, 0xCBE3303674053BB0, - 0xC3F490AA77BD60FCu, 0xBEDBFC4411068A9Cu, 0xF4F1B4D515ACB93Bu, 0xEE92FB5515482D44u, 0x991711052D8BF3C5u, 0x751BDD152D4D1C4Au, 0xBF5CD54678EEF0B6u, 0xD262D45A78A0635D, - 0xEF340A98172AACE4u, 0x86FB897116C87C34u, 0x9580869F0E7AAC0Eu, 0xD45D35E6AE3D4DA0u, 0xBAE0A846D2195712u, 0x8974836059CCA109u, 0xE998D258869FACD7u, 0x2BD1A438703FC94B, - 0x91FF83775423CC06u, 0x7B6306A34627DDCFu, 0xB67F6455292CBF08u, 0x1A3BC84C17B1D542u, 0xE41F3D6A7377EECAu, 0x20CABA5F1D9E4A93u, 0x8E938662882AF53Eu, 0x547EB47B7282EE9C, - 0xB23867FB2A35B28Du, 0xE99E619A4F23AA43u, 0xDEC681F9F4C31F31u, 0x6405FA00E2EC94D4u, 0x8B3C113C38F9F37Eu, 0xDE83BC408DD3DD04u, 0xAE0B158B4738705Eu, 0x9624AB50B148D445, - 0xD98DDAEE19068C76u, 0x3BADD624DD9B0957u, 0x87F8A8D4CFA417C9u, 0xE54CA5D70A80E5D6u, 0xA9F6D30A038D1DBCu, 0x5E9FCF4CCD211F4Cu, 0xD47487CC8470652Bu, 0x7647C3200069671F, - 0x84C8D4DFD2C63F3Bu, 0x29ECD9F40041E073u, 0xA5FB0A17C777CF09u, 0xF468107100525890u, 0xCF79CC9DB955C2CCu, 0x7182148D4066EEB4u, 0x81AC1FE293D599BFu, 0xC6F14CD848405530, - 0xA21727DB38CB002Fu, 0xB8ADA00E5A506A7Cu, 0xCA9CF1D206FDC03Bu, 0xA6D90811F0E4851Cu, 0xFD442E4688BD304Au, 0x908F4A166D1DA663u, 0x9E4A9CEC15763E2Eu, 0x9A598E4E043287FE, - 0xC5DD44271AD3CDBAu, 0x40EFF1E1853F29FDu, 0xF7549530E188C128u, 0xD12BEE59E68EF47Cu, 0x9A94DD3E8CF578B9u, 0x82BB74F8301958CEu, 0xC13A148E3032D6E7u, 0xE36A52363C1FAF01, - 0xF18899B1BC3F8CA1u, 0xDC44E6C3CB279AC1u, 0x96F5600F15A7B7E5u, 0x29AB103A5EF8C0B9u, 0xBCB2B812DB11A5DEu, 0x7415D448F6B6F0E7u, 0xEBDF661791D60F56u, 0x111B495B3464AD21, - 0x936B9FCEBB25C995u, 0xCAB10DD900BEEC34u, 0xB84687C269EF3BFBu, 0x3D5D514F40EEA742u, 0xE65829B3046B0AFAu, 0x0CB4A5A3112A5112u, 0x8FF71A0FE2C2E6DCu, 0x47F0E785EABA72AB, - 0xB3F4E093DB73A093u, 0x59ED216765690F56u, 0xE0F218B8D25088B8u, 0x306869C13EC3532Cu, 0x8C974F7383725573u, 0x1E414218C73A13FBu, 0xAFBD2350644EEACFu, 0xE5D1929EF90898FA, - 0xDBAC6C247D62A583u, 0xDF45F746B74ABF39u, 0x894BC396CE5DA772u, 0x6B8BBA8C328EB783u, 0xAB9EB47C81F5114Fu, 0x066EA92F3F326564u, 0xD686619BA27255A2u, 0xC80A537B0EFEFEBD, - 0x8613FD0145877585u, 0xBD06742CE95F5F36u, 0xA798FC4196E952E7u, 0x2C48113823B73704u, 0xD17F3B51FCA3A7A0u, 0xF75A15862CA504C5u, 0x82EF85133DE648C4u, 0x9A984D73DBE722FB, - 0xA3AB66580D5FDAF5u, 0xC13E60D0D2E0EBBAu, 0xCC963FEE10B7D1B3u, 0x318DF905079926A8u, 0xFFBBCFE994E5C61Fu, 0xFDF17746497F7052u, 0x9FD561F1FD0F9BD3u, 0xFEB6EA8BEDEFA633, - 0xC7CABA6E7C5382C8u, 0xFE64A52EE96B8FC0u, 0xF9BD690A1B68637Bu, 0x3DFDCE7AA3C673B0u, 0x9C1661A651213E2Du, 0x06BEA10CA65C084Eu, 0xC31BFA0FE5698DB8u, 0x486E494FCFF30A62, - 0xF3E2F893DEC3F126u, 0x5A89DBA3C3EFCCFAu, 0x986DDB5C6B3A76B7u, 0xF89629465A75E01Cu, 0xBE89523386091465u, 0xF6BBB397F1135823u, 0xEE2BA6C0678B597Fu, 0x746AA07DED582E2C, - 0x94DB483840B717EFu, 0xA8C2A44EB4571CDCu, 0xBA121A4650E4DDEBu, 0x92F34D62616CE413u, 0xE896A0D7E51E1566u, 0x77B020BAF9C81D17u, 0x915E2486EF32CD60u, 0x0ACE1474DC1D122E, - 0xB5B5ADA8AAFF80B8u, 0x0D819992132456BAu, 0xE3231912D5BF60E6u, 0x10E1FFF697ED6C69u, 0x8DF5EFABC5979C8Fu, 0xCA8D3FFA1EF463C1u, 0xB1736B96B6FD83B3u, 0xBD308FF8A6B17CB2, - 0xDDD0467C64BCE4A0u, 0xAC7CB3F6D05DDBDEu, 0x8AA22C0DBEF60EE4u, 0x6BCDF07A423AA96Bu, 0xAD4AB7112EB3929Du, 0x86C16C98D2C953C6u, 0xD89D64D57A607744u, 0xE871C7BF077BA8B7, - 0x87625F056C7C4A8Bu, 0x11471CD764AD4972u, 0xA93AF6C6C79B5D2Du, 0xD598E40D3DD89BCFu, 0xD389B47879823479u, 0x4AFF1D108D4EC2C3u, 0x843610CB4BF160CBu, 0xCEDF722A585139BA, - 0xA54394FE1EEDB8FEu, 0xC2974EB4EE658828u, 0xCE947A3DA6A9273Eu, 0x733D226229FEEA32u, 0x811CCC668829B887u, 0x0806357D5A3F525Fu, 0xA163FF802A3426A8u, 0xCA07C2DCB0CF26F7, - 0xC9BCFF6034C13052u, 0xFC89B393DD02F0B5u, 0xFC2C3F3841F17C67u, 0xBBAC2078D443ACE2u, 0x9D9BA7832936EDC0u, 0xD54B944B84AA4C0Du, 0xC5029163F384A931u, 0x0A9E795E65D4DF11, - 0xF64335BCF065D37Du, 0x4D4617B5FF4A16D5u, 0x99EA0196163FA42Eu, 0x504BCED1BF8E4E45u, 0xC06481FB9BCF8D39u, 0xE45EC2862F71E1D6u, 0xF07DA27A82C37088u, 0x5D767327BB4E5A4C, - 0x964E858C91BA2655u, 0x3A6A07F8D510F86Fu, 0xBBE226EFB628AFEAu, 0x890489F70A55368Bu, 0xEADAB0ABA3B2DBE5u, 0x2B45AC74CCEA842Eu, 0x92C8AE6B464FC96Fu, 0x3B0B8BC90012929D, - 0xB77ADA0617E3BBCBu, 0x09CE6EBB40173744u, 0xE55990879DDCAABDu, 0xCC420A6A101D0515u, 0x8F57FA54C2A9EAB6u, 0x9FA946824A12232Du, 0xB32DF8E9F3546564u, 0x47939822DC96ABF9, - 0xDFF9772470297EBDu, 0x59787E2B93BC56F7u, 0x8BFBEA76C619EF36u, 0x57EB4EDB3C55B65Au, 0xAEFAE51477A06B03u, 0xEDE622920B6B23F1u, 0xDAB99E59958885C4u, 0xE95FAB368E45ECED, - 0x88B402F7FD75539Bu, 0x11DBCB0218EBB414u, 0xAAE103B5FCD2A881u, 0xD652BDC29F26A119u, 0xD59944A37C0752A2u, 0x4BE76D3346F0495Fu, 0x857FCAE62D8493A5u, 0x6F70A4400C562DDB, - 0xA6DFBD9FB8E5B88Eu, 0xCB4CCD500F6BB952u, 0xD097AD07A71F26B2u, 0x7E2000A41346A7A7u, 0x825ECC24C873782Fu, 0x8ED400668C0C28C8u, 0xA2F67F2DFA90563Bu, 0x728900802F0F32FA, - 0xCBB41EF979346BCAu, 0x4F2B40A03AD2FFB9u, 0xFEA126B7D78186BCu, 0xE2F610C84987BFA8u, 0x9F24B832E6B0F436u, 0x0DD9CA7D2DF4D7C9u, 0xC6EDE63FA05D3143u, 0x91503D1C79720DBB, - 0xF8A95FCF88747D94u, 0x75A44C6397CE912Au, 0x9B69DBE1B548CE7Cu, 0xC986AFBE3EE11ABAu, 0xC24452DA229B021Bu, 0xFBE85BADCE996168u, 0xF2D56790AB41C2A2u, 0xFAE27299423FB9C3, - 0x97C560BA6B0919A5u, 0xDCCD879FC967D41Au, 0xBDB6B8E905CB600Fu, 0x5400E987BBC1C920u, 0xED246723473E3813u, 0x290123E9AAB23B68u, 0x9436C0760C86E30Bu, 0xF9A0B6720AAF6521, - 0xB94470938FA89BCEu, 0xF808E40E8D5B3E69u, 0xE7958CB87392C2C2u, 0xB60B1D1230B20E04u, 0x90BD77F3483BB9B9u, 0xB1C6F22B5E6F48C2u, 0xB4ECD5F01A4AA828u, 0x1E38AEB6360B1AF3, - 0xE2280B6C20DD5232u, 0x25C6DA63C38DE1B0u, 0x8D590723948A535Fu, 0x579C487E5A38AD0Eu, 0xB0AF48EC79ACE837u, 0x2D835A9DF0C6D851u, 0xDCDB1B2798182244u, 0xF8E431456CF88E65, - 0x8A08F0F8BF0F156Bu, 0x1B8E9ECB641B58FFu, 0xAC8B2D36EED2DAC5u, 0xE272467E3D222F3Fu, 0xD7ADF884AA879177u, 0x5B0ED81DCC6ABB0Fu, 0x86CCBB52EA94BAEAu, 0x98E947129FC2B4E9, - 0xA87FEA27A539E9A5u, 0x3F2398D747B36224u, 0xD29FE4B18E88640Eu, 0x8EEC7F0D19A03AADu, 0x83A3EEEEF9153E89u, 0x1953CF68300424ACu, 0xA48CEAAAB75A8E2Bu, 0x5FA8C3423C052DD7, - 0xCDB02555653131B6u, 0x3792F412CB06794Du, 0x808E17555F3EBF11u, 0xE2BBD88BBEE40BD0u, 0xA0B19D2AB70E6ED6u, 0x5B6ACEAEAE9D0EC4u, 0xC8DE047564D20A8Bu, 0xF245825A5A445275, - 0xFB158592BE068D2Eu, 0xEED6E2F0F0D56712u, 0x9CED737BB6C4183Du, 0x55464DD69685606Bu, 0xC428D05AA4751E4Cu, 0xAA97E14C3C26B886u, 0xF53304714D9265DFu, 0xD53DD99F4B3066A8, - 0x993FE2C6D07B7FABu, 0xE546A8038EFE4029u, 0xBF8FDB78849A5F96u, 0xDE98520472BDD033u, 0xEF73D256A5C0F77Cu, 0x963E66858F6D4440u, 0x95A8637627989AADu, 0xDDE7001379A44AA8, - 0xBB127C53B17EC159u, 0x5560C018580D5D52u, 0xE9D71B689DDE71AFu, 0xAAB8F01E6E10B4A6u, 0x9226712162AB070Du, 0xCAB3961304CA70E8u, 0xB6B00D69BB55C8D1u, 0x3D607B97C5FD0D22, - 0xE45C10C42A2B3B05u, 0x8CB89A7DB77C506Au, 0x8EB98A7A9A5B04E3u, 0x77F3608E92ADB242u, 0xB267ED1940F1C61Cu, 0x55F038B237591ED3u, 0xDF01E85F912E37A3u, 0x6B6C46DEC52F6688, - 0x8B61313BBABCE2C6u, 0x2323AC4B3B3DA015u, 0xAE397D8AA96C1B77u, 0xABEC975E0A0D081Au, 0xD9C7DCED53C72255u, 0x96E7BD358C904A21u, 0x881CEA14545C7575u, 0x7E50D64177DA2E54, - 0xAA242499697392D2u, 0xDDE50BD1D5D0B9E9u, 0xD4AD2DBFC3D07787u, 0x955E4EC64B44E864u, 0x84EC3C97DA624AB4u, 0xBD5AF13BEF0B113Eu, 0xA6274BBDD0FADD61u, 0xECB1AD8AEACDD58E, - 0xCFB11EAD453994BAu, 0x67DE18EDA5814AF2u, 0x81CEB32C4B43FCF4u, 0x80EACF948770CED7u, 0xA2425FF75E14FC31u, 0xA1258379A94D028Du, 0xCAD2F7F5359A3B3Eu, 0x096EE45813A04330, - 0xFD87B5F28300CA0Du, 0x8BCA9D6E188853FCu, 0x9E74D1B791E07E48u, 0x775EA264CF55347Du, 0xC612062576589DDAu, 0x95364AFE032A819Du, 0xF79687AED3EEC551u, 0x3A83DDBD83F52204, - 0x9ABE14CD44753B52u, 0xC4926A9672793542u, 0xC16D9A0095928A27u, 0x75B7053C0F178293u, 0xF1C90080BAF72CB1u, 0x5324C68B12DD6338u, 0x971DA05074DA7BEEu, 0xD3F6FC16EBCA5E03, - 0xBCE5086492111AEAu, 0x88F4BB1CA6BCF584u, 0xEC1E4A7DB69561A5u, 0x2B31E9E3D06C32E5u, 0x9392EE8E921D5D07u, 0x3AFF322E62439FCFu, 0xB877AA3236A4B449u, 0x09BEFEB9FAD487C2, - 0xE69594BEC44DE15Bu, 0x4C2EBE687989A9B3u, 0x901D7CF73AB0ACD9u, 0x0F9D37014BF60A10u, 0xB424DC35095CD80Fu, 0x538484C19EF38C94u, 0xE12E13424BB40E13u, 0x2865A5F206B06FB9, - 0x8CBCCC096F5088CBu, 0xF93F87B7442E45D3u, 0xAFEBFF0BCB24AAFEu, 0xF78F69A51539D748u, 0xDBE6FECEBDEDD5BEu, 0xB573440E5A884D1Bu, 0x89705F4136B4A597u, 0x31680A88F8953030, - 0xABCC77118461CEFCu, 0xFDC20D2B36BA7C3Du, 0xD6BF94D5E57A42BCu, 0x3D32907604691B4Cu, 0x8637BD05AF6C69B5u, 0xA63F9A49C2C1B10Fu, 0xA7C5AC471B478423u, 0x0FCF80DC33721D53, - 0xD1B71758E219652Bu, 0xD3C36113404EA4A8u, 0x83126E978D4FDF3Bu, 0x645A1CAC083126E9u, 0xA3D70A3D70A3D70Au, 0x3D70A3D70A3D70A3u, 0xCCCCCCCCCCCCCCCCu, 0xCCCCCCCCCCCCCCCC, - 0x8000000000000000u, 0x0000000000000000u, 0xA000000000000000u, 0x0000000000000000u, 0xC800000000000000u, 0x0000000000000000u, 0xFA00000000000000u, 0x0000000000000000, - 0x9C40000000000000u, 0x0000000000000000u, 0xC350000000000000u, 0x0000000000000000u, 0xF424000000000000u, 0x0000000000000000u, 0x9896800000000000u, 0x0000000000000000, - 0xBEBC200000000000u, 0x0000000000000000u, 0xEE6B280000000000u, 0x0000000000000000u, 0x9502F90000000000u, 0x0000000000000000u, 0xBA43B74000000000u, 0x0000000000000000, - 0xE8D4A51000000000u, 0x0000000000000000u, 0x9184E72A00000000u, 0x0000000000000000u, 0xB5E620F480000000u, 0x0000000000000000u, 0xE35FA931A0000000u, 0x0000000000000000, - 0x8E1BC9BF04000000u, 0x0000000000000000u, 0xB1A2BC2EC5000000u, 0x0000000000000000u, 0xDE0B6B3A76400000u, 0x0000000000000000u, 0x8AC7230489E80000u, 0x0000000000000000, - 0xAD78EBC5AC620000u, 0x0000000000000000u, 0xD8D726B7177A8000u, 0x0000000000000000u, 0x878678326EAC9000u, 0x0000000000000000u, 0xA968163F0A57B400u, 0x0000000000000000, - 0xD3C21BCECCEDA100u, 0x0000000000000000u, 0x84595161401484A0u, 0x0000000000000000u, 0xA56FA5B99019A5C8u, 0x0000000000000000u, 0xCECB8F27F4200F3Au, 0x0000000000000000, - 0x813F3978F8940984u, 0x4000000000000000u, 0xA18F07D736B90BE5u, 0x5000000000000000u, 0xC9F2C9CD04674EDEu, 0xA400000000000000u, 0xFC6F7C4045812296u, 0x4D00000000000000, - 0x9DC5ADA82B70B59Du, 0xF020000000000000u, 0xC5371912364CE305u, 0x6C28000000000000u, 0xF684DF56C3E01BC6u, 0xC732000000000000u, 0x9A130B963A6C115Cu, 0x3C7F400000000000, - 0xC097CE7BC90715B3u, 0x4B9F100000000000u, 0xF0BDC21ABB48DB20u, 0x1E86D40000000000u, 0x96769950B50D88F4u, 0x1314448000000000u, 0xBC143FA4E250EB31u, 0x17D955A000000000, - 0xEB194F8E1AE525FDu, 0x5DCFAB0800000000u, 0x92EFD1B8D0CF37BEu, 0x5AA1CAE500000000u, 0xB7ABC627050305ADu, 0xF14A3D9E40000000u, 0xE596B7B0C643C719u, 0x6D9CCD05D0000000, - 0x8F7E32CE7BEA5C6Fu, 0xE4820023A2000000u, 0xB35DBF821AE4F38Bu, 0xDDA2802C8A800000u, 0xE0352F62A19E306Eu, 0xD50B2037AD200000u, 0x8C213D9DA502DE45u, 0x4526F422CC340000, - 0xAF298D050E4395D6u, 0x9670B12B7F410000u, 0xDAF3F04651D47B4Cu, 0x3C0CDD765F114000u, 0x88D8762BF324CD0Fu, 0xA5880A69FB6AC800u, 0xAB0E93B6EFEE0053u, 0x8EEA0D047A457A00, - 0xD5D238A4ABE98068u, 0x72A4904598D6D880u, 0x85A36366EB71F041u, 0x47A6DA2B7F864750u, 0xA70C3C40A64E6C51u, 0x999090B65F67D924u, 0xD0CF4B50CFE20765u, 0xFFF4B4E3F741CF6D, - 0x82818F1281ED449Fu, 0xBFF8F10E7A8921A4u, 0xA321F2D7226895C7u, 0xAFF72D52192B6A0Du, 0xCBEA6F8CEB02BB39u, 0x9BF4F8A69F764490u, 0xFEE50B7025C36A08u, 0x02F236D04753D5B4, - 0x9F4F2726179A2245u, 0x01D762422C946590u, 0xC722F0EF9D80AAD6u, 0x424D3AD2B7B97EF5u, 0xF8EBAD2B84E0D58Bu, 0xD2E0898765A7DEB2u, 0x9B934C3B330C8577u, 0x63CC55F49F88EB2F, - 0xC2781F49FFCFA6D5u, 0x3CBF6B71C76B25FBu, 0xF316271C7FC3908Au, 0x8BEF464E3945EF7Au, 0x97EDD871CFDA3A56u, 0x97758BF0E3CBB5ACu, 0xBDE94E8E43D0C8ECu, 0x3D52EEED1CBEA317, - 0xED63A231D4C4FB27u, 0x4CA7AAA863EE4BDDu, 0x945E455F24FB1CF8u, 0x8FE8CAA93E74EF6Au, 0xB975D6B6EE39E436u, 0xB3E2FD538E122B44u, 0xE7D34C64A9C85D44u, 0x60DBBCA87196B616, - 0x90E40FBEEA1D3A4Au, 0xBC8955E946FE31CDu, 0xB51D13AEA4A488DDu, 0x6BABAB6398BDBE41u, 0xE264589A4DCDAB14u, 0xC696963C7EED2DD1u, 0x8D7EB76070A08AECu, 0xFC1E1DE5CF543CA2, - 0xB0DE65388CC8ADA8u, 0x3B25A55F43294BCBu, 0xDD15FE86AFFAD912u, 0x49EF0EB713F39EBEu, 0x8A2DBF142DFCC7ABu, 0x6E3569326C784337u, 0xACB92ED9397BF996u, 0x49C2C37F07965404, - 0xD7E77A8F87DAF7FBu, 0xDC33745EC97BE906u, 0x86F0AC99B4E8DAFDu, 0x69A028BB3DED71A3u, 0xA8ACD7C0222311BCu, 0xC40832EA0D68CE0Cu, 0xD2D80DB02AABD62Bu, 0xF50A3FA490C30190, - 0x83C7088E1AAB65DBu, 0x792667C6DA79E0FAu, 0xA4B8CAB1A1563F52u, 0x577001B891185938u, 0xCDE6FD5E09ABCF26u, 0xED4C0226B55E6F86u, 0x80B05E5AC60B6178u, 0x544F8158315B05B4, - 0xA0DC75F1778E39D6u, 0x696361AE3DB1C721u, 0xC913936DD571C84Cu, 0x03BC3A19CD1E38E9u, 0xFB5878494ACE3A5Fu, 0x04AB48A04065C723u, 0x9D174B2DCEC0E47Bu, 0x62EB0D64283F9C76, - 0xC45D1DF942711D9Au, 0x3BA5D0BD324F8394u, 0xF5746577930D6500u, 0xCA8F44EC7EE36479u, 0x9968BF6ABBE85F20u, 0x7E998B13CF4E1ECBu, 0xBFC2EF456AE276E8u, 0x9E3FEDD8C321A67E, - 0xEFB3AB16C59B14A2u, 0xC5CFE94EF3EA101Eu, 0x95D04AEE3B80ECE5u, 0xBBA1F1D158724A12u, 0xBB445DA9CA61281Fu, 0x2A8A6E45AE8EDC97u, 0xEA1575143CF97226u, 0xF52D09D71A3293BD, - 0x924D692CA61BE758u, 0x593C2626705F9C56u, 0xB6E0C377CFA2E12Eu, 0x6F8B2FB00C77836Cu, 0xE498F455C38B997Au, 0x0B6DFB9C0F956447u, 0x8EDF98B59A373FECu, 0x4724BD4189BD5EAC, - 0xB2977EE300C50FE7u, 0x58EDEC91EC2CB657u, 0xDF3D5E9BC0F653E1u, 0x2F2967B66737E3EDu, 0x8B865B215899F46Cu, 0xBD79E0D20082EE74u, 0xAE67F1E9AEC07187u, 0xECD8590680A3AA11, - 0xDA01EE641A708DE9u, 0xE80E6F4820CC9495u, 0x884134FE908658B2u, 0x3109058D147FDCDDu, 0xAA51823E34A7EEDEu, 0xBD4B46F0599FD415u, 0xD4E5E2CDC1D1EA96u, 0x6C9E18AC7007C91A, - 0x850FADC09923329Eu, 0x03E2CF6BC604DDB0u, 0xA6539930BF6BFF45u, 0x84DB8346B786151Cu, 0xCFE87F7CEF46FF16u, 0xE612641865679A63u, 0x81F14FAE158C5F6Eu, 0x4FCB7E8F3F60C07E, - 0xA26DA3999AEF7749u, 0xE3BE5E330F38F09Du, 0xCB090C8001AB551Cu, 0x5CADF5BFD3072CC5u, 0xFDCB4FA002162A63u, 0x73D9732FC7C8F7F6u, 0x9E9F11C4014DDA7Eu, 0x2867E7FDDCDD9AFA, - 0xC646D63501A1511Du, 0xB281E1FD541501B8u, 0xF7D88BC24209A565u, 0x1F225A7CA91A4226u, 0x9AE757596946075Fu, 0x3375788DE9B06958u, 0xC1A12D2FC3978937u, 0x0052D6B1641C83AE, - 0xF209787BB47D6B84u, 0xC0678C5DBD23A49Au, 0x9745EB4D50CE6332u, 0xF840B7BA963646E0u, 0xBD176620A501FBFFu, 0xB650E5A93BC3D898u, 0xEC5D3FA8CE427AFFu, 0xA3E51F138AB4CEBE, - 0x93BA47C980E98CDFu, 0xC66F336C36B10137u, 0xB8A8D9BBE123F017u, 0xB80B0047445D4184u, 0xE6D3102AD96CEC1Du, 0xA60DC059157491E5u, 0x9043EA1AC7E41392u, 0x87C89837AD68DB2F, - 0xB454E4A179DD1877u, 0x29BABE4598C311FBu, 0xE16A1DC9D8545E94u, 0xF4296DD6FEF3D67Au, 0x8CE2529E2734BB1Du, 0x1899E4A65F58660Cu, 0xB01AE745B101E9E4u, 0x5EC05DCFF72E7F8F, - 0xDC21A1171D42645Du, 0x76707543F4FA1F73u, 0x899504AE72497EBAu, 0x6A06494A791C53A8u, 0xABFA45DA0EDBDE69u, 0x0487DB9D17636892u, 0xD6F8D7509292D603u, 0x45A9D2845D3C42B6, - 0x865B86925B9BC5C2u, 0x0B8A2392BA45A9B2u, 0xA7F26836F282B732u, 0x8E6CAC7768D7141Eu, 0xD1EF0244AF2364FFu, 0x3207D795430CD926u, 0x8335616AED761F1Fu, 0x7F44E6BD49E807B8, - 0xA402B9C5A8D3A6E7u, 0x5F16206C9C6209A6u, 0xCD036837130890A1u, 0x36DBA887C37A8C0Fu, 0x802221226BE55A64u, 0xC2494954DA2C9789u, 0xA02AA96B06DEB0FDu, 0xF2DB9BAA10B7BD6C, - 0xC83553C5C8965D3Du, 0x6F92829494E5ACC7u, 0xFA42A8B73ABBF48Cu, 0xCB772339BA1F17F9u, 0x9C69A97284B578D7u, 0xFF2A760414536EFBu, 0xC38413CF25E2D70Du, 0xFEF5138519684ABA, - 0xF46518C2EF5B8CD1u, 0x7EB258665FC25D69u, 0x98BF2F79D5993802u, 0xEF2F773FFBD97A61u, 0xBEEEFB584AFF8603u, 0xAAFB550FFACFD8FAu, 0xEEAABA2E5DBF6784u, 0x95BA2A53F983CF38, - 0x952AB45CFA97A0B2u, 0xDD945A747BF26183u, 0xBA756174393D88DFu, 0x94F971119AEEF9E4u, 0xE912B9D1478CEB17u, 0x7A37CD5601AAB85Du, 0x91ABB422CCB812EEu, 0xAC62E055C10AB33A, - 0xB616A12B7FE617AAu, 0x577B986B314D6009u, 0xE39C49765FDF9D94u, 0xED5A7E85FDA0B80Bu, 0x8E41ADE9FBEBC27Du, 0x14588F13BE847307u, 0xB1D219647AE6B31Cu, 0x596EB2D8AE258FC8, - 0xDE469FBD99A05FE3u, 0x6FCA5F8ED9AEF3BBu, 0x8AEC23D680043BEEu, 0x25DE7BB9480D5854u, 0xADA72CCC20054AE9u, 0xAF561AA79A10AE6Au, 0xD910F7FF28069DA4u, 0x1B2BA1518094DA04, - 0x87AA9AFF79042286u, 0x90FB44D2F05D0842u, 0xA99541BF57452B28u, 0x353A1607AC744A53u, 0xD3FA922F2D1675F2u, 0x42889B8997915CE8u, 0x847C9B5D7C2E09B7u, 0x69956135FEBADA11, - 0xA59BC234DB398C25u, 0x43FAB9837E699095u, 0xCF02B2C21207EF2Eu, 0x94F967E45E03F4BBu, 0x8161AFB94B44F57Du, 0x1D1BE0EEBAC278F5u, 0xA1BA1BA79E1632DCu, 0x6462D92A69731732, - 0xCA28A291859BBF93u, 0x7D7B8F7503CFDCFEu, 0xFCB2CB35E702AF78u, 0x5CDA735244C3D43Eu, 0x9DEFBF01B061ADABu, 0x3A0888136AFA64A7u, 0xC56BAEC21C7A1916u, 0x088AAA1845B8FDD0, - 0xF6C69A72A3989F5Bu, 0x8AAD549E57273D45u, 0x9A3C2087A63F6399u, 0x36AC54E2F678864Bu, 0xC0CB28A98FCF3C7Fu, 0x84576A1BB416A7DDu, 0xF0FDF2D3F3C30B9Fu, 0x656D44A2A11C51D5, - 0x969EB7C47859E743u, 0x9F644AE5A4B1B325u, 0xBC4665B596706114u, 0x873D5D9F0DDE1FEEu, 0xEB57FF22FC0C7959u, 0xA90CB506D155A7EAu, 0x9316FF75DD87CBD8u, 0x09A7F12442D588F2, - 0xB7DCBF5354E9BECEu, 0x0C11ED6D538AEB2Fu, 0xE5D3EF282A242E81u, 0x8F1668C8A86DA5FAu, 0x8FA475791A569D10u, 0xF96E017D694487BCu, 0xB38D92D760EC4455u, 0x37C981DCC395A9AC, - 0xE070F78D3927556Au, 0x85BBE253F47B1417u, 0x8C469AB843B89562u, 0x93956D7478CCEC8Eu, 0xAF58416654A6BABBu, 0x387AC8D1970027B2u, 0xDB2E51BFE9D0696Au, 0x06997B05FCC0319E, - 0x88FCF317F22241E2u, 0x441FECE3BDF81F03u, 0xAB3C2FDDEEAAD25Au, 0xD527E81CAD7626C3u, 0xD60B3BD56A5586F1u, 0x8A71E223D8D3B074u, 0x85C7056562757456u, 0xF6872D5667844E49, - 0xA738C6BEBB12D16Cu, 0xB428F8AC016561DBu, 0xD106F86E69D785C7u, 0xE13336D701BEBA52u, 0x82A45B450226B39Cu, 0xECC0024661173473u, 0xA34D721642B06084u, 0x27F002D7F95D0190, - 0xCC20CE9BD35C78A5u, 0x31EC038DF7B441F4u, 0xFF290242C83396CEu, 0x7E67047175A15271u, 0x9F79A169BD203E41u, 0x0F0062C6E984D386u, 0xC75809C42C684DD1u, 0x52C07B78A3E60868, - 0xF92E0C3537826145u, 0xA7709A56CCDF8A82u, 0x9BBCC7A142B17CCBu, 0x88A66076400BB691u, 0xC2ABF989935DDBFEu, 0x6ACFF893D00EA435u, 0xF356F7EBF83552FEu, 0x0583F6B8C4124D43, - 0x98165AF37B2153DEu, 0xC3727A337A8B704Au, 0xBE1BF1B059E9A8D6u, 0x744F18C0592E4C5Cu, 0xEDA2EE1C7064130Cu, 0x1162DEF06F79DF73u, 0x9485D4D1C63E8BE7u, 0x8ADDCB5645AC2BA8, - 0xB9A74A0637CE2EE1u, 0x6D953E2BD7173692u, 0xE8111C87C5C1BA99u, 0xC8FA8DB6CCDD0437u, 0x910AB1D4DB9914A0u, 0x1D9C9892400A22A2u, 0xB54D5E4A127F59C8u, 0x2503BEB6D00CAB4B, - 0xE2A0B5DC971F303Au, 0x2E44AE64840FD61Du, 0x8DA471A9DE737E24u, 0x5CEAECFED289E5D2u, 0xB10D8E1456105DADu, 0x7425A83E872C5F47u, 0xDD50F1996B947518u, 0xD12F124E28F77719, - 0x8A5296FFE33CC92Fu, 0x82BD6B70D99AAA6Fu, 0xACE73CBFDC0BFB7Bu, 0x636CC64D1001550Bu, 0xD8210BEFD30EFA5Au, 0x3C47F7E05401AA4Eu, 0x8714A775E3E95C78u, 0x65ACFAEC34810A71, - 0xA8D9D1535CE3B396u, 0x7F1839A741A14D0Du, 0xD31045A8341CA07Cu, 0x1EDE48111209A050u, 0x83EA2B892091E44Du, 0x934AED0AAB460432u, 0xA4E4B66B68B65D60u, 0xF81DA84D5617853F, - 0xCE1DE40642E3F4B9u, 0x36251260AB9D668Eu, 0x80D2AE83E9CE78F3u, 0xC1D72B7C6B426019u, 0xA1075A24E4421730u, 0xB24CF65B8612F81Fu, 0xC94930AE1D529CFCu, 0xDEE033F26797B627, - 0xFB9B7CD9A4A7443Cu, 0x169840EF017DA3B1u, 0x9D412E0806E88AA5u, 0x8E1F289560EE864Eu, 0xC491798A08A2AD4Eu, 0xF1A6F2BAB92A27E2u, 0xF5B5D7EC8ACB58A2u, 0xAE10AF696774B1DB, - 0x9991A6F3D6BF1765u, 0xACCA6DA1E0A8EF29u, 0xBFF610B0CC6EDD3Fu, 0x17FD090A58D32AF3u, 0xEFF394DCFF8A948Eu, 0xDDFC4B4CEF07F5B0u, 0x95F83D0A1FB69CD9u, 0x4ABDAF101564F98E, - 0xBB764C4CA7A4440Fu, 0x9D6D1AD41ABE37F1u, 0xEA53DF5FD18D5513u, 0x84C86189216DC5EDu, 0x92746B9BE2F8552Cu, 0x32FD3CF5B4E49BB4u, 0xB7118682DBB66A77u, 0x3FBC8C33221DC2A1, - 0xE4D5E82392A40515u, 0x0FABAF3FEAA5334Au, 0x8F05B1163BA6832Du, 0x29CB4D87F2A7400Eu, 0xB2C71D5BCA9023F8u, 0x743E20E9EF511012u, 0xDF78E4B2BD342CF6u, 0x914DA9246B255416, - 0x8BAB8EEFB6409C1Au, 0x1AD089B6C2F7548Eu, 0xAE9672ABA3D0C320u, 0xA184AC2473B529B1u, 0xDA3C0F568CC4F3E8u, 0xC9E5D72D90A2741Eu, 0x8865899617FB1871u, 0x7E2FA67C7A658892, - 0xAA7EEBFB9DF9DE8Du, 0xDDBB901B98FEEAB7u, 0xD51EA6FA85785631u, 0x552A74227F3EA565u, 0x8533285C936B35DEu, 0xD53A88958F87275Fu, 0xA67FF273B8460356u, 0x8A892ABAF368F137, - 0xD01FEF10A657842Cu, 0x2D2B7569B0432D85u, 0x8213F56A67F6B29Bu, 0x9C3B29620E29FC73u, 0xA298F2C501F45F42u, 0x8349F3BA91B47B8Fu, 0xCB3F2F7642717713u, 0x241C70A936219A73, - 0xFE0EFB53D30DD4D7u, 0xED238CD383AA0110u, 0x9EC95D1463E8A506u, 0xF4363804324A40AAu, 0xC67BB4597CE2CE48u, 0xB143C6053EDCD0D5u, 0xF81AA16FDC1B81DAu, 0xDD94B7868E94050A, - 0x9B10A4E5E9913128u, 0xCA7CF2B4191C8326u, 0xC1D4CE1F63F57D72u, 0xFD1C2F611F63A3F0u, 0xF24A01A73CF2DCCFu, 0xBC633B39673C8CECu, 0x976E41088617CA01u, 0xD5BE0503E085D813, - 0xBD49D14AA79DBC82u, 0x4B2D8644D8A74E18u, 0xEC9C459D51852BA2u, 0xDDF8E7D60ED1219Eu, 0x93E1AB8252F33B45u, 0xCABB90E5C942B503u, 0xB8DA1662E7B00A17u, 0x3D6A751F3B936243, - 0xE7109BFBA19C0C9Du, 0x0CC512670A783AD4u, 0x906A617D450187E2u, 0x27FB2B80668B24C5u, 0xB484F9DC9641E9DAu, 0xB1F9F660802DEDF6u, 0xE1A63853BBD26451u, 0x5E7873F8A0396973, - 0x8D07E33455637EB2u, 0xDB0B487B6423E1E8u, 0xB049DC016ABC5E5Fu, 0x91CE1A9A3D2CDA62u, 0xDC5C5301C56B75F7u, 0x7641A140CC7810FBu, 0x89B9B3E11B6329BAu, 0xA9E904C87FCB0A9D, - 0xAC2820D9623BF429u, 0x546345FA9FBDCD44u, 0xD732290FBACAF133u, 0xA97C177947AD4095u, 0x867F59A9D4BED6C0u, 0x49ED8EABCCCC485Du, 0xA81F301449EE8C70u, 0x5C68F256BFFF5A74, - 0xD226FC195C6A2F8Cu, 0x73832EEC6FFF3111u, 0x83585D8FD9C25DB7u, 0xC831FD53C5FF7EABu, 0xA42E74F3D032F525u, 0xBA3E7CA8B77F5E55u, 0xCD3A1230C43FB26Fu, 0x28CE1BD2E55F35EB, - 0x80444B5E7AA7CF85u, 0x7980D163CF5B81B3u, 0xA0555E361951C366u, 0xD7E105BCC332621Fu, 0xC86AB5C39FA63440u, 0x8DD9472BF3FEFAA7u, 0xFA856334878FC150u, 0xB14F98F6F0FEB951, - 0x9C935E00D4B9D8D2u, 0x6ED1BF9A569F33D3u, 0xC3B8358109E84F07u, 0x0A862F80EC4700C8u, 0xF4A642E14C6262C8u, 0xCD27BB612758C0FAu, 0x98E7E9CCCFBD7DBDu, 0x8038D51CB897789C, - 0xBF21E44003ACDD2Cu, 0xE0470A63E6BD56C3u, 0xEEEA5D5004981478u, 0x1858CCFCE06CAC74u, 0x95527A5202DF0CCBu, 0x0F37801E0C43EBC8u, 0xBAA718E68396CFFDu, 0xD30560258F54E6BA, - 0xE950DF20247C83FDu, 0x47C6B82EF32A2069u, 0x91D28B7416CDD27Eu, 0x4CDC331D57FA5441u, 0xB6472E511C81471Du, 0xE0133FE4ADF8E952u, 0xE3D8F9E563A198E5u, 0x58180FDDD97723A6, - 0x8E679C2F5E44FF8Fu, 0x570F09EAA7EA7648u, 0xB201833B35D63F73u, 0x2CD2CC6551E513DAu, 0xDE81E40A034BCF4Fu, 0xF8077F7EA65E58D1u, 0x8B112E86420F6191u, 0xFB04AFAF27FAF782, - 0xADD57A27D29339F6u, 0x79C5DB9AF1F9B563u, 0xD94AD8B1C7380874u, 0x18375281AE7822BCu, 0x87CEC76F1C830548u, 0x8F2293910D0B15B5u, 0xA9C2794AE3A3C69Au, 0xB2EB3875504DDB22, - 0xD433179D9C8CB841u, 0x5FA60692A46151EBu, 0x849FEEC281D7F328u, 0xDBC7C41BA6BCD333u, 0xA5C7EA73224DEFF3u, 0x12B9B522906C0800u, 0xCF39E50FEAE16BEFu, 0xD768226B34870A00, - 0x81842F29F2CCE375u, 0xE6A1158300D46640u, 0xA1E53AF46F801C53u, 0x60495AE3C1097FD0u, 0xCA5E89B18B602368u, 0x385BB19CB14BDFC4u, 0xFCF62C1DEE382C42u, 0x46729E03DD9ED7B5, - 0x9E19DB92B4E31BA9u, 0x6C07A2C26A8346D1u }; }// namespace jsonifier_internal diff --git a/Include/jsonifier/Tuple.hpp b/Include/jsonifier/Tuple.hpp index c02cb4f22..a3a9beed5 100644 --- a/Include/jsonifier/Tuple.hpp +++ b/Include/jsonifier/Tuple.hpp @@ -25,93 +25,77 @@ #pragma once #include -#include -#include namespace jsonifier_internal { - template jsonifier_constexpr auto copyTuple(value_types... args) { - return std::tuple{ args... }; - } + template struct group_builder { + public: + static constexpr auto op(tuple_t&& object) { + return makeGroupsImpl(std::forward(object), std::make_index_sequence{}); + } - template jsonifier_constexpr void shrinkIndexArrayHelper(auto& arrayNew01, auto& arrayNew00) { - if jsonifier_constexpr (index < indexLimit) { - arrayNew01[index] = arrayNew00[index]; - shrinkIndexArrayHelper(arrayNew01, arrayNew00); + protected: + template static constexpr auto shrinkIndexArray(auto& valuesNew01, std::index_sequence) { + std::array res{}; + ((res[indices] = valuesNew01[indices]), ...); + return res; } - } - - template jsonifier_constexpr auto shrinkIndexArray(auto& arrayNew01) { - ctime_array res{}; - shrinkIndexArrayHelper<0, size>(res, arrayNew01); - return res; - } - - template jsonifier_constexpr auto filter() { - jsonifier_constexpr auto n = std::tuple_size_v; - ctime_array indices{}; - size_t x = 0; - forEach([&](auto I) { - using value_type = jsonifier::concepts::unwrap>; - if jsonifier_constexpr (!std::convertible_to) { - indices[x++] = I - 1; - } - }); - return std::make_pair(indices, x); - } - - template jsonifier_constexpr void groupSizesHelper(auto& diffs, auto& indices) { - if jsonifier_constexpr (index < indexLimit) { - diffs[index] = indices[index + 1] - indices[index]; - groupSizesHelper(diffs, indices); + + static constexpr auto filter() { + constexpr auto n = std::tuple_size_v; + std::array indices{}; + size_t x = 0; + forEach([&](auto index) { + using value_type = jsonifier::concepts::unwrap>; + if constexpr (!std::convertible_to) { + indices[x++] = index - 1; + } + }); + return std::make_pair(indices, x); } - } - - template jsonifier_constexpr auto groupSizes(const ctime_array& indices, size_t n_total) { - ctime_array diffs; - groupSizesHelper<0, nGroups - 1>(diffs, indices); - diffs[nGroups - 1] = n_total - indices[nGroups - 1]; - return diffs; - } - - template jsonifier_constexpr auto makeGroup(tuple_t&& object, std::index_sequence) { - auto get_elem = [&](auto x) { - jsonifier_constexpr auto I = decltype(x)::value; - if jsonifier_constexpr (I == 1) { - return get(object); - } else { - return jsonifier::string_view(get(object)); - } - }; - auto r = copyTuple(get_elem(std::integral_constant{})...); - return r; - } - - template - jsonifier_constexpr auto makeGroupsImpl(tuple_t&& object, std::index_sequence) { - return copyTuple( - makeGroup()]>(object, std::make_index_sequence()]>{})...); - } - - template jsonifier_constexpr auto makeGroupsHelper() { - jsonifier_constexpr auto size = std::tuple_size_v; - - jsonifier_constexpr auto filtered = filter(); - jsonifier_constexpr auto starts = shrinkIndexArray(filtered.first); - jsonifier_constexpr auto sizes = groupSizes(starts, size); - - return std::tuple(starts, sizes); - } - - template struct GroupBuilder { - static jsonifier_constexpr auto h = makeGroupsHelper(); - static jsonifier_constexpr auto starts = get<0>(h); - static jsonifier_constexpr auto sizes = get<1>(h); - - static jsonifier_constexpr auto op(tuple_t&& object) { - jsonifier_constexpr auto nGroups = starts.maxSize(); - return makeGroupsImpl(std::forward(object), std::make_index_sequence{}); + + template static constexpr void groupSizesHelper(auto& diffs, auto& indices, std::index_sequence) { + ((diffs[indicesNew] = indices[indicesNew + 1] - indices[indicesNew]), ...); + } + + template static constexpr auto groupSizes(const std::array& indices, size_t nTotal) { + std::array diffs; + groupSizesHelper(diffs, indices, std::make_index_sequence{}); + diffs[nGroups - 1] = nTotal - indices[nGroups - 1]; + return diffs; } + + template static constexpr auto makeGroup(const tuple_t& t, std::index_sequence) { + auto getElem = [&](auto x) { + constexpr auto value = decltype(x)::value; + using type = decltype(std::get(t)); + if constexpr (value == 0 || std::convertible_to) { + return jsonifier::string_view(std::get(t)); + } else { + return std::get(t); + } + }; + return std::make_tuple(getElem(std::integral_constant{})...); + } + + template static constexpr auto makeGroupsImpl(tuple_t&& object, std::index_sequence) { + auto newTuple{ std::forward(object) }; + return std::make_tuple( + makeGroup()]>(newTuple, std::make_index_sequence()]>{})...); + } + + static constexpr auto makeGroupsHelper() { + constexpr auto nNew = std::tuple_size_v; + constexpr auto filtered = filter(); + constexpr auto startsNew = shrinkIndexArray(filtered.first, std::make_index_sequence{}); + constexpr auto sizesNew = groupSizes(startsNew, nNew); + return std::make_tuple(startsNew, sizesNew); + } + + static constexpr auto h = makeGroupsHelper(); + static constexpr auto starts = get<0>(h); + static constexpr auto sizes = get<1>(h); + static constexpr auto nGroups = starts.size(); }; } \ No newline at end of file diff --git a/Include/jsonifier/TypeEntities.hpp b/Include/jsonifier/TypeEntities.hpp index fa7b45cc9..bcb661128 100644 --- a/Include/jsonifier/TypeEntities.hpp +++ b/Include/jsonifier/TypeEntities.hpp @@ -30,14 +30,6 @@ #include #include -#if !defined(jsonifier_inline) - #define jsonifier_inline inline -#endif - -#if !defined(jsonifier_constexpr) - #define jsonifier_constexpr constexpr -#endif - namespace jsonifier { class raw_json_data; @@ -46,86 +38,98 @@ namespace jsonifier { template struct core {}; +} + +namespace jsonifier_internal { + + template class parser; + template struct array { value_type parseValue; }; - template array(value_type) -> array; - template struct object { value_type parseValue; }; - - template object(value_type) -> object; } namespace jsonifier { namespace concepts { - // From: + // 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 class> constexpr bool is_specialization_v = false; - template typename Ref, typename... Args> struct is_specialization_v, Ref> : std::true_type {}; + template class T, class... Args> constexpr bool is_specialization_v, T> = true; - template using Tag = std::integral_constant; + template using tag = std::integral_constant; - template jsonifier_constexpr Tag TagV{}; + template constexpr tag TagV{}; - template using unwrap = std::unwrap_ref_decay_t; + template struct collect_first_type { + using type = value_type; + }; - template - concept range = requires(value_type& value) { - typename unwrap::value_type; - { value.begin() } -> std::same_as::iterator>; - { value.end() } -> std::same_as::iterator>; - }; + template using unwrap = std::remove_const_t::type>>; template - concept stateless = std::is_empty_v>; + concept range = requires(value_type value) { + typename unwrap::value_type; + { value.begin() } -> std::same_as::const_iterator>; + { value.end() } -> std::same_as::const_iterator>; + } || requires(value_type value) { + typename unwrap::value_type; + { value.begin() } -> std::same_as::iterator>; + { value.end() } -> std::same_as::iterator>; + }; template concept map_subscriptable = requires(value_type value) { - { value[std::declval::key_type>()] } -> std::same_as::mapped_type&>; - } || requires(value_type value) { - { value[std::declval::key_type>()] } -> std::same_as::mapped_type&>; - }; + { value[std::declval::key_type>()] } -> std::same_as::mapped_type&>; + } || requires(value_type value) { + { value[std::declval::key_type>()] } -> std::same_as::mapped_type&>; + }; template concept vector_subscriptable = requires(value_type value) { - { value[std::declval()] } -> std::same_as::const_reference>; - } || requires(value_type value) { - { value[std::declval()] } -> std::same_as::reference>; - }; + { value[std::declval::size_type>()] } -> std::same_as::const_reference>; + } || requires(value_type value) { + { value[std::declval::size_type>()] } -> std::same_as::reference>; + }; + + template + concept has_size = requires(value_type value) { + { value.size() } -> std::same_as::size_type>; + }; template - concept pair_t = requires(value_type value) { - { value.first } -> std::same_as::first_type>; - { value.second } -> std::same_as::second_type>; - }; + concept is_fwd_iterator = std::forward_iterator>; template - concept has_size = requires(value_type value) { - { value.size() } -> std::same_as::size_type>; - }; + concept has_resize = requires(value_type value) { value.resize(std::declval::size_type>()); }; + + template + concept has_data = requires(value_type value) { + { value.data() } -> std::same_as::const_pointer>; + } || requires(value_type value) { + { value.data() } -> std::same_as::pointer>; + }; + + template + concept stateless = std::is_empty_v>; template - concept has_data = requires(value_type data) { - { data.data() } -> std::same_as::const_pointer>; - } || requires(value_type data) { - { data.data() } -> std::same_as::pointer>; - }; + concept is_parser = is_specialization_v>, jsonifier_internal::parser>; template concept void_t = std::is_void_v>; template - concept indexable = stateless || requires(value_type value) { value[Tag<0>()]; }; + concept indexable = stateless || requires(value_type value) { value[tag<0>()]; }; template concept related_ptr = ( std::derived_from, unwrap> || std::is_base_of_v, unwrap> || - std::same_as, unwrap> ) && - std::is_pointer_v>; + std::same_as, unwrap> )&&std::is_pointer_v>; template concept bool_t = std::same_as, bool>; @@ -134,12 +138,10 @@ namespace jsonifier { concept pointer_t = (std::is_pointer_v> || std::is_null_pointer_v>); template - concept signed_t = std::signed_integral> && ! - bool_t; + concept signed_t = std::signed_integral> && !bool_t; template - concept unsigned_t = std::unsigned_integral> && ! - bool_t; + concept unsigned_t = std::unsigned_integral> && !bool_t; template concept unsigned_int16_t = unsigned_t && sizeof(value_type) == 2; @@ -167,75 +169,74 @@ namespace jsonifier { std::same_as, char16_t> || std::same_as, char32_t>; template - concept num_t = ( float_t || unsigned_t || signed_t ) && ! - char_t; + concept num_t = ( float_t || unsigned_t || signed_t )&&!char_t; template concept has_substr = requires(value_type value) { - { value.substr(std::declval(), std::declval()) }; - }; + { value.substr(std::declval::size_type>(), std::declval::size_type>()) } -> std::same_as>; + }; template - concept string_t = has_substr> && has_data> && has_size> && ! - std::same_as>&& vector_subscriptable> && !pointer_t; + concept string_t = has_substr && has_data && has_size && !std::same_as, char> && vector_subscriptable && + !pointer_t; template - concept map_t = requires(value_type data) { - typename unwrap::mapped_type; - typename unwrap::key_type; - } && range && map_subscriptable; + concept map_t = requires(value_type value) { + typename unwrap::mapped_type; + typename unwrap::key_type; + } && range && map_subscriptable; template - concept has_emplace_back = requires(value_type data) { - { data.emplace_back(std::declval::value_type&&>()) } -> std::same_as::value_type&>; - }; + concept has_emplace_back = requires(value_type value) { + { value.emplace_back(std::declval::value_type&&>()) } -> std::same_as::value_type&>; + }; template concept has_release = requires(value_type value) { - { value.release() } -> std::same_as::pointer>; - }; + { value.release() } -> std::same_as::pointer>; + }; + + template + concept copyable = std::copy_constructible; template - concept unique_ptr_t = requires(value_type other) { - typename unwrap::element_type; - typename unwrap::deleter_type; - { other.release() } -> std::same_as::pointer>; - } && has_release && ! - std::is_copy_assignable_v>; + concept unique_ptr_t = requires(value_type value) { + typename unwrap::element_type; + typename unwrap::deleter_type; + } && has_release; template - concept shared_ptr_t = (requires(value_type other) { - typename unwrap::element_type; - typename unwrap::deleter_type; - { other.release() } -> std::same_as::pointer>; - }) && has_release; + concept shared_ptr_t = requires(value_type value) { + typename unwrap::element_type; + typename unwrap::deleter_type; + } && has_release && std::copy_constructible>; template - concept has_find = requires(value_type c) { - { c.find(std::declval::key_type&>()) }; - }; + concept has_find = requires(value_type value) { + { value.find(std::declval::key_type&>()) }; + }; template concept has_excluded_keys = requires(value_type value) { - { value.excludedKeys }; - }; + { value.jsonifierExcludedKeys }; + }; template - concept always_null_t = std::same_as || std::same_as || std::same_as; + concept always_null_t = + std::same_as, std::nullptr_t> || std::same_as, std::monostate> || std::same_as, std::nullopt_t>; template - concept nullable_t = ! - string_t&& requires(value_type t) { - bool(t); - { *t }; - }; + concept nullable_t = !string_t && requires(value_type value) { + bool(value); + { *value }; + }; + + template + concept same_as = std::convertible_to, unwrap> || std::same_as, unwrap>; template concept null_t = nullable_t || always_null_t; - template - concept has_resize = requires(value_type value) { value.resize(0); }; - template concept raw_json_t = std::same_as, jsonifier::raw_json_data>; @@ -243,58 +244,67 @@ namespace jsonifier { concept jsonifier_t = requires { jsonifier::core>::parseValue; }; struct empty_val { - static jsonifier_constexpr std::tuple<> parseValue{}; + static constexpr std::tuple<> parseValue{}; }; - template jsonifier_constexpr auto coreWrapperV = [] { - if jsonifier_constexpr (jsonifier_t) { + template constexpr auto coreWrapperV = [] { + if constexpr (jsonifier_t) { return jsonifier::core>::parseValue; } else { - return empty_val{}; + return empty_val::parseValue; } }(); - template jsonifier_constexpr auto coreV = coreWrapperV.parseValue; + template + concept same_character_size = requires() { sizeof(typename unwrap::value_type) == sizeof(typename unwrap::value_type); } && + string_t && string_t; + + template constexpr auto coreV = coreWrapperV.parseValue; - template using core_t = unwrap)>; + template using core_t = decltype(coreV); template using core_wrapper_t = unwrap)>; template - concept jsonifier_array_t = jsonifier_t && is_specialization_v, jsonifier::array>::value; + concept jsonifier_array_t = jsonifier_t && is_specialization_v, jsonifier_internal::array>; template - concept jsonifier_object_t = jsonifier_t && is_specialization_v, jsonifier::object>::value; + concept jsonifier_object_t = jsonifier_t && is_specialization_v, jsonifier_internal::object>; template - concept enum_t = std::is_enum>::value; + concept enum_t = std::is_enum_v>; template - concept vector_t = ( !map_t && vector_subscriptable && has_data ) && ! - jsonifier_array_t && !has_substr; + concept vector_t = ( !map_t && vector_subscriptable && has_data )&&!jsonifier_array_t && !has_substr; template - concept raw_array_t = std::is_array_v>; + concept raw_array_t = std::is_array_v; template - concept buffer_like = has_resize && vector_subscriptable && has_data; + concept buffer_like = vector_subscriptable && has_data && has_resize; template - concept core_type = is_specialization_v, jsonifier::core>::value; + concept core_type = is_specialization_v>, jsonifier::core>; template - concept time_type = is_specialization_v, std::chrono::duration>::value; + concept time_type = is_specialization_v>, std::chrono::duration>; template - concept uint8_type = std::same_as>; + concept uint8_type = std::same_as, uint8_t>; template concept char_type = uint8_type || char_t; template - concept integer_t = std::integral> && ! - bool_t; + concept integer_t = std::integral> && !bool_t; } }// namespace jsonifier_internal + +namespace std { + + template<> struct variant_size : integral_constant {}; + + template<> struct tuple_size : integral_constant {}; +} \ No newline at end of file diff --git a/Include/jsonifier/Vector.hpp b/Include/jsonifier/Vector.hpp index 6ce758268..0b34eb4e4 100644 --- a/Include/jsonifier/Vector.hpp +++ b/Include/jsonifier/Vector.hpp @@ -44,92 +44,96 @@ namespace jsonifier { using size_type = uint64_t; using allocator = jsonifier_internal::alloc_wrapper; - jsonifier_inline vector() = default; + JSONIFIER_INLINE vector() = default; - jsonifier_inline vector& operator=(vector&& other) noexcept { + JSONIFIER_INLINE vector& operator=(vector&& other) noexcept { if (this != &other && dataVal != other.dataVal) { - reset(); - swap(other); + vector{ other }.swap(*this); } return *this; } - jsonifier_inline vector(vector&& other) noexcept : capacityVal{}, sizeVal{}, dataVal{} { - *this = std::move(other); + JSONIFIER_INLINE vector(vector&& other) noexcept : capacityVal{}, sizeVal{}, dataVal{} { + swap(other); } - jsonifier_inline vector& operator=(const vector& other) { + JSONIFIER_INLINE vector& operator=(const vector& other) { if (this != &other) { - reset(); - auto sizeValNew = other.size(); - reserve(sizeValNew); - std::uninitialized_copy(other.data(), other.data() + sizeValNew, dataVal); - sizeVal = sizeValNew; + vector{ other }.swap(*this); } return *this; } - jsonifier_inline vector(const vector& other) : capacityVal{}, sizeVal{}, dataVal{} { - *this = other; + JSONIFIER_INLINE vector(const vector& other) : capacityVal{}, sizeVal{}, dataVal{} { + auto sizeValNew = other.size(); + if (sizeValNew > 0 && sizeValNew < maxSize()) { + reserve(sizeValNew); + std::uninitialized_copy(other.data(), other.data() + sizeValNew, dataVal); + sizeVal = sizeValNew; + } } - jsonifier_inline vector& operator=(std::vector&& other) { - reset(); - auto sizeValNew = other.size(); - reserve(sizeValNew); - std::uninitialized_move(other.data(), other.data() + sizeValNew, dataVal); - sizeVal = sizeValNew; + JSONIFIER_INLINE vector& operator=(std::vector other) { + vector{ other }.swap(*this); return *this; } - jsonifier_inline explicit vector(std::vector&& other) : capacityVal{}, sizeVal{}, dataVal{} { - *this = std::move(other); + JSONIFIER_INLINE explicit vector(std::vector other) : capacityVal{}, sizeVal{}, dataVal{} { + auto sizeValNew = other.size(); + if (sizeValNew > 0 && sizeValNew < maxSize()) { + reserve(sizeValNew); + std::uninitialized_move(other.data(), other.data() + sizeValNew, dataVal); + sizeVal = sizeValNew; + } } - jsonifier_inline vector& operator=(const std::vector& other) { - reset(); - auto sizeValNew = other.size(); - reserve(sizeValNew); - std::uninitialized_copy(other.data(), other.data() + sizeValNew, dataVal); - sizeVal = sizeValNew; + JSONIFIER_INLINE vector& operator=(const std::vector& other) { + vector{ other }.swap(*this); return *this; } - jsonifier_inline explicit vector(const std::vector& other) : capacityVal{}, sizeVal{}, dataVal{} { - *this = other; + JSONIFIER_INLINE explicit vector(const std::vector& other) : capacityVal{}, sizeVal{}, dataVal{} { + auto sizeValNew = other.size(); + if (sizeValNew > 0 && sizeValNew < maxSize()) { + reserve(sizeValNew); + std::uninitialized_copy(other.data(), other.data() + sizeValNew, dataVal); + sizeVal = sizeValNew; + } } - jsonifier_inline vector& operator=(std::initializer_list other) { - reset(); - auto sizeValNew = other.size(); - reserve(sizeValNew); - std::uninitialized_move(other.begin(), other.begin() + sizeValNew, dataVal); - sizeVal = sizeValNew; + JSONIFIER_INLINE vector& operator=(std::initializer_list other) { + vector{ other }.swap(*this); return *this; } - jsonifier_inline explicit vector(std::initializer_list other) : capacityVal{}, sizeVal{}, dataVal{} { - *this = other; + JSONIFIER_INLINE explicit vector(std::initializer_list other) : capacityVal{}, sizeVal{}, dataVal{} { + auto sizeValNew = other.size(); + if (sizeValNew > 0 && sizeValNew < maxSize()) { + reserve(sizeValNew); + std::uninitialized_move(other.begin(), other.begin() + sizeValNew, dataVal); + sizeVal = sizeValNew; + } } - jsonifier_inline explicit vector(value_type&& other, size_type sizeNew) : capacityVal{}, sizeVal{}, dataVal{} { - reset(); - auto sizeValNew = sizeNew; - reserve(sizeValNew); - std::uninitialized_fill(data(), data() + sizeValNew, other); - sizeVal = sizeValNew; + JSONIFIER_INLINE explicit vector(value_type&& other, size_type newSize) : capacityVal{}, sizeVal{}, dataVal{} { + auto sizeValNew = newSize; + if (sizeValNew > 0 && sizeValNew < maxSize()) { + reserve(sizeValNew); + std::uninitialized_fill(data(), data() + sizeValNew, other); + sizeVal = sizeValNew; + } } - jsonifier_inline vector& operator=(value_type other) { + JSONIFIER_INLINE vector& operator=(value_type other) { emplace_back(other); return *this; } - jsonifier_inline vector(value_type other) : capacityVal{}, sizeVal{}, dataVal{} { + JSONIFIER_INLINE vector(value_type other) : capacityVal{}, sizeVal{}, dataVal{} { *this = other; } - template jsonifier_inline void insert(iterator where, InputIterator first, InputIterator last) { + template JSONIFIER_INLINE void insert(iterator where, InputIterator first, InputIterator last) { size_type insertCount = std::distance(first, last); if (insertCount == 0) { @@ -146,13 +150,13 @@ namespace jsonifier { pointer insertPos = dataVal + insertPosIndex; for (InputIterator it = first; it != last; ++it) { - getAlloc().construct(insertPos++, *it); + allocator::construct(insertPos++, *it); } sizeVal = newSize; } - template jsonifier_inline void insert(iterator where, value_type_newer&& value) { + template JSONIFIER_INLINE void insert(iterator where, value_type_newer&& value) { size_type insertCount = 1; if (insertCount == 0) { @@ -168,106 +172,98 @@ namespace jsonifier { pointer insertPos = dataVal + insertPosIndex; - getAlloc().construct(insertPos++, value); + allocator::construct(insertPos++, value); sizeVal = newSize; } - jsonifier_inline iterator begin() { - return iterator(dataVal); + JSONIFIER_INLINE iterator begin() noexcept { + return iterator{ dataVal }; } - jsonifier_inline iterator end() { - return iterator(dataVal + sizeVal); + JSONIFIER_INLINE iterator end() noexcept { + return iterator{ dataVal + sizeVal }; } - jsonifier_inline const_iterator begin() const { - return const_iterator(dataVal); + JSONIFIER_INLINE reverse_iterator rbegin() noexcept { + return reverse_iterator{ end() }; } - jsonifier_inline const_iterator end() const { - return const_iterator(dataVal + sizeVal); + JSONIFIER_INLINE reverse_iterator rend() noexcept { + return reverse_iterator{ begin() }; } - jsonifier_inline reverse_iterator rbegin() { - return reverse_iterator(end()); + JSONIFIER_INLINE const_iterator begin() const noexcept { + return const_iterator{ dataVal }; } - jsonifier_inline reverse_iterator rend() { - return reverse_iterator(begin()); + JSONIFIER_INLINE const_iterator end() const noexcept { + return const_iterator{ dataVal + sizeVal }; } - jsonifier_inline const_iterator cbegin() const { - return const_iterator(begin()); + JSONIFIER_INLINE const_reverse_iterator rbegin() const noexcept { + return const_reverse_iterator{ end() }; } - jsonifier_inline const_iterator cend() const { - return const_iterator(end()); + JSONIFIER_INLINE const_reverse_iterator rend() const noexcept { + return const_reverse_iterator{ begin() }; } - jsonifier_inline const_reverse_iterator crbegin() const { - return const_reverse_iterator(cend()); - } - - jsonifier_inline const_reverse_iterator crend() const { - return const_reverse_iterator(cbegin()); - } - - jsonifier_inline reference front() { + JSONIFIER_INLINE reference front() { return dataVal[0]; } - jsonifier_inline reference back() { + JSONIFIER_INLINE reference back() { return dataVal[sizeVal - 1]; } - jsonifier_inline const_reference front() const { + JSONIFIER_INLINE const_reference front() const { return dataVal[0]; } - jsonifier_inline const_reference back() const { + JSONIFIER_INLINE const_reference back() const { return dataVal[sizeVal - 1]; } - jsonifier_inline reference at(size_type index) { + JSONIFIER_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." }; } return dataVal[index]; } - jsonifier_inline const_reference at(size_type index) const { + JSONIFIER_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." }; } return dataVal[index]; } - jsonifier_inline const_reference operator[](size_type index) const { + JSONIFIER_INLINE const_reference operator[](size_type index) const { return dataVal[index]; } - jsonifier_inline reference operator[](size_type index) { + JSONIFIER_INLINE reference operator[](size_type index) { return dataVal[index]; } - jsonifier_inline size_type capacity() const { + JSONIFIER_INLINE size_type capacity() const { return capacityVal; } - jsonifier_inline size_type size() const { + JSONIFIER_INLINE size_type size() const { return sizeVal; } - jsonifier_inline pointer data() const { + JSONIFIER_INLINE pointer data() const { return dataVal; } - jsonifier_inline pointer data() { + JSONIFIER_INLINE pointer data() { return dataVal; } - jsonifier_inline explicit operator std::vector() const { + JSONIFIER_INLINE explicit operator std::vector() const { std::vector returnValue{}; for (auto& value: *this) { returnValue.emplace_back(value); @@ -275,16 +271,16 @@ namespace jsonifier { return returnValue; } - template jsonifier_inline reference emplace_back(value_types&&... c) { + template JSONIFIER_INLINE reference emplace_back(value_types&&... c) { if (sizeVal + 1 >= capacityVal) { reserve(capacityVal * 2 + 2); } - getAlloc().construct(&dataVal[sizeVal++], std::forward(c)...); + allocator::construct(&dataVal[sizeVal++], std::forward(c)...); return dataVal[sizeVal - 1]; } - jsonifier_inline void erase(size_type count) { + JSONIFIER_INLINE void erase(size_type count) { if (count >= sizeVal) { return; } @@ -297,7 +293,7 @@ namespace jsonifier { sizeVal = newSize; } - jsonifier_inline void erase(iterator iter) { + JSONIFIER_INLINE void erase(iterator iter) { if (iter < begin() || iter >= end()) { return; } @@ -305,14 +301,14 @@ namespace jsonifier { size_type eraseIndex = static_cast(iter - begin()); size_type newSize = sizeVal - 1; - getAlloc().destroy(dataVal + eraseIndex); + allocator::destroy(dataVal + eraseIndex); std::uninitialized_move(dataVal + eraseIndex + 1, dataVal + sizeVal, dataVal + eraseIndex); sizeVal = newSize; } - jsonifier_inline void shrinkToFit() { + JSONIFIER_INLINE void shrinkToFit() { if (sizeVal == capacityVal) { return; } @@ -324,45 +320,51 @@ namespace jsonifier { swap(newVector); } - jsonifier_constexpr static size_type maxSize() noexcept { + constexpr size_type maxSize() noexcept { return (std::min)(static_cast((std::numeric_limits::max)()), allocator::maxSize()); } - jsonifier_inline void resize(size_type sizeNew) { - if (sizeNew > 0 && sizeNew < maxSize()) [[likely]] { - if (sizeNew > capacityVal) [[likely]] { - pointer newPtr = getAlloc().allocate(sizeNew); - try { - if (dataVal && capacityVal > 0) [[likely]] { + JSONIFIER_INLINE void resize(size_type newSize) { + if (newSize > capacityVal) [[likely]] { + pointer newPtr = allocator::allocate(newSize); + try { + if (sizeVal > 0) { + if constexpr (std::is_copy_constructible_v) { + std::uninitialized_copy(dataVal, dataVal + sizeVal, newPtr); + } else if constexpr (std::is_move_constructible_v) { std::uninitialized_move(dataVal, dataVal + sizeVal, newPtr); - getAlloc().deallocate(dataVal, capacityVal); } - } catch (...) { - getAlloc().deallocate(newPtr, sizeNew); - throw; } - capacityVal = sizeNew; - dataVal = newPtr; - std::uninitialized_fill(dataVal + sizeVal, dataVal + capacityVal, value_type{}); - } else if (sizeNew > sizeVal) [[unlikely]] { - std::uninitialized_fill(dataVal + sizeVal, dataVal + capacityVal, value_type{}); + if (dataVal && capacityVal > 0) [[likely]] { + allocator::deallocate(dataVal, capacityVal); + } + } catch (...) { + allocator::deallocate(newPtr, newSize); + throw; } - sizeVal = sizeNew; - } else { - sizeVal = 0; + capacityVal = newSize; + dataVal = newPtr; + std::uninitialized_fill(dataVal + sizeVal, dataVal + capacityVal, value_type{}); + } else if (newSize > sizeVal) [[unlikely]] { + std::uninitialized_fill(dataVal + sizeVal, dataVal + capacityVal, value_type{}); + } else if (newSize < sizeVal) { + std::destroy(dataVal + newSize, dataVal + sizeVal); } + sizeVal = newSize; } - jsonifier_inline void reserve(size_type capacityNew) { - if (capacityNew > 0 && capacityNew < maxSize()) [[likely]] { - pointer newPtr = getAlloc().allocate(capacityNew); + JSONIFIER_INLINE void reserve(size_type capacityNew) { + if (capacityNew > capacityVal) [[likely]] { + pointer newPtr = allocator::allocate(capacityNew); try { if (dataVal && capacityVal > 0) [[likely]] { - std::uninitialized_move(dataVal, dataVal + sizeVal, newPtr); - getAlloc().deallocate(dataVal, capacityVal); + if (sizeVal > 0) { + std::uninitialized_move(dataVal, dataVal + sizeVal, newPtr); + } + allocator::deallocate(dataVal, capacityVal); } } catch (...) { - getAlloc().deallocate(newPtr, capacityNew); + allocator::deallocate(newPtr, capacityNew); throw; } capacityVal = capacityNew; @@ -370,24 +372,24 @@ namespace jsonifier { } } - jsonifier_inline void clear() { + JSONIFIER_INLINE void clear() { std::destroy(dataVal, dataVal + sizeVal); sizeVal = 0; } - jsonifier_inline void swap(vector& other) { + JSONIFIER_INLINE void swap(vector& other) { std::swap(capacityVal, other.capacityVal); std::swap(sizeVal, other.sizeVal); std::swap(dataVal, other.dataVal); } - jsonifier_inline bool operator==(const vector& rhs) const { + JSONIFIER_INLINE bool operator==(const vector& rhs) const { if (rhs.size() != size()) { return false; } - if jsonifier_constexpr (!std::is_fundamental_v) { + if constexpr (!std::is_fundamental_v) { for (size_type x = 0; x < sizeVal; ++x) { - if (!getObjectComparitor()(rhs.dataVal[x], dataVal[x])) { + if (!object_compare()(rhs.dataVal[x], dataVal[x])) { return false; } } @@ -397,7 +399,7 @@ namespace jsonifier { } } - jsonifier_inline ~vector() { + JSONIFIER_INLINE ~vector() { reset(); }; @@ -406,21 +408,13 @@ namespace jsonifier { size_type sizeVal{}; pointer dataVal{}; - jsonifier_inline const object_compare& getObjectComparitor() const { - return *this; - } - - jsonifier_inline allocator& getAlloc() { - return *this; - } - - jsonifier_inline void reset() { + JSONIFIER_INLINE void reset() { if (dataVal && capacityVal) { if (sizeVal) { std::destroy(dataVal, dataVal + sizeVal); sizeVal = 0; } - getAlloc().deallocate(dataVal, capacityVal); + allocator::deallocate(dataVal, capacityVal); dataVal = nullptr; capacityVal = 0; } @@ -438,7 +432,7 @@ namespace jsonifier_internal { using pointer = structural_index*; using reference = structural_index&; - jsonifier_inline structural_index_vector() { + JSONIFIER_INLINE structural_index_vector() { resize(16384); }; }; diff --git a/ReadMe.md b/ReadMe.md index 51293f997..01d610f2b 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -1,6 +1,6 @@ # Jsonifier -![Commit Activity](https://img.shields.io/github/commit-activity/y/realtimechris/jsonifier?color=999EE0&label=Commits&style=flat) -[![Lines of Code](https://sloc.xyz/github/realtimechris/jsonifier)](https://github.com/RealTimeChris/Jsonifier/) +![Commit Activity](https://img.shields.io/github/commit-activity/y/realtimechris/jsonifier?color=999EE0&label=Commits&style=plastic) +![Lines of Code](https://tokei.rs/b1/github/RealTimeChris/Jsonifier?color=light-blue&label=Lines%20Of%20Code%20&style=plastic) ## A few classes for serializing and parsing objects into/from JSON strings - very rapidly. ### ***It achieves this through the usage of [simd-instructions](https://github.com/RealTimeChris/Jsonifier/blob/dev/Include/jsonifier/Simd.hpp) as well as compile-time hash-maps for the keys of the data being parsed.*** @@ -9,15 +9,15 @@ ## Compiler Support ---- -![MSVC_20922](https://img.shields.io/github/actions/workflow/status/RealTimeChris/Jsonifier/MSVC_2022-Windows.yml?style=plastic&logo=microsoft&logoColor=green&label=MSVC_2022&labelColor=pewter&color=blue) -![CLANG_18](https://img.shields.io/github/actions/workflow/status/RealTimeChris/Jsonifier/CLANG_18-Ubuntu.yml?style=plastic&logo=linux&logoColor=green&label=CLANG_18&labelColor=pewter&color=blue) -![GCC_13](https://img.shields.io/github/actions/workflow/status/RealTimeChris/Jsonifier/GCC_13-MacOS.yml?style=plastic&logo=apple&logoColor=green&label=GCC_13&labelColor=pewter&color=blue) +![MSVC_20922](https://img.shields.io/github/actions/workflow/status/RealTimeChris/Jsonifier/MSVC_2022-Windows.yml?style=plastic&logo=microsoft&logoColor=green&label=MSVC_2022&labelColor=pewter&color=blue&branch=dev) +![CLANG_18](https://img.shields.io/github/actions/workflow/status/RealTimeChris/Jsonifier/CLANG_18-Ubuntu.yml?style=plastic&logo=linux&logoColor=green&label=CLANG_18&labelColor=pewter&color=blue&branch=dev) +![GCC_13](https://img.shields.io/github/actions/workflow/status/RealTimeChris/Jsonifier/GCC_13-MacOS.yml?style=plastic&logo=apple&logoColor=green&label=GCC_13&labelColor=pewter&color=blue&branch=dev) ## Operating System Support ---- -![Windows](https://img.shields.io/github/actions/workflow/status/RealTimeChris/Jsonifier/MSVC_2022-Windows.yml?style=plastic&logo=microsoft&logoColor=green&label=Windows&labelColor=pewter&color=blue) -![Linux](https://img.shields.io/github/actions/workflow/status/RealTimeChris/Jsonifier/CLANG_18-Ubuntu.yml?style=plastic&logo=linux&logoColor=green&label=Linux&labelColor=pewter&color=blue) -![Mac](https://img.shields.io/github/actions/workflow/status/RealTimeChris/Jsonifier/GCC_13-MacOS.yml?style=plastic&logo=apple&logoColor=green&label=MacOS&labelColor=pewter&color=blue) +![Windows](https://img.shields.io/github/actions/workflow/status/RealTimeChris/Jsonifier/MSVC_2022-Windows.yml?style=plastic&logo=microsoft&logoColor=green&label=Windows&labelColor=pewter&color=blue&branch=dev) +![Linux](https://img.shields.io/github/actions/workflow/status/RealTimeChris/Jsonifier/CLANG_18-Ubuntu.yml?style=plastic&logo=linux&logoColor=green&label=Linux&labelColor=pewter&color=blue&branch=dev) +![Mac](https://img.shields.io/github/actions/workflow/status/RealTimeChris/Jsonifier/GCC_13-MacOS.yml?style=plastic&logo=apple&logoColor=green&label=MacOS&labelColor=pewter&color=blue&branch=dev) ## Usage - Serialization/Parsing ---- @@ -58,7 +58,7 @@ namespace TestNS { another_object_t another_object{}; std::vector string_array{}; std::string string{}; - double number{}; + double Number{}; bool boolean{}; bool another_bool{}; }; @@ -68,30 +68,30 @@ namespace jsonifier { template<> struct core { using value_type = TestNS::fixed_object_t; - static jsonifier_constexpr auto parseValue = createObject("int_array", &value_type::int_array, "float_array", &value_type::float_array, "double_array", &value_type::double_array); + static constexpr auto parseValue = createObject("int_array", &value_type::int_array, "float_array", &value_type::float_array, "double_array", &value_type::double_array); }; template<> struct core { using value_type = TestNS::fixed_name_object_t; - static jsonifier_constexpr auto parseValue = createObject("name0", &value_type::name0, "name1", &value_type::name1, "name2", &value_type::name2, "name3", &value_type::name3, "name4", &value_type::name4); + static constexpr auto parseValue = createObject("name0", &value_type::name0, "name1", &value_type::name1, "name2", &value_type::name2, "name3", &value_type::name3, "name4", &value_type::name4); }; template<> struct core { using value_type = TestNS::nested_object_t; - static jsonifier_constexpr auto parseValue = createObject("v3s", &value_type::v3s, "id", &value_type::id); + static constexpr auto parseValue = createObject("v3s", &value_type::v3s, "id", &value_type::id); }; template<> struct core { using value_type = TestNS::another_object_t; - static jsonifier_constexpr auto parseValue = + static constexpr auto parseValue = createObject("string", &value_type::string, "another_string", &value_type::another_string, "boolean", &value_type::boolean, "nested_object", &value_type::nested_object); }; template<> struct core { using value_type = TestNS::obj_t; - static jsonifier_constexpr auto parseValue = + static constexpr auto parseValue = createObject("fixed_object", &value_type::fixed_object, "fixed_name_object", &value_type::fixed_name_object, "another_object", &value_type::another_object, "string_array", - &value_type::string_array, "string", &value_type::string, "number", &value_type::number, "boolean", &value_type::boolean, "another_bool", &value_type::another_bool); + &value_type::string_array, "string", &value_type::string, "Number", &value_type::Number, "boolean", &value_type::boolean, "another_bool", &value_type::another_bool); }; } @@ -120,7 +120,7 @@ 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::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. +To exclude certain keys from being serialized at runtime using the Jsonifier library, you can create a member in your object called jsonifierExcludedKeys 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 `jsonifierExcludedKeys` set. Here's an example of how you can do this: ```c++ @@ -131,10 +131,10 @@ class MyObject { public: std::string name; int32_t age; - std::set excludedKeys; + std::set jsonifierExcludedKeys; MyObject(const std::string& n, int32_t a) : name(n), age(a) { - excludedKeys.insert("age"); // add "age" key to excludedKeys set + jsonifierExcludedKeys.insert("age"); // add "age" key to jsonifierExcludedKeys set } }; @@ -147,13 +147,13 @@ 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 this example, we have a class called `MyObject` with three member variables: `name`, `age`, and `jsonifierExcludedKeys`. The `jsonifierExcludedKeys` 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::jsonifier_core` class, the "age" key will be excluded from the resulting JSON string. +In the constructor of `MyObject`, we add the key "age" to the `jsonifierExcludedKeys` 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::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. +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 `jsonifierExcludedKeys` 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::jsonifier_core` class, you can easily serialize objects with excluded keys to JSON strings. +By using the `jsonifierExcludedKeys` 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. ## Handling Parsing Errors @@ -209,7 +209,7 @@ int32_t main() { With error message output enabled, Jsonifier will provide detailed information about parsing errors encountered during the process. When a parsing error occurs, Jsonifier will output an error message similar to the following: ```ruby -Failed to collect a 0x2Du, at index: 486 instead found a 'i', in file: C:\Users\Chris\source\repos\Jsonifier\Build\Windows-Release-Dev\_deps\jsonifier-src\Include\jsonifier/Parse_Impl.hpp, at: 182:44, in function: void __cdecl JsonifierInternal::ParseNoKeys::op(struct DiscordCoreInternal::WebSocketMessage &,class JsonifierInternal::StructuralIterator &)(). +Failed to collect a 0x2Du, at index: 486 instead found a 'i', in file: C:\Users\Chris\source\repos\Jsonifier\Build\Windows-Release-Dev\_deps\jsonifier-src\Include\jsonifier/Parse_Impl.hpp, at: 182:44, in function: void __cdecl JsonifierInternal::ParseNoKeys::op(struct DiscordCoreInternal::WebSocketMessage &,class JsonifierInternal::SimdStructuralIterator &)(). ``` In the provided error message: @@ -220,7 +220,7 @@ In the provided error message: #### In file: Gives the file path where the parsing error was encountered. #### At: 182:44: - Specifies the line number and column number within the file where the error occurred. + Specifies the line Number and column Number within the file where the error occurred. #### In function: Provides information about the specific function where the parsing error occurred. diff --git a/Tests/main.cpp b/Tests/main.cpp index 34d2e981f..37bfbb6a4 100644 --- a/Tests/main.cpp +++ b/Tests/main.cpp @@ -1,16 +1,149 @@ #if defined(JSONIFIER_CPU_INSTRUCTIONS) -//#undef JSONIFIER_CPU_INSTRUCTIONS -//#define JSONIFIER_CPU_INSTRUCTIONS JSONIFIER_AVX2 + //#undef JSONIFIER_CPU_INSTRUCTIONS +//#define JSONIFIER_CPU_INSTRUCTIONS (JSONIFIER_POPCNT|JSONIFIER_BMI|JSONIFIER_BMI2|JSONIFIER_LZCNT) #endif #include "glaze/core/macros.hpp" -#include #include "glaze/glaze.hpp" +#include #include #include #include "fmt/format.h" #include #include +static constexpr jsonifier::string_view discordData{ + "{\"d\":{\"_trace\":[\"[\\\"gateway-prd-us-east1-c-kxg8\\\",{\\\"micros\\\":156315,\\\"calls\\\":[\\\"id_created\\\",{\\\"micros\\\":1486," + "\\\"calls\\\":[]},\\\"session_lookup_" + "time\\\",{\\\"micros\\\":465,\\\"calls\\\":[]},\\\"session_lookup_finished\\\",{\\\"micros\\\":17,\\\"calls\\\":[]},\\\"discord-sessions-prd-2-" + "98\\\",{\\\"micros\\\":153461," + "\\\"calls\\\":[\\\"start_session\\\",{\\\"micros\\\":101160,\\\"calls\\\":[\\\"discord-api-5b464978d4-8n7pg\\\",{\\\"micros\\\":60256," + "\\\"calls\\\":[\\\"get_user\\\",{" + "\\\"micros\\\":11839},\\\"get_guilds\\\",{\\\"micros\\\":2977},\\\"send_scheduled_deletion_message\\\",{\\\"micros\\\":10},\\\"guild_join_" + "requests\\\",{\\\"micros\\\":5258}," + "\\\"authorized_ip_coro\\\",{\\\"micros\\\":13}]}]},\\\"starting_guild_connect\\\",{\\\"micros\\\":293,\\\"calls\\\":[]},\\\"presence_" + "started\\\",{\\\"micros\\\":292," + "\\\"calls\\\":[]},\\\"guilds_started\\\",{\\\"micros\\\":163,\\\"calls\\\":[]},\\\"guilds_connect\\\",{\\\"micros\\\":2,\\\"calls\\\":[]}," + "\\\"presence_connect\\\",{" + "\\\"micros\\\":51520,\\\"calls\\\":[]},\\\"connect_finished\\\",{\\\"micros\\\":51525,\\\"calls\\\":[]},\\\"build_ready\\\",{\\\"micros\\\":24," + "\\\"calls\\\":[]},\\\"clean_" + "ready\\\",{\\\"micros\\\":1,\\\"calls\\\":[]},\\\"optimize_ready\\\",{\\\"micros\\\":1,\\\"calls\\\":[]},\\\"split_ready\\\",{\\\"micros\\\":0," + "\\\"calls\\\":[]}]}]}]\"]," + "\"application\":{\"flags\":27828224,\"id\":1142733646600614004},\"auth\":{},\"current_location\":[\"CA\",\"CA:ON\"],\"geo_ordered_rtc_regions\":" + "[\"newark\",\"us-east\",\"us-" + "central\",\"atlanta\",\"us-south\"],\"guild_join_requests\":[],\"guilds\":[{\"id\":318872312596267018,\"unavailable\":true},{\"id\":" + "931640556814237706,\"unavailable\":true},{" + "\"id\":991025447875784714,\"unavailable\":true},{\"id\":995048955215872071,\"unavailable\":true},{\"id\":1022405038922006538,\"unavailable\":" + "true},{\"id\":" + "1032783776184533022,\"unavailable\":true},{\"id\":1078501504119476282,\"unavailable\":true},{\"id\":1131853763506880522,\"unavailable\":true},{" + "\"id\":1162943351935467552," + "\"unavailable\":true}],\"presences\":[],\"private_channels\":[],\"relationships\":[],\"resume_gateway_url\":\"wss://" + "gateway-us-east1-c.discord.gg\",\"session_id\":\"8a44f1277caeae224941fff2cc594c8f\",\"session_type\":\"normal\",\"shard\":\"01\",\"user\":{" + "\"avatar\":" + "\"88bd9ce7bf889c0d36fb4afd3725900b\",\"bot\":true,\"discriminator\":\"3055\",\"email\":null,\"flags\":0,\"global_name\":\"\",\"id\":" + "1142733646600614004,\"mfa_enabled\":false," + "\"username\":\"MBot-MusicHouse-2\",\"verified\":true},\"user_settings\":{},\"v\":10},\"op\":0,\"s\":1,\"t\":\"READY\"}" +}; + +struct application { + int64_t flags; + int64_t id; +}; + +struct guild { + int64_t id; + bool unavailable; +}; + +struct user { + std::string avatar; + bool bot; + std::string discriminator; + int64_t flags; + std::string globalName; + int64_t id; + bool mfaEnabled; + std::string username; + bool verified; +}; + +struct d { + std::vector trace; + application applicationVal; + std::vector currentLocation; + std::vector geoOrderedRtcRegions; + std::vector guilds; + std::string resumeGatewayUrl; + std::string sessionId; + std::string sessionType; + std::string shard; + user userVal; + int64_t v; +}; + +struct welcome { + d dVal; + int64_t op; + int64_t s; + std::string t; +}; + +template<> struct jsonifier::core { + using OTy = application; + static constexpr auto parseValue = createObject("flags", &OTy::flags, "id", &OTy::id); +}; + +template<> struct jsonifier::core { + using OTy = guild; + static constexpr auto parseValue = createObject("id", &OTy::id, "unavailable", &OTy::unavailable); +}; + +template<> struct jsonifier::core { + using OTy = user; + static constexpr auto parseValue = createObject("avatar", &OTy::avatar, "bot", &OTy::bot, "discriminator", &OTy::discriminator, "flags", &OTy::flags, "global_name", + &OTy::globalName, "id", &OTy::id, "mfa_enabled", &OTy::mfaEnabled, "username", &OTy::username, "verified", &OTy::verified); +}; + +template<> struct jsonifier::core { + using OTy = d; + static constexpr auto parseValue = createObject("_trace", &OTy::trace, "application", &OTy::applicationVal, "current_location", &OTy::currentLocation, + "geo_ordered_rtc_regions", &OTy::geoOrderedRtcRegions, "guilds", &OTy::guilds, "resume_gateway_url", &OTy::resumeGatewayUrl, "session_id", &OTy::sessionId, "session_type", + &OTy::sessionType, "shard", &OTy::shard, "user", &OTy::userVal, "v", &OTy::v); +}; + +template<> struct jsonifier::core { + using OTy = welcome; + static constexpr auto parseValue = createObject("d", &OTy::dVal, "op", &OTy::op, "s", &OTy::s, "t", &OTy::t); +}; + +template<> struct glz::meta { + using OTy = application; + static constexpr auto value = object("flags", &OTy::flags, "id", &OTy::id); +}; + +template<> struct glz::meta { + using OTy = guild; + static constexpr auto value = object("id", &OTy::id, "unavailable", &OTy::unavailable); +}; + +template<> struct glz::meta { + using OTy = user; + static constexpr auto value = object("avatar", &OTy::avatar, "bot", &OTy::bot, "discriminator", &OTy::discriminator, "flags", &OTy::flags, "global_name", skip{}, "id", + &OTy::id, "mfa_enabled", &OTy::mfaEnabled, "username", &OTy::username, "verified", &OTy::verified, "email", skip{}); +}; + +template<> struct glz::meta { + using OTy = d; + static constexpr auto value = object("_trace", &OTy::trace, "application", &OTy::applicationVal, "auth", skip{}, "current_location", &OTy::currentLocation, + "geo_ordered_rtc_regions", &OTy::geoOrderedRtcRegions, "guilds", &OTy::guilds, "resume_gateway_url", &OTy::resumeGatewayUrl, "session_id", &OTy::sessionId, "session_type", + &OTy::sessionType, "shard", &OTy::shard, "user", &OTy::userVal, "user_settings", skip{}, "v", &OTy::v, "guild_join_requests", skip{}, "presences", skip{}, "relationships", + skip{}, "private_channels", skip{}); +}; + +template<> struct glz::meta { + using OTy = welcome; + static constexpr auto value = object("d", &OTy::dVal, "op", &OTy::op, "s", &OTy::s, "t", &OTy::t); +}; + struct test_struct { jsonifier::vector testStrings{}; jsonifier::vector testUints{}; @@ -33,44 +166,44 @@ template struct TestGenerator { std::random_device randomEngine{}; std::mt19937 gen{ randomEngine() }; - jsonifier::vector arraySizes{}; static constexpr jsonifier::string_view charset{ "!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~\\\r\b\f\t\n" }; - double randomizeNumber(double mean, double stdDeviation) { - std::normal_distribution<> normalDistributionTwo{ mean, stdDeviation }; - auto theResult = normalDistributionTwo(this->randomEngine); + template value_type randomizeNumber(value_type mean, value_type stdDeviation) { + std::normal_distribution<> normalDistributionTwo{ static_cast(mean), static_cast(stdDeviation) }; + auto theResult = normalDistributionTwo(randomEngine); if (theResult < 0) { theResult = -theResult; } - return static_cast(theResult); + return theResult; } - jsonifier_inline static json_data generateJsonData() { - std::string buffer{}; + JSONIFIER_INLINE static json_data generateJsonData() { + jsonifier::string buffer{}; TestGenerator generator{}; jsonifier::jsonifier_core parser{}; parser.serializeJson(generator, buffer); + //std::cout << "SERIALIZED JSON: " << buffer << std::endl; json_data returnData{}; - returnData.arraySizes = generator.arraySizes; returnData.theData = buffer; return returnData; } std::string generateString() { - auto length{ randomizeNumber(35.0f, 10.0f) }; + auto length{ randomizeNumber(45.0f, 10.0f) }; static int32_t charsetSize = charset.size(); std::mt19937 generator(std::random_device{}()); std::uniform_int_distribution distribution(0, charsetSize - 1); std::string result{}; - for (int32_t i = 0; i < length; ++i) { + for (int32_t x = 0; x < length; ++x) { result += charset[distribution(generator)]; } return result; } double generateDouble() { - return static_cast(randomizeNumber(1000000.34342f, 10000.3435454f)); + auto newValue = randomizeNumber(double{}, std::numeric_limits::max() / 50000000); + return generateBool() ? newValue : -newValue; }; bool generateBool() { @@ -78,28 +211,40 @@ template struct TestGenerator { }; uint64_t generateUint() { - return static_cast(randomizeNumber(1000000.0f, 10000.0f)); + return randomizeNumber(std::numeric_limits::max() / 2, std::numeric_limits::max() / 2); }; int64_t generateInt() { - return static_cast(randomizeNumber(1000000.0f, 10000.0f)); + auto newValue = randomizeNumber(int64_t{}, std::numeric_limits::max()); + return generateBool() ? newValue : -newValue; }; TestGenerator() { auto fill = [&](auto& v) { - v.resize(15); - for (uint64_t x = 0; x < 15; ++x) { - if jsonifier_constexpr (std::same_as) { - auto arraySize01 = randomizeNumber(35, 10); - arraySizes.emplace_back(arraySize01); - for (uint64_t y = 0; y < arraySize01; ++y) { - v[x].testStrings.emplace_back(generateString()); - v[x].testBools.emplace_back(generateBool()); - v[x].testUints.emplace_back(generateUint()); - v[x].testInts.emplace_back(generateInt()); - v[x].testDoubles.emplace_back(generateDouble()); - } + auto arraySize01 = randomizeNumber(35, 15); + v.resize(arraySize01); + for (uint64_t x = 0; x < arraySize01; ++x) { + auto arraySize01 = randomizeNumber(20, 5); + for (uint64_t y = 0; y < arraySize01; ++y) { + v[x].testStrings.emplace_back(generateString()); + } + arraySize01 = randomizeNumber(20, 5); + for (uint64_t y = 0; y < arraySize01; ++y) { + v[x].testUints.emplace_back(generateUint()); + } + arraySize01 = randomizeNumber(20, 5); + for (uint64_t y = 0; y < arraySize01; ++y) { + v[x].testInts.emplace_back(generateInt()); + } + arraySize01 = randomizeNumber(20, 5); + for (uint64_t y = 0; y < arraySize01; ++y) { + v[x].testBools.emplace_back(generateBool()); } + arraySize01 = randomizeNumber(20, 5); + for (uint64_t y = 0; y < arraySize01; ++y) { + v[x].testDoubles.emplace_back(generateDouble()); + } + } }; @@ -135,44 +280,44 @@ template struct TestGenerator { GLZ_META(test_struct, testBools, testInts, testUints, testDoubles, testStrings); 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(TestGenerator, 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 AbcTest { + jsonifier::vector 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 = test_struct; - jsonifier_constexpr static auto parseValue = - createObject("testBools", &OTy::testBools, "testInts", &OTy::testInts, "testUints", &OTy::testUints, "testDoubles", &OTy::testDoubles, "testStrings", &OTy::testStrings); + static constexpr auto parseValue = createObject("testBools", &OTy::testBools, "testInts", &OTy::testInts, "testUints", &OTy::testUints, "testDoubles", &OTy::testDoubles, + "testStrings", &OTy::testStrings); }; template<> struct jsonifier::core> { - using OTy = Test; - jsonifier_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 { - jsonifier::vector 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; + using OTy = Test; + static constexpr 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); }; -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 = TestGenerator; - jsonifier_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); + using OTy = TestGenerator; + static constexpr 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 = AbcTest; - jsonifier_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); + using OTy = AbcTest; + static constexpr 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); }; +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); + #if defined(NDEBUG) -jsonifier_constexpr static uint64_t iterations = 100; +constexpr uint64_t iterations = 100; #else -jsonifier_constexpr static uint64_t iterations = 1; +constexpr uint64_t iterations = 1; #endif struct results { @@ -227,7 +372,7 @@ class FileLoader { public: FileLoader(const char* filePathNew) { filePath = filePathNew; - auto theStream = std::ofstream{ filePath, std::ios::binary | std::ios::out | std::ios::in }; + auto theStream = std::ofstream{ filePath.data(), std::ios::binary | std::ios::out | std::ios::in }; std::stringstream inputStream{}; inputStream << theStream.rdbuf(); fileContents = inputStream.str(); @@ -235,7 +380,7 @@ class FileLoader { } void saveFile(std::string fileToSave) { - auto theStream = std::ofstream{ filePath, std::ios::binary | std::ios::out | std::ios::in | std::ios::trunc }; + auto theStream = std::ofstream{ filePath.data(), std::ios::binary | std::ios::out | std::ios::in | std::ios::trunc }; theStream << ""; theStream.write(fileToSave.data(), fileToSave.size()); theStream.close(); @@ -275,26 +420,24 @@ auto jsonifier_single_test(const std::string bufferNew, bool doWePrint = true) { jsonifier::jsonifier_core parser{}; auto result = benchmark( [&]() { - parser.parseJson(uint64Test, buffer); + parser.parseJson(uint64Test, buffer); }, 1); for (auto& value: parser.getErrors()) { std::cout << "Jsonifier Error: " << value << std::endl; } - r.json_read = result; r.json_byte_length = buffer.size(); + r.json_read = result; buffer.clear(); - for (auto& value: uint64Test.a) { - for (auto& value02: value.testStrings) { - //std::cout << "CURRENT VALUE: (JSONIFIER): " << value02 << std::endl; - } - } result = benchmark( [&]() { parser.serializeJson(uint64Test, buffer); }, 1); + for (auto& value: parser.getErrors()) { + std::cout << "Jsonifier Error: " << value << std::endl; + } r.json_write = result; buffer.clear(); if (doWePrint) { @@ -313,7 +456,7 @@ auto jsonifier_test(const std::string bufferNew, bool doWePrint = true) { auto result = benchmark( [&]() { - parser.parseJson(uint64Test, buffer); + parser.parseJson(uint64Test, buffer); }, iterations); for (auto& value: parser.getErrors()) { @@ -329,7 +472,9 @@ auto jsonifier_test(const std::string bufferNew, bool doWePrint = true) { parser.serializeJson(uint64Test, buffer); }, iterations); - + for (auto& value: parser.getErrors()) { + std::cout << "Jsonifier Error: " << value << std::endl; + } r.json_write = result; buffer.clear(); if (doWePrint) { @@ -348,7 +493,7 @@ auto jsonifier_abc_test(const std::string bufferNew, bool doWePrint = true) { auto result = benchmark( [&]() { - parser.parseJson(uint64Test, buffer); + parser.parseJson(uint64Test, buffer); }, iterations); for (auto& value: parser.getErrors()) { @@ -365,6 +510,48 @@ auto jsonifier_abc_test(const std::string bufferNew, bool doWePrint = true) { parser.serializeJson(uint64Test, buffer); }, iterations); + for (auto& value: parser.getErrors()) { + std::cout << "Jsonifier Error: " << value << std::endl; + } + r.json_write = result; + buffer.clear(); + if (doWePrint) { + r.print(); + } + + return r; +} + +auto jsonifier_discord_test(bool doWePrint = true) { + std::string buffer{ discordData }; + auto newSize = buffer.size(); + + results r{ "jsonifier", "Discord Test", "https://github.com/realtimechris/jsonifier", iterations }; + welcome discordDataTest{}; + jsonifier::jsonifier_core parser{}; + + auto result = benchmark( + [&]() { + parser.parseJson(discordDataTest, buffer); + }, + iterations); + for (auto& value: parser.getErrors()) { + std::cout << "Jsonifier Error: " << value << std::endl; + } + + r.json_read = result; + + r.json_byte_length = buffer.size(); + buffer.clear(); + + result = benchmark( + [&]() { + parser.serializeJson(discordDataTest, buffer); + }, + iterations); + for (auto& value: parser.getErrors()) { + std::cout << "Jsonifier Error: " << value << std::endl; + } r.json_write = result; buffer.clear(); if (doWePrint) { @@ -388,21 +575,16 @@ auto glaze_single_test(const std::string bufferNew, bool doWePrint = true) { }, 1); - r.json_read = result; - r.json_byte_length = buffer.size(); + r.json_read = result; buffer.clear(); - for (auto& value: uint64Test.a) { - for (auto& value02: value.testStrings) { - //std::cout << "CURRENT VALUE: (GLAZE): " << value02 << std::endl; - } - } result = benchmark( [&]() { glz::write_json(uint64Test, buffer); }, 1); - r.json_write = result; + r.json_byte_length = buffer.size(); + r.json_write = result; buffer.clear(); if (doWePrint) { r.print(); @@ -477,12 +659,44 @@ auto glaze_abc_test(const std::string bufferNew, bool doWePrint = true) { return r; } +auto glaze_discord_test(bool doWePrint = true) { + std::string buffer{ discordData }; + + results r{ "glaze", "Discord Test", "https://github.com/stephenberry/glaze", iterations }; + welcome discordDataTest{}; + + auto result = benchmark( + [&]() { + if (auto error = glz::read_json(discordDataTest, buffer); error) { + std::cout << "glaze Error: " << glz::format_error(error, buffer) << std::endl; + } + }, + iterations); + + r.json_read = result; + + r.json_byte_length = buffer.size(); + buffer.clear(); + + result = benchmark( + [&]() { + glz::write_json(discordDataTest, buffer); + }, + iterations); + r.json_write = result; + buffer.clear(); + if (doWePrint) { + r.print(); + } + return r; +} + #include "simdjson.h" using namespace simdjson; struct on_demand { - bool read_in_order(Test& obj, const padded_string& json, const jsonifier::vector& arraySizes); + bool read_in_order(Test& obj, const padded_string& json); protected: ondemand::parser parser{}; @@ -490,6 +704,12 @@ struct on_demand { template void simdPullArray(ondemand::array newX, jsonifier::vector& newVector); +void simdPullMap(ondemand::object newX, std::unordered_map& newVector) { + for (auto iter = newX.begin(); iter != newX.end(); ++iter) { + newVector.emplace(static_cast(iter.operator*().key().value().raw()), static_cast(iter.operator*().value().get_string().value())); + } +} + template<> void simdPullArray(ondemand::array newX, jsonifier::vector& newVector) { for (ondemand::value value: newX) { newVector.emplace_back(value.get_double()); @@ -542,7 +762,7 @@ template<> void simdPullArray(ondemand::array newX, jsonifier::vect } \ } -bool on_demand::read_in_order(Test& obj, const padded_string& json, const jsonifier::vector& arraySizes) { +bool on_demand::read_in_order(Test& obj, const padded_string& json) { ondemand::document doc = parser.iterate(json).value(); SIMD_Pull(a); SIMD_Pull(b); @@ -573,7 +793,7 @@ bool on_demand::read_in_order(Test& obj, const padded_string& json, return false; } -auto simdjson_single_test(const std::string& bufferNew, const jsonifier::vector& arraySizes, bool doWePrint = true) { +auto simdjson_single_test(const std::string& bufferNew, bool doWePrint = true) { std::string buffer{ bufferNew }; on_demand parser{}; @@ -584,7 +804,7 @@ auto simdjson_single_test(const std::string& bufferNew, const jsonifier::vector< uint64_t result{}; result = benchmark( [&]() { - parser.read_in_order(uint64Test, buffer, arraySizes); + parser.read_in_order(uint64Test, padded_string{ buffer }); }, 1); @@ -597,7 +817,7 @@ auto simdjson_single_test(const std::string& bufferNew, const jsonifier::vector< return r; } -auto simdjson_test(const std::string& bufferNew, const jsonifier::vector& arraySizes, bool doWePrint = true) { +auto simdjson_test(const std::string& bufferNew, bool doWePrint = true) { std::string buffer{ bufferNew }; on_demand parser{}; @@ -608,7 +828,7 @@ auto simdjson_test(const std::string& bufferNew, const jsonifier::vector& obj, const padded_string& json, const jsonifier::vector& arraySizes); + bool read_out_of_order(AbcTest& obj, const padded_string& json); protected: ondemand::parser parser{}; }; -bool on_demand_abc::read_out_of_order(AbcTest& obj, const padded_string& json, const jsonifier::vector& arraySizes) { +bool on_demand_abc::read_out_of_order(AbcTest& obj, const padded_string& json) { ondemand::document doc = parser.iterate(json).value(); SIMD_Pull(z); SIMD_Pull(y); @@ -659,7 +879,100 @@ bool on_demand_abc::read_out_of_order(AbcTest& obj, const padded_st return false; } -auto simdjson_abc_test(const std::string& bufferNew, const jsonifier::vector& arraySizes, bool doWePrint = true) { +template void extract_value(const simdjson::dom::element& elem, const char* key, T& value) { + simdjson::dom::element val; + if (elem[key].get(val) != simdjson::error_code::SUCCESS) { + throw std::runtime_error("Error extracting value for key: " + std::string(key)); + } + if constexpr (std::same_as) { + value = static_cast(val.get().value()); + } else { + value = val.get(); + } +} + +void extract_array(const simdjson::dom::element& elem, const char* key, std::vector& values) { + simdjson::dom::array arr; + if (elem[key].get(arr) != simdjson::error_code::SUCCESS) { + throw std::runtime_error("Error extracting array for key: " + std::string(key)); + } + for (auto val: arr) { + values.emplace_back(static_cast(val.get().value())); + } +} + +void extract_guilds(const simdjson::dom::element& elem, const char* key, std::vector& guilds) { + simdjson::dom::array arr; + if (elem[key].get(arr) != simdjson::error_code::SUCCESS) { + throw std::runtime_error("Error extracting array for key: " + std::string(key)); + } + for (auto val: arr) { + guild g; + extract_value(val, "id", g.id); + extract_value(val, "unavailable", g.unavailable); + guilds.push_back(g); + } +} + +void extract_user(const simdjson::dom::element& elem, const char* key, user& usr) { + extract_value(elem[key], "avatar", usr.avatar); + extract_value(elem[key], "bot", usr.bot); + extract_value(elem[key], "discriminator", usr.discriminator); + extract_value(elem[key], "flags", usr.flags); + extract_value(elem[key], "global_name", usr.globalName); + extract_value(elem[key], "id", usr.id); + extract_value(elem[key], "mfa_enabled", usr.mfaEnabled); + extract_value(elem[key], "username", usr.username); + extract_value(elem[key], "verified", usr.verified); +} + +void parse_json(const simdjson::dom::element& doc, welcome& welcomeData) { + extract_array(doc["d"], "_trace", welcomeData.dVal.trace); + extract_value(doc["d"], "resume_gateway_url", welcomeData.dVal.resumeGatewayUrl); + extract_value(doc["d"], "session_id", welcomeData.dVal.sessionId); + extract_value(doc["d"], "session_type", welcomeData.dVal.sessionType); + extract_value(doc["d"], "shard", welcomeData.dVal.shard); + extract_value(doc["d"], "v", welcomeData.dVal.v); + + extract_array(doc["d"], "current_location", welcomeData.dVal.currentLocation); + extract_array(doc["d"], "geo_ordered_rtc_regions", welcomeData.dVal.geoOrderedRtcRegions); + extract_guilds(doc["d"], "guilds", welcomeData.dVal.guilds); + + extract_user(doc["d"], "user", welcomeData.dVal.userVal); + + extract_value(doc, "op", welcomeData.op); + extract_value(doc, "s", welcomeData.s); + extract_value(doc, "t", welcomeData.t); +} + +auto simdjson_discord_test(bool doWePrint = true) { + std::string buffer{ discordData }; + + AbcTest obj{}; + + results r{ "simdjson", "Discord Test", "https://github.com/simdjson/simdjson", iterations }; + + simdjson::dom::parser parser; + + welcome welcomeData; + + auto result = benchmark( + [&]() { + simdjson::dom::element doc = parser.parse(buffer); + parse_json(doc, welcomeData); + }, + iterations); + + r.json_byte_length = buffer.size(); + r.json_read = result; + if (doWePrint) { + r.print(); + } + + return r; +} + +auto simdjson_abc_test(const std::string& bufferNew, bool doWePrint = true) { std::string buffer{ bufferNew }; on_demand_abc parser{}; @@ -670,7 +983,7 @@ auto simdjson_abc_test(const std::string& bufferNew, const jsonifier::vector results{}; for (uint32_t x = 0; x < 2; ++x) { - jsonifier_test(jsonData.theData, false); + simdjson_test(jsonData.theData, false); } - results.emplace_back(jsonifier_test(jsonData.theData)); + results.emplace_back(simdjson_test(jsonData.theData)); for (uint32_t x = 0; x < 2; ++x) { glaze_test(jsonData.theData, false); } results.emplace_back(glaze_test(jsonData.theData)); for (uint32_t x = 0; x < 2; ++x) { - simdjson_test(jsonData.theData, jsonData.arraySizes, false); + jsonifier_test(jsonData.theData, false); } - results.emplace_back(simdjson_test(jsonData.theData, jsonData.arraySizes)); + results.emplace_back(jsonifier_test(jsonData.theData)); std::string table{}; const auto n = results.size(); table += table_header + '\n'; - for (uint64_t i = 0; i < n; ++i) { - table += results[i].json_stats(); - if (i != n - 1) { + for (uint64_t x = 0; x < n; ++x) { + table += results[x].json_stats(); + if (x != n - 1) { table += "\n"; } } @@ -717,24 +1030,51 @@ std::string regular_test(const json_data& jsonData) { std::string abc_test(const json_data& jsonData) { jsonifier::vector results{}; for (uint32_t x = 0; x < 2; ++x) { - jsonifier_abc_test(jsonData.theData, false); + simdjson_abc_test(jsonData.theData, false); } - results.emplace_back(jsonifier_abc_test(jsonData.theData)); + results.emplace_back(simdjson_abc_test(jsonData.theData)); for (uint32_t x = 0; x < 2; ++x) { glaze_abc_test(jsonData.theData, false); } results.emplace_back(glaze_abc_test(jsonData.theData)); for (uint32_t x = 0; x < 2; ++x) { - simdjson_abc_test(jsonData.theData, jsonData.arraySizes, false); + jsonifier_abc_test(jsonData.theData, false); } - results.emplace_back(simdjson_abc_test(jsonData.theData, jsonData.arraySizes)); + results.emplace_back(jsonifier_abc_test(jsonData.theData)); std::string table{}; const auto n = results.size(); table += table_header + '\n'; - for (uint64_t i = 0; i < n; ++i) { - table += results[i].json_stats(); - if (i != n - 1) { + for (uint64_t x = 0; x < n; ++x) { + table += results[x].json_stats(); + if (x != n - 1) { + table += "\n"; + } + } + return table; +} + +std::string discord_test(const json_data& jsonData) { + jsonifier::vector results{}; + for (uint32_t x = 0; x < 2; ++x) { + simdjson_discord_test(false); + } + results.emplace_back(simdjson_discord_test()); + for (uint32_t x = 0; x < 2; ++x) { + glaze_discord_test(false); + } + results.emplace_back(glaze_discord_test()); + for (uint32_t x = 0; x < 2; ++x) { + jsonifier_discord_test(false); + } + results.emplace_back(jsonifier_discord_test()); + + std::string table{}; + const auto n = results.size(); + table += table_header + '\n'; + for (uint64_t x = 0; x < n; ++x) { + table += results[x].json_stats(); + if (x != n - 1) { table += "\n"; } } @@ -744,168 +1084,32 @@ std::string abc_test(const json_data& jsonData) { std::string single_test(const json_data& jsonData) { jsonifier::vector results{}; for (uint32_t x = 0; x < 2; ++x) { - jsonifier_single_test(jsonData.theData, false); + simdjson_single_test(jsonData.theData, false); } - results.emplace_back(jsonifier_single_test(jsonData.theData)); + results.emplace_back(simdjson_single_test(jsonData.theData)); for (uint32_t x = 0; x < 2; ++x) { glaze_single_test(jsonData.theData, false); } results.emplace_back(glaze_single_test(jsonData.theData)); for (uint32_t x = 0; x < 2; ++x) { - simdjson_single_test(jsonData.theData, jsonData.arraySizes, false); + jsonifier_single_test(jsonData.theData, false); } - results.emplace_back(simdjson_single_test(jsonData.theData, jsonData.arraySizes)); + results.emplace_back(jsonifier_single_test(jsonData.theData)); std::string table{}; const auto n = results.size(); table += table_header + '\n'; - for (uint64_t i = 0; i < n; ++i) { - table += results[i].json_stats(); - if (i != n - 1) { + for (uint64_t x = 0; x < n; ++x) { + table += results[x].json_stats(); + if (x != n - 1) { table += "\n"; } } return table; }; -struct Calls { - std::string name; - uint64_t micros; - std::vector calls; -}; - -struct GatewayTrace { - std::string traceId; - uint64_t micros; - std::vector calls; -}; - -struct Guild { - uint64_t id; - bool unavailable; -}; - -struct User { - std::string avatar; - bool bot; - std::string discriminator; -}; - -struct Application { - uint64_t flags; - uint64_t id; -}; -struct Auth { - int32_t value{}; -}; - -struct ReadyData { - jsonifier::vector trace; - Application application{}; - Auth auth; - std::vector geoOrderedRtcRegions; - std::vector guildJoinRequests; - std::vector guilds; - std::vector presences; - std::vector privateChannels; - std::vector relationships; - std::string resumeGatewayUrl; - std::string sessionId; - std::string sessionType; - std::string shard; - User user; - int32_t v; -}; - -struct ReadyMessage { - int32_t op; - int32_t s; - std::string t; - ReadyData d; -}; - -template<> struct jsonifier::core { - using OTy = Auth; - jsonifier_constexpr static auto parseValue = createObject("value", &OTy::value); -}; - -template<> struct jsonifier::core { - using OTy = Application; - jsonifier_constexpr static auto parseValue = createObject("flags", &OTy::flags, "id", &OTy::id); -}; - -template<> struct jsonifier::core { - using OTy = Calls; - jsonifier_constexpr static auto parseValue = createObject("name", &OTy::name, "micros", &OTy::micros, "calls", &OTy::calls); -}; - -template<> struct jsonifier::core { - using OTy = GatewayTrace; - jsonifier_constexpr static auto parseValue = createObject("trace_id", &OTy::traceId, "micros", &OTy::micros, "calls", &OTy::calls); -}; - -template<> struct jsonifier::core { - using OTy = Guild; - jsonifier_constexpr static auto parseValue = createObject("id", &OTy::id, "unavailable", &OTy::unavailable); -}; - -template<> struct jsonifier::core { - using OTy = User; - jsonifier_constexpr static auto parseValue = createObject("avatar", &OTy::avatar, "bot", &OTy::bot, "discriminator", &OTy::discriminator); - // Add other attributes as needed. -}; - -template<> struct jsonifier::core { - using OTy = ReadyData; - jsonifier_constexpr static auto parseValue = - createObject("_trace", &OTy::trace, "application", &OTy::application, "auth", &OTy::auth, "geo_ordered_rtc_regions", &OTy::geoOrderedRtcRegions, "guild_join_requests", - &OTy::guildJoinRequests, "guilds", &OTy::guilds, "presences", &OTy::presences, "private_channels", &OTy::privateChannels, "relationships", &OTy::relationships, - "resume_gateway_url", &OTy::resumeGatewayUrl, "session_id", &OTy::sessionId, "session_type", &OTy::sessionType, "shard", &OTy::shard, "user", &OTy::user, "v", &OTy::v); -}; - -template<> struct jsonifier::core { - using OTy = ReadyMessage; - jsonifier_constexpr static auto parseValue = createObject("op", &OTy::op, "s", &OTy::s, "t", &OTy::t, "d", &OTy::d); -}; - int32_t main() { try { - jsonifier::string newString01{ "{\"d\":{\"_trace\":[\"[\\\"gateway-prd-us-east1-d-26rq\\\",{\\\"micros\\\":122986,\\\"calls\\\":[\\\"id_created\\\",{\\\"micros\\\":861," - "\\\"calls\\\":[]},\\\"session_" - "lookup_time\\\",{\\\"micros\\\":4526,\\\"calls\\\":[]},\\\"session_lookup_finished\\\",{\\\"micros\\\":17,\\\"calls\\\":[]},\\\"discord-" - "sessions-prd-2-51\\\",{" - "\\\"micros\\\":117233,\\\"calls\\\":[\\\"start_session\\\",{\\\"micros\\\":66751,\\\"calls\\\":[\\\"discord-api-79bdc49487-hv95g\\\",{" - "\\\"micros\\\":59968," - "\\\"calls\\\":[\\\"get_user\\\",{\\\"micros\\\":9341},\\\"get_guilds\\\",{\\\"micros\\\":7529},\\\"send_scheduled_deletion_message\\\",{" - "\\\"micros\\\":11},\\\"guild_" - "join_requests\\\",{\\\"micros\\\":1},\\\"authorized_ip_coro\\\",{\\\"micros\\\":12}]}]},\\\"starting_guild_connect\\\",{\\\"micros\\\":" - "419,\\\"calls\\\":[]}," - "\\\"presence_started\\\",{\\\"micros\\\":272,\\\"calls\\\":[]},\\\"guilds_started\\\",{\\\"micros\\\":157,\\\"calls\\\":[]},\\\"guilds_" - "connect\\\",{\\\"micros\\\":29," - "\\\"calls\\\":[]},\\\"presence_connect\\\",{\\\"micros\\\":49563,\\\"calls\\\":[]},\\\"connect_finished\\\",{\\\"micros\\\":49598," - "\\\"calls\\\":[]},\\\"build_" - "ready\\\",{\\\"micros\\\":33,\\\"calls\\\":[]},\\\"clean_ready\\\",{\\\"micros\\\":1,\\\"calls\\\":[]},\\\"optimize_ready\\\",{" - "\\\"micros\\\":0,\\\"calls\\\":[]}," - "\\\"split_ready\\\",{\\\"micros\\\":0,\\\"calls\\\":[]}]}]}]\"],\"application\":{\"flags\":27828224,\"id\":1142733646600614004}," - "\"auth\":{},\"geo_ordered_rtc_" - "regions\":[\"newark\",\"us-east\",\"us-central\",\"atlanta\",\"us-south\"],\"guild_join_requests\":[],\"guilds\":[{\"id\":" - "318872312596267018,\"unavailable\":true},{" - "\"id\":931640556814237706,\"unavailable\":true},{\"id\":991025447875784714,\"unavailable\":true},{\"id\":995048955215872071," - "\"unavailable\":true},{\"id\":" - "1022405038922006538,\"unavailable\":true},{\"id\":1032783776184533022,\"unavailable\":true},{\"id\":1078501504119476282,\"unavailable\":" - "true},{\"id\":" - "1131853763506880522,\"unavailable\":true}],\"presences\":[],\"private_channels\":[],\"relationships\":[],\"resume_gateway_url\":\"wss://" - "gateway-us-east1-d.discord.gg\",\"session_id\":\"5b405a8282550f72114b460169cd08f6\",\"session_type\":\"normal\",\"shard\":\"01\"," - "\"user\":{\"avatar\":" - "\"88bd9ce7bf889c0d36fb4afd3725900b\",\"bot\":true,\"discriminator\":\"3055\",\"email\":null,\"flags\":0,\"global_name\":null,\"id\":" - "1142733646600614004,\"mfa_" - "enabled\":false,\"username\":\"MBot-MusicHouse-2\",\"verified\":true},\"user_settings\":{},\"v\":-10},\"op\":0,\"s\":1,\"t\":\"READY\"}" }; - ReadyMessage dataNew{}; - jsonifier::jsonifier_core parser{}; - parser.parseJson(dataNew, newString01); - for (auto& value: parser.getErrors()) { - std::cout << "Jsonifier Error: " << value << std::endl; - } json_data jsonData{ TestGenerator::generateJsonData() }; #if defined(_WIN32) FileLoader fileLoader01{ "../../../ReadMe.md" }; @@ -915,37 +1119,42 @@ int32_t main() { FileLoader fileLoader01{ "../ReadMe.md" }; FileLoader fileLoader02{ "../JsonData.json" }; fileLoader02.saveFile(glz::prettify(jsonData.theData)); -#endif +#endif std::string newTimeString{}; newTimeString.resize(1024); std::tm resultTwo{}; std::time_t result = std::time(nullptr); resultTwo = *localtime(&result); newTimeString.resize(strftime(newTimeString.data(), 1024, "%b %d, %Y", &resultTwo)); - auto singlTestResults = single_test(jsonData); - auto multiTestResults = regular_test(jsonData); - auto abcTestResults = abc_test(jsonData); - std::string newstring = fileLoader01; + auto discordTestResults = discord_test(jsonData); + auto singlTestResults = single_test(jsonData); + auto multiTestResults = regular_test(jsonData); + auto abcTestResults = abc_test(jsonData); + std::string newString = fileLoader01; uint64_t currentStart{ 0 }; uint64_t currentEnd{ 0 }; - currentEnd = newstring.find("Latest results (") + std::string{ "Latest results (" }.size(); - std::string dateLine = newstring.substr(currentStart, currentEnd); + currentEnd = newString.find("Latest results (") + std::string{ "Latest results (" }.size(); + std::string dateLine = newString.substr(currentStart, currentEnd); currentStart = currentEnd + 2 + std::string{ "Jan 01, 2022" }.size(); - currentEnd = newstring.find("Single Iteration Test Results:") + std::string{ "Single Iteration Test Results:" }.size(); - std::string section01 = newstring.substr(currentStart, (currentEnd - currentStart)); - currentStart = newstring.find("Multi Iteration Test Results:"); - currentEnd = newstring.find("Multi Iteration Test Results:") + std::string{ "Multi Iteration Test Results:" }.size(); - std::string section02 = newstring.substr(currentStart, (currentEnd - currentStart)); - currentStart = newstring.find("## ABC Test (Out of Sequence Performance)"); - currentEnd = newstring.find("In contrast, hash-based solutions offer a viable alternative by circumventing these issues and maintaining " + currentEnd = newString.find("Discord Test Results:") + std::string{ "Discord Test Results:" }.size(); + std::string section01 = newString.substr(currentStart, (currentEnd - currentStart)); + currentStart = newString.find("Single Iteration Test Results:"); + currentEnd = newString.find("Single Iteration Test Results:") + std::string{ "Single Iteration Test Results:" }.size(); + std::string section02 = newString.substr(currentStart, (currentEnd - currentStart)); + currentStart = newString.find("Multi Iteration Test Results:"); + currentEnd = newString.find("Multi Iteration Test Results:") + std::string{ "Multi Iteration Test Results:" }.size(); + std::string section03 = newString.substr(currentStart, (currentEnd - currentStart)); + currentStart = newString.find("## ABC Test (Out of Sequence Performance)"); + currentEnd = newString.find("In contrast, hash-based solutions offer a viable alternative by circumventing these issues and maintaining " "optimal performance regardless of the JSON document's scale, or ordering of the keys being parsed.") + std::string{ "In contrast, hash-based solutions offer a viable alternative by circumventing these issues and maintaining optimal " "performance regardless of the JSON document's scale, or ordering of the keys being parsed." } .size(); - std::string section03 = newstring.substr(currentStart, (currentEnd - currentStart)); - std::string newerString = dateLine + newTimeString + "):" + section01 + "\n" + singlTestResults + "\n\n" + section02 + "\n" + multiTestResults + "\n" + "> " + - std::to_string(iterations) + " iterations on a 6 core (Intel i7 8700k)\n\n" + section03 + "\n" + abcTestResults + "\n" + "> " + std::to_string(iterations) + - " iterations on a 6 core (Intel i7 8700k)"; + std::string section04 = newString.substr(currentStart, (currentEnd - currentStart)); + std::string newerString = dateLine + newTimeString + "):" + section01 + "\n" + discordTestResults + "\n\n" + + "[Test object, used in the following tests:](https://github.com/RealTimeChris/Json-Performance/blob/main/JsonData.json)\n\n" + section02 + "\n" + singlTestResults + + "\n\n" + section03 + "\n" + multiTestResults + "\n" + "> " + std::to_string(iterations) + " iterations on a 6 core (Intel i7 8700k)\n\n" + section04 + "\n" + + abcTestResults + "\n" + "> " + std::to_string(iterations) + " iterations on a 6 core (Intel i7 8700k)"; fileLoader01.saveFile(newerString); } catch (std::exception& e) { std::cout << e.what() << std::endl; diff --git a/Vcpkg/ports/jsonifier/portfile.cmake b/Vcpkg/ports/jsonifier/portfile.cmake index 9da72cb91..df512fe38 100644 --- a/Vcpkg/ports/jsonifier/portfile.cmake +++ b/Vcpkg/ports/jsonifier/portfile.cmake @@ -1,13 +1,19 @@ vcpkg_from_github( OUT_SOURCE_PATH SOURCE_PATH REPO realtimechris/jsonifier - REF "v${VERSION}" - SHA512 cb19ac52d4bdcf201c2e27f4b94b8ab1fb5eb18a5431f6dbcba3b520b0eb68a957cc3cb87d6a60d8a66c9e745b342c831a40400e5b2b2fab5fc33b17da58ba67 + REF "v${VERSION}" + SHA512 f03f4a224fd98a17cf72c33910e368b5c8425be856fe427eacb71087c33fd1e8ad415200b1099d6fbc56631dc1216d74fcf9f2bf16c14f630fff99889a7f57cc HEAD_REF main + PATCHES + uninstall-head.patch ) + +set(VCPKG_BUILD_TYPE release) # header-only + vcpkg_cmake_configure( SOURCE_PATH "${SOURCE_PATH}" ) + vcpkg_cmake_install() -file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug") -vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/License.md") + +vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/License.md") \ No newline at end of file diff --git a/Vcpkg/ports/jsonifier/vcpkg.json b/Vcpkg/ports/jsonifier/vcpkg.json index d976f62cb..370186fce 100644 --- a/Vcpkg/ports/jsonifier/vcpkg.json +++ b/Vcpkg/ports/jsonifier/vcpkg.json @@ -1,6 +1,6 @@ { "name": "jsonifier", - "version": "0.9.91", + "version": "0.9.92", "description": "A few classes for parsing and serializing json - very rapidly.", "homepage": "https://github.com/realtimechris/jsonifier", "license": "MIT", @@ -9,10 +9,6 @@ { "name": "vcpkg-cmake", "host": true - }, - { - "name": "vcpkg-cmake-config", - "host": true } ] } diff --git a/Vcpkg/versions/j-/jsonifier.json b/Vcpkg/versions/j-/jsonifier.json index 62aa5f801..0d75479c4 100644 --- a/Vcpkg/versions/j-/jsonifier.json +++ b/Vcpkg/versions/j-/jsonifier.json @@ -1,5 +1,15 @@ { "versions": [ + { + "git-tree": "be9213f10f70e56d8f7fad547c9691558f9babc9", + "version": "0.9.91", + "port-version": 1 + }, + { + "git-tree": "b8901c8d3fee5951e101c1b8a3b64de58c6ebeed", + "version": "0.9.91", + "port-version": 0 + }, { "git-tree": "9e89f30157ff02233bb4ec6661f40356e6a94260", "version": "0.9.9",