From 9adb1c023571ff2c432757a9587b8d3dabcf2b34 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Thu, 7 May 2020 09:43:41 +0200 Subject: [PATCH 01/36] :checkered_flag: do not include unless old MSVC is used #2089 --- include/nlohmann/detail/boolean_operators.hpp | 12 ++ .../nlohmann/detail/conversions/from_json.hpp | 2 +- .../nlohmann/detail/conversions/to_chars.hpp | 3 +- .../nlohmann/detail/conversions/to_json.hpp | 2 +- .../nlohmann/detail/iterators/iter_impl.hpp | 2 +- include/nlohmann/detail/meta/cpp_future.hpp | 3 +- include/nlohmann/detail/meta/type_traits.hpp | 2 +- include/nlohmann/detail/output/serializer.hpp | 2 +- include/nlohmann/detail/value_t.hpp | 3 +- include/nlohmann/json.hpp | 2 +- single_include/nlohmann/json.hpp | 106 +++++++++++------- 11 files changed, 87 insertions(+), 52 deletions(-) create mode 100644 include/nlohmann/detail/boolean_operators.hpp diff --git a/include/nlohmann/detail/boolean_operators.hpp b/include/nlohmann/detail/boolean_operators.hpp new file mode 100644 index 0000000000..ed4b043597 --- /dev/null +++ b/include/nlohmann/detail/boolean_operators.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include + +// Header is needed for older MSVC versions to allow to use the +// alternative operator representations "and", "or", and "not". As the header +// is removed in C++20, we must only include it for old MSVC versions. +// See for more information. + +#if !JSON_HEDLEY_MSVC_VERSION_CHECK(15,5,0) + #include // and, not, or +#endif diff --git a/include/nlohmann/detail/conversions/from_json.hpp b/include/nlohmann/detail/conversions/from_json.hpp index c389dca7ad..d6e02798d4 100644 --- a/include/nlohmann/detail/conversions/from_json.hpp +++ b/include/nlohmann/detail/conversions/from_json.hpp @@ -2,7 +2,6 @@ #include // transform #include // array -#include // and, not #include // forward_list #include // inserter, front_inserter, end #include // map @@ -13,6 +12,7 @@ #include // pair, declval #include // valarray +#include #include #include #include diff --git a/include/nlohmann/detail/conversions/to_chars.hpp b/include/nlohmann/detail/conversions/to_chars.hpp index aed587cc2d..5851fd0ae8 100644 --- a/include/nlohmann/detail/conversions/to_chars.hpp +++ b/include/nlohmann/detail/conversions/to_chars.hpp @@ -2,12 +2,13 @@ #include // array #include // assert -#include // or, and, not #include // signbit, isfinite #include // intN_t, uintN_t #include // memcpy, memmove #include // numeric_limits #include // conditional + +#include #include namespace nlohmann diff --git a/include/nlohmann/detail/conversions/to_json.hpp b/include/nlohmann/detail/conversions/to_json.hpp index 10b21d16b2..7ff1b28276 100644 --- a/include/nlohmann/detail/conversions/to_json.hpp +++ b/include/nlohmann/detail/conversions/to_json.hpp @@ -1,7 +1,6 @@ #pragma once #include // copy -#include // or, and, not #include // begin, end #include // string #include // tuple, get @@ -10,6 +9,7 @@ #include // valarray #include // vector +#include #include #include #include diff --git a/include/nlohmann/detail/iterators/iter_impl.hpp b/include/nlohmann/detail/iterators/iter_impl.hpp index 3a36297190..0b79202a57 100644 --- a/include/nlohmann/detail/iterators/iter_impl.hpp +++ b/include/nlohmann/detail/iterators/iter_impl.hpp @@ -1,9 +1,9 @@ #pragma once -#include // not #include // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next #include // conditional, is_const, remove_const +#include #include #include #include diff --git a/include/nlohmann/detail/meta/cpp_future.hpp b/include/nlohmann/detail/meta/cpp_future.hpp index 948cd4fb0c..11f88acc9d 100644 --- a/include/nlohmann/detail/meta/cpp_future.hpp +++ b/include/nlohmann/detail/meta/cpp_future.hpp @@ -1,9 +1,10 @@ #pragma once -#include // not #include // size_t #include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type +#include + namespace nlohmann { namespace detail diff --git a/include/nlohmann/detail/meta/type_traits.hpp b/include/nlohmann/detail/meta/type_traits.hpp index 13e92cb48c..3b93fa8b95 100644 --- a/include/nlohmann/detail/meta/type_traits.hpp +++ b/include/nlohmann/detail/meta/type_traits.hpp @@ -1,10 +1,10 @@ #pragma once -#include // not #include // numeric_limits #include // false_type, is_constructible, is_integral, is_same, true_type #include // declval +#include #include #include #include diff --git a/include/nlohmann/detail/output/serializer.hpp b/include/nlohmann/detail/output/serializer.hpp index f83f4a3778..9dbb157bd8 100644 --- a/include/nlohmann/detail/output/serializer.hpp +++ b/include/nlohmann/detail/output/serializer.hpp @@ -3,7 +3,6 @@ #include // reverse, remove, fill, find, none_of #include // array #include // assert -#include // and, or #include // localeconv, lconv #include // labs, isfinite, isnan, signbit #include // size_t, ptrdiff_t @@ -14,6 +13,7 @@ #include // is_same #include // move +#include #include #include #include diff --git a/include/nlohmann/detail/value_t.hpp b/include/nlohmann/detail/value_t.hpp index 86b4630b96..7580d856af 100644 --- a/include/nlohmann/detail/value_t.hpp +++ b/include/nlohmann/detail/value_t.hpp @@ -1,11 +1,12 @@ #pragma once #include // array -#include // and #include // size_t #include // uint8_t #include // string +#include + namespace nlohmann { namespace detail diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 237a48b175..0008f18d15 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -36,7 +36,6 @@ SOFTWARE. #include // all_of, find, for_each #include // assert -#include // and, not, or #include // nullptr_t, ptrdiff_t, size_t #include // hash, less #include // initializer_list @@ -49,6 +48,7 @@ SOFTWARE. #include // vector #include +#include #include #include #include diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index f04091d02a..6eeef012af 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -36,7 +36,6 @@ SOFTWARE. #include // all_of, find, for_each #include // assert -#include // and, not, or #include // nullptr_t, ptrdiff_t, size_t #include // hash, less #include // initializer_list @@ -58,7 +57,6 @@ SOFTWARE. #include // transform #include // array -#include // and, not #include // forward_list #include // inserter, front_inserter, end #include // map @@ -69,41 +67,8 @@ SOFTWARE. #include // pair, declval #include // valarray -// #include - +// #include -#include // exception -#include // runtime_error -#include // to_string - -// #include - - -#include // size_t - -namespace nlohmann -{ -namespace detail -{ -/// struct to capture the start position of the current token -struct position_t -{ - /// the total number of characters read - std::size_t chars_read_total = 0; - /// the number of characters read in the current line - std::size_t chars_read_current_line = 0; - /// the number of lines read - std::size_t lines_read = 0; - - /// conversion to size_t to preserve SAX interface - constexpr operator size_t() const - { - return chars_read_total; - } -}; - -} // namespace detail -} // namespace nlohmann // #include @@ -2142,6 +2107,49 @@ JSON_HEDLEY_DIAGNOSTIC_POP AllocatorType, JSONSerializer, BinaryType> +#if !JSON_HEDLEY_MSVC_VERSION_CHECK(15,5,0) + #include // and, not, or +#endif + +// #include + + +#include // exception +#include // runtime_error +#include // to_string + +// #include + + +#include // size_t + +namespace nlohmann +{ +namespace detail +{ +/// struct to capture the start position of the current token +struct position_t +{ + /// the total number of characters read + std::size_t chars_read_total = 0; + /// the number of characters read in the current line + std::size_t chars_read_current_line = 0; + /// the number of lines read + std::size_t lines_read = 0; + + /// conversion to size_t to preserve SAX interface + constexpr operator size_t() const + { + return chars_read_total; + } +}; + +} // namespace detail +} // namespace nlohmann + +// #include + + namespace nlohmann { namespace detail @@ -2495,10 +2503,12 @@ class other_error : public exception // #include -#include // not #include // size_t #include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type +// #include + + namespace nlohmann { namespace detail @@ -2560,11 +2570,12 @@ constexpr T static_const::value; // #include -#include // not #include // numeric_limits #include // false_type, is_constructible, is_integral, is_same, true_type #include // declval +// #include + // #include @@ -3145,11 +3156,13 @@ struct is_constructible_tuple> : conjunction // array -#include // and #include // size_t #include // uint8_t #include // string +// #include + + namespace nlohmann { namespace detail @@ -3599,7 +3612,6 @@ constexpr const auto& from_json = detail::static_const::va #include // copy -#include // or, and, not #include // begin, end #include // string #include // tuple, get @@ -3608,6 +3620,8 @@ constexpr const auto& from_json = detail::static_const::va #include // valarray #include // vector +// #include + // #include @@ -4192,6 +4206,8 @@ struct adl_serializer } // namespace nlohmann +// #include + // #include // #include @@ -10034,10 +10050,11 @@ template struct internal_iterator // #include -#include // not #include // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next #include // conditional, is_const, remove_const +// #include + // #include // #include @@ -13543,7 +13560,6 @@ class binary_writer #include // reverse, remove, fill, find, none_of #include // array #include // assert -#include // and, or #include // localeconv, lconv #include // labs, isfinite, isnan, signbit #include // size_t, ptrdiff_t @@ -13554,17 +13570,21 @@ class binary_writer #include // is_same #include // move +// #include + // #include #include // array #include // assert -#include // or, and, not #include // signbit, isfinite #include // intN_t, uintN_t #include // memcpy, memmove #include // numeric_limits #include // conditional + +// #include + // #include From 8c2b26de4a9886751b8c7d88b788dc33c515f9f0 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Thu, 7 May 2020 10:17:32 +0200 Subject: [PATCH 02/36] :alembic: do not include with C++20 #2089 --- include/nlohmann/detail/boolean_operators.hpp | 8 +- single_include/nlohmann/json.hpp | 86 +++++++++---------- 2 files changed, 45 insertions(+), 49 deletions(-) diff --git a/include/nlohmann/detail/boolean_operators.hpp b/include/nlohmann/detail/boolean_operators.hpp index ed4b043597..06335866b1 100644 --- a/include/nlohmann/detail/boolean_operators.hpp +++ b/include/nlohmann/detail/boolean_operators.hpp @@ -1,12 +1,8 @@ #pragma once -#include - -// Header is needed for older MSVC versions to allow to use the -// alternative operator representations "and", "or", and "not". As the header -// is removed in C++20, we must only include it for old MSVC versions. +// Header is removed in C++20. // See for more information. -#if !JSON_HEDLEY_MSVC_VERSION_CHECK(15,5,0) +#if __cplusplus <= 201703L #include // and, not, or #endif diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 6eeef012af..b1ed374f9e 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -70,6 +70,49 @@ SOFTWARE. // #include +// Header is removed in C++20. +// See for more information. + +#if __cplusplus <= 201703L + #include // and, not, or +#endif + +// #include + + +#include // exception +#include // runtime_error +#include // to_string + +// #include + + +#include // size_t + +namespace nlohmann +{ +namespace detail +{ +/// struct to capture the start position of the current token +struct position_t +{ + /// the total number of characters read + std::size_t chars_read_total = 0; + /// the number of characters read in the current line + std::size_t chars_read_current_line = 0; + /// the number of lines read + std::size_t lines_read = 0; + + /// conversion to size_t to preserve SAX interface + constexpr operator size_t() const + { + return chars_read_total; + } +}; + +} // namespace detail +} // namespace nlohmann + // #include @@ -2107,49 +2150,6 @@ JSON_HEDLEY_DIAGNOSTIC_POP AllocatorType, JSONSerializer, BinaryType> -#if !JSON_HEDLEY_MSVC_VERSION_CHECK(15,5,0) - #include // and, not, or -#endif - -// #include - - -#include // exception -#include // runtime_error -#include // to_string - -// #include - - -#include // size_t - -namespace nlohmann -{ -namespace detail -{ -/// struct to capture the start position of the current token -struct position_t -{ - /// the total number of characters read - std::size_t chars_read_total = 0; - /// the number of characters read in the current line - std::size_t chars_read_current_line = 0; - /// the number of lines read - std::size_t lines_read = 0; - - /// conversion to size_t to preserve SAX interface - constexpr operator size_t() const - { - return chars_read_total; - } -}; - -} // namespace detail -} // namespace nlohmann - -// #include - - namespace nlohmann { namespace detail From cd76f59af6852d577c334e75a9fae16b1f3b572f Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Tue, 12 May 2020 20:26:17 +0200 Subject: [PATCH 03/36] :construction_worker: add more GitHub actions workflows --- .github/workflows/macos.yml | 19 +++++++++++++++++++ .github/workflows/{ccpp.yml => ubuntu.yml} | 4 ++-- .github/workflows/windows.yml | 19 +++++++++++++++++++ 3 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/macos.yml rename .github/workflows/{ccpp.yml => ubuntu.yml} (93%) create mode 100644 .github/workflows/windows.yml diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml new file mode 100644 index 0000000000..f00d5ff3af --- /dev/null +++ b/.github/workflows/macos.yml @@ -0,0 +1,19 @@ +name: Windows + +on: [push] + +jobs: + build: + + runs-on: windows-latest + + steps: + - uses: actions/checkout@v1 + - name: prepare + run: mkdir build + - name: cmake + run: cd build ; cmake .. + - name: build + run: make -C build + - name: test + run: cd build ; ctest -j 10 diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ubuntu.yml similarity index 93% rename from .github/workflows/ccpp.yml rename to .github/workflows/ubuntu.yml index c6f8afb3c2..cedc027898 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ubuntu.yml @@ -1,4 +1,4 @@ -name: C/C++ CI +name: Ubuntu on: [push] @@ -6,7 +6,7 @@ jobs: build: runs-on: ubuntu-latest - + steps: - uses: actions/checkout@v1 - name: prepare diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml new file mode 100644 index 0000000000..1116e1ca8c --- /dev/null +++ b/.github/workflows/windows.yml @@ -0,0 +1,19 @@ +name: macOS + +on: [push] + +jobs: + build: + + runs-on: macos-latest + + steps: + - uses: actions/checkout@v1 + - name: prepare + run: mkdir build + - name: cmake + run: cd build ; cmake .. + - name: build + run: make -C build + - name: test + run: cd build ; ctest -j 10 From ab02b0829688a812da2c092c7ce496ebf28d6452 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Tue, 12 May 2020 20:30:11 +0200 Subject: [PATCH 04/36] :construction_worker: rename workflows --- .github/workflows/macos.yml | 4 ++-- .github/workflows/windows.yml | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index f00d5ff3af..1116e1ca8c 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -1,11 +1,11 @@ -name: Windows +name: macOS on: [push] jobs: build: - runs-on: windows-latest + runs-on: macos-latest steps: - uses: actions/checkout@v1 diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 1116e1ca8c..ea467fb62b 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -1,18 +1,18 @@ -name: macOS +name: Windows on: [push] jobs: build: - runs-on: macos-latest + runs-on: windows-latest steps: - uses: actions/checkout@v1 - name: prepare run: mkdir build - name: cmake - run: cd build ; cmake .. + run: cd build ; cmake .. -G "Visual Studio 16 2019" - name: build run: make -C build - name: test From 6e59c8301ad474e6bea311a10563d703add1d3da Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Tue, 12 May 2020 20:37:50 +0200 Subject: [PATCH 05/36] :construction_worker: simplify CMake invocations --- .github/workflows/macos.yml | 6 ++---- .github/workflows/ubuntu.yml | 6 ++---- .github/workflows/windows.yml | 6 ++---- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 1116e1ca8c..3647bc02b3 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -9,11 +9,9 @@ jobs: steps: - uses: actions/checkout@v1 - - name: prepare - run: mkdir build - name: cmake - run: cd build ; cmake .. + run: cmake -S . -B build - name: build - run: make -C build + run: cmake --build build - name: test run: cd build ; ctest -j 10 diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index cedc027898..902afc5bc2 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -9,11 +9,9 @@ jobs: steps: - uses: actions/checkout@v1 - - name: prepare - run: mkdir build - name: cmake - run: cd build ; cmake .. + run: cmake -S . -B build - name: build - run: make -C build + run: cmake --build build - name: test run: cd build ; ctest -j 10 diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index ea467fb62b..3ba5905967 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -9,11 +9,9 @@ jobs: steps: - uses: actions/checkout@v1 - - name: prepare - run: mkdir build - name: cmake - run: cd build ; cmake .. -G "Visual Studio 16 2019" + run: cmake -S . -B build -G "Visual Studio 16 2019" - name: build - run: make -C build + run: cmake --build build - name: test run: cd build ; ctest -j 10 From 77e0ba87506fc614b5dc23669d32902595beb4b4 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Tue, 12 May 2020 20:45:18 +0200 Subject: [PATCH 06/36] :construction_worker: parallelize builds --- .github/workflows/macos.yml | 2 +- .github/workflows/ubuntu.yml | 2 +- .github/workflows/windows.yml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 3647bc02b3..dbace9c336 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -12,6 +12,6 @@ jobs: - name: cmake run: cmake -S . -B build - name: build - run: cmake --build build + run: cmake --build build --parallel 10 - name: test run: cd build ; ctest -j 10 diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 902afc5bc2..7792796662 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -12,6 +12,6 @@ jobs: - name: cmake run: cmake -S . -B build - name: build - run: cmake --build build + run: cmake --build build --parallel 10 - name: test run: cd build ; ctest -j 10 diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 3ba5905967..d3fb8cbd35 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -12,6 +12,6 @@ jobs: - name: cmake run: cmake -S . -B build -G "Visual Studio 16 2019" - name: build - run: cmake --build build + run: cmake --build build --parallel 10 - name: test - run: cd build ; ctest -j 10 + run: cd build ; ctest -j 10 -C Release From 44a2158b18876afb70ebfe7c1afa9c8ab7545038 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Tue, 12 May 2020 20:51:45 +0200 Subject: [PATCH 07/36] :construction_worker: make debug build --- .github/workflows/macos.yml | 2 +- .github/workflows/ubuntu.yml | 2 +- .github/workflows/windows.yml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index dbace9c336..ff700dc1d0 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -10,7 +10,7 @@ jobs: steps: - uses: actions/checkout@v1 - name: cmake - run: cmake -S . -B build + run: cmake -S . -B build -D CMAKE_BUILD_TYPE=Debug - name: build run: cmake --build build --parallel 10 - name: test diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 7792796662..aa2aa1da7e 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -10,7 +10,7 @@ jobs: steps: - uses: actions/checkout@v1 - name: cmake - run: cmake -S . -B build + run: cmake -S . -B build -D CMAKE_BUILD_TYPE=Debug - name: build run: cmake --build build --parallel 10 - name: test diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index d3fb8cbd35..81517fa63c 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -10,8 +10,8 @@ jobs: steps: - uses: actions/checkout@v1 - name: cmake - run: cmake -S . -B build -G "Visual Studio 16 2019" + run: cmake -S . -B build -G "Visual Studio 16 2019" -D CMAKE_BUILD_TYPE=Debug - name: build run: cmake --build build --parallel 10 - name: test - run: cd build ; ctest -j 10 -C Release + run: cd build ; ctest -j 10 -C Debug From 8c44c7b6de1ea68993f400b9c10e71307383ea3a Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Tue, 12 May 2020 21:18:08 +0200 Subject: [PATCH 08/36] :checkered_flag: set Windows CI to Release mode --- .github/workflows/windows.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 81517fa63c..f1cf8a083d 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -10,8 +10,8 @@ jobs: steps: - uses: actions/checkout@v1 - name: cmake - run: cmake -S . -B build -G "Visual Studio 16 2019" -D CMAKE_BUILD_TYPE=Debug + run: cmake -S . -B build -G "Visual Studio 16 2019" -D CMAKE_BUILD_TYPE=Release - name: build run: cmake --build build --parallel 10 - name: test - run: cd build ; ctest -j 10 -C Debug + run: cd build ; ctest -j 10 -C Release From 94115a302e43da82feb6192a8592ad1e79d2a8e7 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Tue, 12 May 2020 21:22:47 +0200 Subject: [PATCH 09/36] :checkered_flag: exclude slow Unicode test --- .github/workflows/windows.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index f1cf8a083d..ceb6c9e985 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -10,8 +10,8 @@ jobs: steps: - uses: actions/checkout@v1 - name: cmake - run: cmake -S . -B build -G "Visual Studio 16 2019" -D CMAKE_BUILD_TYPE=Release + run: cmake -S . -B build -G "Visual Studio 16 2019" -D CMAKE_BUILD_TYPE=Debug - name: build run: cmake --build build --parallel 10 - name: test - run: cd build ; ctest -j 10 -C Release + run: cd build ; ctest -j 10 -C Debug --exclude-regex "test-unicode" From 7dbe5cf904f34c69045324d28f2ebf86f246990b Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Tue, 12 May 2020 21:43:33 +0200 Subject: [PATCH 10/36] :memo: update badges --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 612b8a6651..1a52347273 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,11 @@ [![Build Status](https://travis-ci.org/nlohmann/json.svg?branch=master)](https://travis-ci.org/nlohmann/json) [![Build Status](https://ci.appveyor.com/api/projects/status/1acb366xfyg3qybk/branch/develop?svg=true)](https://ci.appveyor.com/project/nlohmann/json) +![Ubuntu](https://github.com/nlohmann/json/workflows/Ubuntu/badge.svg) +![macOS](https://github.com/nlohmann/json/workflows/macOS/badge.svg) +![Windows](https://github.com/nlohmann/json/workflows/Windows/badge.svg) [![Build Status](https://circleci.com/gh/nlohmann/json.svg?style=svg)](https://circleci.com/gh/nlohmann/json) -[![Coverage Status](https://img.shields.io/coveralls/nlohmann/json.svg)](https://coveralls.io/r/nlohmann/json) +[![Coverage Status](https://coveralls.io/repos/github/nlohmann/json/badge.svg?branch=develop)](https://coveralls.io/github/nlohmann/json?branch=develop) [![Coverity Scan Build Status](https://scan.coverity.com/projects/5550/badge.svg)](https://scan.coverity.com/projects/nlohmann-json) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/f3732b3327e34358a0e9d1fe9f661f08)](https://www.codacy.com/app/nlohmann/json?utm_source=github.com&utm_medium=referral&utm_content=nlohmann/json&utm_campaign=Badge_Grade) [![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/nlohmann/json.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/nlohmann/json/context:cpp) From 6778ad8b0a84d1cdc536ada8b63947c4d0df8bdb Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Tue, 12 May 2020 22:26:55 +0200 Subject: [PATCH 11/36] :memo: update year --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1a52347273..d439d4a8e4 100644 --- a/README.md +++ b/README.md @@ -1053,10 +1053,10 @@ json j_from_ubjson = json::from_ubjson(v_ubjson); ## Supported compilers -Though it's 2019 already, the support for C++11 is still a bit sparse. Currently, the following compilers are known to work: +Though it's 2020 already, the support for C++11 is still a bit sparse. Currently, the following compilers are known to work: -- GCC 4.8 - 9.2 (and possibly later) -- Clang 3.4 - 9.0 (and possibly later) +- GCC 4.8 - 10.0 (and possibly later) +- Clang 3.4 - 10.0 (and possibly later) - Intel C++ Compiler 17.0.2 (and possibly later) - Microsoft Visual C++ 2015 / Build Tools 14.0.25123.0 (and possibly later) - Microsoft Visual C++ 2017 / Build Tools 15.5.180.51428 (and possibly later) From f6f350a5c74b76eaa77e8d07ba281a004477aaa7 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Wed, 13 May 2020 14:25:51 +0200 Subject: [PATCH 12/36] :loud_sound: add operating system output --- cmake/download_test_data.cmake | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/cmake/download_test_data.cmake b/cmake/download_test_data.cmake index c6dc135b78..757998d211 100644 --- a/cmake/download_test_data.cmake +++ b/cmake/download_test_data.cmake @@ -12,3 +12,15 @@ add_custom_target(download_test_data # create a header with the path to the downloaded test data file(WRITE ${CMAKE_BINARY_DIR}/include/test_data.hpp "#define TEST_DATA_DIRECTORY \"${CMAKE_BINARY_DIR}/json_test_data\"\n") + +# determine the operating system (for debug and support purposes) +find_program(UNAME_COMMAND uname) +find_program(VER_COMMAND ver) +if (UNAME_COMMAND) + execute_process(COMMAND ${UNAME_COMMAND} -a OUTPUT_VARIABLE UNAME_COMMAND_RESULT OUTPUT_STRIP_TRAILING_WHITESPACE) +endif() +if (VER_COMMAND) + execute_process(COMMAND ${VER_COMMAND} OUTPUT_VARIABLE VER_COMMAND_RESULT OUTPUT_STRIP_TRAILING_WHITESPACE) +endif() + +message(STATUS "Operating system: ${UNAME_COMMAND_RESULT} ${VER_COMMAND_RESULT} ${CMAKE_SYSTEM}") From ec68bb33872f6b6808b0a89f930af387f8ccf416 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Wed, 13 May 2020 20:18:56 +0200 Subject: [PATCH 13/36] :memo: update CI list --- README.md | 59 +++++++++++++++++++++++++++---------------------------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index d439d4a8e4..5c6272b0be 100644 --- a/README.md +++ b/README.md @@ -1081,36 +1081,35 @@ Please note: - Unsupported versions of GCC and Clang are rejected by `#error` directives. This can be switched off by defining `JSON_SKIP_UNSUPPORTED_COMPILER_CHECK`. Note that you can expect no support in this case. -The following compilers are currently used in continuous integration at [Travis](https://travis-ci.org/nlohmann/json), [AppVeyor](https://ci.appveyor.com/project/nlohmann/json), and [CircleCI](https://circleci.com/gh/nlohmann/json): - -| Compiler | Operating System | Version String | -|-----------------------|------------------------------|----------------| -| GCC 4.8.5 | Ubuntu 14.04.5 LTS | g++-4.8 (Ubuntu 4.8.5-2ubuntu1~14.04.2) 4.8.5 | -| GCC 4.9.4 | Ubuntu 14.04.1 LTS | g++-4.9 (Ubuntu 4.9.4-2ubuntu1~14.04.1) 4.9.4 | -| GCC 5.5.0 | Ubuntu 14.04.1 LTS | g++-5 (Ubuntu 5.5.0-12ubuntu1~14.04) 5.5.0 20171010 | -| GCC 6.3.0 | Debian 9 (stretch) | g++ (Debian 6.3.0-18+deb9u1) 6.3.0 20170516 | -| GCC 6.4.0 | Ubuntu 14.04.1 LTS | g++-6 (Ubuntu 6.4.0-17ubuntu1~14.04) 6.4.0 20180424 | -| GCC 7.3.0 | Ubuntu 14.04.1 LTS | g++-7 (Ubuntu 7.3.0-21ubuntu1~14.04) 7.3.0 | -| GCC 7.3.0 | Windows Server 2012 R2 (x64) | g++ (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 7.3.0 | -| GCC 8.1.0 | Ubuntu 14.04.1 LTS | g++-8 (Ubuntu 8.1.0-5ubuntu1~14.04) 8.1.0 | -| GCC 9.2.1 | Ubuntu 14.05.1 LTS | g++-9 (Ubuntu 9.2.1-16ubuntu1~14.04.1) 9.2.1 20191030 | -| Clang 3.5.0 | Ubuntu 14.04.1 LTS | clang version 3.5.0-4ubuntu2~trusty2 (tags/RELEASE_350/final) (based on LLVM 3.5.0) | -| Clang 3.6.2 | Ubuntu 14.04.1 LTS | clang version 3.6.2-svn240577-1~exp1 (branches/release_36) (based on LLVM 3.6.2) | -| Clang 3.7.1 | Ubuntu 14.04.1 LTS | clang version 3.7.1-svn253571-1~exp1 (branches/release_37) (based on LLVM 3.7.1) | -| Clang 3.8.0 | Ubuntu 14.04.1 LTS | clang version 3.8.0-2ubuntu3~trusty5 (tags/RELEASE_380/final) | -| Clang 3.9.1 | Ubuntu 14.04.1 LTS | clang version 3.9.1-4ubuntu3~14.04.3 (tags/RELEASE_391/rc2) | -| Clang 4.0.1 | Ubuntu 14.04.1 LTS | clang version 4.0.1-svn305264-1~exp1 (branches/release_40) | -| Clang 5.0.2 | Ubuntu 14.04.1 LTS | clang version 5.0.2-svn328729-1~exp1~20180509123505.100 (branches/release_50) | -| Clang 6.0.1 | Ubuntu 14.04.1 LTS | clang version 6.0.1-svn334776-1~exp1~20180726133705.85 (branches/release_60) | -| Clang 7.0.1 | Ubuntu 14.04.1 LTS | clang version 7.0.1-svn348686-1~exp1~20181213084532.54 (branches/release_70) | -| Clang Xcode 9.3 | OSX 10.13.3 | Apple LLVM version 9.1.0 (clang-902.0.39.2) | -| Clang Xcode 10.0 | OSX 10.13.3 | Apple LLVM version 10.0.0 (clang-1000.11.45.2) | -| Clang Xcode 10.1 | OSX 10.13.3 | Apple LLVM version 10.0.0 (clang-1000.11.45.5) | -| Clang Xcode 10.2 | OSX 10.14.4 | Apple LLVM version 10.0.1 (clang-1001.0.46.4) | -| Clang Xcode 11.2.1 | OSX 10.14.4 | Apple LLVM version 11.0.0 (clang-1100.0.33.12) | -| Visual Studio 14 2015 | Windows Server 2012 R2 (x64) | Microsoft (R) Build Engine version 14.0.25420.1, MSVC 19.0.24215.1 | -| Visual Studio 15 2017 | Windows Server 2012 R2 (x64) | Microsoft (R) Build Engine version 15.9.21+g9802d43bc3, MSVC 19.16.27032.1 | -| Visual Studio 16 2019 | Windows Server 2012 R2 (x64) | Microsoft (R) Build Engine version 16.3.1+1def00d3d, MSVC 19.23.28106.4 | +The following compilers are currently used in continuous integration at [Travis](https://travis-ci.org/nlohmann/json), [AppVeyor](https://ci.appveyor.com/project/nlohmann/json), [GitHub Actions](https://github.com/nlohmann/json/actions), and [CircleCI](https://circleci.com/gh/nlohmann/json): + +| Compiler | Operating System | CI Provider | +|----------------------------|--------------------------|----------------| +| AppleClang 10.0.0.10001145 | Darwin-17.7.0 | Travis | +| AppleClang 10.0.1.10010046 | Darwin-18.5.0 | Travis | +| AppleClang 11.0.0.11000033 | Darwin-18.7.0 | Travis | +| AppleClang 11.0.3.11030032 | Darwin-19.4.0 | GitHub Actions | +| AppleClang 9.1.0.9020039 | Darwin-17.4.0 | Travis | +| AppleClang 9.1.0.9020039 | Darwin-17.7.0 | Travis | +| Clang 3.5.0 | Linux-4.4.0-104-generic | Travis | +| Clang 3.6.2 | Linux-4.4.0-104-generic | Travis | +| Clang 3.7.1 | Linux-4.4.0-104-generic | Travis | +| Clang 3.8.0 | Linux-4.4.0-104-generic | Travis | +| Clang 3.9.1 | Linux-4.4.0-104-generic | Travis | +| Clang 4.0.1 | Linux-4.4.0-104-generic | Travis | +| Clang 5.0.2 | Linux-4.4.0-104-generic | Travis | +| Clang 6.0.1 | Linux-4.4.0-104-generic | Travis | +| Clang 7.1.0 | Linux-4.4.0-104-generi | Travis | +| GNU 4.8.5 | Linux-4.4.0-104-generic | Travis | +| GNU 4.9.4 | Linux-4.4.0-104-generic | Travis | +| GNU 5.5.0 | Linux-4.4.0-104-generic | Travis | +| GNU 6.3.0 | Linux-5.3.0-1017-aws | Circle CI | +| GNU 6.5.0 | Linux-4.4.0-104-generic | Travis | +| GNU 7.5.0 | Linux-4.4.0-104-generic | Travis | +| GNU 7.5.0 | Linux-5.3.0-1020-azure | GitHub Actions | +| GNU 8.4.0 | Linux-4.4.0-104-generic | Travis | +| GNU 9.3.0 | Linux-4.4.0-104-generic | Travis | +| MSVC 19.25.28614.0 | Windows-10.0.17763 | GitHub Actions | ## License From 33ae93beed9cbebdf2206c88d62c8385a7de1207 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Thu, 14 May 2020 07:55:01 +0200 Subject: [PATCH 14/36] :memo: update CI list --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5c6272b0be..adeb36bb78 100644 --- a/README.md +++ b/README.md @@ -1085,12 +1085,12 @@ The following compilers are currently used in continuous integration at [Travis] | Compiler | Operating System | CI Provider | |----------------------------|--------------------------|----------------| +| AppleClang 9.1.0.9020039 | Darwin-17.4.0 | Travis | +| AppleClang 9.1.0.9020039 | Darwin-17.7.0 | Travis | | AppleClang 10.0.0.10001145 | Darwin-17.7.0 | Travis | | AppleClang 10.0.1.10010046 | Darwin-18.5.0 | Travis | | AppleClang 11.0.0.11000033 | Darwin-18.7.0 | Travis | | AppleClang 11.0.3.11030032 | Darwin-19.4.0 | GitHub Actions | -| AppleClang 9.1.0.9020039 | Darwin-17.4.0 | Travis | -| AppleClang 9.1.0.9020039 | Darwin-17.7.0 | Travis | | Clang 3.5.0 | Linux-4.4.0-104-generic | Travis | | Clang 3.6.2 | Linux-4.4.0-104-generic | Travis | | Clang 3.7.1 | Linux-4.4.0-104-generic | Travis | @@ -1105,10 +1105,14 @@ The following compilers are currently used in continuous integration at [Travis] | GNU 5.5.0 | Linux-4.4.0-104-generic | Travis | | GNU 6.3.0 | Linux-5.3.0-1017-aws | Circle CI | | GNU 6.5.0 | Linux-4.4.0-104-generic | Travis | +| GNU 7.3.0 (MinGW) | Windows-6.3.9600 | AppVeyor | | GNU 7.5.0 | Linux-4.4.0-104-generic | Travis | | GNU 7.5.0 | Linux-5.3.0-1020-azure | GitHub Actions | | GNU 8.4.0 | Linux-4.4.0-104-generic | Travis | | GNU 9.3.0 | Linux-4.4.0-104-generic | Travis | +| MSVC 19.0.24241.7 | Windows-6.3.9600 | AppVeyor | +| MSVC 19.16.27035.0 | Windows-10.0.14393 | AppVeyor | +| MSVC 19.25.28614.0 | Windows-10.0.17763 | AppVeyor | | MSVC 19.25.28614.0 | Windows-10.0.17763 | GitHub Actions | ## License From e91236e6d36baeb6cd2a2f8443e793cb922e4dc7 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Thu, 14 May 2020 13:33:10 +0200 Subject: [PATCH 15/36] :loud_sound: add compiler version output --- cmake/download_test_data.cmake | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/cmake/download_test_data.cmake b/cmake/download_test_data.cmake index 757998d211..64845bd42e 100644 --- a/cmake/download_test_data.cmake +++ b/cmake/download_test_data.cmake @@ -16,11 +16,36 @@ file(WRITE ${CMAKE_BINARY_DIR}/include/test_data.hpp "#define TEST_DATA_DIRECTOR # determine the operating system (for debug and support purposes) find_program(UNAME_COMMAND uname) find_program(VER_COMMAND ver) -if (UNAME_COMMAND) - execute_process(COMMAND ${UNAME_COMMAND} -a OUTPUT_VARIABLE UNAME_COMMAND_RESULT OUTPUT_STRIP_TRAILING_WHITESPACE) -endif() +find_program(LSB_RELEASE_COMMAND lsb_release) +find_program(SW_VERS_COMMAND sw_vers) +set(OS_VERSION_STRINGS "${CMAKE_SYSTEM}") if (VER_COMMAND) execute_process(COMMAND ${VER_COMMAND} OUTPUT_VARIABLE VER_COMMAND_RESULT OUTPUT_STRIP_TRAILING_WHITESPACE) + set(OS_VERSION_STRINGS "${OS_VERSION_STRINGS}; ${VER_COMMAND_RESULT}") +endif() +if (SW_VERS_COMMAND) + execute_process(COMMAND ${SW_VERS_COMMAND} OUTPUT_VARIABLE SW_VERS_COMMAND_RESULT OUTPUT_STRIP_TRAILING_WHITESPACE) + string(REGEX REPLACE "[ ]*\n" "; " SW_VERS_COMMAND_RESULT "${SW_VERS_COMMAND_RESULT}") + set(OS_VERSION_STRINGS "${OS_VERSION_STRINGS}; ${SW_VERS_COMMAND_RESULT}") +endif() +if (LSB_RELEASE_COMMAND) + execute_process(COMMAND ${LSB_RELEASE_COMMAND} -a OUTPUT_VARIABLE LSB_RELEASE_COMMAND_RESULT OUTPUT_STRIP_TRAILING_WHITESPACE) + string(REGEX REPLACE "[ ]*\n" "; " LSB_RELEASE_COMMAND_RESULT "${LSB_RELEASE_COMMAND_RESULT}") + set(OS_VERSION_STRINGS "${OS_VERSION_STRINGS}; ${LSB_RELEASE_COMMAND_RESULT}") +endif() +if (UNAME_COMMAND) + execute_process(COMMAND ${UNAME_COMMAND} -a OUTPUT_VARIABLE UNAME_COMMAND_RESULT OUTPUT_STRIP_TRAILING_WHITESPACE) + set(OS_VERSION_STRINGS "${OS_VERSION_STRINGS}; ${UNAME_COMMAND_RESULT}") endif() -message(STATUS "Operating system: ${UNAME_COMMAND_RESULT} ${VER_COMMAND_RESULT} ${CMAKE_SYSTEM}") +message(STATUS "Operating system: ${OS_VERSION_STRINGS}") + +# determine the compiler (for debug and support purposes) +if (MSVC) + execute_process(COMMAND ${CMAKE_CXX_COMPILER} OUTPUT_VARIABLE CXX_VERSION_RESULT OUTPUT_STRIP_TRAILING_WHITESPACE) + set(CMAKE_CXX_COMPILER "${CXX_VERSION_RESULT}; MSVC_VERSION=${MSVC_VERSION}; MSVC_TOOLSET_VERSION=${MSVC_TOOLSET_VERSION}") +else() + execute_process(COMMAND ${CMAKE_CXX_COMPILER} --version OUTPUT_VARIABLE CXX_VERSION_RESULT OUTPUT_STRIP_TRAILING_WHITESPACE) +endif() +string(REGEX REPLACE "[ ]*\n" "; " CXX_VERSION_RESULT "${CXX_VERSION_RESULT}") +message(STATUS "Compiler: ${CXX_VERSION_RESULT}") From f4cc7290549d75185a0203b320c9ce345e347af6 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Thu, 14 May 2020 13:37:59 +0200 Subject: [PATCH 16/36] :loud_sound: add compiler version output --- cmake/download_test_data.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/download_test_data.cmake b/cmake/download_test_data.cmake index 64845bd42e..0940382acd 100644 --- a/cmake/download_test_data.cmake +++ b/cmake/download_test_data.cmake @@ -42,7 +42,7 @@ message(STATUS "Operating system: ${OS_VERSION_STRINGS}") # determine the compiler (for debug and support purposes) if (MSVC) - execute_process(COMMAND ${CMAKE_CXX_COMPILER} OUTPUT_VARIABLE CXX_VERSION_RESULT OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND ${CMAKE_CXX_COMPILER} OUTPUT_VARIABLE CXX_VERSION_RESULT OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_VARIABLE CXX_VERSION_RESULT ERROR_STRIP_TRAILING_WHITESPACE) set(CMAKE_CXX_COMPILER "${CXX_VERSION_RESULT}; MSVC_VERSION=${MSVC_VERSION}; MSVC_TOOLSET_VERSION=${MSVC_TOOLSET_VERSION}") else() execute_process(COMMAND ${CMAKE_CXX_COMPILER} --version OUTPUT_VARIABLE CXX_VERSION_RESULT OUTPUT_STRIP_TRAILING_WHITESPACE) From fc267af9092bc2042b37d844053ad934397ae631 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Thu, 14 May 2020 17:53:00 +0200 Subject: [PATCH 17/36] :memo: update CI list --- README.md | 64 ++++++++++++++++++---------------- cmake/download_test_data.cmake | 6 ++-- 2 files changed, 36 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index adeb36bb78..fa5cef6897 100644 --- a/README.md +++ b/README.md @@ -1083,37 +1083,39 @@ Please note: The following compilers are currently used in continuous integration at [Travis](https://travis-ci.org/nlohmann/json), [AppVeyor](https://ci.appveyor.com/project/nlohmann/json), [GitHub Actions](https://github.com/nlohmann/json/actions), and [CircleCI](https://circleci.com/gh/nlohmann/json): -| Compiler | Operating System | CI Provider | -|----------------------------|--------------------------|----------------| -| AppleClang 9.1.0.9020039 | Darwin-17.4.0 | Travis | -| AppleClang 9.1.0.9020039 | Darwin-17.7.0 | Travis | -| AppleClang 10.0.0.10001145 | Darwin-17.7.0 | Travis | -| AppleClang 10.0.1.10010046 | Darwin-18.5.0 | Travis | -| AppleClang 11.0.0.11000033 | Darwin-18.7.0 | Travis | -| AppleClang 11.0.3.11030032 | Darwin-19.4.0 | GitHub Actions | -| Clang 3.5.0 | Linux-4.4.0-104-generic | Travis | -| Clang 3.6.2 | Linux-4.4.0-104-generic | Travis | -| Clang 3.7.1 | Linux-4.4.0-104-generic | Travis | -| Clang 3.8.0 | Linux-4.4.0-104-generic | Travis | -| Clang 3.9.1 | Linux-4.4.0-104-generic | Travis | -| Clang 4.0.1 | Linux-4.4.0-104-generic | Travis | -| Clang 5.0.2 | Linux-4.4.0-104-generic | Travis | -| Clang 6.0.1 | Linux-4.4.0-104-generic | Travis | -| Clang 7.1.0 | Linux-4.4.0-104-generi | Travis | -| GNU 4.8.5 | Linux-4.4.0-104-generic | Travis | -| GNU 4.9.4 | Linux-4.4.0-104-generic | Travis | -| GNU 5.5.0 | Linux-4.4.0-104-generic | Travis | -| GNU 6.3.0 | Linux-5.3.0-1017-aws | Circle CI | -| GNU 6.5.0 | Linux-4.4.0-104-generic | Travis | -| GNU 7.3.0 (MinGW) | Windows-6.3.9600 | AppVeyor | -| GNU 7.5.0 | Linux-4.4.0-104-generic | Travis | -| GNU 7.5.0 | Linux-5.3.0-1020-azure | GitHub Actions | -| GNU 8.4.0 | Linux-4.4.0-104-generic | Travis | -| GNU 9.3.0 | Linux-4.4.0-104-generic | Travis | -| MSVC 19.0.24241.7 | Windows-6.3.9600 | AppVeyor | -| MSVC 19.16.27035.0 | Windows-10.0.14393 | AppVeyor | -| MSVC 19.25.28614.0 | Windows-10.0.17763 | AppVeyor | -| MSVC 19.25.28614.0 | Windows-10.0.17763 | GitHub Actions | +| Compiler | Operating System | CI Provider | +|-----------------------------------------------------------------|--------------------|----------------| +| Apple Clang 9.1.0 (clang-902.0.39.1); Xcode 9.3 | macOS 10.13.3 | Travis | +| Apple Clang 9.1.0 (clang-902.0.39.2); Xcode 9.4.1 | macOS 10.13.6 | Travis | +| Apple Clang 10.0.0 (clang-1000.11.45.2); Xcode 10.0 | macOS 10.13.6 | Travis | +| Apple Clang 10.0.0 (clang-1000.11.45.5); Xcode 10.1 | macOS 10.13.6 | Travis | +| Apple Clang 10.0.1 (clang-1001.0.46.4); Xcode 10.2.1 | macOS 10.14.4 | Travis | +| Apple Clang 11.0.0 (clang-1100.0.33.12); Xcode 11.2.1 | macOS 10.14.6 | Travis | +| Apple Clang 11.0.3 (clang-1103.0.32.59); Xcode 11.4.1 | macOS 10.15.4 | GitHub Actions | +| Clang 3.5.0 (3.5.0-4ubuntu2~trusty2) | Ubuntu 14.04.5 LTS | Travis | +| Clang 3.6.2 (3.6.2-svn240577-1~exp1) | Ubuntu 14.04.5 LTS | Travis | +| Clang 3.7.1 (3.7.1-svn253571-1~exp1) | Ubuntu 14.04.5 LTS | Travis | +| Clang 3.8.0 (3.8.0-2ubuntu3~trusty5) | Ubuntu 14.04.5 LTS | Travis | +| Clang 3.9.1 (3.9.1-4ubuntu3~14.04.3) | Ubuntu 14.04.5 LTS | Travis | +| Clang 4.0.1 (4.0.1-svn305264-1~exp1) | Ubuntu 14.04.5 LTS | Travis | +| Clang 5.0.2 (version 5.0.2-svn328729-1~exp1~20180509123505.100) | Ubuntu 14.04.5 LTS | Travis | +| Clang 6.0.1 (6.0.1-svn334776-1~exp1~20190309042707.121) | Ubuntu 14.04.5 LTS | Travis | +| Clang 7.1.0 (7.1.0-svn353565-1~exp1~20190419134007.64) | Ubuntu 14.04.5 LTS | Travis | +| Clang 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04) | Ubuntu 18.04.4 LTS | Travis | +| GCC 4.8.5 (Ubuntu 4.8.5-4ubuntu8~14.04.2) | Ubuntu 14.04.5 LTS | Travis | +| GCC 4.9.4 (Ubuntu 4.9.4-2ubuntu1~14.04.1) | Ubuntu 14.04.5 LTS | Travis | +| GCC 5.5.0 (Ubuntu 5.5.0-12ubuntu1~14.04) | Ubuntu 14.04.5 LTS | Travis | +| GCC 6.3.0 (Debian 6.3.0-18+deb9u1) | Debian 9 | Circle CI | +| GCC 6.5.0 (Ubuntu 6.5.0-2ubuntu1~14.04.1) | Ubuntu 14.04.5 LTS | Travis | +| GCC 7.3.0 (x86_64-posix-seh-rev0, Built by MinGW-W64 project) | Windows-6.3.9600 | AppVeyor | +| GCC 7.5.0 (Ubuntu 7.5.0-3ubuntu1~14.04.1) | Ubuntu 14.04.5 LTS | Travis | +| GCC 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04) | Ubuntu 18.04.4 LTS | GitHub Actions | +| GCC 8.4.0 (Ubuntu 8.4.0-1ubuntu1~14.04) | Ubuntu 14.04.5 LTS | Travis | +| GCC 9.3.0 (Ubuntu 9.3.0-11ubuntu0~14.04) | Ubuntu 14.04.5 LTS | Travis | +| MSVC 19.0.24241.7 (Build Engine version 14.0.25420.1) | Windows-6.3.9600 | AppVeyor | +| MSVC 19.16.27035.0 (15.9.21+g9802d43bc3 for .NET Framework) | Windows-10.0.14393 | AppVeyor | +| MSVC 19.25.28614.0 (Build Engine version 16.5.0+d4cbfca49 for .NET Framework) | Windows-10.0.17763 | AppVeyor | +| MSVC 19.25.28614.0 (Build Engine version 16.5.0+d4cbfca49 for .NET Framework) | Windows-10.0.17763 | GitHub Actions | ## License diff --git a/cmake/download_test_data.cmake b/cmake/download_test_data.cmake index 0940382acd..53aef17fe6 100644 --- a/cmake/download_test_data.cmake +++ b/cmake/download_test_data.cmake @@ -24,17 +24,17 @@ if (VER_COMMAND) set(OS_VERSION_STRINGS "${OS_VERSION_STRINGS}; ${VER_COMMAND_RESULT}") endif() if (SW_VERS_COMMAND) - execute_process(COMMAND ${SW_VERS_COMMAND} OUTPUT_VARIABLE SW_VERS_COMMAND_RESULT OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND ${SW_VERS_COMMAND} OUTPUT_VARIABLE SW_VERS_COMMAND_RESULT OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET) string(REGEX REPLACE "[ ]*\n" "; " SW_VERS_COMMAND_RESULT "${SW_VERS_COMMAND_RESULT}") set(OS_VERSION_STRINGS "${OS_VERSION_STRINGS}; ${SW_VERS_COMMAND_RESULT}") endif() if (LSB_RELEASE_COMMAND) - execute_process(COMMAND ${LSB_RELEASE_COMMAND} -a OUTPUT_VARIABLE LSB_RELEASE_COMMAND_RESULT OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND ${LSB_RELEASE_COMMAND} -a OUTPUT_VARIABLE LSB_RELEASE_COMMAND_RESULT OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET) string(REGEX REPLACE "[ ]*\n" "; " LSB_RELEASE_COMMAND_RESULT "${LSB_RELEASE_COMMAND_RESULT}") set(OS_VERSION_STRINGS "${OS_VERSION_STRINGS}; ${LSB_RELEASE_COMMAND_RESULT}") endif() if (UNAME_COMMAND) - execute_process(COMMAND ${UNAME_COMMAND} -a OUTPUT_VARIABLE UNAME_COMMAND_RESULT OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND ${UNAME_COMMAND} -a OUTPUT_VARIABLE UNAME_COMMAND_RESULT OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET) set(OS_VERSION_STRINGS "${OS_VERSION_STRINGS}; ${UNAME_COMMAND_RESULT}") endif() From daf2d296ddf3b6574abd682fe61a0af19a7a7c63 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Fri, 15 May 2020 14:12:32 +0200 Subject: [PATCH 18/36] :recycle: move wrapped binary type to separate file --- .../nlohmann/detail/conversions/from_json.hpp | 13 +- .../nlohmann/detail/conversions/to_json.hpp | 14 +- include/nlohmann/detail/input/json_sax.hpp | 4 - include/nlohmann/detail/wrapped_binary_t.hpp | 52 +++++++ include/nlohmann/json.hpp | 62 +------- single_include/nlohmann/json.hpp | 146 ++++++++++-------- test/src/unit-constructor1.cpp | 17 ++ test/src/unit-pointer_access.cpp | 38 ++--- 8 files changed, 192 insertions(+), 154 deletions(-) create mode 100644 include/nlohmann/detail/wrapped_binary_t.hpp diff --git a/include/nlohmann/detail/conversions/from_json.hpp b/include/nlohmann/detail/conversions/from_json.hpp index c389dca7ad..53eb40e372 100644 --- a/include/nlohmann/detail/conversions/from_json.hpp +++ b/include/nlohmann/detail/conversions/from_json.hpp @@ -228,9 +228,9 @@ template ::value and not is_constructible_object_type::value and not is_constructible_string_type::value and + not std::is_same::value and not is_basic_json::value, int > = 0 > - auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr) -> decltype(from_json_array_impl(j, arr, priority_tag<3> {}), j.template get(), @@ -245,6 +245,17 @@ void()) from_json_array_impl(j, arr, priority_tag<3> {}); } +template +void from_json(const BasicJsonType& j, typename BasicJsonType::internal_binary_t& bin) +{ + if (JSON_HEDLEY_UNLIKELY(not j.is_binary())) + { + JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(j.type_name()))); + } + + bin = *j.template get_ptr(); +} + template::value, int> = 0> void from_json(const BasicJsonType& j, ConstructibleObjectType& obj) diff --git a/include/nlohmann/detail/conversions/to_json.hpp b/include/nlohmann/detail/conversions/to_json.hpp index 10b21d16b2..0a087c22ba 100644 --- a/include/nlohmann/detail/conversions/to_json.hpp +++ b/include/nlohmann/detail/conversions/to_json.hpp @@ -71,7 +71,7 @@ template<> struct external_constructor { template - static void construct(BasicJsonType& j, const typename BasicJsonType::binary_t& b) + static void construct(BasicJsonType& j, const typename BasicJsonType::internal_binary_t& b) { j.m_type = value_t::binary; typename BasicJsonType::internal_binary_t value{b}; @@ -80,7 +80,7 @@ struct external_constructor } template - static void construct(BasicJsonType& j, typename BasicJsonType::binary_t&& b) + static void construct(BasicJsonType& j, typename BasicJsonType::internal_binary_t&& b) { j.m_type = value_t::binary; typename BasicJsonType::internal_binary_t value{std::move(b)}; @@ -278,9 +278,9 @@ void to_json(BasicJsonType& j, const std::vector& e) template ::value and - not is_compatible_object_type< - BasicJsonType, CompatibleArrayType>::value and + not is_compatible_object_type::value and not is_compatible_string_type::value and + not std::is_same::value and not is_basic_json::value, int> = 0> void to_json(BasicJsonType& j, const CompatibleArrayType& arr) @@ -288,6 +288,12 @@ void to_json(BasicJsonType& j, const CompatibleArrayType& arr) external_constructor::construct(j, arr); } +template +void to_json(BasicJsonType& j, const typename BasicJsonType::internal_binary_t& bin) +{ + external_constructor::construct(j, bin); +} + template::value, int> = 0> void to_json(BasicJsonType& j, const std::valarray& arr) diff --git a/include/nlohmann/detail/input/json_sax.hpp b/include/nlohmann/detail/input/json_sax.hpp index c54b80df7d..ac41e6bb40 100644 --- a/include/nlohmann/detail/input/json_sax.hpp +++ b/include/nlohmann/detail/input/json_sax.hpp @@ -23,13 +23,9 @@ input. template struct json_sax { - /// type for (signed) integers using number_integer_t = typename BasicJsonType::number_integer_t; - /// type for unsigned integers using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - /// type for floating-point numbers using number_float_t = typename BasicJsonType::number_float_t; - /// type for strings using string_t = typename BasicJsonType::string_t; using binary_t = typename BasicJsonType::binary_t; diff --git a/include/nlohmann/detail/wrapped_binary_t.hpp b/include/nlohmann/detail/wrapped_binary_t.hpp new file mode 100644 index 0000000000..f0ccba27c3 --- /dev/null +++ b/include/nlohmann/detail/wrapped_binary_t.hpp @@ -0,0 +1,52 @@ +#pragma once + +#include // uint8_t +#include // move + +namespace nlohmann +{ +namespace detail +{ + +/*! +@brief an internal type for a backed binary type + +This type is designed to be `binary_t` but with the subtype implementation +detail. This type exists so that the user does not have to specify a struct +his- or herself with a specific naming scheme in order to override the +binary type. I.e. it's for ease of use. +*/ +template +struct wrapped_binary_t : public BinaryType +{ + using binary_t = BinaryType; + + wrapped_binary_t() noexcept(noexcept(binary_t())) = default; + + wrapped_binary_t(const binary_t& bint) noexcept(noexcept(binary_t(bint))) + : binary_t(bint) + {} + + wrapped_binary_t(binary_t&& bint) noexcept(noexcept(binary_t(std::move(bint)))) + : binary_t(std::move(bint)) + {} + + wrapped_binary_t(const binary_t& bint, + std::uint8_t st) noexcept(noexcept(binary_t(bint))) + : binary_t(bint) + , subtype(st) + , has_subtype(true) + {} + + wrapped_binary_t(binary_t&& bint, std::uint8_t st) noexcept(noexcept(binary_t(std::move(bint)))) + : binary_t(std::move(bint)) + , subtype(st) + , has_subtype(true) + {} + + std::uint8_t subtype = 0; + bool has_subtype = false; +}; + +} // namespace detail +} // namespace nlohmann diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index b72ea58d47..e965016525 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -70,6 +70,7 @@ SOFTWARE. #include #include #include +#include #include /*! @@ -839,7 +840,7 @@ class basic_json This type is a type designed to carry binary data that appears in various serialized formats, such as CBOR's Major Type 2, MessagePack's bin, and BSON's generic binary subtype. This type is NOT a part of standard JSON and - exists solely for compatibility with these binary types. As such, it is + exists solely for compatibility with these binary types. As such, it is simply defined as an ordered sequence of zero or more byte values. Additionally, as an implementation detail, the subtype of the binary data is @@ -850,9 +851,8 @@ class basic_json [CBOR's RFC 7049](https://tools.ietf.org/html/rfc7049) describes this type as: - > Major type 2: a byte string. The string's length in bytes is - > represented following the rules for positive integers (major type - > 0). + > Major type 2: a byte string. The string's length in bytes is represented + > following the rules for positive integers (major type 0). [MessagePack's documentation on the bin type family](https://github.com/msgpack/msgpack/blob/master/spec.md#bin-format-family) @@ -868,7 +868,7 @@ class basic_json None of these impose any limitations on the internal representation other than the basic unit of storage be some type of array whose parts are - decomposible into bytes. + decomposable into bytes. The default representation of this binary format is a `std::vector`, which is a very common way to represent a byte @@ -880,7 +880,7 @@ class basic_json #### Storage - Binary Arrays are stored as pointers in a @ref basic_json type. That is, + Binary Arrays are stored as pointers in a @ref basic_json type. That is, for any access to array values, a pointer of the type `binary_t*` must be dereferenced. @@ -890,43 +890,7 @@ class basic_json */ using binary_t = BinaryType; - /*! - @brief an internal type for a backed binary type - - This type is designed to be `binary_t` but with the subtype implementation - detail. This type exists so that the user does not have to specify a struct - his- or herself with a specific naming scheme in order to override the - binary type. I.e. it's for ease of use. - */ - struct internal_binary_t : public BinaryType - { - using BinaryType::BinaryType; - internal_binary_t() noexcept(noexcept(BinaryType())) - : BinaryType() - {} - internal_binary_t(const BinaryType& bint) noexcept(noexcept(BinaryType(bint))) - : BinaryType(bint) - {} - internal_binary_t(BinaryType&& bint) noexcept(noexcept(BinaryType(std::move(bint)))) - : BinaryType(std::move(bint)) - {} - internal_binary_t(const BinaryType& bint, std::uint8_t st) noexcept(noexcept(BinaryType(bint))) - : BinaryType(bint) - , subtype(st) - , has_subtype(true) - {} - internal_binary_t(BinaryType&& bint, std::uint8_t st) noexcept(noexcept(BinaryType(std::move(bint)))) - : BinaryType(std::move(bint)) - , subtype(st) - , has_subtype(true) - {} - - // TOOD: If minimum C++ version is ever bumped to C++17, this field - // deserves to be a std::optional - std::uint8_t subtype = 0; - bool has_subtype = false; - }; - + using internal_binary_t = nlohmann::detail::wrapped_binary_t; /// @} private: @@ -2802,18 +2766,6 @@ class basic_json return is_number_float() ? &m_value.number_float : nullptr; } - /// get a pointer to the value (binary) - binary_t* get_impl_ptr(binary_t* /*unused*/) noexcept - { - return is_binary() ? reinterpret_cast(m_value.binary) : nullptr; - } - - /// get a pointer to the value (binary) - constexpr const binary_t* get_impl_ptr(const binary_t* /*unused*/) const noexcept - { - return is_binary() ? m_value.binary : nullptr; - } - /// get a pointer to the value (binary) internal_binary_t* get_impl_ptr(internal_binary_t* /*unused*/) noexcept { diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index c21a4308dd..0727b00563 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -3435,9 +3435,9 @@ template ::value and not is_constructible_object_type::value and not is_constructible_string_type::value and + not std::is_same::value and not is_basic_json::value, int > = 0 > - auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr) -> decltype(from_json_array_impl(j, arr, priority_tag<3> {}), j.template get(), @@ -3452,6 +3452,17 @@ void()) from_json_array_impl(j, arr, priority_tag<3> {}); } +template +void from_json(const BasicJsonType& j, typename BasicJsonType::internal_binary_t& bin) +{ + if (JSON_HEDLEY_UNLIKELY(not j.is_binary())) + { + JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(j.type_name()))); + } + + bin = *j.template get_ptr(); +} + template::value, int> = 0> void from_json(const BasicJsonType& j, ConstructibleObjectType& obj) @@ -3851,7 +3862,7 @@ template<> struct external_constructor { template - static void construct(BasicJsonType& j, const typename BasicJsonType::binary_t& b) + static void construct(BasicJsonType& j, const typename BasicJsonType::internal_binary_t& b) { j.m_type = value_t::binary; typename BasicJsonType::internal_binary_t value{b}; @@ -3860,7 +3871,7 @@ struct external_constructor } template - static void construct(BasicJsonType& j, typename BasicJsonType::binary_t&& b) + static void construct(BasicJsonType& j, typename BasicJsonType::internal_binary_t&& b) { j.m_type = value_t::binary; typename BasicJsonType::internal_binary_t value{std::move(b)}; @@ -4058,9 +4069,9 @@ void to_json(BasicJsonType& j, const std::vector& e) template ::value and - not is_compatible_object_type< - BasicJsonType, CompatibleArrayType>::value and + not is_compatible_object_type::value and not is_compatible_string_type::value and + not std::is_same::value and not is_basic_json::value, int> = 0> void to_json(BasicJsonType& j, const CompatibleArrayType& arr) @@ -4068,6 +4079,12 @@ void to_json(BasicJsonType& j, const CompatibleArrayType& arr) external_constructor::construct(j, arr); } +template +void to_json(BasicJsonType& j, const typename BasicJsonType::internal_binary_t& bin) +{ + external_constructor::construct(j, bin); +} + template::value, int> = 0> void to_json(BasicJsonType& j, const std::valarray& arr) @@ -4727,13 +4744,9 @@ input. template struct json_sax { - /// type for (signed) integers using number_integer_t = typename BasicJsonType::number_integer_t; - /// type for unsigned integers using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - /// type for floating-point numbers using number_float_t = typename BasicJsonType::number_float_t; - /// type for strings using string_t = typename BasicJsonType::string_t; using binary_t = typename BasicJsonType::binary_t; @@ -15560,6 +15573,60 @@ class serializer // #include +// #include + + +#include // uint8_t +#include // move + +namespace nlohmann +{ +namespace detail +{ + +/*! +@brief an internal type for a backed binary type + +This type is designed to be `binary_t` but with the subtype implementation +detail. This type exists so that the user does not have to specify a struct +his- or herself with a specific naming scheme in order to override the +binary type. I.e. it's for ease of use. +*/ +template +struct wrapped_binary_t : public BinaryType +{ + using binary_t = BinaryType; + + wrapped_binary_t() noexcept(noexcept(binary_t())) = default; + + wrapped_binary_t(const binary_t& bint) noexcept(noexcept(binary_t(bint))) + : binary_t(bint) + {} + + wrapped_binary_t(binary_t&& bint) noexcept(noexcept(binary_t(std::move(bint)))) + : binary_t(std::move(bint)) + {} + + wrapped_binary_t(const binary_t& bint, + std::uint8_t st) noexcept(noexcept(binary_t(bint))) + : binary_t(bint) + , subtype(st) + , has_subtype(true) + {} + + wrapped_binary_t(binary_t&& bint, std::uint8_t st) noexcept(noexcept(binary_t(std::move(bint)))) + : binary_t(std::move(bint)) + , subtype(st) + , has_subtype(true) + {} + + std::uint8_t subtype = 0; + bool has_subtype = false; +}; + +} // namespace detail +} // namespace nlohmann + // #include @@ -16330,7 +16397,7 @@ class basic_json This type is a type designed to carry binary data that appears in various serialized formats, such as CBOR's Major Type 2, MessagePack's bin, and BSON's generic binary subtype. This type is NOT a part of standard JSON and - exists solely for compatibility with these binary types. As such, it is + exists solely for compatibility with these binary types. As such, it is simply defined as an ordered sequence of zero or more byte values. Additionally, as an implementation detail, the subtype of the binary data is @@ -16341,9 +16408,8 @@ class basic_json [CBOR's RFC 7049](https://tools.ietf.org/html/rfc7049) describes this type as: - > Major type 2: a byte string. The string's length in bytes is - > represented following the rules for positive integers (major type - > 0). + > Major type 2: a byte string. The string's length in bytes is represented + > following the rules for positive integers (major type 0). [MessagePack's documentation on the bin type family](https://github.com/msgpack/msgpack/blob/master/spec.md#bin-format-family) @@ -16359,7 +16425,7 @@ class basic_json None of these impose any limitations on the internal representation other than the basic unit of storage be some type of array whose parts are - decomposible into bytes. + decomposable into bytes. The default representation of this binary format is a `std::vector`, which is a very common way to represent a byte @@ -16371,7 +16437,7 @@ class basic_json #### Storage - Binary Arrays are stored as pointers in a @ref basic_json type. That is, + Binary Arrays are stored as pointers in a @ref basic_json type. That is, for any access to array values, a pointer of the type `binary_t*` must be dereferenced. @@ -16381,43 +16447,7 @@ class basic_json */ using binary_t = BinaryType; - /*! - @brief an internal type for a backed binary type - - This type is designed to be `binary_t` but with the subtype implementation - detail. This type exists so that the user does not have to specify a struct - his- or herself with a specific naming scheme in order to override the - binary type. I.e. it's for ease of use. - */ - struct internal_binary_t : public BinaryType - { - using BinaryType::BinaryType; - internal_binary_t() noexcept(noexcept(BinaryType())) - : BinaryType() - {} - internal_binary_t(const BinaryType& bint) noexcept(noexcept(BinaryType(bint))) - : BinaryType(bint) - {} - internal_binary_t(BinaryType&& bint) noexcept(noexcept(BinaryType(std::move(bint)))) - : BinaryType(std::move(bint)) - {} - internal_binary_t(const BinaryType& bint, std::uint8_t st) noexcept(noexcept(BinaryType(bint))) - : BinaryType(bint) - , subtype(st) - , has_subtype(true) - {} - internal_binary_t(BinaryType&& bint, std::uint8_t st) noexcept(noexcept(BinaryType(std::move(bint)))) - : BinaryType(std::move(bint)) - , subtype(st) - , has_subtype(true) - {} - - // TOOD: If minimum C++ version is ever bumped to C++17, this field - // deserves to be a std::optional - std::uint8_t subtype = 0; - bool has_subtype = false; - }; - + using internal_binary_t = nlohmann::detail::wrapped_binary_t; /// @} private: @@ -18293,18 +18323,6 @@ class basic_json return is_number_float() ? &m_value.number_float : nullptr; } - /// get a pointer to the value (binary) - binary_t* get_impl_ptr(binary_t* /*unused*/) noexcept - { - return is_binary() ? reinterpret_cast(m_value.binary) : nullptr; - } - - /// get a pointer to the value (binary) - constexpr const binary_t* get_impl_ptr(const binary_t* /*unused*/) const noexcept - { - return is_binary() ? m_value.binary : nullptr; - } - /// get a pointer to the value (binary) internal_binary_t* get_impl_ptr(internal_binary_t* /*unused*/) noexcept { diff --git a/test/src/unit-constructor1.cpp b/test/src/unit-constructor1.cpp index 96a0be0f1b..742bdcd9d6 100644 --- a/test/src/unit-constructor1.cpp +++ b/test/src/unit-constructor1.cpp @@ -481,6 +481,23 @@ TEST_CASE("constructors") } } + SECTION("create a binary (explicit)") + { + SECTION("empty binary") + { + json::internal_binary_t b{}; + json j(b); + CHECK(j.type() == json::value_t::binary); + } + + SECTION("filled binary") + { + json::internal_binary_t b({1, 2, 3}); + json j(b); + CHECK(j.type() == json::value_t::binary); + } + } + SECTION("create an integer number (explicit)") { SECTION("uninitialized value") diff --git a/test/src/unit-pointer_access.cpp b/test/src/unit-pointer_access.cpp index ed245dc696..5f3f9e314a 100644 --- a/test/src/unit-pointer_access.cpp +++ b/test/src/unit-pointer_access.cpp @@ -60,7 +60,6 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); - CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); } @@ -90,7 +89,6 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); - CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); } @@ -120,7 +118,6 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); - CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); } @@ -150,7 +147,6 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); - CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); } @@ -180,7 +176,6 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); - CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); } @@ -210,7 +205,6 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); - CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); } @@ -240,7 +234,6 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); - CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); } @@ -270,8 +263,6 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); - CHECK(value.get_ptr() == nullptr); - CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); } @@ -301,7 +292,6 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() != nullptr); CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); - CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); } @@ -331,7 +321,6 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() != nullptr); CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); - CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); } @@ -361,7 +350,6 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() != nullptr); CHECK(value.get_ptr() != nullptr); CHECK(value.get_ptr() == nullptr); - CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); } @@ -391,7 +379,6 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() != nullptr); CHECK(value.get_ptr() != nullptr); CHECK(value.get_ptr() == nullptr); - CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); } @@ -421,7 +408,6 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() != nullptr); - CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); } @@ -451,26 +437,26 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() != nullptr); - CHECK(value.get_ptr() == nullptr); + CHECK(value.get_ptr() == nullptr); } - SECTION("pointer access to const binary_t") + SECTION("pointer access to const internal_binary_t") { - using test_type = const json::binary_t; - const json value = json::binary_array({}); + using test_type = const json::internal_binary_t; + const json value = json::binary_array({1, 2, 3}); // check if pointers are returned correctly test_type* p1 = value.get_ptr(); CHECK(p1 == value.get_ptr()); - //CHECK(*p1 == value.get()); + CHECK(*p1 == value.get()); const test_type* p2 = value.get_ptr(); CHECK(p2 == value.get_ptr()); - //CHECK(*p2 == value.get()); + CHECK(*p2 == value.get()); const test_type* const p3 = value.get_ptr(); CHECK(p3 == value.get_ptr()); - //CHECK(*p3 == value.get()); + CHECK(*p3 == value.get()); // check if null pointers are returned correctly CHECK(value.get_ptr() == nullptr); @@ -480,10 +466,10 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); - CHECK(value.get_ptr() != nullptr); + CHECK(value.get_ptr() != nullptr); } - SECTION("pointer access to const binary_t") + SECTION("pointer access to const internal_binary_t") { using test_type = const json::internal_binary_t; const json value = json::binary_array({}); @@ -491,15 +477,15 @@ TEST_CASE("pointer access") // check if pointers are returned correctly test_type* p1 = value.get_ptr(); CHECK(p1 == value.get_ptr()); - //CHECK(*p1 == value.get()); + CHECK(*p1 == value.get()); const test_type* p2 = value.get_ptr(); CHECK(p2 == value.get_ptr()); - //CHECK(*p2 == value.get()); + CHECK(*p2 == value.get()); const test_type* const p3 = value.get_ptr(); CHECK(p3 == value.get_ptr()); - //CHECK(*p3 == value.get()); + CHECK(*p3 == value.get()); // check if null pointers are returned correctly CHECK(value.get_ptr() == nullptr); From a452e8a0a18c4269bc15148c7371469ea504b356 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Fri, 15 May 2020 22:38:18 +0200 Subject: [PATCH 19/36] :green_heart: fix GCC 4.9 compilation --- include/nlohmann/detail/wrapped_binary_t.hpp | 4 +++- single_include/nlohmann/json.hpp | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/nlohmann/detail/wrapped_binary_t.hpp b/include/nlohmann/detail/wrapped_binary_t.hpp index f0ccba27c3..1ec6a98a7f 100644 --- a/include/nlohmann/detail/wrapped_binary_t.hpp +++ b/include/nlohmann/detail/wrapped_binary_t.hpp @@ -21,7 +21,9 @@ struct wrapped_binary_t : public BinaryType { using binary_t = BinaryType; - wrapped_binary_t() noexcept(noexcept(binary_t())) = default; + wrapped_binary_t() noexcept(noexcept(binary_t())) + : binary_t() + {} wrapped_binary_t(const binary_t& bint) noexcept(noexcept(binary_t(bint))) : binary_t(bint) diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 0727b00563..2d12e89527 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -15597,7 +15597,9 @@ struct wrapped_binary_t : public BinaryType { using binary_t = BinaryType; - wrapped_binary_t() noexcept(noexcept(binary_t())) = default; + wrapped_binary_t() noexcept(noexcept(binary_t())) + : binary_t() + {} wrapped_binary_t(const binary_t& bint) noexcept(noexcept(binary_t(bint))) : binary_t(bint) From bc1886fb6022097dcf771d63e169276afb16be3e Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Fri, 15 May 2020 23:21:49 +0200 Subject: [PATCH 20/36] :recycle: refine interface of wrapped_binary_t --- .../nlohmann/detail/input/binary_reader.hpp | 36 ++--- .../nlohmann/detail/output/binary_writer.hpp | 13 +- include/nlohmann/detail/wrapped_binary_t.hpp | 57 +++++++- include/nlohmann/json.hpp | 30 ++-- single_include/nlohmann/json.hpp | 136 ++++++++++++------ 5 files changed, 186 insertions(+), 86 deletions(-) diff --git a/include/nlohmann/detail/input/binary_reader.hpp b/include/nlohmann/detail/input/binary_reader.hpp index 5f497089e8..8955ee7aaf 100644 --- a/include/nlohmann/detail/input/binary_reader.hpp +++ b/include/nlohmann/detail/input/binary_reader.hpp @@ -227,8 +227,8 @@ class binary_reader return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, "byte array length cannot be negative, is " + std::to_string(len), "binary"))); } - result.has_subtype = true; // All BSON binary values have a subtype - get_number(input_format_t::bson, result.subtype); + result.m_has_subtype = true; // All BSON binary values have a subtype + get_number(input_format_t::bson, result.m_subtype); return get_binary(input_format_t::bson, len, result); } @@ -1524,58 +1524,58 @@ class binary_reader case 0xC7: // ext 8 { std::uint8_t len; - result.has_subtype = true; + result.m_has_subtype = true; return get_number(input_format_t::msgpack, len) and - get_number(input_format_t::msgpack, result.subtype) and + get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, len, result); } case 0xC8: // ext 16 { std::uint16_t len; - result.has_subtype = true; + result.m_has_subtype = true; return get_number(input_format_t::msgpack, len) and - get_number(input_format_t::msgpack, result.subtype) and + get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, len, result); } case 0xC9: // ext 32 { std::uint32_t len; - result.has_subtype = true; + result.m_has_subtype = true; return get_number(input_format_t::msgpack, len) and - get_number(input_format_t::msgpack, result.subtype) and + get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, len, result); } case 0xD4: // fixext 1 { - result.has_subtype = true; - return get_number(input_format_t::msgpack, result.subtype) and get_binary(input_format_t::msgpack, 1, result); + result.m_has_subtype = true; + return get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, 1, result); } case 0xD5: // fixext 2 { - result.has_subtype = true; - return get_number(input_format_t::msgpack, result.subtype) and get_binary(input_format_t::msgpack, 2, result); + result.m_has_subtype = true; + return get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, 2, result); } case 0xD6: // fixext 4 { - result.has_subtype = true; - return get_number(input_format_t::msgpack, result.subtype) and get_binary(input_format_t::msgpack, 4, result); + result.m_has_subtype = true; + return get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, 4, result); } case 0xD7: // fixext 8 { - result.has_subtype = true; - return get_number(input_format_t::msgpack, result.subtype) and get_binary(input_format_t::msgpack, 8, result); + result.m_has_subtype = true; + return get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, 8, result); } case 0xD8: // fixext 16 { - result.has_subtype = true; - return get_number(input_format_t::msgpack, result.subtype) and get_binary(input_format_t::msgpack, 16, result); + result.m_has_subtype = true; + return get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, 16, result); } default: // LCOV_EXCL_LINE diff --git a/include/nlohmann/detail/output/binary_writer.hpp b/include/nlohmann/detail/output/binary_writer.hpp index 7d4a403149..39935d10ec 100644 --- a/include/nlohmann/detail/output/binary_writer.hpp +++ b/include/nlohmann/detail/output/binary_writer.hpp @@ -550,7 +550,7 @@ class binary_writer { // step 0: determine if the binary type has a set subtype to // determine whether or not to use the ext or fixext types - const bool use_ext = j.m_value.binary->has_subtype; + const bool use_ext = j.m_value.binary->has_subtype(); // step 1: write control byte and the byte string length const auto N = j.m_value.binary->size(); @@ -630,7 +630,9 @@ class binary_writer // step 1.5: if this is an ext type, write the subtype if (use_ext) { - write_number(j.m_value.binary->subtype); + std::uint8_t subtype; + write_number(subtype); + j.m_value.binary->set_subtype(subtype); } // step 2: write the byte string @@ -1085,12 +1087,7 @@ class binary_writer write_bson_entry_header(name, 0x05); write_number(static_cast(value.size())); - std::uint8_t subtype = 0x00; // Generic Binary Subtype - if (value.has_subtype) - { - subtype = value.subtype; - } - write_number(subtype); + write_number(value.has_subtype() ? value.subtype() : 0x00); oa->write_characters(reinterpret_cast(value.data()), value.size()); } diff --git a/include/nlohmann/detail/wrapped_binary_t.hpp b/include/nlohmann/detail/wrapped_binary_t.hpp index 1ec6a98a7f..8514f049d9 100644 --- a/include/nlohmann/detail/wrapped_binary_t.hpp +++ b/include/nlohmann/detail/wrapped_binary_t.hpp @@ -17,8 +17,13 @@ his- or herself with a specific naming scheme in order to override the binary type. I.e. it's for ease of use. */ template -struct wrapped_binary_t : public BinaryType +class wrapped_binary_t : public BinaryType { + public: + // to simplify code in binary_reader + template + friend class binary_reader; + using binary_t = BinaryType; wrapped_binary_t() noexcept(noexcept(binary_t())) @@ -36,18 +41,56 @@ struct wrapped_binary_t : public BinaryType wrapped_binary_t(const binary_t& bint, std::uint8_t st) noexcept(noexcept(binary_t(bint))) : binary_t(bint) - , subtype(st) - , has_subtype(true) + , m_subtype(st) + , m_has_subtype(true) {} wrapped_binary_t(binary_t&& bint, std::uint8_t st) noexcept(noexcept(binary_t(std::move(bint)))) : binary_t(std::move(bint)) - , subtype(st) - , has_subtype(true) + , m_subtype(st) + , m_has_subtype(true) {} - std::uint8_t subtype = 0; - bool has_subtype = false; + /*! + @brief set the subtype + @param subtype subtype to set (implementation specific) + */ + void set_subtype(std::uint8_t subtype) noexcept + { + m_subtype = subtype; + m_has_subtype = true; + } + + /*! + @brief get the subtype + @return subtype (implementation specific) + */ + constexpr std::uint8_t subtype() const noexcept + { + return m_subtype; + } + + /*! + @brief get whether a subtype was set + @return whether a subtype was set + */ + constexpr bool has_subtype() const noexcept + { + return m_has_subtype; + } + + /*! + @brief clear the subtype + */ + void clear_subtype() noexcept + { + m_subtype = 0; + m_has_subtype = false; + } + + private: + std::uint8_t m_subtype = 0; + bool m_has_subtype = false; }; } // namespace detail diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index e965016525..21becba4d4 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -839,15 +839,15 @@ class basic_json This type is a type designed to carry binary data that appears in various serialized formats, such as CBOR's Major Type 2, MessagePack's bin, and - BSON's generic binary subtype. This type is NOT a part of standard JSON and + BSON's generic binary subtype. This type is NOT a part of standard JSON and exists solely for compatibility with these binary types. As such, it is simply defined as an ordered sequence of zero or more byte values. Additionally, as an implementation detail, the subtype of the binary data is - carried around as a `unint8_t`, which is compatible with both of the binary - data formats that use binary subtyping, (though the specific numbering is - incompatible with each other, and it is up to the user to translate between - them). + carried around as a `std::uint8_t`, which is compatible with both of the + binary data formats that use binary subtyping, (though the specific + numbering is incompatible with each other, and it is up to the user to + translate between them). [CBOR's RFC 7049](https://tools.ietf.org/html/rfc7049) describes this type as: @@ -890,6 +890,18 @@ class basic_json */ using binary_t = BinaryType; + /*! + @brief binary array with a binary type + + This type is used to store binary types internally. It wrapps the template + type `BinaryType` (@ref binary_t) and adds a subtype to allow to distinguish + different binary types from different formats. + + While @ref binary_t is used to define how binary values are stored, this + type is used to access binary values once they are parsed. + + @sa @ref binary_array -- create a binary array + */ using internal_binary_t = nlohmann::detail::wrapped_binary_t; /// @} @@ -3882,8 +3894,7 @@ class basic_json { if (is_binary()) { - m_value.binary->has_subtype = true; - m_value.binary->subtype = subtype; + m_value.binary->set_subtype(subtype); } } @@ -3911,8 +3922,7 @@ class basic_json { if (is_binary()) { - m_value.binary->has_subtype = false; - m_value.binary->subtype = 0; + m_value.binary->clear_subtype(); } } @@ -3936,7 +3946,7 @@ class basic_json */ bool has_subtype() const noexcept { - return is_binary() and m_value.binary->has_subtype; + return is_binary() and m_value.binary->has_subtype(); } /*! diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 2d12e89527..8b01d2416c 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -5804,8 +5804,8 @@ class binary_reader return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, "byte array length cannot be negative, is " + std::to_string(len), "binary"))); } - result.has_subtype = true; // All BSON binary values have a subtype - get_number(input_format_t::bson, result.subtype); + result.m_has_subtype = true; // All BSON binary values have a subtype + get_number(input_format_t::bson, result.m_subtype); return get_binary(input_format_t::bson, len, result); } @@ -7101,58 +7101,58 @@ class binary_reader case 0xC7: // ext 8 { std::uint8_t len; - result.has_subtype = true; + result.m_has_subtype = true; return get_number(input_format_t::msgpack, len) and - get_number(input_format_t::msgpack, result.subtype) and + get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, len, result); } case 0xC8: // ext 16 { std::uint16_t len; - result.has_subtype = true; + result.m_has_subtype = true; return get_number(input_format_t::msgpack, len) and - get_number(input_format_t::msgpack, result.subtype) and + get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, len, result); } case 0xC9: // ext 32 { std::uint32_t len; - result.has_subtype = true; + result.m_has_subtype = true; return get_number(input_format_t::msgpack, len) and - get_number(input_format_t::msgpack, result.subtype) and + get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, len, result); } case 0xD4: // fixext 1 { - result.has_subtype = true; - return get_number(input_format_t::msgpack, result.subtype) and get_binary(input_format_t::msgpack, 1, result); + result.m_has_subtype = true; + return get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, 1, result); } case 0xD5: // fixext 2 { - result.has_subtype = true; - return get_number(input_format_t::msgpack, result.subtype) and get_binary(input_format_t::msgpack, 2, result); + result.m_has_subtype = true; + return get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, 2, result); } case 0xD6: // fixext 4 { - result.has_subtype = true; - return get_number(input_format_t::msgpack, result.subtype) and get_binary(input_format_t::msgpack, 4, result); + result.m_has_subtype = true; + return get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, 4, result); } case 0xD7: // fixext 8 { - result.has_subtype = true; - return get_number(input_format_t::msgpack, result.subtype) and get_binary(input_format_t::msgpack, 8, result); + result.m_has_subtype = true; + return get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, 8, result); } case 0xD8: // fixext 16 { - result.has_subtype = true; - return get_number(input_format_t::msgpack, result.subtype) and get_binary(input_format_t::msgpack, 16, result); + result.m_has_subtype = true; + return get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, 16, result); } default: // LCOV_EXCL_LINE @@ -12557,7 +12557,7 @@ class binary_writer { // step 0: determine if the binary type has a set subtype to // determine whether or not to use the ext or fixext types - const bool use_ext = j.m_value.binary->has_subtype; + const bool use_ext = j.m_value.binary->has_subtype(); // step 1: write control byte and the byte string length const auto N = j.m_value.binary->size(); @@ -12637,7 +12637,9 @@ class binary_writer // step 1.5: if this is an ext type, write the subtype if (use_ext) { - write_number(j.m_value.binary->subtype); + std::uint8_t subtype; + write_number(subtype); + j.m_value.binary->set_subtype(subtype); } // step 2: write the byte string @@ -13092,12 +13094,7 @@ class binary_writer write_bson_entry_header(name, 0x05); write_number(static_cast(value.size())); - std::uint8_t subtype = 0x00; // Generic Binary Subtype - if (value.has_subtype) - { - subtype = value.subtype; - } - write_number(subtype); + write_number(value.has_subtype() ? value.subtype() : 0x00); oa->write_characters(reinterpret_cast(value.data()), value.size()); } @@ -15593,8 +15590,13 @@ his- or herself with a specific naming scheme in order to override the binary type. I.e. it's for ease of use. */ template -struct wrapped_binary_t : public BinaryType +class wrapped_binary_t : public BinaryType { + public: + // to simplify code in binary_reader + template + friend class binary_reader; + using binary_t = BinaryType; wrapped_binary_t() noexcept(noexcept(binary_t())) @@ -15612,18 +15614,56 @@ struct wrapped_binary_t : public BinaryType wrapped_binary_t(const binary_t& bint, std::uint8_t st) noexcept(noexcept(binary_t(bint))) : binary_t(bint) - , subtype(st) - , has_subtype(true) + , m_subtype(st) + , m_has_subtype(true) {} wrapped_binary_t(binary_t&& bint, std::uint8_t st) noexcept(noexcept(binary_t(std::move(bint)))) : binary_t(std::move(bint)) - , subtype(st) - , has_subtype(true) + , m_subtype(st) + , m_has_subtype(true) {} - std::uint8_t subtype = 0; - bool has_subtype = false; + /*! + @brief set the subtype + @param subtype subtype to set (implementation specific) + */ + void set_subtype(std::uint8_t subtype) noexcept + { + m_subtype = subtype; + m_has_subtype = true; + } + + /*! + @brief get the subtype + @return subtype (implementation specific) + */ + constexpr std::uint8_t subtype() const noexcept + { + return m_subtype; + } + + /*! + @brief get whether a subtype was set + @return whether a subtype was set + */ + constexpr bool has_subtype() const noexcept + { + return m_has_subtype; + } + + /*! + @brief clear the subtype + */ + void clear_subtype() noexcept + { + m_subtype = 0; + m_has_subtype = false; + } + + private: + std::uint8_t m_subtype = 0; + bool m_has_subtype = false; }; } // namespace detail @@ -16398,15 +16438,15 @@ class basic_json This type is a type designed to carry binary data that appears in various serialized formats, such as CBOR's Major Type 2, MessagePack's bin, and - BSON's generic binary subtype. This type is NOT a part of standard JSON and + BSON's generic binary subtype. This type is NOT a part of standard JSON and exists solely for compatibility with these binary types. As such, it is simply defined as an ordered sequence of zero or more byte values. Additionally, as an implementation detail, the subtype of the binary data is - carried around as a `unint8_t`, which is compatible with both of the binary - data formats that use binary subtyping, (though the specific numbering is - incompatible with each other, and it is up to the user to translate between - them). + carried around as a `std::uint8_t`, which is compatible with both of the + binary data formats that use binary subtyping, (though the specific + numbering is incompatible with each other, and it is up to the user to + translate between them). [CBOR's RFC 7049](https://tools.ietf.org/html/rfc7049) describes this type as: @@ -16449,6 +16489,18 @@ class basic_json */ using binary_t = BinaryType; + /*! + @brief binary array with a binary type + + This type is used to store binary types internally. It wrapps the template + type `BinaryType` (@ref binary_t) and adds a subtype to allow to distinguish + different binary types from different formats. + + While @ref binary_t is used to define how binary values are stored, this + type is used to access binary values once they are parsed. + + @sa @ref binary_array -- create a binary array + */ using internal_binary_t = nlohmann::detail::wrapped_binary_t; /// @} @@ -19441,8 +19493,7 @@ class basic_json { if (is_binary()) { - m_value.binary->has_subtype = true; - m_value.binary->subtype = subtype; + m_value.binary->set_subtype(subtype); } } @@ -19470,8 +19521,7 @@ class basic_json { if (is_binary()) { - m_value.binary->has_subtype = false; - m_value.binary->subtype = 0; + m_value.binary->clear_subtype(); } } @@ -19495,7 +19545,7 @@ class basic_json */ bool has_subtype() const noexcept { - return is_binary() and m_value.binary->has_subtype; + return is_binary() and m_value.binary->has_subtype(); } /*! From 3ed059f6ffe44ae78a9b80c7323584ecb9b2ed5d Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sat, 16 May 2020 12:56:18 +0200 Subject: [PATCH 21/36] :rewind: revert faulty changes --- include/nlohmann/detail/output/binary_writer.hpp | 6 ++---- single_include/nlohmann/json.hpp | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/include/nlohmann/detail/output/binary_writer.hpp b/include/nlohmann/detail/output/binary_writer.hpp index 39935d10ec..48364547d3 100644 --- a/include/nlohmann/detail/output/binary_writer.hpp +++ b/include/nlohmann/detail/output/binary_writer.hpp @@ -630,9 +630,7 @@ class binary_writer // step 1.5: if this is an ext type, write the subtype if (use_ext) { - std::uint8_t subtype; - write_number(subtype); - j.m_value.binary->set_subtype(subtype); + write_number(j.m_value.binary->subtype()); } // step 2: write the byte string @@ -1087,7 +1085,7 @@ class binary_writer write_bson_entry_header(name, 0x05); write_number(static_cast(value.size())); - write_number(value.has_subtype() ? value.subtype() : 0x00); + write_number(value.has_subtype() ? value.subtype() : std::uint8_t(0x00)); oa->write_characters(reinterpret_cast(value.data()), value.size()); } diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 8b01d2416c..9a650b9d81 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -12637,9 +12637,7 @@ class binary_writer // step 1.5: if this is an ext type, write the subtype if (use_ext) { - std::uint8_t subtype; - write_number(subtype); - j.m_value.binary->set_subtype(subtype); + write_number(j.m_value.binary->subtype()); } // step 2: write the byte string @@ -13094,7 +13092,7 @@ class binary_writer write_bson_entry_header(name, 0x05); write_number(static_cast(value.size())); - write_number(value.has_subtype() ? value.subtype() : 0x00); + write_number(value.has_subtype() ? value.subtype() : std::uint8_t(0x00)); oa->write_characters(reinterpret_cast(value.data()), value.size()); } From 28e20bd9e40387574479f753cd46ff66ed8aa21d Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sat, 16 May 2020 14:26:17 +0200 Subject: [PATCH 22/36] :rotating_light: fix warnings #2113 --- Makefile | 14 +++++++++----- include/nlohmann/detail/input/binary_reader.hpp | 2 +- .../nlohmann/detail/output/binary_writer.hpp | 6 +++--- single_include/nlohmann/json.hpp | 8 ++++---- test/src/unit-cbor.cpp | 8 ++++---- test/src/unit-noexcept.cpp | 17 ++++++++++++++++- test/src/unit-udt.cpp | 10 +++++++++- test/thirdparty/doctest/doctest.h | 2 +- 8 files changed, 47 insertions(+), 20 deletions(-) diff --git a/Makefile b/Makefile index a2884812bd..08c40d2f34 100644 --- a/Makefile +++ b/Makefile @@ -102,7 +102,8 @@ doctest: # -Wno-switch-enum -Wno-covered-switch-default: pedantic/contradicting warnings about switches # -Wno-weak-vtables: exception class is defined inline, but has virtual method pedantic_clang: - $(MAKE) json_unit CXX=c++ CXXFLAGS=" \ + rm -fr build_pedantic + CXXFLAGS=" \ -std=c++11 -Wno-c++98-compat -Wno-c++98-compat-pedantic \ -Werror \ -Weverything \ @@ -115,11 +116,13 @@ pedantic_clang: -Wno-padded \ -Wno-range-loop-analysis \ -Wno-switch-enum -Wno-covered-switch-default \ - -Wno-weak-vtables" + -Wno-weak-vtables" cmake -S . -B build_pedantic -GNinja -DCMAKE_BUILD_TYPE=Debug -DJSON_MultipleHeaders=ON + cmake --build build_pedantic # calling GCC with most warnings pedantic_gcc: - $(MAKE) json_unit CXX=/usr/local/bin/g++-9 CXXFLAGS=" \ + rm -fr build_pedantic + CXXFLAGS=" \ -std=c++11 \ -Waddress \ -Waddress-of-packed-member \ @@ -233,7 +236,7 @@ pedantic_gcc: -Wno-system-headers \ -Wno-templates \ -Wno-undef \ - -Wnoexcept \ + -Wno-noexcept \ -Wnoexcept-type \ -Wnon-template-friend \ -Wnon-virtual-dtor \ @@ -340,7 +343,8 @@ pedantic_gcc: -Wvolatile-register-var \ -Wwrite-strings \ -Wzero-as-null-pointer-constant \ - " + " cmake -S . -B build_pedantic -GNinja -DCMAKE_BUILD_TYPE=Debug -DJSON_MultipleHeaders=ON + cmake --build build_pedantic ########################################################################## # benchmarks diff --git a/include/nlohmann/detail/input/binary_reader.hpp b/include/nlohmann/detail/input/binary_reader.hpp index 5f497089e8..a40693a00a 100644 --- a/include/nlohmann/detail/input/binary_reader.hpp +++ b/include/nlohmann/detail/input/binary_reader.hpp @@ -32,7 +32,7 @@ namespace detail @note from https://stackoverflow.com/a/1001328/266378 */ -static bool little_endianess(int num = 1) noexcept +static inline bool little_endianess(int num = 1) noexcept { return *reinterpret_cast(&num) == 1; } diff --git a/include/nlohmann/detail/output/binary_writer.hpp b/include/nlohmann/detail/output/binary_writer.hpp index 9c6e615b58..c4cf618c2a 100644 --- a/include/nlohmann/detail/output/binary_writer.hpp +++ b/include/nlohmann/detail/output/binary_writer.hpp @@ -194,9 +194,9 @@ class binary_writer } else { - if (j.m_value.number_float >= std::numeric_limits::lowest() and - j.m_value.number_float <= std::numeric_limits::max() and - static_cast(static_cast(j.m_value.number_float)) == j.m_value.number_float) + if (static_cast(j.m_value.number_float) >= static_cast(std::numeric_limits::lowest()) and + static_cast(j.m_value.number_float) <= static_cast(std::numeric_limits::max()) and + static_cast(static_cast(j.m_value.number_float)) == static_cast(j.m_value.number_float)) { oa->write_character(get_cbor_float_prefix(static_cast(j.m_value.number_float))); write_number(static_cast(j.m_value.number_float)); diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index c5ef3f7f08..4db36ef289 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -5596,7 +5596,7 @@ namespace detail @note from https://stackoverflow.com/a/1001328/266378 */ -static bool little_endianess(int num = 1) noexcept +static inline bool little_endianess(int num = 1) noexcept { return *reinterpret_cast(&num) == 1; } @@ -12188,9 +12188,9 @@ class binary_writer } else { - if (j.m_value.number_float >= std::numeric_limits::lowest() and - j.m_value.number_float <= std::numeric_limits::max() and - static_cast(static_cast(j.m_value.number_float)) == j.m_value.number_float) + if (static_cast(j.m_value.number_float) >= static_cast(std::numeric_limits::lowest()) and + static_cast(j.m_value.number_float) <= static_cast(std::numeric_limits::max()) and + static_cast(static_cast(j.m_value.number_float)) == static_cast(j.m_value.number_float)) { oa->write_character(get_cbor_float_prefix(static_cast(j.m_value.number_float))); write_number(static_cast(j.m_value.number_float)); diff --git a/test/src/unit-cbor.cpp b/test/src/unit-cbor.cpp index 2800325876..2a53bb5295 100644 --- a/test/src/unit-cbor.cpp +++ b/test/src/unit-cbor.cpp @@ -939,7 +939,7 @@ TEST_CASE("CBOR") } SECTION("-3.40282e+38(lowest float)") { - double v = std::numeric_limits::lowest(); + double v = static_cast(std::numeric_limits::lowest()); json j = v; std::vector expected = { @@ -953,7 +953,7 @@ TEST_CASE("CBOR") } SECTION("1 + 3.40282e+38(more than max float)") { - double v = std::numeric_limits::max() + 0.1e+34; + double v = static_cast(std::numeric_limits::max()) + 0.1e+34; json j = v; std::vector expected = { @@ -968,7 +968,7 @@ TEST_CASE("CBOR") } SECTION("-1 - 3.40282e+38(less than lowest float)") { - double v = std::numeric_limits::lowest() - 1; + double v = static_cast(std::numeric_limits::lowest()) - 1.0; json j = v; std::vector expected = { @@ -1582,7 +1582,7 @@ TEST_CASE("CBOR") auto j = json::from_cbor(input); CHECK(j.is_binary()); auto k = json::binary_array({0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x99}); - CAPTURE(j.dump(0, ' ', false, json::error_handler_t::strict, true)); + CAPTURE(j.dump(0, ' ', false, json::error_handler_t::strict, true)) CHECK(j == k); } diff --git a/test/src/unit-noexcept.cpp b/test/src/unit-noexcept.cpp index 8fbe9f9165..6952c0ee81 100644 --- a/test/src/unit-noexcept.cpp +++ b/test/src/unit-noexcept.cpp @@ -46,7 +46,12 @@ void to_json(json&, pod) noexcept; void to_json(json&, pod_bis); void from_json(const json&, pod) noexcept; void from_json(const json&, pod_bis); -static json* j; +void to_json(json&, pod) noexcept {} +void to_json(json&, pod_bis) {} +void from_json(const json&, pod) noexcept {} +void from_json(const json&, pod_bis) {} + +static json* j = nullptr; static_assert(noexcept(json{}), ""); static_assert(noexcept(nlohmann::to_json(*j, 2)), ""); @@ -79,4 +84,14 @@ TEST_CASE("runtime checks") CHECK(std::is_nothrow_copy_constructible::value == std::is_nothrow_copy_constructible::value); CHECK(std::is_nothrow_copy_constructible::value == std::is_nothrow_copy_constructible::value); } + + SECTION("silence -Wunneeded-internal-declaration errors") + { + j = nullptr; + json j2; + to_json(j2, pod()); + to_json(j2, pod_bis()); + from_json(j2, pod()); + from_json(j2, pod_bis()); + } } diff --git a/test/src/unit-udt.cpp b/test/src/unit-udt.cpp index b1da8c3743..cd9ce69fb5 100644 --- a/test/src/unit-udt.cpp +++ b/test/src/unit-udt.cpp @@ -120,6 +120,8 @@ static void to_json(BasicJsonType& j, country c) case country::russia: j = u8"Российская Федерация"; return; + default: + break; } } @@ -803,7 +805,9 @@ class Evil public: Evil() = default; template - Evil(T) {} + Evil(T t) : m_i(sizeof(t)) {} + + int m_i = 0; }; void from_json(const json&, Evil&) {} @@ -816,6 +820,10 @@ TEST_CASE("Issue #924") CHECK_NOTHROW(j.get()); CHECK_NOTHROW(j.get>()); + + // silence Wunused-template warnings + Evil e(1); + CHECK(e.m_i >= 0); } TEST_CASE("Issue #1237") diff --git a/test/thirdparty/doctest/doctest.h b/test/thirdparty/doctest/doctest.h index 4f3a0e330c..2f0ff2131f 100755 --- a/test/thirdparty/doctest/doctest.h +++ b/test/thirdparty/doctest/doctest.h @@ -2913,7 +2913,7 @@ typedef timer_large_integer::type ticks_t; //unsigned int getElapsedMilliseconds() const { // return static_cast(getElapsedMicroseconds() / 1000); //} - double getElapsedSeconds() const { return (getCurrentTicks() - m_ticks) / 1000000.0; } + double getElapsedSeconds() const { return static_cast((getCurrentTicks() - m_ticks)) / 1000000.0; } private: ticks_t m_ticks = 0; From dead99eb0e2c7b1ca1d097e28dff865215f17744 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 17 May 2020 13:51:59 +0200 Subject: [PATCH 23/36] :hammer: overwork binary subtypes --- .../nlohmann/detail/input/binary_reader.hpp | 85 ++++++---- include/nlohmann/detail/input/json_sax.hpp | 20 +-- .../nlohmann/detail/output/binary_writer.hpp | 2 +- include/nlohmann/detail/wrapped_binary_t.hpp | 31 ++-- include/nlohmann/json.hpp | 15 ++ single_include/nlohmann/json.hpp | 153 +++++++++++------- test/src/unit-class_parser.cpp | 4 +- test/src/unit-deserialization.cpp | 2 +- 8 files changed, 195 insertions(+), 117 deletions(-) diff --git a/include/nlohmann/detail/input/binary_reader.hpp b/include/nlohmann/detail/input/binary_reader.hpp index e03f95fb9c..35d7dbd633 100644 --- a/include/nlohmann/detail/input/binary_reader.hpp +++ b/include/nlohmann/detail/input/binary_reader.hpp @@ -227,8 +227,10 @@ class binary_reader return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, "byte array length cannot be negative, is " + std::to_string(len), "binary"))); } - result.m_has_subtype = true; // All BSON binary values have a subtype - get_number(input_format_t::bson, result.m_subtype); + // All BSON binary values have a subtype + std::uint8_t subtype; + get_number(input_format_t::bson, subtype); + result.set_subtype(subtype); return get_binary(input_format_t::bson, len, result); } @@ -901,25 +903,29 @@ class binary_reader case 0x58: // Binary data (one-byte uint8_t for n follows) { std::uint8_t len; - return get_number(input_format_t::cbor, len) and get_binary(input_format_t::cbor, len, result); + return get_number(input_format_t::cbor, len) and + get_binary(input_format_t::cbor, len, result); } case 0x59: // Binary data (two-byte uint16_t for n follow) { std::uint16_t len; - return get_number(input_format_t::cbor, len) and get_binary(input_format_t::cbor, len, result); + return get_number(input_format_t::cbor, len) and + get_binary(input_format_t::cbor, len, result); } case 0x5A: // Binary data (four-byte uint32_t for n follow) { std::uint32_t len; - return get_number(input_format_t::cbor, len) and get_binary(input_format_t::cbor, len, result); + return get_number(input_format_t::cbor, len) and + get_binary(input_format_t::cbor, len, result); } case 0x5B: // Binary data (eight-byte uint64_t for n follow) { std::uint64_t len; - return get_number(input_format_t::cbor, len) and get_binary(input_format_t::cbor, len, result); + return get_number(input_format_t::cbor, len) and + get_binary(input_format_t::cbor, len, result); } case 0x5F: // Binary data (indefinite length) @@ -1501,81 +1507,104 @@ class binary_reader */ bool get_msgpack_binary(internal_binary_t& result) { + // helper function to set the subtype + auto assign_and_return_true = [&result](std::int8_t subtype) + { + result.set_subtype(static_cast(subtype)); + return true; + }; + switch (current) { case 0xC4: // bin 8 { std::uint8_t len; - return get_number(input_format_t::msgpack, len) and get_binary(input_format_t::msgpack, len, result); + return get_number(input_format_t::msgpack, len) and + get_binary(input_format_t::msgpack, len, result); } case 0xC5: // bin 16 { std::uint16_t len; - return get_number(input_format_t::msgpack, len) and get_binary(input_format_t::msgpack, len, result); + return get_number(input_format_t::msgpack, len) and + get_binary(input_format_t::msgpack, len, result); } case 0xC6: // bin 32 { std::uint32_t len; - return get_number(input_format_t::msgpack, len) and get_binary(input_format_t::msgpack, len, result); + return get_number(input_format_t::msgpack, len) and + get_binary(input_format_t::msgpack, len, result); } case 0xC7: // ext 8 { std::uint8_t len; - result.m_has_subtype = true; + std::int8_t subtype; return get_number(input_format_t::msgpack, len) and - get_number(input_format_t::msgpack, result.m_subtype) and - get_binary(input_format_t::msgpack, len, result); + get_number(input_format_t::msgpack, subtype) and + get_binary(input_format_t::msgpack, len, result) and + assign_and_return_true(subtype); } case 0xC8: // ext 16 { std::uint16_t len; - result.m_has_subtype = true; + std::int8_t subtype; return get_number(input_format_t::msgpack, len) and - get_number(input_format_t::msgpack, result.m_subtype) and - get_binary(input_format_t::msgpack, len, result); + get_number(input_format_t::msgpack, subtype) and + get_binary(input_format_t::msgpack, len, result) and + assign_and_return_true(subtype); } case 0xC9: // ext 32 { std::uint32_t len; - result.m_has_subtype = true; + std::int8_t subtype; return get_number(input_format_t::msgpack, len) and - get_number(input_format_t::msgpack, result.m_subtype) and - get_binary(input_format_t::msgpack, len, result); + get_number(input_format_t::msgpack, subtype) and + get_binary(input_format_t::msgpack, len, result) and + assign_and_return_true(subtype); } case 0xD4: // fixext 1 { - result.m_has_subtype = true; - return get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, 1, result); + std::int8_t subtype; + return get_number(input_format_t::msgpack, subtype) and + get_binary(input_format_t::msgpack, 1, result) and + assign_and_return_true(subtype); } case 0xD5: // fixext 2 { - result.m_has_subtype = true; - return get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, 2, result); + std::int8_t subtype; + return get_number(input_format_t::msgpack, subtype) and + get_binary(input_format_t::msgpack, 2, result) and + assign_and_return_true(subtype); } case 0xD6: // fixext 4 { - result.m_has_subtype = true; - return get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, 4, result); + std::int8_t subtype; + return get_number(input_format_t::msgpack, subtype) and + get_binary(input_format_t::msgpack, 4, result) and + assign_and_return_true(subtype); } case 0xD7: // fixext 8 { - result.m_has_subtype = true; - return get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, 8, result); + std::int8_t subtype; + return get_number(input_format_t::msgpack, subtype) and + get_binary(input_format_t::msgpack, 8, result) and + assign_and_return_true(subtype); } case 0xD8: // fixext 16 { - result.m_has_subtype = true; - return get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, 16, result); + std::int8_t subtype; + return get_number(input_format_t::msgpack, subtype) and + get_binary(input_format_t::msgpack, 16, result) and + assign_and_return_true(subtype); } default: // LCOV_EXCL_LINE diff --git a/include/nlohmann/detail/input/json_sax.hpp b/include/nlohmann/detail/input/json_sax.hpp index ac41e6bb40..54b53fd341 100644 --- a/include/nlohmann/detail/input/json_sax.hpp +++ b/include/nlohmann/detail/input/json_sax.hpp @@ -27,7 +27,7 @@ struct json_sax using number_unsigned_t = typename BasicJsonType::number_unsigned_t; using number_float_t = typename BasicJsonType::number_float_t; using string_t = typename BasicJsonType::string_t; - using binary_t = typename BasicJsonType::binary_t; + using internal_binary_t = typename BasicJsonType::internal_binary_t; /*! @brief a null value was read @@ -78,7 +78,7 @@ struct json_sax @return whether parsing should proceed @note It is safe to move the passed binary. */ - virtual bool binary(binary_t& val) = 0; + virtual bool binary(internal_binary_t& val) = 0; /*! @brief the beginning of an object was read @@ -154,7 +154,7 @@ class json_sax_dom_parser using number_unsigned_t = typename BasicJsonType::number_unsigned_t; using number_float_t = typename BasicJsonType::number_float_t; using string_t = typename BasicJsonType::string_t; - using binary_t = typename BasicJsonType::binary_t; + using internal_binary_t = typename BasicJsonType::internal_binary_t; /*! @param[in, out] r reference to a JSON value that is manipulated while @@ -208,9 +208,9 @@ class json_sax_dom_parser return true; } - bool binary(binary_t& val) + bool binary(internal_binary_t& val) { - handle_value(BasicJsonType::binary_array(std::move(val))); + handle_value(std::move(val)); return true; } @@ -343,7 +343,7 @@ class json_sax_dom_callback_parser using number_unsigned_t = typename BasicJsonType::number_unsigned_t; using number_float_t = typename BasicJsonType::number_float_t; using string_t = typename BasicJsonType::string_t; - using binary_t = typename BasicJsonType::binary_t; + using internal_binary_t = typename BasicJsonType::internal_binary_t; using parser_callback_t = typename BasicJsonType::parser_callback_t; using parse_event_t = typename BasicJsonType::parse_event_t; @@ -398,9 +398,9 @@ class json_sax_dom_callback_parser return true; } - bool binary(binary_t& val) + bool binary(internal_binary_t& val) { - handle_value(BasicJsonType::binary_array(val)); + handle_value(std::move(val)); return true; } @@ -654,7 +654,7 @@ class json_sax_acceptor using number_unsigned_t = typename BasicJsonType::number_unsigned_t; using number_float_t = typename BasicJsonType::number_float_t; using string_t = typename BasicJsonType::string_t; - using binary_t = typename BasicJsonType::binary_t; + using internal_binary_t = typename BasicJsonType::internal_binary_t; bool null() { @@ -686,7 +686,7 @@ class json_sax_acceptor return true; } - bool binary(binary_t& /*unused*/) + bool binary(internal_binary_t& /*unused*/) { return true; } diff --git a/include/nlohmann/detail/output/binary_writer.hpp b/include/nlohmann/detail/output/binary_writer.hpp index cd826f0922..1feb95dc64 100644 --- a/include/nlohmann/detail/output/binary_writer.hpp +++ b/include/nlohmann/detail/output/binary_writer.hpp @@ -658,7 +658,7 @@ class binary_writer // step 1.5: if this is an ext type, write the subtype if (use_ext) { - write_number(j.m_value.binary->subtype()); + write_number(static_cast(j.m_value.binary->subtype())); } // step 2: write the byte string diff --git a/include/nlohmann/detail/wrapped_binary_t.hpp b/include/nlohmann/detail/wrapped_binary_t.hpp index 8514f049d9..230641bda8 100644 --- a/include/nlohmann/detail/wrapped_binary_t.hpp +++ b/include/nlohmann/detail/wrapped_binary_t.hpp @@ -12,42 +12,37 @@ namespace detail @brief an internal type for a backed binary type This type is designed to be `binary_t` but with the subtype implementation -detail. This type exists so that the user does not have to specify a struct -his- or herself with a specific naming scheme in order to override the -binary type. I.e. it's for ease of use. +detail. This type exists so that the user does not have to specify a type +themselves with a specific naming scheme in order to override the binary type. */ template class wrapped_binary_t : public BinaryType { public: - // to simplify code in binary_reader - template - friend class binary_reader; - using binary_t = BinaryType; wrapped_binary_t() noexcept(noexcept(binary_t())) : binary_t() {} - wrapped_binary_t(const binary_t& bint) noexcept(noexcept(binary_t(bint))) - : binary_t(bint) + wrapped_binary_t(const binary_t& b) noexcept(noexcept(binary_t(b))) + : binary_t(b) {} - wrapped_binary_t(binary_t&& bint) noexcept(noexcept(binary_t(std::move(bint)))) - : binary_t(std::move(bint)) + wrapped_binary_t(binary_t&& b) noexcept(noexcept(binary_t(std::move(b)))) + : binary_t(std::move(b)) {} - wrapped_binary_t(const binary_t& bint, - std::uint8_t st) noexcept(noexcept(binary_t(bint))) - : binary_t(bint) - , m_subtype(st) + wrapped_binary_t(const binary_t& b, + std::uint8_t subtype) noexcept(noexcept(binary_t(b))) + : binary_t(b) + , m_subtype(subtype) , m_has_subtype(true) {} - wrapped_binary_t(binary_t&& bint, std::uint8_t st) noexcept(noexcept(binary_t(std::move(bint)))) - : binary_t(std::move(bint)) - , m_subtype(st) + wrapped_binary_t(binary_t&& b, std::uint8_t subtype) noexcept(noexcept(binary_t(std::move(b)))) + : binary_t(std::move(b)) + , m_subtype(subtype) , m_has_subtype(true) {} diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 270c2787ff..2b976d91b4 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -900,6 +900,21 @@ class basic_json While @ref binary_t is used to define how binary values are stored, this type is used to access binary values once they are parsed. + Notes on subtypes: + + - CBOR + - Binary values are represented as byte strings. No subtypes are + supported and will be ignored when CBOR is written. + - MessagePack + - If a subtype is given and the binary array contains exactly 1, 2, 4, 8, + or 16 elements, the fixext family (fixext1, fixext2, fixext4, fixext8) + is used. For other sizes, the ext family (ext8, ext16, ext32) is used. + The subtype is then added as singed 8-bit integer. + - If no subtype is given, the bin family (bin8, bin16, bin32) is used. + - BSON + - If a subtype is given, it is used and added as unsigned 8-bit integer. + - If no subtype is given, the generic binary subtype 0x00 is used. + @sa @ref binary_array -- create a binary array */ using internal_binary_t = nlohmann::detail::wrapped_binary_t; diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 395be7c89b..1a8aa14cbd 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -4764,7 +4764,7 @@ struct json_sax using number_unsigned_t = typename BasicJsonType::number_unsigned_t; using number_float_t = typename BasicJsonType::number_float_t; using string_t = typename BasicJsonType::string_t; - using binary_t = typename BasicJsonType::binary_t; + using internal_binary_t = typename BasicJsonType::internal_binary_t; /*! @brief a null value was read @@ -4815,7 +4815,7 @@ struct json_sax @return whether parsing should proceed @note It is safe to move the passed binary. */ - virtual bool binary(binary_t& val) = 0; + virtual bool binary(internal_binary_t& val) = 0; /*! @brief the beginning of an object was read @@ -4891,7 +4891,7 @@ class json_sax_dom_parser using number_unsigned_t = typename BasicJsonType::number_unsigned_t; using number_float_t = typename BasicJsonType::number_float_t; using string_t = typename BasicJsonType::string_t; - using binary_t = typename BasicJsonType::binary_t; + using internal_binary_t = typename BasicJsonType::internal_binary_t; /*! @param[in, out] r reference to a JSON value that is manipulated while @@ -4945,9 +4945,9 @@ class json_sax_dom_parser return true; } - bool binary(binary_t& val) + bool binary(internal_binary_t& val) { - handle_value(BasicJsonType::binary_array(std::move(val))); + handle_value(std::move(val)); return true; } @@ -5080,7 +5080,7 @@ class json_sax_dom_callback_parser using number_unsigned_t = typename BasicJsonType::number_unsigned_t; using number_float_t = typename BasicJsonType::number_float_t; using string_t = typename BasicJsonType::string_t; - using binary_t = typename BasicJsonType::binary_t; + using internal_binary_t = typename BasicJsonType::internal_binary_t; using parser_callback_t = typename BasicJsonType::parser_callback_t; using parse_event_t = typename BasicJsonType::parse_event_t; @@ -5135,9 +5135,9 @@ class json_sax_dom_callback_parser return true; } - bool binary(binary_t& val) + bool binary(internal_binary_t& val) { - handle_value(BasicJsonType::binary_array(val)); + handle_value(std::move(val)); return true; } @@ -5391,7 +5391,7 @@ class json_sax_acceptor using number_unsigned_t = typename BasicJsonType::number_unsigned_t; using number_float_t = typename BasicJsonType::number_float_t; using string_t = typename BasicJsonType::string_t; - using binary_t = typename BasicJsonType::binary_t; + using internal_binary_t = typename BasicJsonType::internal_binary_t; bool null() { @@ -5423,7 +5423,7 @@ class json_sax_acceptor return true; } - bool binary(binary_t& /*unused*/) + bool binary(internal_binary_t& /*unused*/) { return true; } @@ -5820,8 +5820,10 @@ class binary_reader return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, "byte array length cannot be negative, is " + std::to_string(len), "binary"))); } - result.m_has_subtype = true; // All BSON binary values have a subtype - get_number(input_format_t::bson, result.m_subtype); + // All BSON binary values have a subtype + std::uint8_t subtype; + get_number(input_format_t::bson, subtype); + result.set_subtype(subtype); return get_binary(input_format_t::bson, len, result); } @@ -6494,25 +6496,29 @@ class binary_reader case 0x58: // Binary data (one-byte uint8_t for n follows) { std::uint8_t len; - return get_number(input_format_t::cbor, len) and get_binary(input_format_t::cbor, len, result); + return get_number(input_format_t::cbor, len) and + get_binary(input_format_t::cbor, len, result); } case 0x59: // Binary data (two-byte uint16_t for n follow) { std::uint16_t len; - return get_number(input_format_t::cbor, len) and get_binary(input_format_t::cbor, len, result); + return get_number(input_format_t::cbor, len) and + get_binary(input_format_t::cbor, len, result); } case 0x5A: // Binary data (four-byte uint32_t for n follow) { std::uint32_t len; - return get_number(input_format_t::cbor, len) and get_binary(input_format_t::cbor, len, result); + return get_number(input_format_t::cbor, len) and + get_binary(input_format_t::cbor, len, result); } case 0x5B: // Binary data (eight-byte uint64_t for n follow) { std::uint64_t len; - return get_number(input_format_t::cbor, len) and get_binary(input_format_t::cbor, len, result); + return get_number(input_format_t::cbor, len) and + get_binary(input_format_t::cbor, len, result); } case 0x5F: // Binary data (indefinite length) @@ -7094,81 +7100,104 @@ class binary_reader */ bool get_msgpack_binary(internal_binary_t& result) { + // helper function to set the subtype + auto assign_and_return_true = [&result](std::int8_t subtype) + { + result.set_subtype(static_cast(subtype)); + return true; + }; + switch (current) { case 0xC4: // bin 8 { std::uint8_t len; - return get_number(input_format_t::msgpack, len) and get_binary(input_format_t::msgpack, len, result); + return get_number(input_format_t::msgpack, len) and + get_binary(input_format_t::msgpack, len, result); } case 0xC5: // bin 16 { std::uint16_t len; - return get_number(input_format_t::msgpack, len) and get_binary(input_format_t::msgpack, len, result); + return get_number(input_format_t::msgpack, len) and + get_binary(input_format_t::msgpack, len, result); } case 0xC6: // bin 32 { std::uint32_t len; - return get_number(input_format_t::msgpack, len) and get_binary(input_format_t::msgpack, len, result); + return get_number(input_format_t::msgpack, len) and + get_binary(input_format_t::msgpack, len, result); } case 0xC7: // ext 8 { std::uint8_t len; - result.m_has_subtype = true; + std::int8_t subtype; return get_number(input_format_t::msgpack, len) and - get_number(input_format_t::msgpack, result.m_subtype) and - get_binary(input_format_t::msgpack, len, result); + get_number(input_format_t::msgpack, subtype) and + get_binary(input_format_t::msgpack, len, result) and + assign_and_return_true(subtype); } case 0xC8: // ext 16 { std::uint16_t len; - result.m_has_subtype = true; + std::int8_t subtype; return get_number(input_format_t::msgpack, len) and - get_number(input_format_t::msgpack, result.m_subtype) and - get_binary(input_format_t::msgpack, len, result); + get_number(input_format_t::msgpack, subtype) and + get_binary(input_format_t::msgpack, len, result) and + assign_and_return_true(subtype); } case 0xC9: // ext 32 { std::uint32_t len; - result.m_has_subtype = true; + std::int8_t subtype; return get_number(input_format_t::msgpack, len) and - get_number(input_format_t::msgpack, result.m_subtype) and - get_binary(input_format_t::msgpack, len, result); + get_number(input_format_t::msgpack, subtype) and + get_binary(input_format_t::msgpack, len, result) and + assign_and_return_true(subtype); } case 0xD4: // fixext 1 { - result.m_has_subtype = true; - return get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, 1, result); + std::int8_t subtype; + return get_number(input_format_t::msgpack, subtype) and + get_binary(input_format_t::msgpack, 1, result) and + assign_and_return_true(subtype); } case 0xD5: // fixext 2 { - result.m_has_subtype = true; - return get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, 2, result); + std::int8_t subtype; + return get_number(input_format_t::msgpack, subtype) and + get_binary(input_format_t::msgpack, 2, result) and + assign_and_return_true(subtype); } case 0xD6: // fixext 4 { - result.m_has_subtype = true; - return get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, 4, result); + std::int8_t subtype; + return get_number(input_format_t::msgpack, subtype) and + get_binary(input_format_t::msgpack, 4, result) and + assign_and_return_true(subtype); } case 0xD7: // fixext 8 { - result.m_has_subtype = true; - return get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, 8, result); + std::int8_t subtype; + return get_number(input_format_t::msgpack, subtype) and + get_binary(input_format_t::msgpack, 8, result) and + assign_and_return_true(subtype); } case 0xD8: // fixext 16 { - result.m_has_subtype = true; - return get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, 16, result); + std::int8_t subtype; + return get_number(input_format_t::msgpack, subtype) and + get_binary(input_format_t::msgpack, 16, result) and + assign_and_return_true(subtype); } default: // LCOV_EXCL_LINE @@ -12682,7 +12711,7 @@ class binary_writer // step 1.5: if this is an ext type, write the subtype if (use_ext) { - write_number(j.m_value.binary->subtype()); + write_number(static_cast(j.m_value.binary->subtype())); } // step 2: write the byte string @@ -15631,42 +15660,37 @@ namespace detail @brief an internal type for a backed binary type This type is designed to be `binary_t` but with the subtype implementation -detail. This type exists so that the user does not have to specify a struct -his- or herself with a specific naming scheme in order to override the -binary type. I.e. it's for ease of use. +detail. This type exists so that the user does not have to specify a type +themselves with a specific naming scheme in order to override the binary type. */ template class wrapped_binary_t : public BinaryType { public: - // to simplify code in binary_reader - template - friend class binary_reader; - using binary_t = BinaryType; wrapped_binary_t() noexcept(noexcept(binary_t())) : binary_t() {} - wrapped_binary_t(const binary_t& bint) noexcept(noexcept(binary_t(bint))) - : binary_t(bint) + wrapped_binary_t(const binary_t& b) noexcept(noexcept(binary_t(b))) + : binary_t(b) {} - wrapped_binary_t(binary_t&& bint) noexcept(noexcept(binary_t(std::move(bint)))) - : binary_t(std::move(bint)) + wrapped_binary_t(binary_t&& b) noexcept(noexcept(binary_t(std::move(b)))) + : binary_t(std::move(b)) {} - wrapped_binary_t(const binary_t& bint, - std::uint8_t st) noexcept(noexcept(binary_t(bint))) - : binary_t(bint) - , m_subtype(st) + wrapped_binary_t(const binary_t& b, + std::uint8_t subtype) noexcept(noexcept(binary_t(b))) + : binary_t(b) + , m_subtype(subtype) , m_has_subtype(true) {} - wrapped_binary_t(binary_t&& bint, std::uint8_t st) noexcept(noexcept(binary_t(std::move(bint)))) - : binary_t(std::move(bint)) - , m_subtype(st) + wrapped_binary_t(binary_t&& b, std::uint8_t subtype) noexcept(noexcept(binary_t(std::move(b)))) + : binary_t(std::move(b)) + , m_subtype(subtype) , m_has_subtype(true) {} @@ -16545,6 +16569,21 @@ class basic_json While @ref binary_t is used to define how binary values are stored, this type is used to access binary values once they are parsed. + Notes on subtypes: + + - CBOR + - Binary values are represented as byte strings. No subtypes are + supported and will be ignored when CBOR is written. + - MessagePack + - If a subtype is given and the binary array contains exactly 1, 2, 4, 8, + or 16 elements, the fixext family (fixext1, fixext2, fixext4, fixext8) + is used. For other sizes, the ext family (ext8, ext16, ext32) is used. + The subtype is then added as singed 8-bit integer. + - If no subtype is given, the bin family (bin8, bin16, bin32) is used. + - BSON + - If a subtype is given, it is used and added as unsigned 8-bit integer. + - If no subtype is given, the generic binary subtype 0x00 is used. + @sa @ref binary_array -- create a binary array */ using internal_binary_t = nlohmann::detail::wrapped_binary_t; diff --git a/test/src/unit-class_parser.cpp b/test/src/unit-class_parser.cpp index 6f6b121ee0..f8eb6112f9 100644 --- a/test/src/unit-class_parser.cpp +++ b/test/src/unit-class_parser.cpp @@ -77,7 +77,7 @@ class SaxEventLogger return true; } - bool binary(std::vector& val) + bool binary(json::internal_binary_t& val) { std::string binary_contents = "binary("; std::string comma_space = ""; @@ -183,7 +183,7 @@ class SaxCountdown : public nlohmann::json::json_sax_t return events_left-- > 0; } - bool binary(std::vector&) override + bool binary(json::internal_binary_t&) override { return events_left-- > 0; } diff --git a/test/src/unit-deserialization.cpp b/test/src/unit-deserialization.cpp index a868871540..52ea9259d1 100644 --- a/test/src/unit-deserialization.cpp +++ b/test/src/unit-deserialization.cpp @@ -76,7 +76,7 @@ struct SaxEventLogger : public nlohmann::json_sax return true; } - bool binary(std::vector& val) override + bool binary(json::internal_binary_t& val) override { std::string binary_contents = "binary("; std::string comma_space = ""; From 904642f261f5698c6c2c611567252abec0f17247 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 17 May 2020 22:50:27 +0200 Subject: [PATCH 24/36] :recycle: rename internal_binary_t with binary_t --- README.md | 30 ++ doc/examples/is_array.cpp | 2 + doc/examples/is_array.link | 2 +- doc/examples/is_array.output | 1 + doc/examples/is_binary.cpp | 30 ++ doc/examples/is_binary.link | 1 + doc/examples/is_binary.output | 9 + doc/examples/is_boolean.cpp | 2 + doc/examples/is_boolean.link | 2 +- doc/examples/is_boolean.output | 1 + doc/examples/is_discarded.cpp | 2 + doc/examples/is_discarded.link | 2 +- doc/examples/is_discarded.output | 1 + doc/examples/is_null.cpp | 2 + doc/examples/is_null.link | 2 +- doc/examples/is_null.output | 1 + doc/examples/is_number.cpp | 2 + doc/examples/is_number.link | 2 +- doc/examples/is_number.output | 1 + doc/examples/is_number_float.cpp | 2 + doc/examples/is_number_float.link | 2 +- doc/examples/is_number_float.output | 1 + doc/examples/is_number_integer.cpp | 2 + doc/examples/is_number_integer.link | 2 +- doc/examples/is_number_integer.output | 1 + doc/examples/is_number_unsigned.cpp | 2 + doc/examples/is_number_unsigned.link | 2 +- doc/examples/is_number_unsigned.output | 1 + doc/examples/is_object.cpp | 2 + doc/examples/is_object.link | 2 +- doc/examples/is_object.output | 1 + doc/examples/is_primitive.cpp | 2 + doc/examples/is_primitive.link | 2 +- doc/examples/is_primitive.output | 1 + doc/examples/is_string.cpp | 2 + doc/examples/is_string.link | 2 +- doc/examples/is_string.output | 1 + doc/examples/is_structured.cpp | 2 + doc/examples/is_structured.link | 2 +- doc/examples/is_structured.output | 1 + doc/examples/sax_parse.cpp | 2 +- doc/examples/sax_parse.link | 2 +- doc/index.md | 9 +- .../nlohmann/detail/conversions/from_json.hpp | 6 +- .../nlohmann/detail/conversions/to_json.hpp | 12 +- .../nlohmann/detail/input/binary_reader.hpp | 18 +- include/nlohmann/detail/input/json_sax.hpp | 16 +- .../detail/iterators/internal_iterator.hpp | 2 +- .../nlohmann/detail/output/binary_writer.hpp | 6 +- include/nlohmann/detail/output/serializer.hpp | 4 +- include/nlohmann/detail/wrapped_binary_t.hpp | 98 ++++- include/nlohmann/json.hpp | 224 ++++------ single_include/nlohmann/json.hpp | 386 +++++++++--------- test/src/unit-class_parser.cpp | 4 +- test/src/unit-constructor1.cpp | 4 +- test/src/unit-deserialization.cpp | 2 +- test/src/unit-modifiers.cpp | 20 +- test/src/unit-msgpack.cpp | 6 +- test/src/unit-pointer_access.cpp | 40 +- 59 files changed, 535 insertions(+), 456 deletions(-) create mode 100644 doc/examples/is_binary.cpp create mode 100644 doc/examples/is_binary.link create mode 100644 doc/examples/is_binary.output diff --git a/README.md b/README.md index 612b8a6651..d2c3f9785e 100644 --- a/README.md +++ b/README.md @@ -1047,6 +1047,36 @@ std::vector v_ubjson = json::to_ubjson(j); json j_from_ubjson = json::from_ubjson(v_ubjson); ``` +The library also supports binary types from BSON, CBOR (byte strings), and MessagePack (bin, ext, fixext). They are stored by default as `std::vector` to be processed outside of the library. + +```cpp +// CBOR byte string with payload 0xCAFE +std::vector v = {0x42, 0xCA, 0xFE}; + +// read value +json j = json::from_cbor(v); + +// the JSON value has type binary +j.is_binary(); // true + +// get reference to stored binary value +auto& binary = j.get_binary(); + +// the binary value has no subtype (CBOR has no binary subtypes) +binary.has_subtype(); // false + +// access std::vector member functions +binary.size(); // 2 +binary[0]; // 0xCA +binary[1]; // 0xFE + +// set subtype to 0x10 +binary.set_subtype(0x10); + +// serialize to MessagePack +auto cbor = json::to_msgpack(j); // 0xD5 (fixext2), 0x10, 0xCA, 0xFE +``` + ## Supported compilers diff --git a/doc/examples/is_array.cpp b/doc/examples/is_array.cpp index 235dab7690..8286697b43 100644 --- a/doc/examples/is_array.cpp +++ b/doc/examples/is_array.cpp @@ -14,6 +14,7 @@ int main() json j_object = {{"one", 1}, {"two", 2}}; json j_array = {1, 2, 4, 8, 16}; json j_string = "Hello, world"; + json j_binary = json::binary_array({1, 2, 3}); // call is_array() std::cout << std::boolalpha; @@ -25,4 +26,5 @@ int main() std::cout << j_object.is_array() << '\n'; std::cout << j_array.is_array() << '\n'; std::cout << j_string.is_array() << '\n'; + std::cout << j_binary.is_array() << '\n'; } diff --git a/doc/examples/is_array.link b/doc/examples/is_array.link index 4232a9223f..fc292eb64a 100644 --- a/doc/examples/is_array.link +++ b/doc/examples/is_array.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/is_array.output b/doc/examples/is_array.output index 5b8cc40c96..7b7ef3f191 100644 --- a/doc/examples/is_array.output +++ b/doc/examples/is_array.output @@ -6,3 +6,4 @@ false false true false +false diff --git a/doc/examples/is_binary.cpp b/doc/examples/is_binary.cpp new file mode 100644 index 0000000000..74173e911d --- /dev/null +++ b/doc/examples/is_binary.cpp @@ -0,0 +1,30 @@ +#include +#include + +using json = nlohmann::json; + +int main() +{ + // create JSON values + json j_null; + json j_boolean = true; + json j_number_integer = 17; + json j_number_unsigned_integer = 12345678987654321u; + json j_number_float = 23.42; + json j_object = {{"one", 1}, {"two", 2}}; + json j_array = {1, 2, 4, 8, 16}; + json j_string = "Hello, world"; + json j_binary = json::binary_array({1, 2, 3}); + + // call is_binary() + std::cout << std::boolalpha; + std::cout << j_null.is_binary() << '\n'; + std::cout << j_boolean.is_binary() << '\n'; + std::cout << j_number_integer.is_binary() << '\n'; + std::cout << j_number_unsigned_integer.is_binary() << '\n'; + std::cout << j_number_float.is_binary() << '\n'; + std::cout << j_object.is_binary() << '\n'; + std::cout << j_array.is_binary() << '\n'; + std::cout << j_string.is_binary() << '\n'; + std::cout << j_binary.is_binary() << '\n'; +} diff --git a/doc/examples/is_binary.link b/doc/examples/is_binary.link new file mode 100644 index 0000000000..cc8e715ebe --- /dev/null +++ b/doc/examples/is_binary.link @@ -0,0 +1 @@ +online \ No newline at end of file diff --git a/doc/examples/is_binary.output b/doc/examples/is_binary.output new file mode 100644 index 0000000000..505e76e4ff --- /dev/null +++ b/doc/examples/is_binary.output @@ -0,0 +1,9 @@ +false +false +false +false +false +false +false +false +true diff --git a/doc/examples/is_boolean.cpp b/doc/examples/is_boolean.cpp index ccc202d03b..d51d594e46 100644 --- a/doc/examples/is_boolean.cpp +++ b/doc/examples/is_boolean.cpp @@ -14,6 +14,7 @@ int main() json j_object = {{"one", 1}, {"two", 2}}; json j_array = {1, 2, 4, 8, 16}; json j_string = "Hello, world"; + json j_binary = json::binary_array({1, 2, 3}); // call is_boolean() std::cout << std::boolalpha; @@ -25,4 +26,5 @@ int main() std::cout << j_object.is_boolean() << '\n'; std::cout << j_array.is_boolean() << '\n'; std::cout << j_string.is_boolean() << '\n'; + std::cout << j_binary.is_boolean() << '\n'; } diff --git a/doc/examples/is_boolean.link b/doc/examples/is_boolean.link index 19f0b0081d..779a36e9c4 100644 --- a/doc/examples/is_boolean.link +++ b/doc/examples/is_boolean.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/is_boolean.output b/doc/examples/is_boolean.output index 721b3a5e2e..eace89d22e 100644 --- a/doc/examples/is_boolean.output +++ b/doc/examples/is_boolean.output @@ -6,3 +6,4 @@ false false false false +false diff --git a/doc/examples/is_discarded.cpp b/doc/examples/is_discarded.cpp index 782e649982..914890c451 100644 --- a/doc/examples/is_discarded.cpp +++ b/doc/examples/is_discarded.cpp @@ -14,6 +14,7 @@ int main() json j_object = {{"one", 1}, {"two", 2}}; json j_array = {1, 2, 4, 8, 16}; json j_string = "Hello, world"; + json j_binary = json::binary_array({1, 2, 3}); // call is_discarded() std::cout << std::boolalpha; @@ -25,4 +26,5 @@ int main() std::cout << j_object.is_discarded() << '\n'; std::cout << j_array.is_discarded() << '\n'; std::cout << j_string.is_discarded() << '\n'; + std::cout << j_binary.is_discarded() << '\n'; } diff --git a/doc/examples/is_discarded.link b/doc/examples/is_discarded.link index 9ec778f791..c51128f6fc 100644 --- a/doc/examples/is_discarded.link +++ b/doc/examples/is_discarded.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/is_discarded.output b/doc/examples/is_discarded.output index 485b169670..14718f64ea 100644 --- a/doc/examples/is_discarded.output +++ b/doc/examples/is_discarded.output @@ -6,3 +6,4 @@ false false false false +false diff --git a/doc/examples/is_null.cpp b/doc/examples/is_null.cpp index 4a635092c4..2e2730e17d 100644 --- a/doc/examples/is_null.cpp +++ b/doc/examples/is_null.cpp @@ -14,6 +14,7 @@ int main() json j_object = {{"one", 1}, {"two", 2}}; json j_array = {1, 2, 4, 8, 16}; json j_string = "Hello, world"; + json j_binary = json::binary_array({1, 2, 3}); // call is_null() std::cout << std::boolalpha; @@ -25,4 +26,5 @@ int main() std::cout << j_object.is_null() << '\n'; std::cout << j_array.is_null() << '\n'; std::cout << j_string.is_null() << '\n'; + std::cout << j_binary.is_null() << '\n'; } diff --git a/doc/examples/is_null.link b/doc/examples/is_null.link index dd1a5aab3d..fe02d31f93 100644 --- a/doc/examples/is_null.link +++ b/doc/examples/is_null.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/is_null.output b/doc/examples/is_null.output index 4cc64628d6..42bbee2a79 100644 --- a/doc/examples/is_null.output +++ b/doc/examples/is_null.output @@ -6,3 +6,4 @@ false false false false +false diff --git a/doc/examples/is_number.cpp b/doc/examples/is_number.cpp index eb23bd244a..8ef27b0ad6 100644 --- a/doc/examples/is_number.cpp +++ b/doc/examples/is_number.cpp @@ -14,6 +14,7 @@ int main() json j_object = {{"one", 1}, {"two", 2}}; json j_array = {1, 2, 4, 8, 16}; json j_string = "Hello, world"; + json j_binary = json::binary_array({1, 2, 3}); // call is_number() std::cout << std::boolalpha; @@ -25,4 +26,5 @@ int main() std::cout << j_object.is_number() << '\n'; std::cout << j_array.is_number() << '\n'; std::cout << j_string.is_number() << '\n'; + std::cout << j_binary.is_number() << '\n'; } diff --git a/doc/examples/is_number.link b/doc/examples/is_number.link index 43c52b47a3..c2623b2989 100644 --- a/doc/examples/is_number.link +++ b/doc/examples/is_number.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/is_number.output b/doc/examples/is_number.output index 06dbc28239..53ef340bb0 100644 --- a/doc/examples/is_number.output +++ b/doc/examples/is_number.output @@ -6,3 +6,4 @@ true false false false +false diff --git a/doc/examples/is_number_float.cpp b/doc/examples/is_number_float.cpp index 3435a7e09e..8b8fa3bfd4 100644 --- a/doc/examples/is_number_float.cpp +++ b/doc/examples/is_number_float.cpp @@ -14,6 +14,7 @@ int main() json j_object = {{"one", 1}, {"two", 2}}; json j_array = {1, 2, 4, 8, 16}; json j_string = "Hello, world"; + json j_binary = json::binary_array({1, 2, 3}); // call is_number_float() std::cout << std::boolalpha; @@ -25,4 +26,5 @@ int main() std::cout << j_object.is_number_float() << '\n'; std::cout << j_array.is_number_float() << '\n'; std::cout << j_string.is_number_float() << '\n'; + std::cout << j_binary.is_number_float() << '\n'; } diff --git a/doc/examples/is_number_float.link b/doc/examples/is_number_float.link index 4d8f0ea86c..ec3c822e32 100644 --- a/doc/examples/is_number_float.link +++ b/doc/examples/is_number_float.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/is_number_float.output b/doc/examples/is_number_float.output index 09afae4c97..0e64601abd 100644 --- a/doc/examples/is_number_float.output +++ b/doc/examples/is_number_float.output @@ -6,3 +6,4 @@ true false false false +false diff --git a/doc/examples/is_number_integer.cpp b/doc/examples/is_number_integer.cpp index 6f6e42043a..efd76a7dd0 100644 --- a/doc/examples/is_number_integer.cpp +++ b/doc/examples/is_number_integer.cpp @@ -14,6 +14,7 @@ int main() json j_object = {{"one", 1}, {"two", 2}}; json j_array = {1, 2, 4, 8, 16}; json j_string = "Hello, world"; + json j_binary = json::binary_array({1, 2, 3}); // call is_number_integer() std::cout << std::boolalpha; @@ -25,4 +26,5 @@ int main() std::cout << j_object.is_number_integer() << '\n'; std::cout << j_array.is_number_integer() << '\n'; std::cout << j_string.is_number_integer() << '\n'; + std::cout << j_binary.is_number_integer() << '\n'; } diff --git a/doc/examples/is_number_integer.link b/doc/examples/is_number_integer.link index 0233e0f727..49b57e66ee 100644 --- a/doc/examples/is_number_integer.link +++ b/doc/examples/is_number_integer.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/is_number_integer.output b/doc/examples/is_number_integer.output index be0f739368..c1df310f4c 100644 --- a/doc/examples/is_number_integer.output +++ b/doc/examples/is_number_integer.output @@ -6,3 +6,4 @@ false false false false +false diff --git a/doc/examples/is_number_unsigned.cpp b/doc/examples/is_number_unsigned.cpp index 2ea2673e55..1a85b83233 100644 --- a/doc/examples/is_number_unsigned.cpp +++ b/doc/examples/is_number_unsigned.cpp @@ -14,6 +14,7 @@ int main() json j_object = {{"one", 1}, {"two", 2}}; json j_array = {1, 2, 4, 8, 16}; json j_string = "Hello, world"; + json j_binary = json::binary_array({1, 2, 3}); // call is_number_unsigned() std::cout << std::boolalpha; @@ -25,4 +26,5 @@ int main() std::cout << j_object.is_number_unsigned() << '\n'; std::cout << j_array.is_number_unsigned() << '\n'; std::cout << j_string.is_number_unsigned() << '\n'; + std::cout << j_binary.is_number_unsigned() << '\n'; } diff --git a/doc/examples/is_number_unsigned.link b/doc/examples/is_number_unsigned.link index 8981763044..1af8cef1a0 100644 --- a/doc/examples/is_number_unsigned.link +++ b/doc/examples/is_number_unsigned.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/is_number_unsigned.output b/doc/examples/is_number_unsigned.output index fdf264e0c4..e6059d48fd 100644 --- a/doc/examples/is_number_unsigned.output +++ b/doc/examples/is_number_unsigned.output @@ -6,3 +6,4 @@ false false false false +false diff --git a/doc/examples/is_object.cpp b/doc/examples/is_object.cpp index 42cedf8f0f..63728eab76 100644 --- a/doc/examples/is_object.cpp +++ b/doc/examples/is_object.cpp @@ -14,6 +14,7 @@ int main() json j_object = {{"one", 1}, {"two", 2}}; json j_array = {1, 2, 4, 8, 16}; json j_string = "Hello, world"; + json j_binary = json::binary_array({1, 2, 3}); // call is_object() std::cout << std::boolalpha; @@ -25,4 +26,5 @@ int main() std::cout << j_object.is_object() << '\n'; std::cout << j_array.is_object() << '\n'; std::cout << j_string.is_object() << '\n'; + std::cout << j_binary.is_object() << '\n'; } diff --git a/doc/examples/is_object.link b/doc/examples/is_object.link index 5dd305bbb0..ce82ff855e 100644 --- a/doc/examples/is_object.link +++ b/doc/examples/is_object.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/is_object.output b/doc/examples/is_object.output index e041e39228..d9a429f8fd 100644 --- a/doc/examples/is_object.output +++ b/doc/examples/is_object.output @@ -6,3 +6,4 @@ false true false false +false diff --git a/doc/examples/is_primitive.cpp b/doc/examples/is_primitive.cpp index d70c83e372..88b0a6a901 100644 --- a/doc/examples/is_primitive.cpp +++ b/doc/examples/is_primitive.cpp @@ -14,6 +14,7 @@ int main() json j_object = {{"one", 1}, {"two", 2}}; json j_array = {1, 2, 4, 8, 16}; json j_string = "Hello, world"; + json j_binary = json::binary_array({1, 2, 3}); // call is_primitive() std::cout << std::boolalpha; @@ -25,4 +26,5 @@ int main() std::cout << j_object.is_primitive() << '\n'; std::cout << j_array.is_primitive() << '\n'; std::cout << j_string.is_primitive() << '\n'; + std::cout << j_binary.is_primitive() << '\n'; } diff --git a/doc/examples/is_primitive.link b/doc/examples/is_primitive.link index ae58b2d7c9..4571494d9a 100644 --- a/doc/examples/is_primitive.link +++ b/doc/examples/is_primitive.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/is_primitive.output b/doc/examples/is_primitive.output index 635db6e348..77af24c009 100644 --- a/doc/examples/is_primitive.output +++ b/doc/examples/is_primitive.output @@ -6,3 +6,4 @@ true false false true +true diff --git a/doc/examples/is_string.cpp b/doc/examples/is_string.cpp index 2679cd1c5f..8bab27945c 100644 --- a/doc/examples/is_string.cpp +++ b/doc/examples/is_string.cpp @@ -14,6 +14,7 @@ int main() json j_object = {{"one", 1}, {"two", 2}}; json j_array = {1, 2, 4, 8, 16}; json j_string = "Hello, world"; + json j_binary = json::binary_array({1, 2, 3}); // call is_string() std::cout << std::boolalpha; @@ -25,4 +26,5 @@ int main() std::cout << j_object.is_string() << '\n'; std::cout << j_array.is_string() << '\n'; std::cout << j_string.is_string() << '\n'; + std::cout << j_binary.is_string() << '\n'; } diff --git a/doc/examples/is_string.link b/doc/examples/is_string.link index 92b05e7580..9d126a95ba 100644 --- a/doc/examples/is_string.link +++ b/doc/examples/is_string.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/is_string.output b/doc/examples/is_string.output index 672eb43858..6446f18784 100644 --- a/doc/examples/is_string.output +++ b/doc/examples/is_string.output @@ -6,3 +6,4 @@ false false false true +false diff --git a/doc/examples/is_structured.cpp b/doc/examples/is_structured.cpp index 33e2bbd059..b022285b2e 100644 --- a/doc/examples/is_structured.cpp +++ b/doc/examples/is_structured.cpp @@ -14,6 +14,7 @@ int main() json j_object = {{"one", 1}, {"two", 2}}; json j_array = {1, 2, 4, 8, 16}; json j_string = "Hello, world"; + json j_binary = json::binary_array({1, 2, 3}); // call is_structured() std::cout << std::boolalpha; @@ -25,4 +26,5 @@ int main() std::cout << j_object.is_structured() << '\n'; std::cout << j_array.is_structured() << '\n'; std::cout << j_string.is_structured() << '\n'; + std::cout << j_binary.is_structured() << '\n'; } diff --git a/doc/examples/is_structured.link b/doc/examples/is_structured.link index 44e06e9ffc..f3eb6272cc 100644 --- a/doc/examples/is_structured.link +++ b/doc/examples/is_structured.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/is_structured.output b/doc/examples/is_structured.output index e1186dd8f8..625c124b52 100644 --- a/doc/examples/is_structured.output +++ b/doc/examples/is_structured.output @@ -6,3 +6,4 @@ false true true false +false diff --git a/doc/examples/sax_parse.cpp b/doc/examples/sax_parse.cpp index 82a99f7de1..45273eb6c2 100644 --- a/doc/examples/sax_parse.cpp +++ b/doc/examples/sax_parse.cpp @@ -79,7 +79,7 @@ class sax_event_consumer : public json::json_sax_t return true; } - bool binary(binary_t& val) override + bool binary(json::binary_t& val) override { events.push_back("binary"); return true; diff --git a/doc/examples/sax_parse.link b/doc/examples/sax_parse.link index c51f517c8e..034b48c919 100644 --- a/doc/examples/sax_parse.link +++ b/doc/examples/sax_parse.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/index.md b/doc/index.md index f2de2e3a71..3691461d8a 100644 --- a/doc/index.md +++ b/doc/index.md @@ -22,12 +22,14 @@ These pages contain the API documentation of JSON for Modern C++, a C++11 header @link nlohmann::basic_json::is_object is_object @endlink, @link nlohmann::basic_json::is_array is_array @endlink, @link nlohmann::basic_json::is_string is_string @endlink, - @link nlohmann::basic_json::is_discarded is_discarded @endlink -- check for value type + @link nlohmann::basic_json::is_discarded is_discarded @endlink, + @link nlohmann::basic_json::is_binary is_binary @endlink -- check for value type - @link nlohmann::basic_json::operator value_t() const operator value_t @endlink -- type of the value (implicit conversion) - value access - @link nlohmann::basic_json::get get @endlink -- get a value - @link nlohmann::basic_json::get_ptr get_ptr @endlink -- get a value pointer - @link nlohmann::basic_json::get_ref get_ref @endlink -- get a value reference + - @link nlohmann::basic_json::get_binary get_binary @endlink -- get a binary value - @link nlohmann::basic_json::operator ValueType() const operator ValueType @endlink -- get a value (implicit conversion) - @link nlohmann::basic_json::value value @endlink -- get a value from an object and return default value if key is not present - exceptions @@ -67,8 +69,9 @@ These pages contain the API documentation of JSON for Modern C++, a C++11 header - @link nlohmann::basic_json::number_integer_t signed integers @endlink - @link nlohmann::basic_json::number_unsigned_t unsigned integers @endlink - @link nlohmann::basic_json::number_float_t floating-point @endlink + - @link nlohmann::basic_json::binary_t binary values @endlink - further JSON standards - - @link nlohmann::json_pointer JSON Pointer @endlink (REF 6901) + - @link nlohmann::json_pointer JSON Pointer @endlink (RFC 6901) - @link nlohmann::basic_json::patch JSON Patch @endlink (RFC 6902) - @link nlohmann::basic_json::merge_patch JSON Merge Patch @endlink (RFC 7396) @@ -324,7 +327,7 @@ Note that this table only lists those exceptions thrown due to the type. For ins -@copyright Copyright © 2013-2019 Niels Lohmann. The code is licensed under the [MIT License](http://opensource.org/licenses/MIT). +@copyright Copyright © 2013-2020 Niels Lohmann. The code is licensed under the [MIT License](http://opensource.org/licenses/MIT). @author [Niels Lohmann](http://nlohmann.me) @see https://github.com/nlohmann/json to download the source code diff --git a/include/nlohmann/detail/conversions/from_json.hpp b/include/nlohmann/detail/conversions/from_json.hpp index b6105b0582..e8731f2235 100644 --- a/include/nlohmann/detail/conversions/from_json.hpp +++ b/include/nlohmann/detail/conversions/from_json.hpp @@ -228,7 +228,7 @@ template ::value and not is_constructible_object_type::value and not is_constructible_string_type::value and - not std::is_same::value and + not std::is_same::value and not is_basic_json::value, int > = 0 > auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr) @@ -246,14 +246,14 @@ void()) } template -void from_json(const BasicJsonType& j, typename BasicJsonType::internal_binary_t& bin) +void from_json(const BasicJsonType& j, typename BasicJsonType::binary_t& bin) { if (JSON_HEDLEY_UNLIKELY(not j.is_binary())) { JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(j.type_name()))); } - bin = *j.template get_ptr(); + bin = *j.template get_ptr(); } template struct external_constructor { template - static void construct(BasicJsonType& j, const typename BasicJsonType::internal_binary_t& b) + static void construct(BasicJsonType& j, const typename BasicJsonType::binary_t& b) { j.m_type = value_t::binary; - typename BasicJsonType::internal_binary_t value{b}; + typename BasicJsonType::binary_t value{b}; j.m_value = value; j.assert_invariant(); } template - static void construct(BasicJsonType& j, typename BasicJsonType::internal_binary_t&& b) + static void construct(BasicJsonType& j, typename BasicJsonType::binary_t&& b) { j.m_type = value_t::binary; - typename BasicJsonType::internal_binary_t value{std::move(b)}; + typename BasicJsonType::binary_t value{std::move(b)}; j.m_value = value; j.assert_invariant(); } @@ -280,7 +280,7 @@ template ::value and not is_compatible_object_type::value and not is_compatible_string_type::value and - not std::is_same::value and + not std::is_same::value and not is_basic_json::value, int> = 0> void to_json(BasicJsonType& j, const CompatibleArrayType& arr) @@ -289,7 +289,7 @@ void to_json(BasicJsonType& j, const CompatibleArrayType& arr) } template -void to_json(BasicJsonType& j, const typename BasicJsonType::internal_binary_t& bin) +void to_json(BasicJsonType& j, const typename BasicJsonType::binary_t& bin) { external_constructor::construct(j, bin); } diff --git a/include/nlohmann/detail/input/binary_reader.hpp b/include/nlohmann/detail/input/binary_reader.hpp index 35d7dbd633..e859c7d12d 100644 --- a/include/nlohmann/detail/input/binary_reader.hpp +++ b/include/nlohmann/detail/input/binary_reader.hpp @@ -52,7 +52,7 @@ class binary_reader using number_unsigned_t = typename BasicJsonType::number_unsigned_t; using number_float_t = typename BasicJsonType::number_float_t; using string_t = typename BasicJsonType::string_t; - using internal_binary_t = typename BasicJsonType::internal_binary_t; + using binary_t = typename BasicJsonType::binary_t; using json_sax_t = SAX; public: @@ -219,7 +219,7 @@ class binary_reader @return `true` if the byte array was successfully parsed */ template - bool get_bson_binary(const NumberType len, internal_binary_t& result) + bool get_bson_binary(const NumberType len, binary_t& result) { if (JSON_HEDLEY_UNLIKELY(len < 0)) { @@ -276,7 +276,7 @@ class binary_reader case 0x05: // binary { std::int32_t len; - internal_binary_t value; + binary_t value; return get_number(input_format_t::bson, len) and get_bson_binary(len, value) and sax->binary(value); } @@ -532,7 +532,7 @@ class binary_reader case 0x5B: // Binary data (eight-byte uint64_t for n follow) case 0x5F: // Binary data (indefinite length) { - internal_binary_t b; + binary_t b; return get_cbor_binary(b) and sax->binary(b); } @@ -862,7 +862,7 @@ class binary_reader @return whether byte array creation completed */ - bool get_cbor_binary(internal_binary_t& result) + bool get_cbor_binary(binary_t& result) { if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::cbor, "binary"))) { @@ -932,7 +932,7 @@ class binary_reader { while (get() != 0xFF) { - internal_binary_t chunk; + binary_t chunk; if (not get_cbor_binary(chunk)) { return false; @@ -1282,7 +1282,7 @@ class binary_reader case 0xD7: // fixext 8 case 0xD8: // fixext 16 { - internal_binary_t b; + binary_t b; return get_msgpack_binary(b) and sax->binary(b); } @@ -1505,7 +1505,7 @@ class binary_reader @return whether byte array creation completed */ - bool get_msgpack_binary(internal_binary_t& result) + bool get_msgpack_binary(binary_t& result) { // helper function to set the subtype auto assign_and_return_true = [&result](std::int8_t subtype) @@ -2223,7 +2223,7 @@ class binary_reader template bool get_binary(const input_format_t format, const NumberType len, - internal_binary_t& result) + binary_t& result) { bool success = true; std::generate_n(std::back_inserter(result), len, [this, &success, &format]() diff --git a/include/nlohmann/detail/input/json_sax.hpp b/include/nlohmann/detail/input/json_sax.hpp index 54b53fd341..25be7e4b85 100644 --- a/include/nlohmann/detail/input/json_sax.hpp +++ b/include/nlohmann/detail/input/json_sax.hpp @@ -27,7 +27,7 @@ struct json_sax using number_unsigned_t = typename BasicJsonType::number_unsigned_t; using number_float_t = typename BasicJsonType::number_float_t; using string_t = typename BasicJsonType::string_t; - using internal_binary_t = typename BasicJsonType::internal_binary_t; + using binary_t = typename BasicJsonType::binary_t; /*! @brief a null value was read @@ -78,7 +78,7 @@ struct json_sax @return whether parsing should proceed @note It is safe to move the passed binary. */ - virtual bool binary(internal_binary_t& val) = 0; + virtual bool binary(binary_t& val) = 0; /*! @brief the beginning of an object was read @@ -154,7 +154,7 @@ class json_sax_dom_parser using number_unsigned_t = typename BasicJsonType::number_unsigned_t; using number_float_t = typename BasicJsonType::number_float_t; using string_t = typename BasicJsonType::string_t; - using internal_binary_t = typename BasicJsonType::internal_binary_t; + using binary_t = typename BasicJsonType::binary_t; /*! @param[in, out] r reference to a JSON value that is manipulated while @@ -208,7 +208,7 @@ class json_sax_dom_parser return true; } - bool binary(internal_binary_t& val) + bool binary(binary_t& val) { handle_value(std::move(val)); return true; @@ -343,7 +343,7 @@ class json_sax_dom_callback_parser using number_unsigned_t = typename BasicJsonType::number_unsigned_t; using number_float_t = typename BasicJsonType::number_float_t; using string_t = typename BasicJsonType::string_t; - using internal_binary_t = typename BasicJsonType::internal_binary_t; + using binary_t = typename BasicJsonType::binary_t; using parser_callback_t = typename BasicJsonType::parser_callback_t; using parse_event_t = typename BasicJsonType::parse_event_t; @@ -398,7 +398,7 @@ class json_sax_dom_callback_parser return true; } - bool binary(internal_binary_t& val) + bool binary(binary_t& val) { handle_value(std::move(val)); return true; @@ -654,7 +654,7 @@ class json_sax_acceptor using number_unsigned_t = typename BasicJsonType::number_unsigned_t; using number_float_t = typename BasicJsonType::number_float_t; using string_t = typename BasicJsonType::string_t; - using internal_binary_t = typename BasicJsonType::internal_binary_t; + using binary_t = typename BasicJsonType::binary_t; bool null() { @@ -686,7 +686,7 @@ class json_sax_acceptor return true; } - bool binary(internal_binary_t& /*unused*/) + bool binary(binary_t& /*unused*/) { return true; } diff --git a/include/nlohmann/detail/iterators/internal_iterator.hpp b/include/nlohmann/detail/iterators/internal_iterator.hpp index 71539a6acf..742df483a1 100644 --- a/include/nlohmann/detail/iterators/internal_iterator.hpp +++ b/include/nlohmann/detail/iterators/internal_iterator.hpp @@ -19,7 +19,7 @@ template struct internal_iterator /// iterator for JSON arrays typename BasicJsonType::array_t::iterator array_iterator {}; /// iterator for JSON binary arrays - typename BasicJsonType::binary_t::iterator binary_iterator {}; + typename BasicJsonType::binary_t::container_type::iterator binary_iterator {}; /// generic iterator for all other types primitive_iterator_t primitive_iterator {}; }; diff --git a/include/nlohmann/detail/output/binary_writer.hpp b/include/nlohmann/detail/output/binary_writer.hpp index 1feb95dc64..4478ab3407 100644 --- a/include/nlohmann/detail/output/binary_writer.hpp +++ b/include/nlohmann/detail/output/binary_writer.hpp @@ -27,7 +27,7 @@ template class binary_writer { using string_t = typename BasicJsonType::string_t; - using internal_binary_t = typename BasicJsonType::internal_binary_t; + using binary_t = typename BasicJsonType::binary_t; public: /*! @@ -1080,7 +1080,7 @@ class binary_writer /*! @return The size of the BSON-encoded binary array @a value */ - static std::size_t calc_bson_binary_size(const typename BasicJsonType::internal_binary_t& value) + static std::size_t calc_bson_binary_size(const typename BasicJsonType::binary_t& value) { return sizeof(std::int32_t) + value.size() + 1ul; } @@ -1108,7 +1108,7 @@ class binary_writer @brief Writes a BSON element with key @a name and binary value @a value */ void write_bson_binary(const string_t& name, - const internal_binary_t& value) + const binary_t& value) { write_bson_entry_header(name, 0x05); diff --git a/include/nlohmann/detail/output/serializer.hpp b/include/nlohmann/detail/output/serializer.hpp index 75ce6783c5..dc963f5370 100644 --- a/include/nlohmann/detail/output/serializer.hpp +++ b/include/nlohmann/detail/output/serializer.hpp @@ -45,7 +45,7 @@ class serializer using number_float_t = typename BasicJsonType::number_float_t; using number_integer_t = typename BasicJsonType::number_integer_t; using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using binary_t = typename BasicJsonType::binary_t; + using binary_char_t = typename BasicJsonType::binary_t::value_type; static constexpr std::uint8_t UTF8_ACCEPT = 0; static constexpr std::uint8_t UTF8_REJECT = 1; @@ -624,7 +624,7 @@ class serializer template::value or std::is_same::value or - std::is_same::value, + std::is_same::value, int> = 0> void dump_integer(NumberType x) { diff --git a/include/nlohmann/detail/wrapped_binary_t.hpp b/include/nlohmann/detail/wrapped_binary_t.hpp index 230641bda8..6edd7b52ec 100644 --- a/include/nlohmann/detail/wrapped_binary_t.hpp +++ b/include/nlohmann/detail/wrapped_binary_t.hpp @@ -19,36 +19,51 @@ template class wrapped_binary_t : public BinaryType { public: - using binary_t = BinaryType; + /// the type of the underlying container + using container_type = BinaryType; - wrapped_binary_t() noexcept(noexcept(binary_t())) - : binary_t() + wrapped_binary_t() noexcept(noexcept(container_type())) + : container_type() {} - wrapped_binary_t(const binary_t& b) noexcept(noexcept(binary_t(b))) - : binary_t(b) + wrapped_binary_t(const container_type& b) noexcept(noexcept(container_type(b))) + : container_type(b) {} - wrapped_binary_t(binary_t&& b) noexcept(noexcept(binary_t(std::move(b)))) - : binary_t(std::move(b)) + wrapped_binary_t(container_type&& b) noexcept(noexcept(container_type(std::move(b)))) + : container_type(std::move(b)) {} - wrapped_binary_t(const binary_t& b, - std::uint8_t subtype) noexcept(noexcept(binary_t(b))) - : binary_t(b) + wrapped_binary_t(const container_type& b, + std::uint8_t subtype) noexcept(noexcept(container_type(b))) + : container_type(b) , m_subtype(subtype) , m_has_subtype(true) {} - wrapped_binary_t(binary_t&& b, std::uint8_t subtype) noexcept(noexcept(binary_t(std::move(b)))) - : binary_t(std::move(b)) + wrapped_binary_t(container_type&& b, std::uint8_t subtype) noexcept(noexcept(container_type(std::move(b)))) + : container_type(std::move(b)) , m_subtype(subtype) , m_has_subtype(true) {} /*! - @brief set the subtype - @param subtype subtype to set (implementation specific) + @brief sets the binary subtype + + Sets the binary subtype of the value, also flags a binary JSON value as + having a subtype, which has implications for serialization. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @sa @ref subtype() -- return the binary subtype + @sa @ref clear_subtype() -- clears the binary subtype + @sa @ref has_subtype() -- returns whether or not the binary value has a + subtype + + @since version 3.8.0 */ void set_subtype(std::uint8_t subtype) noexcept { @@ -57,8 +72,25 @@ class wrapped_binary_t : public BinaryType } /*! - @brief get the subtype - @return subtype (implementation specific) + @brief return the binary subtype + + Returns the numerical subtype of the value if it has a subtype. If it does + not have a subtype, this function will return size_t(-1) as a sentinel + value. + + @return the numerical subtype of the binary value + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @sa @ref set_subtype() -- sets the binary subtype + @sa @ref clear_subtype() -- clears the binary subtype + @sa @ref has_subtype() -- returns whether or not the binary value has a + subtype + + @since version 3.8.0 */ constexpr std::uint8_t subtype() const noexcept { @@ -66,8 +98,20 @@ class wrapped_binary_t : public BinaryType } /*! - @brief get whether a subtype was set - @return whether a subtype was set + @brief return whether the value has a subtype + + @return whether the value has a subtype + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @sa @ref subtype() -- return the binary subtype + @sa @ref set_subtype() -- sets the binary subtype + @sa @ref clear_subtype() -- clears the binary subtype + + @since version 3.8.0 */ constexpr bool has_subtype() const noexcept { @@ -75,7 +119,23 @@ class wrapped_binary_t : public BinaryType } /*! - @brief clear the subtype + @brief clears the binary subtype + + Clears the binary subtype and flags the value as not having a subtype, which + has implications for serialization; for instance MessagePack will prefer the + bin family over the ext family. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @sa @ref subtype() -- return the binary subtype + @sa @ref set_subtype() -- sets the binary subtype + @sa @ref has_subtype() -- returns whether or not the binary value has a + subtype + + @since version 3.8.0 */ void clear_subtype() noexcept { diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 2b976d91b4..fc849a3883 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -884,23 +884,7 @@ class basic_json for any access to array values, a pointer of the type `binary_t*` must be dereferenced. - @sa @ref array_t -- type for an array value - - @since version 3.8.0 - */ - using binary_t = BinaryType; - - /*! - @brief binary array with a binary type - - This type is used to store binary types internally. It wrapps the template - type `BinaryType` (@ref binary_t) and adds a subtype to allow to distinguish - different binary types from different formats. - - While @ref binary_t is used to define how binary values are stored, this - type is used to access binary values once they are parsed. - - Notes on subtypes: + #### Notes on subtypes - CBOR - Binary values are represented as byte strings. No subtypes are @@ -911,13 +895,15 @@ class basic_json is used. For other sizes, the ext family (ext8, ext16, ext32) is used. The subtype is then added as singed 8-bit integer. - If no subtype is given, the bin family (bin8, bin16, bin32) is used. - - BSON + - BSON - If a subtype is given, it is used and added as unsigned 8-bit integer. - If no subtype is given, the generic binary subtype 0x00 is used. @sa @ref binary_array -- create a binary array + + @since version 3.8.0 */ - using internal_binary_t = nlohmann::detail::wrapped_binary_t; + using binary_t = nlohmann::detail::wrapped_binary_t; /// @} private: @@ -978,7 +964,7 @@ class basic_json /// string (stored with pointer to save storage) string_t* string; /// binary (stored with pointer to save storage) - internal_binary_t* binary; + binary_t* binary; /// boolean boolean_t boolean; /// number (integer) @@ -1023,7 +1009,7 @@ class basic_json case value_t::binary: { - binary = create(); + binary = create(); break; } @@ -1106,27 +1092,27 @@ class basic_json } /// constructor for binary arrays - json_value(const binary_t& value) + json_value(const typename binary_t::container_type& value) { - binary = create(value); + binary = create(value); } /// constructor for rvalue binary arrays - json_value(binary_t&& value) + json_value(typename binary_t::container_type&& value) { - binary = create(std::move(value)); + binary = create(std::move(value)); } /// constructor for binary arrays (internal type) - json_value(const internal_binary_t& value) + json_value(const binary_t& value) { - binary = create(value); + binary = create(value); } /// constructor for rvalue binary arrays (internal type) - json_value(internal_binary_t&& value) + json_value(binary_t&& value) { - binary = create(std::move(value)); + binary = create(std::move(value)); } void destroy(value_t t) noexcept @@ -1206,7 +1192,7 @@ class basic_json case value_t::binary: { - AllocatorType alloc; + AllocatorType alloc; std::allocator_traits::destroy(alloc, binary); std::allocator_traits::deallocate(alloc, binary, 1); break; @@ -1492,7 +1478,7 @@ class basic_json using other_string_t = typename BasicJsonType::string_t; using other_object_t = typename BasicJsonType::object_t; using other_array_t = typename BasicJsonType::array_t; - using other_binary_t = typename BasicJsonType::internal_binary_t; + using other_binary_t = typename BasicJsonType::binary_t; switch (val.type()) { @@ -1686,7 +1672,7 @@ class basic_json @since version 3.8.0 */ JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json binary_array(const binary_t& init) + static basic_json binary_array(const typename binary_t::container_type& init) { auto res = basic_json(); res.m_type = value_t::binary; @@ -1695,11 +1681,11 @@ class basic_json } JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json binary_array(const binary_t& init, std::uint8_t subtype) + static basic_json binary_array(const typename binary_t::container_type& init, std::uint8_t subtype) { auto res = basic_json(); res.m_type = value_t::binary; - res.m_value = internal_binary_t(init, subtype); + res.m_value = binary_t(init, subtype); return res; } @@ -1731,7 +1717,7 @@ class basic_json @since version 3.8.0 */ JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json binary_array(binary_t&& init) + static basic_json binary_array(typename binary_t::container_type&& init) { auto res = basic_json(); res.m_type = value_t::binary; @@ -1740,11 +1726,11 @@ class basic_json } JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json binary_array(binary_t&& init, std::uint8_t subtype) + static basic_json binary_array(typename binary_t::container_type&& init, std::uint8_t subtype) { auto res = basic_json(); res.m_type = value_t::binary; - res.m_value = internal_binary_t(std::move(init), subtype); + res.m_value = binary_t(std::move(init), subtype); return res; } @@ -2794,13 +2780,13 @@ class basic_json } /// get a pointer to the value (binary) - internal_binary_t* get_impl_ptr(internal_binary_t* /*unused*/) noexcept + binary_t* get_impl_ptr(binary_t* /*unused*/) noexcept { return is_binary() ? m_value.binary : nullptr; } /// get a pointer to the value (binary) - constexpr const internal_binary_t* get_impl_ptr(const internal_binary_t* /*unused*/) const noexcept + constexpr const binary_t* get_impl_ptr(const binary_t* /*unused*/) const noexcept { return is_binary() ? m_value.binary : nullptr; } @@ -3230,6 +3216,36 @@ class basic_json return get(); } + /*! + @return reference to the binary value + + @throw type_error.302 if the value is not binary + + @sa @ref is_binary() to check if the value is binary + + @since version 3.8.0 + */ + binary_t& get_binary() + { + if (not is_binary()) + { + JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(type_name()))); + } + + return *get_ptr(); + } + + /// @copydoc get_binary() + const binary_t& get_binary() const + { + if (not is_binary()) + { + JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(type_name()))); + } + + return *get_ptr(); + } + /// @} @@ -3852,118 +3868,6 @@ class basic_json return value(ptr, string_t(default_value)); } - /*! - @brief return the binary subtype - - Returns the numerical subtype of the JSON value, if the JSON value is of - type "binary", and it has a subtype. If it does not have a subtype (or the - object is not of type binary) this function will return size_t(-1) as a - sentinel value. - - @return the numerical subtype of the binary JSON value - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @sa @ref set_subtype() -- sets the binary subtype - @sa @ref clear_subtype() -- clears the binary subtype - @sa @ref has_subtype() -- returns whether or not the binary value has a - subtype - - @since version 3.8.0 - */ - std::size_t get_subtype() const noexcept - { - if (is_binary() and m_value.binary->has_subtype) - { - return m_value.binary->subtype; - } - - return std::size_t(-1); - } - - /*! - @brief sets the binary subtype - - Sets the binary subtype of the JSON value, also flags a binary JSON value as - having a subtype, which has implications for serialization to msgpack (will - prefer ext file formats over bin). If the JSON value is not a binary value, - this function does nothing. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @sa @ref get_subtype() -- return the binary subtype - @sa @ref clear_subtype() -- clears the binary subtype - @sa @ref has_subtype() -- returns whether or not the binary value has a - subtype - - @since version 3.8.0 - */ - - void set_subtype(std::uint8_t subtype) noexcept - { - if (is_binary()) - { - m_value.binary->set_subtype(subtype); - } - } - - /*! - @brief clears the binary subtype - - Clears the binary subtype of the JSON value, also flags a binary JSON value - as not having a subtype, which has implications for serialization to msgpack - (will prefer bin file formats over ext). If the JSON value is not a binary - value, this function does nothing. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @sa @ref get_subtype() -- return the binary subtype - @sa @ref set_subtype() -- sets the binary subtype - @sa @ref has_subtype() -- returns whether or not the binary value has a - subtype - - @since version 3.8.0 - */ - void clear_subtype() noexcept - { - if (is_binary()) - { - m_value.binary->clear_subtype(); - } - } - - /*! - @brief return whether or not the binary subtype has a value - - Returns whether or not the binary subtype has a value. - - @return whether or not the binary subtype has a value. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @sa @ref get_subtype() -- return the binary subtype - @sa @ref set_subtype() -- sets the binary subtype - @sa @ref clear_subtype() -- clears the binary subtype - - @since version 3.8.0 - */ - bool has_subtype() const noexcept - { - return is_binary() and m_value.binary->has_subtype(); - } - /*! @brief access the first element @@ -4133,7 +4037,7 @@ class basic_json } else if (is_binary()) { - AllocatorType alloc; + AllocatorType alloc; std::allocator_traits::destroy(alloc, m_value.binary); std::allocator_traits::deallocate(alloc, m_value.binary, 1); m_value.binary = nullptr; @@ -4247,7 +4151,7 @@ class basic_json } else if (is_binary()) { - AllocatorType alloc; + AllocatorType alloc; std::allocator_traits::destroy(alloc, m_value.binary); std::allocator_traits::deallocate(alloc, m_value.binary, 1); m_value.binary = nullptr; @@ -6087,6 +5991,20 @@ class basic_json } } + /// @copydoc swap(binary_t) + void swap(typename binary_t::container_type& other) + { + // swap only works for strings + if (JSON_HEDLEY_LIKELY(is_binary())) + { + std::swap(*(m_value.binary), other); + } + else + { + JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); + } + } + /// @} public: diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 1a8aa14cbd..0033be2316 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -3448,7 +3448,7 @@ template ::value and not is_constructible_object_type::value and not is_constructible_string_type::value and - not std::is_same::value and + not std::is_same::value and not is_basic_json::value, int > = 0 > auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr) @@ -3466,14 +3466,14 @@ void()) } template -void from_json(const BasicJsonType& j, typename BasicJsonType::internal_binary_t& bin) +void from_json(const BasicJsonType& j, typename BasicJsonType::binary_t& bin) { if (JSON_HEDLEY_UNLIKELY(not j.is_binary())) { JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(j.type_name()))); } - bin = *j.template get_ptr(); + bin = *j.template get_ptr(); } template struct external_constructor { template - static void construct(BasicJsonType& j, const typename BasicJsonType::internal_binary_t& b) + static void construct(BasicJsonType& j, const typename BasicJsonType::binary_t& b) { j.m_type = value_t::binary; - typename BasicJsonType::internal_binary_t value{b}; + typename BasicJsonType::binary_t value{b}; j.m_value = value; j.assert_invariant(); } template - static void construct(BasicJsonType& j, typename BasicJsonType::internal_binary_t&& b) + static void construct(BasicJsonType& j, typename BasicJsonType::binary_t&& b) { j.m_type = value_t::binary; - typename BasicJsonType::internal_binary_t value{std::move(b)}; + typename BasicJsonType::binary_t value{std::move(b)}; j.m_value = value; j.assert_invariant(); } @@ -4085,7 +4085,7 @@ template ::value and not is_compatible_object_type::value and not is_compatible_string_type::value and - not std::is_same::value and + not std::is_same::value and not is_basic_json::value, int> = 0> void to_json(BasicJsonType& j, const CompatibleArrayType& arr) @@ -4094,7 +4094,7 @@ void to_json(BasicJsonType& j, const CompatibleArrayType& arr) } template -void to_json(BasicJsonType& j, const typename BasicJsonType::internal_binary_t& bin) +void to_json(BasicJsonType& j, const typename BasicJsonType::binary_t& bin) { external_constructor::construct(j, bin); } @@ -4764,7 +4764,7 @@ struct json_sax using number_unsigned_t = typename BasicJsonType::number_unsigned_t; using number_float_t = typename BasicJsonType::number_float_t; using string_t = typename BasicJsonType::string_t; - using internal_binary_t = typename BasicJsonType::internal_binary_t; + using binary_t = typename BasicJsonType::binary_t; /*! @brief a null value was read @@ -4815,7 +4815,7 @@ struct json_sax @return whether parsing should proceed @note It is safe to move the passed binary. */ - virtual bool binary(internal_binary_t& val) = 0; + virtual bool binary(binary_t& val) = 0; /*! @brief the beginning of an object was read @@ -4891,7 +4891,7 @@ class json_sax_dom_parser using number_unsigned_t = typename BasicJsonType::number_unsigned_t; using number_float_t = typename BasicJsonType::number_float_t; using string_t = typename BasicJsonType::string_t; - using internal_binary_t = typename BasicJsonType::internal_binary_t; + using binary_t = typename BasicJsonType::binary_t; /*! @param[in, out] r reference to a JSON value that is manipulated while @@ -4945,7 +4945,7 @@ class json_sax_dom_parser return true; } - bool binary(internal_binary_t& val) + bool binary(binary_t& val) { handle_value(std::move(val)); return true; @@ -5080,7 +5080,7 @@ class json_sax_dom_callback_parser using number_unsigned_t = typename BasicJsonType::number_unsigned_t; using number_float_t = typename BasicJsonType::number_float_t; using string_t = typename BasicJsonType::string_t; - using internal_binary_t = typename BasicJsonType::internal_binary_t; + using binary_t = typename BasicJsonType::binary_t; using parser_callback_t = typename BasicJsonType::parser_callback_t; using parse_event_t = typename BasicJsonType::parse_event_t; @@ -5135,7 +5135,7 @@ class json_sax_dom_callback_parser return true; } - bool binary(internal_binary_t& val) + bool binary(binary_t& val) { handle_value(std::move(val)); return true; @@ -5391,7 +5391,7 @@ class json_sax_acceptor using number_unsigned_t = typename BasicJsonType::number_unsigned_t; using number_float_t = typename BasicJsonType::number_float_t; using string_t = typename BasicJsonType::string_t; - using internal_binary_t = typename BasicJsonType::internal_binary_t; + using binary_t = typename BasicJsonType::binary_t; bool null() { @@ -5423,7 +5423,7 @@ class json_sax_acceptor return true; } - bool binary(internal_binary_t& /*unused*/) + bool binary(binary_t& /*unused*/) { return true; } @@ -5645,7 +5645,7 @@ class binary_reader using number_unsigned_t = typename BasicJsonType::number_unsigned_t; using number_float_t = typename BasicJsonType::number_float_t; using string_t = typename BasicJsonType::string_t; - using internal_binary_t = typename BasicJsonType::internal_binary_t; + using binary_t = typename BasicJsonType::binary_t; using json_sax_t = SAX; public: @@ -5812,7 +5812,7 @@ class binary_reader @return `true` if the byte array was successfully parsed */ template - bool get_bson_binary(const NumberType len, internal_binary_t& result) + bool get_bson_binary(const NumberType len, binary_t& result) { if (JSON_HEDLEY_UNLIKELY(len < 0)) { @@ -5869,7 +5869,7 @@ class binary_reader case 0x05: // binary { std::int32_t len; - internal_binary_t value; + binary_t value; return get_number(input_format_t::bson, len) and get_bson_binary(len, value) and sax->binary(value); } @@ -6125,7 +6125,7 @@ class binary_reader case 0x5B: // Binary data (eight-byte uint64_t for n follow) case 0x5F: // Binary data (indefinite length) { - internal_binary_t b; + binary_t b; return get_cbor_binary(b) and sax->binary(b); } @@ -6455,7 +6455,7 @@ class binary_reader @return whether byte array creation completed */ - bool get_cbor_binary(internal_binary_t& result) + bool get_cbor_binary(binary_t& result) { if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::cbor, "binary"))) { @@ -6525,7 +6525,7 @@ class binary_reader { while (get() != 0xFF) { - internal_binary_t chunk; + binary_t chunk; if (not get_cbor_binary(chunk)) { return false; @@ -6875,7 +6875,7 @@ class binary_reader case 0xD7: // fixext 8 case 0xD8: // fixext 16 { - internal_binary_t b; + binary_t b; return get_msgpack_binary(b) and sax->binary(b); } @@ -7098,7 +7098,7 @@ class binary_reader @return whether byte array creation completed */ - bool get_msgpack_binary(internal_binary_t& result) + bool get_msgpack_binary(binary_t& result) { // helper function to set the subtype auto assign_and_return_true = [&result](std::int8_t subtype) @@ -7816,7 +7816,7 @@ class binary_reader template bool get_binary(const input_format_t format, const NumberType len, - internal_binary_t& result) + binary_t& result) { bool success = true; std::generate_n(std::back_inserter(result), len, [this, &success, &format]() @@ -10089,7 +10089,7 @@ template struct internal_iterator /// iterator for JSON arrays typename BasicJsonType::array_t::iterator array_iterator {}; /// iterator for JSON binary arrays - typename BasicJsonType::binary_t::iterator binary_iterator {}; + typename BasicJsonType::binary_t::container_type::iterator binary_iterator {}; /// generic iterator for all other types primitive_iterator_t primitive_iterator {}; }; @@ -12080,7 +12080,7 @@ template class binary_writer { using string_t = typename BasicJsonType::string_t; - using internal_binary_t = typename BasicJsonType::internal_binary_t; + using binary_t = typename BasicJsonType::binary_t; public: /*! @@ -13133,7 +13133,7 @@ class binary_writer /*! @return The size of the BSON-encoded binary array @a value */ - static std::size_t calc_bson_binary_size(const typename BasicJsonType::internal_binary_t& value) + static std::size_t calc_bson_binary_size(const typename BasicJsonType::binary_t& value) { return sizeof(std::int32_t) + value.size() + 1ul; } @@ -13161,7 +13161,7 @@ class binary_writer @brief Writes a BSON element with key @a name and binary value @a value */ void write_bson_binary(const string_t& name, - const internal_binary_t& value) + const binary_t& value) { write_bson_entry_header(name, 0x05); @@ -14789,7 +14789,7 @@ class serializer using number_float_t = typename BasicJsonType::number_float_t; using number_integer_t = typename BasicJsonType::number_integer_t; using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using binary_t = typename BasicJsonType::binary_t; + using binary_char_t = typename BasicJsonType::binary_t::value_type; static constexpr std::uint8_t UTF8_ACCEPT = 0; static constexpr std::uint8_t UTF8_REJECT = 1; @@ -15368,7 +15368,7 @@ class serializer template::value or std::is_same::value or - std::is_same::value, + std::is_same::value, int> = 0> void dump_integer(NumberType x) { @@ -15667,36 +15667,51 @@ template class wrapped_binary_t : public BinaryType { public: - using binary_t = BinaryType; + /// the type of the underlying container + using container_type = BinaryType; - wrapped_binary_t() noexcept(noexcept(binary_t())) - : binary_t() + wrapped_binary_t() noexcept(noexcept(container_type())) + : container_type() {} - wrapped_binary_t(const binary_t& b) noexcept(noexcept(binary_t(b))) - : binary_t(b) + wrapped_binary_t(const container_type& b) noexcept(noexcept(container_type(b))) + : container_type(b) {} - wrapped_binary_t(binary_t&& b) noexcept(noexcept(binary_t(std::move(b)))) - : binary_t(std::move(b)) + wrapped_binary_t(container_type&& b) noexcept(noexcept(container_type(std::move(b)))) + : container_type(std::move(b)) {} - wrapped_binary_t(const binary_t& b, - std::uint8_t subtype) noexcept(noexcept(binary_t(b))) - : binary_t(b) + wrapped_binary_t(const container_type& b, + std::uint8_t subtype) noexcept(noexcept(container_type(b))) + : container_type(b) , m_subtype(subtype) , m_has_subtype(true) {} - wrapped_binary_t(binary_t&& b, std::uint8_t subtype) noexcept(noexcept(binary_t(std::move(b)))) - : binary_t(std::move(b)) + wrapped_binary_t(container_type&& b, std::uint8_t subtype) noexcept(noexcept(container_type(std::move(b)))) + : container_type(std::move(b)) , m_subtype(subtype) , m_has_subtype(true) {} /*! - @brief set the subtype - @param subtype subtype to set (implementation specific) + @brief sets the binary subtype + + Sets the binary subtype of the value, also flags a binary JSON value as + having a subtype, which has implications for serialization. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @sa @ref subtype() -- return the binary subtype + @sa @ref clear_subtype() -- clears the binary subtype + @sa @ref has_subtype() -- returns whether or not the binary value has a + subtype + + @since version 3.8.0 */ void set_subtype(std::uint8_t subtype) noexcept { @@ -15705,8 +15720,25 @@ class wrapped_binary_t : public BinaryType } /*! - @brief get the subtype - @return subtype (implementation specific) + @brief return the binary subtype + + Returns the numerical subtype of the value if it has a subtype. If it does + not have a subtype, this function will return size_t(-1) as a sentinel + value. + + @return the numerical subtype of the binary value + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @sa @ref set_subtype() -- sets the binary subtype + @sa @ref clear_subtype() -- clears the binary subtype + @sa @ref has_subtype() -- returns whether or not the binary value has a + subtype + + @since version 3.8.0 */ constexpr std::uint8_t subtype() const noexcept { @@ -15714,8 +15746,20 @@ class wrapped_binary_t : public BinaryType } /*! - @brief get whether a subtype was set - @return whether a subtype was set + @brief return whether the value has a subtype + + @return whether the value has a subtype + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @sa @ref subtype() -- return the binary subtype + @sa @ref set_subtype() -- sets the binary subtype + @sa @ref clear_subtype() -- clears the binary subtype + + @since version 3.8.0 */ constexpr bool has_subtype() const noexcept { @@ -15723,7 +15767,23 @@ class wrapped_binary_t : public BinaryType } /*! - @brief clear the subtype + @brief clears the binary subtype + + Clears the binary subtype and flags the value as not having a subtype, which + has implications for serialization; for instance MessagePack will prefer the + bin family over the ext family. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @sa @ref subtype() -- return the binary subtype + @sa @ref set_subtype() -- sets the binary subtype + @sa @ref has_subtype() -- returns whether or not the binary value has a + subtype + + @since version 3.8.0 */ void clear_subtype() noexcept { @@ -16553,23 +16613,7 @@ class basic_json for any access to array values, a pointer of the type `binary_t*` must be dereferenced. - @sa @ref array_t -- type for an array value - - @since version 3.8.0 - */ - using binary_t = BinaryType; - - /*! - @brief binary array with a binary type - - This type is used to store binary types internally. It wrapps the template - type `BinaryType` (@ref binary_t) and adds a subtype to allow to distinguish - different binary types from different formats. - - While @ref binary_t is used to define how binary values are stored, this - type is used to access binary values once they are parsed. - - Notes on subtypes: + #### Notes on subtypes - CBOR - Binary values are represented as byte strings. No subtypes are @@ -16580,13 +16624,15 @@ class basic_json is used. For other sizes, the ext family (ext8, ext16, ext32) is used. The subtype is then added as singed 8-bit integer. - If no subtype is given, the bin family (bin8, bin16, bin32) is used. - - BSON + - BSON - If a subtype is given, it is used and added as unsigned 8-bit integer. - If no subtype is given, the generic binary subtype 0x00 is used. @sa @ref binary_array -- create a binary array + + @since version 3.8.0 */ - using internal_binary_t = nlohmann::detail::wrapped_binary_t; + using binary_t = nlohmann::detail::wrapped_binary_t; /// @} private: @@ -16647,7 +16693,7 @@ class basic_json /// string (stored with pointer to save storage) string_t* string; /// binary (stored with pointer to save storage) - internal_binary_t* binary; + binary_t* binary; /// boolean boolean_t boolean; /// number (integer) @@ -16692,7 +16738,7 @@ class basic_json case value_t::binary: { - binary = create(); + binary = create(); break; } @@ -16775,27 +16821,27 @@ class basic_json } /// constructor for binary arrays - json_value(const binary_t& value) + json_value(const typename binary_t::container_type& value) { - binary = create(value); + binary = create(value); } /// constructor for rvalue binary arrays - json_value(binary_t&& value) + json_value(typename binary_t::container_type&& value) { - binary = create(std::move(value)); + binary = create(std::move(value)); } /// constructor for binary arrays (internal type) - json_value(const internal_binary_t& value) + json_value(const binary_t& value) { - binary = create(value); + binary = create(value); } /// constructor for rvalue binary arrays (internal type) - json_value(internal_binary_t&& value) + json_value(binary_t&& value) { - binary = create(std::move(value)); + binary = create(std::move(value)); } void destroy(value_t t) noexcept @@ -16875,7 +16921,7 @@ class basic_json case value_t::binary: { - AllocatorType alloc; + AllocatorType alloc; std::allocator_traits::destroy(alloc, binary); std::allocator_traits::deallocate(alloc, binary, 1); break; @@ -17161,7 +17207,7 @@ class basic_json using other_string_t = typename BasicJsonType::string_t; using other_object_t = typename BasicJsonType::object_t; using other_array_t = typename BasicJsonType::array_t; - using other_binary_t = typename BasicJsonType::internal_binary_t; + using other_binary_t = typename BasicJsonType::binary_t; switch (val.type()) { @@ -17355,7 +17401,7 @@ class basic_json @since version 3.8.0 */ JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json binary_array(const binary_t& init) + static basic_json binary_array(const typename binary_t::container_type& init) { auto res = basic_json(); res.m_type = value_t::binary; @@ -17364,11 +17410,11 @@ class basic_json } JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json binary_array(const binary_t& init, std::uint8_t subtype) + static basic_json binary_array(const typename binary_t::container_type& init, std::uint8_t subtype) { auto res = basic_json(); res.m_type = value_t::binary; - res.m_value = internal_binary_t(init, subtype); + res.m_value = binary_t(init, subtype); return res; } @@ -17400,7 +17446,7 @@ class basic_json @since version 3.8.0 */ JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json binary_array(binary_t&& init) + static basic_json binary_array(typename binary_t::container_type&& init) { auto res = basic_json(); res.m_type = value_t::binary; @@ -17409,11 +17455,11 @@ class basic_json } JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json binary_array(binary_t&& init, std::uint8_t subtype) + static basic_json binary_array(typename binary_t::container_type&& init, std::uint8_t subtype) { auto res = basic_json(); res.m_type = value_t::binary; - res.m_value = internal_binary_t(std::move(init), subtype); + res.m_value = binary_t(std::move(init), subtype); return res; } @@ -18463,13 +18509,13 @@ class basic_json } /// get a pointer to the value (binary) - internal_binary_t* get_impl_ptr(internal_binary_t* /*unused*/) noexcept + binary_t* get_impl_ptr(binary_t* /*unused*/) noexcept { return is_binary() ? m_value.binary : nullptr; } /// get a pointer to the value (binary) - constexpr const internal_binary_t* get_impl_ptr(const internal_binary_t* /*unused*/) const noexcept + constexpr const binary_t* get_impl_ptr(const binary_t* /*unused*/) const noexcept { return is_binary() ? m_value.binary : nullptr; } @@ -18899,6 +18945,36 @@ class basic_json return get(); } + /*! + @return reference to the binary value + + @throw type_error.302 if the value is not binary + + @sa @ref is_binary() to check if the value is binary + + @since version 3.8.0 + */ + binary_t& get_binary() + { + if (not is_binary()) + { + JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(type_name()))); + } + + return *get_ptr(); + } + + /// @copydoc get_binary() + const binary_t& get_binary() const + { + if (not is_binary()) + { + JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(type_name()))); + } + + return *get_ptr(); + } + /// @} @@ -19521,118 +19597,6 @@ class basic_json return value(ptr, string_t(default_value)); } - /*! - @brief return the binary subtype - - Returns the numerical subtype of the JSON value, if the JSON value is of - type "binary", and it has a subtype. If it does not have a subtype (or the - object is not of type binary) this function will return size_t(-1) as a - sentinel value. - - @return the numerical subtype of the binary JSON value - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @sa @ref set_subtype() -- sets the binary subtype - @sa @ref clear_subtype() -- clears the binary subtype - @sa @ref has_subtype() -- returns whether or not the binary value has a - subtype - - @since version 3.8.0 - */ - std::size_t get_subtype() const noexcept - { - if (is_binary() and m_value.binary->has_subtype) - { - return m_value.binary->subtype; - } - - return std::size_t(-1); - } - - /*! - @brief sets the binary subtype - - Sets the binary subtype of the JSON value, also flags a binary JSON value as - having a subtype, which has implications for serialization to msgpack (will - prefer ext file formats over bin). If the JSON value is not a binary value, - this function does nothing. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @sa @ref get_subtype() -- return the binary subtype - @sa @ref clear_subtype() -- clears the binary subtype - @sa @ref has_subtype() -- returns whether or not the binary value has a - subtype - - @since version 3.8.0 - */ - - void set_subtype(std::uint8_t subtype) noexcept - { - if (is_binary()) - { - m_value.binary->set_subtype(subtype); - } - } - - /*! - @brief clears the binary subtype - - Clears the binary subtype of the JSON value, also flags a binary JSON value - as not having a subtype, which has implications for serialization to msgpack - (will prefer bin file formats over ext). If the JSON value is not a binary - value, this function does nothing. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @sa @ref get_subtype() -- return the binary subtype - @sa @ref set_subtype() -- sets the binary subtype - @sa @ref has_subtype() -- returns whether or not the binary value has a - subtype - - @since version 3.8.0 - */ - void clear_subtype() noexcept - { - if (is_binary()) - { - m_value.binary->clear_subtype(); - } - } - - /*! - @brief return whether or not the binary subtype has a value - - Returns whether or not the binary subtype has a value. - - @return whether or not the binary subtype has a value. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @sa @ref get_subtype() -- return the binary subtype - @sa @ref set_subtype() -- sets the binary subtype - @sa @ref clear_subtype() -- clears the binary subtype - - @since version 3.8.0 - */ - bool has_subtype() const noexcept - { - return is_binary() and m_value.binary->has_subtype(); - } - /*! @brief access the first element @@ -19802,7 +19766,7 @@ class basic_json } else if (is_binary()) { - AllocatorType alloc; + AllocatorType alloc; std::allocator_traits::destroy(alloc, m_value.binary); std::allocator_traits::deallocate(alloc, m_value.binary, 1); m_value.binary = nullptr; @@ -19916,7 +19880,7 @@ class basic_json } else if (is_binary()) { - AllocatorType alloc; + AllocatorType alloc; std::allocator_traits::destroy(alloc, m_value.binary); std::allocator_traits::deallocate(alloc, m_value.binary, 1); m_value.binary = nullptr; @@ -21756,6 +21720,20 @@ class basic_json } } + /// @copydoc swap(binary_t) + void swap(typename binary_t::container_type& other) + { + // swap only works for strings + if (JSON_HEDLEY_LIKELY(is_binary())) + { + std::swap(*(m_value.binary), other); + } + else + { + JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); + } + } + /// @} public: diff --git a/test/src/unit-class_parser.cpp b/test/src/unit-class_parser.cpp index f8eb6112f9..d43099f264 100644 --- a/test/src/unit-class_parser.cpp +++ b/test/src/unit-class_parser.cpp @@ -77,7 +77,7 @@ class SaxEventLogger return true; } - bool binary(json::internal_binary_t& val) + bool binary(json::binary_t& val) { std::string binary_contents = "binary("; std::string comma_space = ""; @@ -183,7 +183,7 @@ class SaxCountdown : public nlohmann::json::json_sax_t return events_left-- > 0; } - bool binary(json::internal_binary_t&) override + bool binary(json::binary_t&) override { return events_left-- > 0; } diff --git a/test/src/unit-constructor1.cpp b/test/src/unit-constructor1.cpp index 742bdcd9d6..81fca64ac5 100644 --- a/test/src/unit-constructor1.cpp +++ b/test/src/unit-constructor1.cpp @@ -485,14 +485,14 @@ TEST_CASE("constructors") { SECTION("empty binary") { - json::internal_binary_t b{}; + json::binary_t b{}; json j(b); CHECK(j.type() == json::value_t::binary); } SECTION("filled binary") { - json::internal_binary_t b({1, 2, 3}); + json::binary_t b({1, 2, 3}); json j(b); CHECK(j.type() == json::value_t::binary); } diff --git a/test/src/unit-deserialization.cpp b/test/src/unit-deserialization.cpp index 52ea9259d1..15744b9eb7 100644 --- a/test/src/unit-deserialization.cpp +++ b/test/src/unit-deserialization.cpp @@ -76,7 +76,7 @@ struct SaxEventLogger : public nlohmann::json_sax return true; } - bool binary(json::internal_binary_t& val) override + bool binary(json::binary_t& val) override { std::string binary_contents = "binary("; std::string comma_space = ""; diff --git a/test/src/unit-modifiers.cpp b/test/src/unit-modifiers.cpp index 2349dc1434..fc29016286 100644 --- a/test/src/unit-modifiers.cpp +++ b/test/src/unit-modifiers.cpp @@ -968,21 +968,35 @@ TEST_CASE("modifiers") SECTION("binary_t type") { json j = json::binary_array({1, 2, 3, 4}); - json::binary_t s = {1, 2, 3, 4}; + json::binary_t s = {{5, 6, 7, 8}}; + + j.swap(s); + + CHECK(j == json::binary_array({5, 6, 7, 8})); j.swap(s); CHECK(j == json::binary_array({1, 2, 3, 4})); + } + + SECTION("binary_t::container_type type") + { + json j = json::binary_array({1, 2, 3, 4}); + std::vector s = {{5, 6, 7, 8}}; + + j.swap(s); + + CHECK(j == json::binary_array({5, 6, 7, 8})); j.swap(s); CHECK(j == json::binary_array({1, 2, 3, 4})); } - SECTION("non-string_t type") + SECTION("non-binary_t type") { json j = 17; - json::binary_t s = {1, 2, 3, 4}; + json::binary_t s = {{1, 2, 3, 4}}; CHECK_THROWS_AS(j.swap(s), json::type_error&); CHECK_THROWS_WITH(j.swap(s), "[json.exception.type_error.310] cannot use swap() with number"); diff --git a/test/src/unit-msgpack.cpp b/test/src/unit-msgpack.cpp index 40b63735e7..acdafaa83d 100644 --- a/test/src/unit-msgpack.cpp +++ b/test/src/unit-msgpack.cpp @@ -1134,7 +1134,7 @@ TEST_CASE("MessagePack") const auto s = std::vector(N, 'x'); json j = json::binary_array(s); std::uint8_t subtype = 42; - j.set_subtype(subtype); + j.get_binary().set_subtype(subtype); // create expected byte vector std::vector expected; @@ -1209,7 +1209,7 @@ TEST_CASE("MessagePack") const auto s = std::vector(N, 'x'); json j = json::binary_array(s); std::uint8_t subtype = 42; - j.set_subtype(subtype); + j.get_binary().set_subtype(subtype); // create expected byte vector (hack: create string first) std::vector expected(N, 'x'); @@ -1245,7 +1245,7 @@ TEST_CASE("MessagePack") const auto s = std::vector(N, 'x'); json j = json::binary_array(s); std::uint8_t subtype = 42; - j.set_subtype(subtype); + j.get_binary().set_subtype(subtype); // create expected byte vector (hack: create string first) std::vector expected(N, 'x'); diff --git a/test/src/unit-pointer_access.cpp b/test/src/unit-pointer_access.cpp index 5f3f9e314a..72ee1ab7dc 100644 --- a/test/src/unit-pointer_access.cpp +++ b/test/src/unit-pointer_access.cpp @@ -60,7 +60,7 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); - CHECK(value.get_ptr() == nullptr); + CHECK(value.get_ptr() == nullptr); } SECTION("pointer access to const object_t") @@ -89,7 +89,7 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); - CHECK(value.get_ptr() == nullptr); + CHECK(value.get_ptr() == nullptr); } SECTION("pointer access to array_t") @@ -118,7 +118,7 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); - CHECK(value.get_ptr() == nullptr); + CHECK(value.get_ptr() == nullptr); } SECTION("pointer access to const array_t") @@ -147,7 +147,7 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); - CHECK(value.get_ptr() == nullptr); + CHECK(value.get_ptr() == nullptr); } SECTION("pointer access to string_t") @@ -176,7 +176,7 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); - CHECK(value.get_ptr() == nullptr); + CHECK(value.get_ptr() == nullptr); } SECTION("pointer access to const string_t") @@ -205,7 +205,7 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); - CHECK(value.get_ptr() == nullptr); + CHECK(value.get_ptr() == nullptr); } SECTION("pointer access to boolean_t") @@ -234,7 +234,7 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); - CHECK(value.get_ptr() == nullptr); + CHECK(value.get_ptr() == nullptr); } SECTION("pointer access to const boolean_t") @@ -263,7 +263,7 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); - CHECK(value.get_ptr() == nullptr); + CHECK(value.get_ptr() == nullptr); } SECTION("pointer access to number_integer_t") @@ -292,7 +292,7 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() != nullptr); CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); - CHECK(value.get_ptr() == nullptr); + CHECK(value.get_ptr() == nullptr); } SECTION("pointer access to const number_integer_t") @@ -321,7 +321,7 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() != nullptr); CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); - CHECK(value.get_ptr() == nullptr); + CHECK(value.get_ptr() == nullptr); } SECTION("pointer access to number_unsigned_t") @@ -350,7 +350,7 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() != nullptr); CHECK(value.get_ptr() != nullptr); CHECK(value.get_ptr() == nullptr); - CHECK(value.get_ptr() == nullptr); + CHECK(value.get_ptr() == nullptr); } SECTION("pointer access to const number_unsigned_t") @@ -379,7 +379,7 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() != nullptr); CHECK(value.get_ptr() != nullptr); CHECK(value.get_ptr() == nullptr); - CHECK(value.get_ptr() == nullptr); + CHECK(value.get_ptr() == nullptr); } SECTION("pointer access to number_float_t") @@ -408,7 +408,7 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() != nullptr); - CHECK(value.get_ptr() == nullptr); + CHECK(value.get_ptr() == nullptr); } SECTION("pointer access to const number_float_t") @@ -437,12 +437,12 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() != nullptr); - CHECK(value.get_ptr() == nullptr); + CHECK(value.get_ptr() == nullptr); } - SECTION("pointer access to const internal_binary_t") + SECTION("pointer access to const binary_t") { - using test_type = const json::internal_binary_t; + using test_type = const json::binary_t; const json value = json::binary_array({1, 2, 3}); // check if pointers are returned correctly @@ -466,12 +466,12 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); - CHECK(value.get_ptr() != nullptr); + CHECK(value.get_ptr() != nullptr); } - SECTION("pointer access to const internal_binary_t") + SECTION("pointer access to const binary_t") { - using test_type = const json::internal_binary_t; + using test_type = const json::binary_t; const json value = json::binary_array({}); // check if pointers are returned correctly @@ -495,6 +495,6 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); - CHECK(value.get_ptr() != nullptr); + CHECK(value.get_ptr() != nullptr); } } From 16d78a82e0ba307b666c28d02b29e553685a2a4a Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Mon, 18 May 2020 09:12:18 +0200 Subject: [PATCH 25/36] :construction_worker: add link to GitHub workflows --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index fa5cef6897..40ccf17646 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@ [![Build Status](https://travis-ci.org/nlohmann/json.svg?branch=master)](https://travis-ci.org/nlohmann/json) [![Build Status](https://ci.appveyor.com/api/projects/status/1acb366xfyg3qybk/branch/develop?svg=true)](https://ci.appveyor.com/project/nlohmann/json) -![Ubuntu](https://github.com/nlohmann/json/workflows/Ubuntu/badge.svg) -![macOS](https://github.com/nlohmann/json/workflows/macOS/badge.svg) -![Windows](https://github.com/nlohmann/json/workflows/Windows/badge.svg) +[![Ubuntu](https://github.com/nlohmann/json/workflows/Ubuntu/badge.svg)](https://github.com/nlohmann/json/actions?query=workflow%3AUbuntu) +[![macOS](https://github.com/nlohmann/json/workflows/macOS/badge.svg)](https://github.com/nlohmann/json/actions?query=workflow%3AmacOS) +[![Windows](https://github.com/nlohmann/json/workflows/Windows/badge.svg)](https://github.com/nlohmann/json/actions?query=workflow%3AWindows) [![Build Status](https://circleci.com/gh/nlohmann/json.svg?style=svg)](https://circleci.com/gh/nlohmann/json) [![Coverage Status](https://coveralls.io/repos/github/nlohmann/json/badge.svg?branch=develop)](https://coveralls.io/github/nlohmann/json?branch=develop) [![Coverity Scan Build Status](https://scan.coverity.com/projects/5550/badge.svg)](https://scan.coverity.com/projects/nlohmann-json) From 454480f581a0b7a05f14c93b8e94006f5bcd8e62 Mon Sep 17 00:00:00 2001 From: gistrec Date: Mon, 18 May 2020 14:57:04 +0700 Subject: [PATCH 26/36] fixed a compilation error in MSVC --- include/nlohmann/detail/output/binary_writer.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/nlohmann/detail/output/binary_writer.hpp b/include/nlohmann/detail/output/binary_writer.hpp index c4cf618c2a..4fbd4c9ae0 100644 --- a/include/nlohmann/detail/output/binary_writer.hpp +++ b/include/nlohmann/detail/output/binary_writer.hpp @@ -195,7 +195,7 @@ class binary_writer else { if (static_cast(j.m_value.number_float) >= static_cast(std::numeric_limits::lowest()) and - static_cast(j.m_value.number_float) <= static_cast(std::numeric_limits::max()) and + static_cast(j.m_value.number_float) <= static_cast((std::numeric_limits::max)()) and static_cast(static_cast(j.m_value.number_float)) == static_cast(j.m_value.number_float)) { oa->write_character(get_cbor_float_prefix(static_cast(j.m_value.number_float))); From 3f0cf26f7a96c35f4c79edf964e772ff836d7936 Mon Sep 17 00:00:00 2001 From: gistrec Date: Mon, 18 May 2020 10:17:45 +0000 Subject: [PATCH 27/36] changes to the single header were applied --- single_include/nlohmann/json.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index ed622b9a68..5202845d8b 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -12206,7 +12206,7 @@ class binary_writer else { if (static_cast(j.m_value.number_float) >= static_cast(std::numeric_limits::lowest()) and - static_cast(j.m_value.number_float) <= static_cast(std::numeric_limits::max()) and + static_cast(j.m_value.number_float) <= static_cast((std::numeric_limits::max)()) and static_cast(static_cast(j.m_value.number_float)) == static_cast(j.m_value.number_float)) { oa->write_character(get_cbor_float_prefix(static_cast(j.m_value.number_float))); From 9e765f5aedc46d3c116786367d017d4691f8dddb Mon Sep 17 00:00:00 2001 From: gistrec Date: Mon, 18 May 2020 10:25:38 +0000 Subject: [PATCH 28/36] Fixed std::numeric_limit::max() call --- test/src/unit-cbor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/src/unit-cbor.cpp b/test/src/unit-cbor.cpp index 2a53bb5295..873940f99b 100644 --- a/test/src/unit-cbor.cpp +++ b/test/src/unit-cbor.cpp @@ -925,7 +925,7 @@ TEST_CASE("CBOR") } SECTION("3.40282e+38(max float)") { - float v = std::numeric_limits::max(); + float v = (std::numeric_limits::max)(); json j = v; std::vector expected = { @@ -953,7 +953,7 @@ TEST_CASE("CBOR") } SECTION("1 + 3.40282e+38(more than max float)") { - double v = static_cast(std::numeric_limits::max()) + 0.1e+34; + double v = static_cast((std::numeric_limits::max)()) + 0.1e+34; json j = v; std::vector expected = { From 9eb19bcc279623c56547ee1e51b39b13d013c4fc Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Mon, 18 May 2020 12:33:26 +0200 Subject: [PATCH 29/36] :white_check_mark: add more tests for binary type --- test/src/unit-conversions.cpp | 119 +++++++++++++++++++++++++++++++++- test/src/unit-modifiers.cpp | 7 +- test/src/unit-udt.cpp | 7 ++ 3 files changed, 129 insertions(+), 4 deletions(-) diff --git a/test/src/unit-conversions.cpp b/test/src/unit-conversions.cpp index 8477cf6392..d37e8e9b23 100644 --- a/test/src/unit-conversions.cpp +++ b/test/src/unit-conversions.cpp @@ -189,7 +189,6 @@ TEST_CASE("value conversion") } } - SECTION("get an object (implicit)") { json::object_t o_reference = {{"object", json::object()}, @@ -1259,6 +1258,124 @@ TEST_CASE("value conversion") } } + SECTION("get a binary value (explicit)") + { + json::binary_t n_reference{{1, 2, 3}}; + json j(n_reference); + + SECTION("binary_t") + { + json::binary_t b = j.get(); + CHECK(*json(b).m_value.binary == *j.m_value.binary); + } + + SECTION("get_binary()") + { + SECTION("non-const") + { + auto& b = j.get_binary(); + CHECK(*json(b).m_value.binary == *j.m_value.binary); + } + + SECTION("non-const") + { + const json j_const = j; + const auto& b = j_const.get_binary(); + CHECK(*json(b).m_value.binary == *j.m_value.binary); + } + } + + SECTION("exception in case of a non-string type") + { + json j_null(json::value_t::null); + json j_object(json::value_t::object); + json j_array(json::value_t::array); + json j_string(json::value_t::string); + json j_boolean(json::value_t::boolean); + const json j_null_const(json::value_t::null); + const json j_object_const(json::value_t::object); + const json j_array_const(json::value_t::array); + const json j_string_const(json::value_t::string); + const json j_boolean_const(json::value_t::boolean); + + CHECK_THROWS_WITH_AS(j_null.get(), + "[json.exception.type_error.302] type must be binary, but is null", + json::type_error&); + CHECK_THROWS_WITH_AS(j_object.get(), + "[json.exception.type_error.302] type must be binary, but is object", + json::type_error&); + CHECK_THROWS_WITH_AS(j_array.get(), + "[json.exception.type_error.302] type must be binary, but is array", + json::type_error&); + CHECK_THROWS_WITH_AS(j_string.get(), + "[json.exception.type_error.302] type must be binary, but is string", + json::type_error&); + CHECK_THROWS_WITH_AS(j_boolean.get(), + "[json.exception.type_error.302] type must be binary, but is boolean", + json::type_error&); + + CHECK_THROWS_WITH_AS(j_null_const.get(), + "[json.exception.type_error.302] type must be binary, but is null", + json::type_error&); + CHECK_THROWS_WITH_AS(j_object_const.get(), + "[json.exception.type_error.302] type must be binary, but is object", + json::type_error&); + CHECK_THROWS_WITH_AS(j_array_const.get(), + "[json.exception.type_error.302] type must be binary, but is array", + json::type_error&); + CHECK_THROWS_WITH_AS(j_string_const.get(), + "[json.exception.type_error.302] type must be binary, but is string", + json::type_error&); + CHECK_THROWS_WITH_AS(j_boolean_const.get(), + "[json.exception.type_error.302] type must be binary, but is boolean", + json::type_error&); + + CHECK_THROWS_WITH_AS(j_null.get_binary(), + "[json.exception.type_error.302] type must be binary, but is null", + json::type_error&); + CHECK_THROWS_WITH_AS(j_object.get_binary(), + "[json.exception.type_error.302] type must be binary, but is object", + json::type_error&); + CHECK_THROWS_WITH_AS(j_array.get_binary(), + "[json.exception.type_error.302] type must be binary, but is array", + json::type_error&); + CHECK_THROWS_WITH_AS(j_string.get_binary(), + "[json.exception.type_error.302] type must be binary, but is string", + json::type_error&); + CHECK_THROWS_WITH_AS(j_boolean.get_binary(), + "[json.exception.type_error.302] type must be binary, but is boolean", + json::type_error&); + + CHECK_THROWS_WITH_AS(j_null_const.get_binary(), + "[json.exception.type_error.302] type must be binary, but is null", + json::type_error&); + CHECK_THROWS_WITH_AS(j_object_const.get_binary(), + "[json.exception.type_error.302] type must be binary, but is object", + json::type_error&); + CHECK_THROWS_WITH_AS(j_array_const.get_binary(), + "[json.exception.type_error.302] type must be binary, but is array", + json::type_error&); + CHECK_THROWS_WITH_AS(j_string_const.get_binary(), + "[json.exception.type_error.302] type must be binary, but is string", + json::type_error&); + CHECK_THROWS_WITH_AS(j_boolean_const.get_binary(), + "[json.exception.type_error.302] type must be binary, but is boolean", + json::type_error&); + } + } + + SECTION("get a binary value (implicit)") + { + json::binary_t n_reference{{1, 2, 3}}; + json j(n_reference); + + SECTION("binary_t") + { + json::binary_t b = j; + CHECK(*json(b).m_value.binary == *j.m_value.binary); + } + } + SECTION("get an enum") { enum c_enum { value_1, value_2 }; diff --git a/test/src/unit-modifiers.cpp b/test/src/unit-modifiers.cpp index fc29016286..955051a6b0 100644 --- a/test/src/unit-modifiers.cpp +++ b/test/src/unit-modifiers.cpp @@ -996,10 +996,11 @@ TEST_CASE("modifiers") SECTION("non-binary_t type") { json j = 17; - json::binary_t s = {{1, 2, 3, 4}}; + json::binary_t s1 = {{1, 2, 3, 4}}; + std::vector s2 = {{5, 6, 7, 8}}; - CHECK_THROWS_AS(j.swap(s), json::type_error&); - CHECK_THROWS_WITH(j.swap(s), "[json.exception.type_error.310] cannot use swap() with number"); + CHECK_THROWS_WITH_AS(j.swap(s1), "[json.exception.type_error.310] cannot use swap() with number", json::type_error); + CHECK_THROWS_WITH_AS(j.swap(s2), "[json.exception.type_error.310] cannot use swap() with number", json::type_error); } } } diff --git a/test/src/unit-udt.cpp b/test/src/unit-udt.cpp index cd9ce69fb5..42b1375ef7 100644 --- a/test/src/unit-udt.cpp +++ b/test/src/unit-udt.cpp @@ -763,6 +763,13 @@ TEST_CASE("different basic_json types conversions") CHECK(cj == "forty-two"); } + SECTION("binary") + { + json j = json::binary_array({1, 2, 3}); + custom_json cj = j; + CHECK(cj.get_binary() == j.get_binary()); + } + SECTION("object") { json j = {{"forty", "two"}}; From b7ff40029a68ba33a18258cc18aa9c40fbff259a Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Mon, 18 May 2020 13:53:20 +0200 Subject: [PATCH 30/36] :boom: change serialization of binary values --- include/nlohmann/detail/output/serializer.hpp | 101 +++++++++---- include/nlohmann/json.hpp | 21 ++- single_include/nlohmann/json.hpp | 122 +++++++++++----- test/src/unit-cbor.cpp | 2 +- test/src/unit-regression.cpp | 3 +- test/src/unit-serialization.cpp | 138 +++++++++++++----- 6 files changed, 272 insertions(+), 115 deletions(-) diff --git a/include/nlohmann/detail/output/serializer.hpp b/include/nlohmann/detail/output/serializer.hpp index dc963f5370..e8f31fd8a5 100644 --- a/include/nlohmann/detail/output/serializer.hpp +++ b/include/nlohmann/detail/output/serializer.hpp @@ -84,19 +84,22 @@ class serializer - strings and object keys are escaped using `escape_string()` - integer numbers are converted implicitly via `operator<<` - floating-point numbers are converted to a string using `"%g"` format - - if specified to, binary values are output using the syntax `b[]`, otherwise an exception is thrown + - binary values are serialized as objects containing the subtype and the + byte array @param[in] val value to serialize @param[in] pretty_print whether the output shall be pretty-printed + @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters + in the output are escaped with `\uXXXX` sequences, and the result consists + of ASCII characters only. @param[in] indent_step the indent level @param[in] current_indent the current indent level (only used internally) - @param[in] serialize_binary whether the output shall include non-standard binary output */ - void dump(const BasicJsonType& val, const bool pretty_print, + void dump(const BasicJsonType& val, + const bool pretty_print, const bool ensure_ascii, const unsigned int indent_step, - const unsigned int current_indent = 0, - const bool serialize_binary = false) + const unsigned int current_indent = 0) { switch (val.m_type) { @@ -127,7 +130,7 @@ class serializer o->write_character('\"'); dump_escaped(i->first, ensure_ascii); o->write_characters("\": ", 3); - dump(i->second, true, ensure_ascii, indent_step, new_indent, serialize_binary); + dump(i->second, true, ensure_ascii, indent_step, new_indent); o->write_characters(",\n", 2); } @@ -138,7 +141,7 @@ class serializer o->write_character('\"'); dump_escaped(i->first, ensure_ascii); o->write_characters("\": ", 3); - dump(i->second, true, ensure_ascii, indent_step, new_indent, serialize_binary); + dump(i->second, true, ensure_ascii, indent_step, new_indent); o->write_character('\n'); o->write_characters(indent_string.c_str(), current_indent); @@ -155,7 +158,7 @@ class serializer o->write_character('\"'); dump_escaped(i->first, ensure_ascii); o->write_characters("\":", 2); - dump(i->second, false, ensure_ascii, indent_step, current_indent, serialize_binary); + dump(i->second, false, ensure_ascii, indent_step, current_indent); o->write_character(','); } @@ -165,7 +168,7 @@ class serializer o->write_character('\"'); dump_escaped(i->first, ensure_ascii); o->write_characters("\":", 2); - dump(i->second, false, ensure_ascii, indent_step, current_indent, serialize_binary); + dump(i->second, false, ensure_ascii, indent_step, current_indent); o->write_character('}'); } @@ -197,14 +200,14 @@ class serializer i != val.m_value.array->cend() - 1; ++i) { o->write_characters(indent_string.c_str(), new_indent); - dump(*i, true, ensure_ascii, indent_step, new_indent, serialize_binary); + dump(*i, true, ensure_ascii, indent_step, new_indent); o->write_characters(",\n", 2); } // last element assert(not val.m_value.array->empty()); o->write_characters(indent_string.c_str(), new_indent); - dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent, serialize_binary); + dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent); o->write_character('\n'); o->write_characters(indent_string.c_str(), current_indent); @@ -218,13 +221,13 @@ class serializer for (auto i = val.m_value.array->cbegin(); i != val.m_value.array->cend() - 1; ++i) { - dump(*i, false, ensure_ascii, indent_step, current_indent, serialize_binary); + dump(*i, false, ensure_ascii, indent_step, current_indent); o->write_character(','); } // last element assert(not val.m_value.array->empty()); - dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent, serialize_binary); + dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent); o->write_character(']'); } @@ -242,27 +245,73 @@ class serializer case value_t::binary: { - if (not serialize_binary) + if (pretty_print) { - JSON_THROW(type_error::create(317, "cannot serialize binary data to text JSON")); - } + o->write_characters("{\n", 2); - if (val.m_value.binary->empty()) - { - o->write_characters("b[]", 3); + // variable to hold indentation for recursive calls + const auto new_indent = current_indent + indent_step; + if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent)) + { + indent_string.resize(indent_string.size() * 2, ' '); + } + + o->write_characters(indent_string.c_str(), new_indent); + + o->write_characters("\"bytes\": [", 10); + + if (not val.m_value.binary->empty()) + { + for (auto i = val.m_value.binary->cbegin(); + i != val.m_value.binary->cend() - 1; ++i) + { + dump_integer(*i); + o->write_characters(", ", 2); + } + dump_integer(val.m_value.binary->back()); + } + + o->write_characters("],\n", 3); + o->write_characters(indent_string.c_str(), new_indent); + + o->write_characters("\"subtype\": ", 11); + if (val.m_value.binary->has_subtype()) + { + dump_integer(val.m_value.binary->subtype()); + } + else + { + o->write_characters("null", 4); + } + o->write_character('\n'); + o->write_characters(indent_string.c_str(), current_indent); + o->write_character('}'); } else { - o->write_characters("b[", 2); - for (auto i = val.m_value.binary->cbegin(); - i != val.m_value.binary->cend() - 1; ++i) + o->write_characters("{\"bytes\":[", 10); + + if (not val.m_value.binary->empty()) { - dump_integer(*i); - o->write_character(','); + for (auto i = val.m_value.binary->cbegin(); + i != val.m_value.binary->cend() - 1; ++i) + { + dump_integer(*i); + o->write_character(','); + } + dump_integer(val.m_value.binary->back()); } - dump_integer(val.m_value.binary->back()); - o->write_character(']'); + o->write_characters("],\"subtype\":", 12); + if (val.m_value.binary->has_subtype()) + { + dump_integer(val.m_value.binary->subtype()); + o->write_character('}'); + } + else + { + o->write_characters("null}", 5); + } } return; } diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index fc849a3883..fc4d8da103 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -2234,16 +2234,15 @@ class basic_json possible values: `strict` (throws and exception in case a decoding error occurs; default), `replace` (replace invalid UTF-8 sequences with U+FFFD), and `ignore` (ignore invalid UTF-8 sequences during serialization). - @param[in] serialize_binary Whether or not to allow serialization of binary - types to JSON. Because binary types are non-standard, this will produce - non-conformant JSON, and is disabled by default. This flag is primarily - useful for debugging. Will output the binary value as a list of 8-bit - numbers prefixed by "b" (e.g. "bindata" = b[3, 0, 42, 255]). @return string containing the serialization of the JSON value @throw type_error.316 if a string stored inside the JSON value is not - UTF-8 encoded + UTF-8 encoded and @a error_handler is set to strict + + @note Binary values are serialized as object containing two keys: + - "bytes": an array of bytes as integers + - "subtype": the subtype as integer or "null" if the binary has no subtype @complexity Linear. @@ -2258,24 +2257,24 @@ class basic_json @since version 1.0.0; indentation character @a indent_char, option @a ensure_ascii and exceptions added in version 3.0.0; error - handlers added in version 3.4.0. + handlers added in version 3.4.0; serialization of binary values added + in version 3.8.0. */ string_t dump(const int indent = -1, const char indent_char = ' ', const bool ensure_ascii = false, - const error_handler_t error_handler = error_handler_t::strict, - const bool serialize_binary = false) const + const error_handler_t error_handler = error_handler_t::strict) const { string_t result; serializer s(detail::output_adapter(result), indent_char, error_handler); if (indent >= 0) { - s.dump(*this, true, ensure_ascii, static_cast(indent), 0, serialize_binary); + s.dump(*this, true, ensure_ascii, static_cast(indent)); } else { - s.dump(*this, false, ensure_ascii, 0, 0, serialize_binary); + s.dump(*this, false, ensure_ascii, 0); } return result; diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 0033be2316..c94336e24a 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -14828,19 +14828,22 @@ class serializer - strings and object keys are escaped using `escape_string()` - integer numbers are converted implicitly via `operator<<` - floating-point numbers are converted to a string using `"%g"` format - - if specified to, binary values are output using the syntax `b[]`, otherwise an exception is thrown + - binary values are serialized as objects containing the subtype and the + byte array @param[in] val value to serialize @param[in] pretty_print whether the output shall be pretty-printed + @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters + in the output are escaped with `\uXXXX` sequences, and the result consists + of ASCII characters only. @param[in] indent_step the indent level @param[in] current_indent the current indent level (only used internally) - @param[in] serialize_binary whether the output shall include non-standard binary output */ - void dump(const BasicJsonType& val, const bool pretty_print, + void dump(const BasicJsonType& val, + const bool pretty_print, const bool ensure_ascii, const unsigned int indent_step, - const unsigned int current_indent = 0, - const bool serialize_binary = false) + const unsigned int current_indent = 0) { switch (val.m_type) { @@ -14871,7 +14874,7 @@ class serializer o->write_character('\"'); dump_escaped(i->first, ensure_ascii); o->write_characters("\": ", 3); - dump(i->second, true, ensure_ascii, indent_step, new_indent, serialize_binary); + dump(i->second, true, ensure_ascii, indent_step, new_indent); o->write_characters(",\n", 2); } @@ -14882,7 +14885,7 @@ class serializer o->write_character('\"'); dump_escaped(i->first, ensure_ascii); o->write_characters("\": ", 3); - dump(i->second, true, ensure_ascii, indent_step, new_indent, serialize_binary); + dump(i->second, true, ensure_ascii, indent_step, new_indent); o->write_character('\n'); o->write_characters(indent_string.c_str(), current_indent); @@ -14899,7 +14902,7 @@ class serializer o->write_character('\"'); dump_escaped(i->first, ensure_ascii); o->write_characters("\":", 2); - dump(i->second, false, ensure_ascii, indent_step, current_indent, serialize_binary); + dump(i->second, false, ensure_ascii, indent_step, current_indent); o->write_character(','); } @@ -14909,7 +14912,7 @@ class serializer o->write_character('\"'); dump_escaped(i->first, ensure_ascii); o->write_characters("\":", 2); - dump(i->second, false, ensure_ascii, indent_step, current_indent, serialize_binary); + dump(i->second, false, ensure_ascii, indent_step, current_indent); o->write_character('}'); } @@ -14941,14 +14944,14 @@ class serializer i != val.m_value.array->cend() - 1; ++i) { o->write_characters(indent_string.c_str(), new_indent); - dump(*i, true, ensure_ascii, indent_step, new_indent, serialize_binary); + dump(*i, true, ensure_ascii, indent_step, new_indent); o->write_characters(",\n", 2); } // last element assert(not val.m_value.array->empty()); o->write_characters(indent_string.c_str(), new_indent); - dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent, serialize_binary); + dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent); o->write_character('\n'); o->write_characters(indent_string.c_str(), current_indent); @@ -14962,13 +14965,13 @@ class serializer for (auto i = val.m_value.array->cbegin(); i != val.m_value.array->cend() - 1; ++i) { - dump(*i, false, ensure_ascii, indent_step, current_indent, serialize_binary); + dump(*i, false, ensure_ascii, indent_step, current_indent); o->write_character(','); } // last element assert(not val.m_value.array->empty()); - dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent, serialize_binary); + dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent); o->write_character(']'); } @@ -14986,27 +14989,73 @@ class serializer case value_t::binary: { - if (not serialize_binary) + if (pretty_print) { - JSON_THROW(type_error::create(317, "cannot serialize binary data to text JSON")); - } + o->write_characters("{\n", 2); - if (val.m_value.binary->empty()) - { - o->write_characters("b[]", 3); + // variable to hold indentation for recursive calls + const auto new_indent = current_indent + indent_step; + if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent)) + { + indent_string.resize(indent_string.size() * 2, ' '); + } + + o->write_characters(indent_string.c_str(), new_indent); + + o->write_characters("\"bytes\": [", 10); + + if (not val.m_value.binary->empty()) + { + for (auto i = val.m_value.binary->cbegin(); + i != val.m_value.binary->cend() - 1; ++i) + { + dump_integer(*i); + o->write_characters(", ", 2); + } + dump_integer(val.m_value.binary->back()); + } + + o->write_characters("],\n", 3); + o->write_characters(indent_string.c_str(), new_indent); + + o->write_characters("\"subtype\": ", 11); + if (val.m_value.binary->has_subtype()) + { + dump_integer(val.m_value.binary->subtype()); + } + else + { + o->write_characters("null", 4); + } + o->write_character('\n'); + o->write_characters(indent_string.c_str(), current_indent); + o->write_character('}'); } else { - o->write_characters("b[", 2); - for (auto i = val.m_value.binary->cbegin(); - i != val.m_value.binary->cend() - 1; ++i) + o->write_characters("{\"bytes\":[", 10); + + if (not val.m_value.binary->empty()) { - dump_integer(*i); - o->write_character(','); + for (auto i = val.m_value.binary->cbegin(); + i != val.m_value.binary->cend() - 1; ++i) + { + dump_integer(*i); + o->write_character(','); + } + dump_integer(val.m_value.binary->back()); } - dump_integer(val.m_value.binary->back()); - o->write_character(']'); + o->write_characters("],\"subtype\":", 12); + if (val.m_value.binary->has_subtype()) + { + dump_integer(val.m_value.binary->subtype()); + o->write_character('}'); + } + else + { + o->write_characters("null}", 5); + } } return; } @@ -17963,16 +18012,15 @@ class basic_json possible values: `strict` (throws and exception in case a decoding error occurs; default), `replace` (replace invalid UTF-8 sequences with U+FFFD), and `ignore` (ignore invalid UTF-8 sequences during serialization). - @param[in] serialize_binary Whether or not to allow serialization of binary - types to JSON. Because binary types are non-standard, this will produce - non-conformant JSON, and is disabled by default. This flag is primarily - useful for debugging. Will output the binary value as a list of 8-bit - numbers prefixed by "b" (e.g. "bindata" = b[3, 0, 42, 255]). @return string containing the serialization of the JSON value @throw type_error.316 if a string stored inside the JSON value is not - UTF-8 encoded + UTF-8 encoded and @a error_handler is set to strict + + @note Binary values are serialized as object containing two keys: + - "bytes": an array of bytes as integers + - "subtype": the subtype as integer or "null" if the binary has no subtype @complexity Linear. @@ -17987,24 +18035,24 @@ class basic_json @since version 1.0.0; indentation character @a indent_char, option @a ensure_ascii and exceptions added in version 3.0.0; error - handlers added in version 3.4.0. + handlers added in version 3.4.0; serialization of binary values added + in version 3.8.0. */ string_t dump(const int indent = -1, const char indent_char = ' ', const bool ensure_ascii = false, - const error_handler_t error_handler = error_handler_t::strict, - const bool serialize_binary = false) const + const error_handler_t error_handler = error_handler_t::strict) const { string_t result; serializer s(detail::output_adapter(result), indent_char, error_handler); if (indent >= 0) { - s.dump(*this, true, ensure_ascii, static_cast(indent), 0, serialize_binary); + s.dump(*this, true, ensure_ascii, static_cast(indent)); } else { - s.dump(*this, false, ensure_ascii, 0, 0, serialize_binary); + s.dump(*this, false, ensure_ascii, 0); } return result; diff --git a/test/src/unit-cbor.cpp b/test/src/unit-cbor.cpp index 2a53bb5295..d34ae7890f 100644 --- a/test/src/unit-cbor.cpp +++ b/test/src/unit-cbor.cpp @@ -1582,7 +1582,7 @@ TEST_CASE("CBOR") auto j = json::from_cbor(input); CHECK(j.is_binary()); auto k = json::binary_array({0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x99}); - CAPTURE(j.dump(0, ' ', false, json::error_handler_t::strict, true)) + CAPTURE(j.dump(0, ' ', false, json::error_handler_t::strict)) CHECK(j == k); } diff --git a/test/src/unit-regression.cpp b/test/src/unit-regression.cpp index c191628abe..373344d8d2 100644 --- a/test/src/unit-regression.cpp +++ b/test/src/unit-regression.cpp @@ -1919,8 +1919,7 @@ TEST_CASE("regression tests") j.dump(4, // Indent ' ', // Indent char false, // Ensure ascii - json::error_handler_t::strict, // Error - true // Allow binary data + json::error_handler_t::strict // Error ) ); } diff --git a/test/src/unit-serialization.cpp b/test/src/unit-serialization.cpp index 2681ab535d..d0ddc58f05 100644 --- a/test/src/unit-serialization.cpp +++ b/test/src/unit-serialization.cpp @@ -209,52 +209,114 @@ TEST_CASE_TEMPLATE("serialization for extreme integer values", T, int32_t, uint3 TEST_CASE("dump with binary values") { - SECTION("serialize_binary = false") + auto binary = json::binary_array({1, 2, 3, 4}); + auto binary_empty = json::binary_array({}); + auto binary_with_subtype = json::binary_array({1, 2, 3, 4}, 128); + auto binary_empty_with_subtype = json::binary_array({}, 128); + + json object = {{"key", binary}}; + json object_empty = {{"key", binary_empty}}; + json object_with_subtype = {{"key", binary_with_subtype}}; + json object_empty_with_subtype = {{"key", binary_empty_with_subtype}}; + + json array = {"value", 1, binary}; + json array_empty = {"value", 1, binary_empty}; + json array_with_subtype = {"value", 1, binary_with_subtype}; + json array_empty_with_subtype = {"value", 1, binary_empty_with_subtype}; + + SECTION("normal") { - auto binary = json::binary_array({1, 2, 3, 4}); - auto binary_empty = json::binary_array({}); - json object = {{"key", binary}}; - json array = {"value", 1, binary}; - - CHECK_THROWS_AS(binary.dump(), json::type_error); - CHECK_THROWS_AS(binary_empty.dump(), json::type_error); - CHECK_THROWS_AS(object.dump(), json::type_error); - CHECK_THROWS_AS(array.dump(), json::type_error); - CHECK_THROWS_WITH(binary.dump(), "[json.exception.type_error.317] cannot serialize binary data to text JSON"); - CHECK_THROWS_WITH(binary_empty.dump(), "[json.exception.type_error.317] cannot serialize binary data to text JSON"); - CHECK_THROWS_WITH(object.dump(), "[json.exception.type_error.317] cannot serialize binary data to text JSON"); - CHECK_THROWS_WITH(array.dump(), "[json.exception.type_error.317] cannot serialize binary data to text JSON"); + CHECK(binary.dump() == "{\"bytes\":[1,2,3,4],\"subtype\":null}"); + CHECK(binary_empty.dump() == "{\"bytes\":[],\"subtype\":null}"); + CHECK(binary_with_subtype.dump() == "{\"bytes\":[1,2,3,4],\"subtype\":128}"); + CHECK(binary_empty_with_subtype.dump() == "{\"bytes\":[],\"subtype\":128}"); + + CHECK(object.dump() == "{\"key\":{\"bytes\":[1,2,3,4],\"subtype\":null}}"); + CHECK(object_empty.dump() == "{\"key\":{\"bytes\":[],\"subtype\":null}}"); + CHECK(object_with_subtype.dump() == "{\"key\":{\"bytes\":[1,2,3,4],\"subtype\":128}}"); + CHECK(object_empty_with_subtype.dump() == "{\"key\":{\"bytes\":[],\"subtype\":128}}"); + + CHECK(array.dump() == "[\"value\",1,{\"bytes\":[1,2,3,4],\"subtype\":null}]"); + CHECK(array_empty.dump() == "[\"value\",1,{\"bytes\":[],\"subtype\":null}]"); + CHECK(array_with_subtype.dump() == "[\"value\",1,{\"bytes\":[1,2,3,4],\"subtype\":128}]"); + CHECK(array_empty_with_subtype.dump() == "[\"value\",1,{\"bytes\":[],\"subtype\":128}]"); } - SECTION("serialize_binary = true") + SECTION("pretty-printed") { - auto binary = json::binary_array({1, 2, 3, 4}); - auto binary_empty = json::binary_array({}); - json object = {{"key", binary}}; - json array = {"value", 1, binary}; - - CHECK(binary.dump(-1, ' ', false, json::error_handler_t::strict, true) == "b[1,2,3,4]"); - CHECK(binary_empty.dump(-1, ' ', false, json::error_handler_t::strict, true) == "b[]"); - CHECK(object.dump(-1, ' ', false, json::error_handler_t::strict, true) == "{\"key\":b[1,2,3,4]}"); - CHECK(array.dump(-1, ' ', false, json::error_handler_t::strict, true) == "[\"value\",1,b[1,2,3,4]]"); - } + CHECK(binary.dump(4) == "{\n" + " \"bytes\": [1, 2, 3, 4],\n" + " \"subtype\": null\n" + "}"); + CHECK(binary_empty.dump(4) == "{\n" + " \"bytes\": [],\n" + " \"subtype\": null\n" + "}"); + CHECK(binary_with_subtype.dump(4) == "{\n" + " \"bytes\": [1, 2, 3, 4],\n" + " \"subtype\": 128\n" + "}"); + CHECK(binary_empty_with_subtype.dump(4) == "{\n" + " \"bytes\": [],\n" + " \"subtype\": 128\n" + "}"); - SECTION("serialize_binary = true, pretty-printed") - { - auto binary = json::binary_array({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}); - auto binary_empty = json::binary_array({}); - json object = {{"key", binary}}; - json array = {"value", 1, binary}; - - CHECK(binary.dump(4, ' ', false, json::error_handler_t::strict, true) == "b[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]"); - CHECK(binary_empty.dump(4, ' ', false, json::error_handler_t::strict, true) == "b[]"); - CHECK(object.dump(4, ' ', false, json::error_handler_t::strict, true) == "{\n" - " \"key\": b[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]\n" + CHECK(object.dump(4) == "{\n" + " \"key\": {\n" + " \"bytes\": [1, 2, 3, 4],\n" + " \"subtype\": null\n" + " }\n" + "}"); + CHECK(object_empty.dump(4) == "{\n" + " \"key\": {\n" + " \"bytes\": [],\n" + " \"subtype\": null\n" + " }\n" + "}"); + CHECK(object_with_subtype.dump(4) == "{\n" + " \"key\": {\n" + " \"bytes\": [1, 2, 3, 4],\n" + " \"subtype\": 128\n" + " }\n" "}"); - CHECK(array.dump(4, ' ', false, json::error_handler_t::strict, true) == "[\n" + CHECK(object_empty_with_subtype.dump(4) == "{\n" + " \"key\": {\n" + " \"bytes\": [],\n" + " \"subtype\": 128\n" + " }\n" + "}"); + + CHECK(array.dump(4) == "[\n" + " \"value\",\n" + " 1,\n" + " {\n" + " \"bytes\": [1, 2, 3, 4],\n" + " \"subtype\": null\n" + " }\n" + "]"); + CHECK(array_empty.dump(4) == "[\n" + " \"value\",\n" + " 1,\n" + " {\n" + " \"bytes\": [],\n" + " \"subtype\": null\n" + " }\n" + "]"); + CHECK(array_with_subtype.dump(4) == "[\n" + " \"value\",\n" + " 1,\n" + " {\n" + " \"bytes\": [1, 2, 3, 4],\n" + " \"subtype\": 128\n" + " }\n" + "]"); + CHECK(array_empty_with_subtype.dump(4) == "[\n" " \"value\",\n" " 1,\n" - " b[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]\n" + " {\n" + " \"bytes\": [],\n" + " \"subtype\": 128\n" + " }\n" "]"); } } From 5cfa8a586ee1a656190491c1de20a82fb40fab5d Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Mon, 18 May 2020 14:01:54 +0200 Subject: [PATCH 31/36] :construction_worker: run workflows on pull requests --- .github/workflows/macos.yml | 2 +- .github/workflows/ubuntu.yml | 2 +- .github/workflows/windows.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index ff700dc1d0..96435a636f 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -1,6 +1,6 @@ name: macOS -on: [push] +on: [push, pull_request] jobs: build: diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index aa2aa1da7e..5aa0dacbb7 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -1,6 +1,6 @@ name: Ubuntu -on: [push] +on: [push, pull_request] jobs: build: diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index ceb6c9e985..2758c185de 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -1,6 +1,6 @@ name: Windows -on: [push] +on: [push, pull_request] jobs: build: From 79347b484b9df853ba13b34e7f8b438bee9c2f46 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Tue, 19 May 2020 12:40:32 +0200 Subject: [PATCH 32/36] :white_check_mark: improve test coverage --- test/src/unit-inspection.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/src/unit-inspection.cpp b/test/src/unit-inspection.cpp index c464b69893..d14b89afd2 100644 --- a/test/src/unit-inspection.cpp +++ b/test/src/unit-inspection.cpp @@ -261,6 +261,9 @@ TEST_CASE("object inspection") // important test, because it yields a resize of the indent_string // inside the dump() function CHECK(j.dump(1024).size() == 15472); + + const auto binary = json::binary_array({1, 2, 3}, 128); + CHECK(binary.dump(1024).size() == 2086); } SECTION("dump and floating-point numbers") From 952a87a4f473d3c5dc676e40a04cde2697f4615c Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Tue, 19 May 2020 13:08:18 +0200 Subject: [PATCH 33/36] :truck: move byte container outside detail namespace --- doc/examples/swap__binary_t.cpp | 20 + doc/examples/swap__binary_t.output | 2 + ..._t.hpp => byte_container_with_subtype.hpp} | 29 +- include/nlohmann/json.hpp | 65 +-- single_include/nlohmann/json.hpp | 374 +++++++++--------- 5 files changed, 264 insertions(+), 226 deletions(-) create mode 100644 doc/examples/swap__binary_t.cpp create mode 100644 doc/examples/swap__binary_t.output rename include/nlohmann/{detail/wrapped_binary_t.hpp => byte_container_with_subtype.hpp} (76%) diff --git a/doc/examples/swap__binary_t.cpp b/doc/examples/swap__binary_t.cpp new file mode 100644 index 0000000000..48fe956632 --- /dev/null +++ b/doc/examples/swap__binary_t.cpp @@ -0,0 +1,20 @@ +#include +#include + +using json = nlohmann::json; + +int main() +{ + // create a binary value + json value = json::binary_array({1, 2, 3}); + + // create a binary_t + json::binary_t binary = {{4, 5, 6}}; + + // swap the object stored in the JSON value + value.swap(binary); + + // output the values + std::cout << "value = " << value << '\n'; + std::cout << "binary = " << json(binary) << '\n'; +} diff --git a/doc/examples/swap__binary_t.output b/doc/examples/swap__binary_t.output new file mode 100644 index 0000000000..68cd768921 --- /dev/null +++ b/doc/examples/swap__binary_t.output @@ -0,0 +1,2 @@ +value = {"bytes":[4,5,6],"subtype":null} +binary = {"bytes":[1,2,3],"subtype":null} diff --git a/include/nlohmann/detail/wrapped_binary_t.hpp b/include/nlohmann/byte_container_with_subtype.hpp similarity index 76% rename from include/nlohmann/detail/wrapped_binary_t.hpp rename to include/nlohmann/byte_container_with_subtype.hpp index 6edd7b52ec..243ece37a5 100644 --- a/include/nlohmann/detail/wrapped_binary_t.hpp +++ b/include/nlohmann/byte_container_with_subtype.hpp @@ -5,43 +5,47 @@ namespace nlohmann { -namespace detail -{ /*! @brief an internal type for a backed binary type -This type is designed to be `binary_t` but with the subtype implementation -detail. This type exists so that the user does not have to specify a type -themselves with a specific naming scheme in order to override the binary type. +This type extends the template parameter @a BinaryType provided to `basic_json` +with a subtype used by BSON and MessagePack. This type exists so that the user +does not have to specify a type themselves with a specific naming scheme in +order to override the binary type. + +@tparam BinaryType container to store bytes (`std::vector` by + default) + +@since version 3.8.0 */ template -class wrapped_binary_t : public BinaryType +class byte_container_with_subtype : public BinaryType { public: /// the type of the underlying container using container_type = BinaryType; - wrapped_binary_t() noexcept(noexcept(container_type())) + byte_container_with_subtype() noexcept(noexcept(container_type())) : container_type() {} - wrapped_binary_t(const container_type& b) noexcept(noexcept(container_type(b))) + byte_container_with_subtype(const container_type& b) noexcept(noexcept(container_type(b))) : container_type(b) {} - wrapped_binary_t(container_type&& b) noexcept(noexcept(container_type(std::move(b)))) + byte_container_with_subtype(container_type&& b) noexcept(noexcept(container_type(std::move(b)))) : container_type(std::move(b)) {} - wrapped_binary_t(const container_type& b, - std::uint8_t subtype) noexcept(noexcept(container_type(b))) + byte_container_with_subtype(const container_type& b, + std::uint8_t subtype) noexcept(noexcept(container_type(b))) : container_type(b) , m_subtype(subtype) , m_has_subtype(true) {} - wrapped_binary_t(container_type&& b, std::uint8_t subtype) noexcept(noexcept(container_type(std::move(b)))) + byte_container_with_subtype(container_type&& b, std::uint8_t subtype) noexcept(noexcept(container_type(std::move(b)))) : container_type(std::move(b)) , m_subtype(subtype) , m_has_subtype(true) @@ -148,5 +152,4 @@ class wrapped_binary_t : public BinaryType bool m_has_subtype = false; }; -} // namespace detail } // namespace nlohmann diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index fc4d8da103..38f8f20326 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -48,6 +48,7 @@ SOFTWARE. #include // vector #include +#include #include #include #include @@ -70,7 +71,6 @@ SOFTWARE. #include #include #include -#include #include /*! @@ -903,7 +903,7 @@ class basic_json @since version 3.8.0 */ - using binary_t = nlohmann::detail::wrapped_binary_t; + using binary_t = nlohmann::byte_container_with_subtype; /// @} private: @@ -946,7 +946,7 @@ class basic_json number | number_integer | @ref number_integer_t number | number_unsigned | @ref number_unsigned_t number | number_float | @ref number_float_t - binary | binary | pointer to @ref internal_binary_t + binary | binary | pointer to @ref binary_t null | null | *no value is stored* @note Variable-length types (objects, arrays, and strings) are stored as @@ -1645,22 +1645,22 @@ class basic_json } /*! - @brief explicitly create a binary array from an already constructed copy of - its base type + @brief explicitly create a binary array (without subtype) - Creates a JSON binary array value from a given `binary_t`. Binary values are - part of various binary formats, such as CBOR, MsgPack, and BSON. And this - constructor is used to create a value for serialization to those formats. + Creates a JSON binary array value from a given binary container. Binary + values are part of various binary formats, such as CBOR, MessagePack, and + BSON. This constructor is used to create a value for serialization to those + formats. @note Note, this function exists because of the difficulty in correctly specifying the correct template overload in the standard value ctor, as both JSON arrays and JSON binary arrays are backed with some form of a - `std::vector`. Because JSON binary arrays are a non-standard extension it + `std::vector`. Because JSON binary arrays are a non-standard extension it was decided that it would be best to prevent automatic initialization of a binary array type, for backwards compatibility and so it does not happen on accident. - @param[in] init `binary_t` with JSON values to create a binary array from + @param[in] init container containing bytes to use as binary type @return JSON binary array value @@ -1680,32 +1680,24 @@ class basic_json return res; } - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json binary_array(const typename binary_t::container_type& init, std::uint8_t subtype) - { - auto res = basic_json(); - res.m_type = value_t::binary; - res.m_value = binary_t(init, subtype); - return res; - } - /*! - @brief explicitly create a binary array from an already constructed rvalue - copy of its base type + @brief explicitly create a binary array (with subtype) - Creates a JSON binary array value from a given `binary_t`. Binary values are - part of various binary formats, such as CBOR, MsgPack, and BSON. And this - constructor is used to create a value for serialization to those formats. + Creates a JSON binary array value from a given binary container. Binary + values are part of various binary formats, such as CBOR, MessagePack, and + BSON. This constructor is used to create a value for serialization to those + formats. @note Note, this function exists because of the difficulty in correctly specifying the correct template overload in the standard value ctor, as both JSON arrays and JSON binary arrays are backed with some form of a - `std::vector`. Because JSON binary arrays are a non-standard extension it + `std::vector`. Because JSON binary arrays are a non-standard extension it was decided that it would be best to prevent automatic initialization of a - binary array type, for backwards compatibility and so it doesn't happen on + binary array type, for backwards compatibility and so it does not happen on accident. - @param[in] init `binary_t` with JSON values to create a binary array from + @param[in] init container containing bytes to use as binary type + @param[in] subtype subtype to use in MessagePack and BSON @return JSON binary array value @@ -1717,6 +1709,16 @@ class basic_json @since version 3.8.0 */ JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json binary_array(const typename binary_t::container_type& init, std::uint8_t subtype) + { + auto res = basic_json(); + res.m_type = value_t::binary; + res.m_value = binary_t(init, subtype); + return res; + } + + /// @copydoc binary_array(const typename binary_t::container_type&) + JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json binary_array(typename binary_t::container_type&& init) { auto res = basic_json(); @@ -1725,6 +1727,7 @@ class basic_json return res; } + /// @copydoc binary_array(const typename binary_t::container_type&, std::uint8_t) JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json binary_array(typename binary_t::container_type&& init, std::uint8_t subtype) { @@ -6959,7 +6962,8 @@ class basic_json number_unsigned | 256..65535 | Unsigned integer (2 bytes follow) | 0x19 number_unsigned | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1A number_unsigned | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1B - number_float | *any value* | Double-Precision Float | 0xFB + number_float | *any value representable by a float* | Single-Precision Float | 0xFA + number_float | *any value NOT representable by a float* | Double-Precision Float | 0xFB string | *length*: 0..23 | UTF-8 string | 0x60..0x77 string | *length*: 23..255 | UTF-8 string (1 byte follow) | 0x78 string | *length*: 256..65535 | UTF-8 string (2 bytes follow) | 0x79 @@ -7001,7 +7005,7 @@ class basic_json - expected conversions (0xD5..0xD7) - simple values (0xE0..0xF3, 0xF8) - undefined (0xF7) - - half and single-precision floats (0xF9-0xFA) + - half-precision floats (0xF9) - break (0xFF) @param[in] j JSON value to serialize @@ -7019,7 +7023,8 @@ class basic_json @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the related UBJSON format - @since version 2.0.9 + @since version 2.0.9; compact representation of floating-point numbers + since version 3.8.0 */ static std::vector to_cbor(const basic_json& j) { diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index c94336e24a..f774377265 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -4223,6 +4223,163 @@ struct adl_serializer } // namespace nlohmann +// #include + + +#include // uint8_t +#include // move + +namespace nlohmann +{ + +/*! +@brief an internal type for a backed binary type + +This type extends the template parameter @a BinaryType provided to `basic_json` +with a subtype used by BSON and MessagePack. This type exists so that the user +does not have to specify a type themselves with a specific naming scheme in +order to override the binary type. + +@tparam BinaryType container to store bytes (`std::vector` by + default) + +@since version 3.8.0 +*/ +template +class byte_container_with_subtype : public BinaryType +{ + public: + /// the type of the underlying container + using container_type = BinaryType; + + byte_container_with_subtype() noexcept(noexcept(container_type())) + : container_type() + {} + + byte_container_with_subtype(const container_type& b) noexcept(noexcept(container_type(b))) + : container_type(b) + {} + + byte_container_with_subtype(container_type&& b) noexcept(noexcept(container_type(std::move(b)))) + : container_type(std::move(b)) + {} + + byte_container_with_subtype(const container_type& b, + std::uint8_t subtype) noexcept(noexcept(container_type(b))) + : container_type(b) + , m_subtype(subtype) + , m_has_subtype(true) + {} + + byte_container_with_subtype(container_type&& b, std::uint8_t subtype) noexcept(noexcept(container_type(std::move(b)))) + : container_type(std::move(b)) + , m_subtype(subtype) + , m_has_subtype(true) + {} + + /*! + @brief sets the binary subtype + + Sets the binary subtype of the value, also flags a binary JSON value as + having a subtype, which has implications for serialization. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @sa @ref subtype() -- return the binary subtype + @sa @ref clear_subtype() -- clears the binary subtype + @sa @ref has_subtype() -- returns whether or not the binary value has a + subtype + + @since version 3.8.0 + */ + void set_subtype(std::uint8_t subtype) noexcept + { + m_subtype = subtype; + m_has_subtype = true; + } + + /*! + @brief return the binary subtype + + Returns the numerical subtype of the value if it has a subtype. If it does + not have a subtype, this function will return size_t(-1) as a sentinel + value. + + @return the numerical subtype of the binary value + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @sa @ref set_subtype() -- sets the binary subtype + @sa @ref clear_subtype() -- clears the binary subtype + @sa @ref has_subtype() -- returns whether or not the binary value has a + subtype + + @since version 3.8.0 + */ + constexpr std::uint8_t subtype() const noexcept + { + return m_subtype; + } + + /*! + @brief return whether the value has a subtype + + @return whether the value has a subtype + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @sa @ref subtype() -- return the binary subtype + @sa @ref set_subtype() -- sets the binary subtype + @sa @ref clear_subtype() -- clears the binary subtype + + @since version 3.8.0 + */ + constexpr bool has_subtype() const noexcept + { + return m_has_subtype; + } + + /*! + @brief clears the binary subtype + + Clears the binary subtype and flags the value as not having a subtype, which + has implications for serialization; for instance MessagePack will prefer the + bin family over the ext family. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @sa @ref subtype() -- return the binary subtype + @sa @ref set_subtype() -- sets the binary subtype + @sa @ref has_subtype() -- returns whether or not the binary value has a + subtype + + @since version 3.8.0 + */ + void clear_subtype() noexcept + { + m_subtype = 0; + m_has_subtype = false; + } + + private: + std::uint8_t m_subtype = 0; + bool m_has_subtype = false; +}; + +} // namespace nlohmann + // #include // #include @@ -15694,160 +15851,6 @@ class serializer // #include -// #include - - -#include // uint8_t -#include // move - -namespace nlohmann -{ -namespace detail -{ - -/*! -@brief an internal type for a backed binary type - -This type is designed to be `binary_t` but with the subtype implementation -detail. This type exists so that the user does not have to specify a type -themselves with a specific naming scheme in order to override the binary type. -*/ -template -class wrapped_binary_t : public BinaryType -{ - public: - /// the type of the underlying container - using container_type = BinaryType; - - wrapped_binary_t() noexcept(noexcept(container_type())) - : container_type() - {} - - wrapped_binary_t(const container_type& b) noexcept(noexcept(container_type(b))) - : container_type(b) - {} - - wrapped_binary_t(container_type&& b) noexcept(noexcept(container_type(std::move(b)))) - : container_type(std::move(b)) - {} - - wrapped_binary_t(const container_type& b, - std::uint8_t subtype) noexcept(noexcept(container_type(b))) - : container_type(b) - , m_subtype(subtype) - , m_has_subtype(true) - {} - - wrapped_binary_t(container_type&& b, std::uint8_t subtype) noexcept(noexcept(container_type(std::move(b)))) - : container_type(std::move(b)) - , m_subtype(subtype) - , m_has_subtype(true) - {} - - /*! - @brief sets the binary subtype - - Sets the binary subtype of the value, also flags a binary JSON value as - having a subtype, which has implications for serialization. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @sa @ref subtype() -- return the binary subtype - @sa @ref clear_subtype() -- clears the binary subtype - @sa @ref has_subtype() -- returns whether or not the binary value has a - subtype - - @since version 3.8.0 - */ - void set_subtype(std::uint8_t subtype) noexcept - { - m_subtype = subtype; - m_has_subtype = true; - } - - /*! - @brief return the binary subtype - - Returns the numerical subtype of the value if it has a subtype. If it does - not have a subtype, this function will return size_t(-1) as a sentinel - value. - - @return the numerical subtype of the binary value - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @sa @ref set_subtype() -- sets the binary subtype - @sa @ref clear_subtype() -- clears the binary subtype - @sa @ref has_subtype() -- returns whether or not the binary value has a - subtype - - @since version 3.8.0 - */ - constexpr std::uint8_t subtype() const noexcept - { - return m_subtype; - } - - /*! - @brief return whether the value has a subtype - - @return whether the value has a subtype - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @sa @ref subtype() -- return the binary subtype - @sa @ref set_subtype() -- sets the binary subtype - @sa @ref clear_subtype() -- clears the binary subtype - - @since version 3.8.0 - */ - constexpr bool has_subtype() const noexcept - { - return m_has_subtype; - } - - /*! - @brief clears the binary subtype - - Clears the binary subtype and flags the value as not having a subtype, which - has implications for serialization; for instance MessagePack will prefer the - bin family over the ext family. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @sa @ref subtype() -- return the binary subtype - @sa @ref set_subtype() -- sets the binary subtype - @sa @ref has_subtype() -- returns whether or not the binary value has a - subtype - - @since version 3.8.0 - */ - void clear_subtype() noexcept - { - m_subtype = 0; - m_has_subtype = false; - } - - private: - std::uint8_t m_subtype = 0; - bool m_has_subtype = false; -}; - -} // namespace detail -} // namespace nlohmann - // #include @@ -16681,7 +16684,7 @@ class basic_json @since version 3.8.0 */ - using binary_t = nlohmann::detail::wrapped_binary_t; + using binary_t = nlohmann::byte_container_with_subtype; /// @} private: @@ -16724,7 +16727,7 @@ class basic_json number | number_integer | @ref number_integer_t number | number_unsigned | @ref number_unsigned_t number | number_float | @ref number_float_t - binary | binary | pointer to @ref internal_binary_t + binary | binary | pointer to @ref binary_t null | null | *no value is stored* @note Variable-length types (objects, arrays, and strings) are stored as @@ -17423,22 +17426,22 @@ class basic_json } /*! - @brief explicitly create a binary array from an already constructed copy of - its base type + @brief explicitly create a binary array (without subtype) - Creates a JSON binary array value from a given `binary_t`. Binary values are - part of various binary formats, such as CBOR, MsgPack, and BSON. And this - constructor is used to create a value for serialization to those formats. + Creates a JSON binary array value from a given binary container. Binary + values are part of various binary formats, such as CBOR, MessagePack, and + BSON. This constructor is used to create a value for serialization to those + formats. @note Note, this function exists because of the difficulty in correctly specifying the correct template overload in the standard value ctor, as both JSON arrays and JSON binary arrays are backed with some form of a - `std::vector`. Because JSON binary arrays are a non-standard extension it + `std::vector`. Because JSON binary arrays are a non-standard extension it was decided that it would be best to prevent automatic initialization of a binary array type, for backwards compatibility and so it does not happen on accident. - @param[in] init `binary_t` with JSON values to create a binary array from + @param[in] init container containing bytes to use as binary type @return JSON binary array value @@ -17458,32 +17461,24 @@ class basic_json return res; } - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json binary_array(const typename binary_t::container_type& init, std::uint8_t subtype) - { - auto res = basic_json(); - res.m_type = value_t::binary; - res.m_value = binary_t(init, subtype); - return res; - } - /*! - @brief explicitly create a binary array from an already constructed rvalue - copy of its base type + @brief explicitly create a binary array (with subtype) - Creates a JSON binary array value from a given `binary_t`. Binary values are - part of various binary formats, such as CBOR, MsgPack, and BSON. And this - constructor is used to create a value for serialization to those formats. + Creates a JSON binary array value from a given binary container. Binary + values are part of various binary formats, such as CBOR, MessagePack, and + BSON. This constructor is used to create a value for serialization to those + formats. @note Note, this function exists because of the difficulty in correctly specifying the correct template overload in the standard value ctor, as both JSON arrays and JSON binary arrays are backed with some form of a - `std::vector`. Because JSON binary arrays are a non-standard extension it + `std::vector`. Because JSON binary arrays are a non-standard extension it was decided that it would be best to prevent automatic initialization of a - binary array type, for backwards compatibility and so it doesn't happen on + binary array type, for backwards compatibility and so it does not happen on accident. - @param[in] init `binary_t` with JSON values to create a binary array from + @param[in] init container containing bytes to use as binary type + @param[in] subtype subtype to use in MessagePack and BSON @return JSON binary array value @@ -17495,6 +17490,16 @@ class basic_json @since version 3.8.0 */ JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json binary_array(const typename binary_t::container_type& init, std::uint8_t subtype) + { + auto res = basic_json(); + res.m_type = value_t::binary; + res.m_value = binary_t(init, subtype); + return res; + } + + /// @copydoc binary_array(const typename binary_t::container_type&) + JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json binary_array(typename binary_t::container_type&& init) { auto res = basic_json(); @@ -17503,6 +17508,7 @@ class basic_json return res; } + /// @copydoc binary_array(const typename binary_t::container_type&, std::uint8_t) JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json binary_array(typename binary_t::container_type&& init, std::uint8_t subtype) { @@ -22737,7 +22743,8 @@ class basic_json number_unsigned | 256..65535 | Unsigned integer (2 bytes follow) | 0x19 number_unsigned | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1A number_unsigned | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1B - number_float | *any value* | Double-Precision Float | 0xFB + number_float | *any value representable by a float* | Single-Precision Float | 0xFA + number_float | *any value NOT representable by a float* | Double-Precision Float | 0xFB string | *length*: 0..23 | UTF-8 string | 0x60..0x77 string | *length*: 23..255 | UTF-8 string (1 byte follow) | 0x78 string | *length*: 256..65535 | UTF-8 string (2 bytes follow) | 0x79 @@ -22779,7 +22786,7 @@ class basic_json - expected conversions (0xD5..0xD7) - simple values (0xE0..0xF3, 0xF8) - undefined (0xF7) - - half and single-precision floats (0xF9-0xFA) + - half-precision floats (0xF9) - break (0xFF) @param[in] j JSON value to serialize @@ -22797,7 +22804,8 @@ class basic_json @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the related UBJSON format - @since version 2.0.9 + @since version 2.0.9; compact representation of floating-point numbers + since version 3.8.0 */ static std::vector to_cbor(const basic_json& j) { From 21b1680ea18165d5ceb0854a2d27aa4e2b5a3e4e Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Tue, 19 May 2020 13:30:22 +0200 Subject: [PATCH 34/36] :truck: rename binary_array() to binary() --- .../nlohmann/byte_container_with_subtype.hpp | 12 +++++++++ include/nlohmann/json.hpp | 14 +++++----- single_include/nlohmann/json.hpp | 26 ++++++++++++++----- test/src/unit-bson.cpp | 4 +-- test/src/unit-cbor.cpp | 14 +++++----- test/src/unit-comparison.cpp | 2 +- test/src/unit-constructor1.cpp | 6 ++--- test/src/unit-constructor2.cpp | 4 +-- test/src/unit-element_access1.cpp | 8 +++--- test/src/unit-inspection.cpp | 4 +-- test/src/unit-modifiers.cpp | 16 ++++++------ test/src/unit-msgpack.cpp | 12 ++++----- test/src/unit-pointer_access.cpp | 4 +-- test/src/unit-serialization.cpp | 8 +++--- test/src/unit-ubjson.cpp | 10 +++---- test/src/unit-udt.cpp | 2 +- 16 files changed, 85 insertions(+), 61 deletions(-) diff --git a/include/nlohmann/byte_container_with_subtype.hpp b/include/nlohmann/byte_container_with_subtype.hpp index 243ece37a5..b2eef1b7cb 100644 --- a/include/nlohmann/byte_container_with_subtype.hpp +++ b/include/nlohmann/byte_container_with_subtype.hpp @@ -1,6 +1,7 @@ #pragma once #include // uint8_t +#include // tie #include // move namespace nlohmann @@ -51,6 +52,17 @@ class byte_container_with_subtype : public BinaryType , m_has_subtype(true) {} + bool operator==(const byte_container_with_subtype& rhs) const + { + return std::tie(static_cast(*this), m_subtype, m_has_subtype) == + std::tie(static_cast(rhs), rhs.m_subtype, rhs.m_has_subtype); + } + + bool operator!=(const byte_container_with_subtype& rhs) const + { + return !(rhs == *this); + } + /*! @brief sets the binary subtype diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 38f8f20326..df0066949e 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -899,7 +899,7 @@ class basic_json - If a subtype is given, it is used and added as unsigned 8-bit integer. - If no subtype is given, the generic binary subtype 0x00 is used. - @sa @ref binary_array -- create a binary array + @sa @ref binary -- create a binary array @since version 3.8.0 */ @@ -1672,7 +1672,7 @@ class basic_json @since version 3.8.0 */ JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json binary_array(const typename binary_t::container_type& init) + static basic_json binary(const typename binary_t::container_type& init) { auto res = basic_json(); res.m_type = value_t::binary; @@ -1709,7 +1709,7 @@ class basic_json @since version 3.8.0 */ JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json binary_array(const typename binary_t::container_type& init, std::uint8_t subtype) + static basic_json binary(const typename binary_t::container_type& init, std::uint8_t subtype) { auto res = basic_json(); res.m_type = value_t::binary; @@ -1717,9 +1717,9 @@ class basic_json return res; } - /// @copydoc binary_array(const typename binary_t::container_type&) + /// @copydoc binary(const typename binary_t::container_type&) JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json binary_array(typename binary_t::container_type&& init) + static basic_json binary(typename binary_t::container_type&& init) { auto res = basic_json(); res.m_type = value_t::binary; @@ -1727,9 +1727,9 @@ class basic_json return res; } - /// @copydoc binary_array(const typename binary_t::container_type&, std::uint8_t) + /// @copydoc binary(const typename binary_t::container_type&, std::uint8_t) JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json binary_array(typename binary_t::container_type&& init, std::uint8_t subtype) + static basic_json binary(typename binary_t::container_type&& init, std::uint8_t subtype) { auto res = basic_json(); res.m_type = value_t::binary; diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index f774377265..e8c7ecb9a1 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -4227,6 +4227,7 @@ struct adl_serializer #include // uint8_t +#include // tie #include // move namespace nlohmann @@ -4277,6 +4278,17 @@ class byte_container_with_subtype : public BinaryType , m_has_subtype(true) {} + bool operator==(const byte_container_with_subtype& rhs) const + { + return std::tie(static_cast(*this), m_subtype, m_has_subtype) == + std::tie(static_cast(rhs), rhs.m_subtype, rhs.m_has_subtype); + } + + bool operator!=(const byte_container_with_subtype& rhs) const + { + return !(rhs == *this); + } + /*! @brief sets the binary subtype @@ -16680,7 +16692,7 @@ class basic_json - If a subtype is given, it is used and added as unsigned 8-bit integer. - If no subtype is given, the generic binary subtype 0x00 is used. - @sa @ref binary_array -- create a binary array + @sa @ref binary -- create a binary array @since version 3.8.0 */ @@ -17453,7 +17465,7 @@ class basic_json @since version 3.8.0 */ JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json binary_array(const typename binary_t::container_type& init) + static basic_json binary(const typename binary_t::container_type& init) { auto res = basic_json(); res.m_type = value_t::binary; @@ -17490,7 +17502,7 @@ class basic_json @since version 3.8.0 */ JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json binary_array(const typename binary_t::container_type& init, std::uint8_t subtype) + static basic_json binary(const typename binary_t::container_type& init, std::uint8_t subtype) { auto res = basic_json(); res.m_type = value_t::binary; @@ -17498,9 +17510,9 @@ class basic_json return res; } - /// @copydoc binary_array(const typename binary_t::container_type&) + /// @copydoc binary(const typename binary_t::container_type&) JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json binary_array(typename binary_t::container_type&& init) + static basic_json binary(typename binary_t::container_type&& init) { auto res = basic_json(); res.m_type = value_t::binary; @@ -17508,9 +17520,9 @@ class basic_json return res; } - /// @copydoc binary_array(const typename binary_t::container_type&, std::uint8_t) + /// @copydoc binary(const typename binary_t::container_type&, std::uint8_t) JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json binary_array(typename binary_t::container_type&& init, std::uint8_t subtype) + static basic_json binary(typename binary_t::container_type&& init, std::uint8_t subtype) { auto res = basic_json(); res.m_type = value_t::binary; diff --git a/test/src/unit-bson.cpp b/test/src/unit-bson.cpp index 318286d124..2a17f180e5 100644 --- a/test/src/unit-bson.cpp +++ b/test/src/unit-bson.cpp @@ -499,7 +499,7 @@ TEST_CASE("BSON") const auto s = std::vector(N, 'x'); json j = { - { "entry", json::binary_array(s) } + { "entry", json::binary(s) } }; std::vector expected = @@ -529,7 +529,7 @@ TEST_CASE("BSON") const std::vector md5hash = {0xd7, 0x7e, 0x27, 0x54, 0xbe, 0x12, 0x37, 0xfe, 0xd6, 0x0c, 0x33, 0x98, 0x30, 0x3b, 0x8d, 0xc4}; json j = { - { "entry", json::binary_array(md5hash, 5) } + { "entry", json::binary(md5hash, 5) } }; std::vector expected = diff --git a/test/src/unit-cbor.cpp b/test/src/unit-cbor.cpp index d34ae7890f..d7b872557f 100644 --- a/test/src/unit-cbor.cpp +++ b/test/src/unit-cbor.cpp @@ -1450,7 +1450,7 @@ TEST_CASE("CBOR") // create JSON value with byte array containing of N * 'x' const auto s = std::vector(N, 'x'); - json j = json::binary_array(s); + json j = json::binary(s); // create expected byte vector std::vector expected; @@ -1484,7 +1484,7 @@ TEST_CASE("CBOR") // create JSON value with string containing of N * 'x' const auto s = std::vector(N, 'x'); - json j = json::binary_array(s); + json j = json::binary(s); // create expected byte vector std::vector expected; @@ -1519,7 +1519,7 @@ TEST_CASE("CBOR") // create JSON value with string containing of N * 'x' const auto s = std::vector(N, 'x'); - json j = json::binary_array(s); + json j = json::binary(s); // create expected byte vector (hack: create string first) std::vector expected(N, 'x'); @@ -1552,7 +1552,7 @@ TEST_CASE("CBOR") // create JSON value with string containing of N * 'x' const auto s = std::vector(N, 'x'); - json j = json::binary_array(s); + json j = json::binary(s); // create expected byte vector (hack: create string first) std::vector expected(N, 'x'); @@ -1581,7 +1581,7 @@ TEST_CASE("CBOR") std::vector input = {0x5F, 0x44, 0xaa, 0xbb, 0xcc, 0xdd, 0x43, 0xee, 0xff, 0x99, 0xFF}; auto j = json::from_cbor(input); CHECK(j.is_binary()); - auto k = json::binary_array({0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x99}); + auto k = json::binary({0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x99}); CAPTURE(j.dump(0, ' ', false, json::error_handler_t::strict)) CHECK(j == k); } @@ -1633,7 +1633,7 @@ TEST_CASE("CBOR") 0x00, 0x00, 0x00, 0x01, 0x61 }; json j = json::from_cbor(given); - CHECK(j == json::binary_array(std::vector {'a'})); + CHECK(j == json::binary(std::vector {'a'})); } SECTION("0x7b (string)") @@ -2502,7 +2502,7 @@ TEST_CASE("examples from RFC 7049 Appendix A") std::ifstream f_bin(TEST_DATA_DIRECTORY "/binary_data/cbor_binary.out", std::ios::binary); std::vector expected((std::istreambuf_iterator(f_bin)), std::istreambuf_iterator()); - CHECK(j == json::binary_array(expected)); + CHECK(j == json::binary(expected)); } SECTION("arrays") diff --git a/test/src/unit-comparison.cpp b/test/src/unit-comparison.cpp index 91fbe1b461..db46507cab 100644 --- a/test/src/unit-comparison.cpp +++ b/test/src/unit-comparison.cpp @@ -101,7 +101,7 @@ TEST_CASE("lexicographical comparison operators") true, false, {1, 2, 3}, {"one", "two", "three"}, {{"first", 1}, {"second", 2}}, {{"a", "A"}, {"b", {"B"}}}, - json::binary_array({1, 2, 3}), json::binary_array({1, 2, 4}) + json::binary({1, 2, 3}), json::binary({1, 2, 4}) }; SECTION("comparison: equal") diff --git a/test/src/unit-constructor1.cpp b/test/src/unit-constructor1.cpp index 81fca64ac5..0240feef4d 100644 --- a/test/src/unit-constructor1.cpp +++ b/test/src/unit-constructor1.cpp @@ -121,7 +121,7 @@ TEST_CASE("constructors") auto t = json::value_t::binary; json j(t); CHECK(j.type() == t); - CHECK(j == json::binary_array({})); + CHECK(j == json::binary({})); } } @@ -1482,12 +1482,12 @@ TEST_CASE("constructors") SECTION("binary") { { - json j = json::binary_array({1, 2, 3}); + json j = json::binary({1, 2, 3}); json j_new(j.begin(), j.end()); CHECK((j == j_new)); } { - json j = json::binary_array({1, 2, 3}); + json j = json::binary({1, 2, 3}); json j_new(j.cbegin(), j.cend()); CHECK((j == j_new)); } diff --git a/test/src/unit-constructor2.cpp b/test/src/unit-constructor2.cpp index 8bbb5197c7..df20695cf3 100644 --- a/test/src/unit-constructor2.cpp +++ b/test/src/unit-constructor2.cpp @@ -94,7 +94,7 @@ TEST_CASE("other constructors and destructor") SECTION("binary") { - json j = json::binary_array({1, 2, 3}); + json j = json::binary({1, 2, 3}); json k(j); CHECK(j == k); } @@ -177,7 +177,7 @@ TEST_CASE("other constructors and destructor") SECTION("binary") { - json j = json::binary_array({1, 2, 3}); + json j = json::binary({1, 2, 3}); json k; k = j; CHECK(j == k); diff --git a/test/src/unit-element_access1.cpp b/test/src/unit-element_access1.cpp index 46638e2728..a0a18fecb8 100644 --- a/test/src/unit-element_access1.cpp +++ b/test/src/unit-element_access1.cpp @@ -698,13 +698,13 @@ TEST_CASE("element access 1") SECTION("binary") { { - json j = json::binary_array({1, 2, 3}); + json j = json::binary({1, 2, 3}); json::iterator it = j.erase(j.begin()); CHECK(j.type() == json::value_t::null); CHECK(it == j.end()); } { - json j = json::binary_array({1, 2, 3}); + json j = json::binary({1, 2, 3}); json::const_iterator it = j.erase(j.cbegin()); CHECK(j.type() == json::value_t::null); CHECK(it == j.end()); @@ -896,13 +896,13 @@ TEST_CASE("element access 1") SECTION("binary") { { - json j = json::binary_array({1, 2, 3}); + json j = json::binary({1, 2, 3}); json::iterator it = j.erase(j.begin(), j.end()); CHECK(j.type() == json::value_t::null); CHECK(it == j.end()); } { - json j = json::binary_array({1, 2, 3}); + json j = json::binary({1, 2, 3}); json::const_iterator it = j.erase(j.cbegin(), j.cend()); CHECK(j.type() == json::value_t::null); CHECK(it == j.end()); diff --git a/test/src/unit-inspection.cpp b/test/src/unit-inspection.cpp index d14b89afd2..a5f4519b61 100644 --- a/test/src/unit-inspection.cpp +++ b/test/src/unit-inspection.cpp @@ -262,7 +262,7 @@ TEST_CASE("object inspection") // inside the dump() function CHECK(j.dump(1024).size() == 15472); - const auto binary = json::binary_array({1, 2, 3}, 128); + const auto binary = json::binary({1, 2, 3}, 128); CHECK(binary.dump(1024).size() == 2086); } @@ -472,7 +472,7 @@ TEST_CASE("object inspection") SECTION("binary") { - json j = json::binary_array({}); + json j = json::binary({}); json::value_t t = j; CHECK(t == j.type()); } diff --git a/test/src/unit-modifiers.cpp b/test/src/unit-modifiers.cpp index 955051a6b0..9214c60822 100644 --- a/test/src/unit-modifiers.cpp +++ b/test/src/unit-modifiers.cpp @@ -110,7 +110,7 @@ TEST_CASE("modifiers") { SECTION("empty binary") { - json j = json::binary_array({}); + json j = json::binary({}); json k = j; j.clear(); @@ -121,7 +121,7 @@ TEST_CASE("modifiers") SECTION("filled binary") { - json j = json::binary_array({1, 2, 3, 4, 5}); + json j = json::binary({1, 2, 3, 4, 5}); json k = j; j.clear(); @@ -967,30 +967,30 @@ TEST_CASE("modifiers") { SECTION("binary_t type") { - json j = json::binary_array({1, 2, 3, 4}); + json j = json::binary({1, 2, 3, 4}); json::binary_t s = {{5, 6, 7, 8}}; j.swap(s); - CHECK(j == json::binary_array({5, 6, 7, 8})); + CHECK(j == json::binary({5, 6, 7, 8})); j.swap(s); - CHECK(j == json::binary_array({1, 2, 3, 4})); + CHECK(j == json::binary({1, 2, 3, 4})); } SECTION("binary_t::container_type type") { - json j = json::binary_array({1, 2, 3, 4}); + json j = json::binary({1, 2, 3, 4}); std::vector s = {{5, 6, 7, 8}}; j.swap(s); - CHECK(j == json::binary_array({5, 6, 7, 8})); + CHECK(j == json::binary({5, 6, 7, 8})); j.swap(s); - CHECK(j == json::binary_array({1, 2, 3, 4})); + CHECK(j == json::binary({1, 2, 3, 4})); } SECTION("non-binary_t type") diff --git a/test/src/unit-msgpack.cpp b/test/src/unit-msgpack.cpp index acdafaa83d..2fb89533b2 100644 --- a/test/src/unit-msgpack.cpp +++ b/test/src/unit-msgpack.cpp @@ -1132,7 +1132,7 @@ TEST_CASE("MessagePack") // create JSON value with byte array containing of N * 'x' const auto s = std::vector(N, 'x'); - json j = json::binary_array(s); + json j = json::binary(s); std::uint8_t subtype = 42; j.get_binary().set_subtype(subtype); @@ -1207,7 +1207,7 @@ TEST_CASE("MessagePack") // create JSON value with string containing of N * 'x' const auto s = std::vector(N, 'x'); - json j = json::binary_array(s); + json j = json::binary(s); std::uint8_t subtype = 42; j.get_binary().set_subtype(subtype); @@ -1243,7 +1243,7 @@ TEST_CASE("MessagePack") // create JSON value with string containing of N * 'x' const auto s = std::vector(N, 'x'); - json j = json::binary_array(s); + json j = json::binary(s); std::uint8_t subtype = 42; j.get_binary().set_subtype(subtype); @@ -1281,7 +1281,7 @@ TEST_CASE("MessagePack") // create JSON value with byte array containing of N * 'x' const auto s = std::vector(N, 'x'); - json j = json::binary_array(s); + json j = json::binary(s); // create expected byte vector std::vector expected; @@ -1319,7 +1319,7 @@ TEST_CASE("MessagePack") // create JSON value with string containing of N * 'x' const auto s = std::vector(N, 'x'); - json j = json::binary_array(s); + json j = json::binary(s); // create expected byte vector (hack: create string first) std::vector expected(N, 'x'); @@ -1352,7 +1352,7 @@ TEST_CASE("MessagePack") // create JSON value with string containing of N * 'x' const auto s = std::vector(N, 'x'); - json j = json::binary_array(s); + json j = json::binary(s); // create expected byte vector (hack: create string first) std::vector expected(N, 'x'); diff --git a/test/src/unit-pointer_access.cpp b/test/src/unit-pointer_access.cpp index 72ee1ab7dc..36a052498f 100644 --- a/test/src/unit-pointer_access.cpp +++ b/test/src/unit-pointer_access.cpp @@ -443,7 +443,7 @@ TEST_CASE("pointer access") SECTION("pointer access to const binary_t") { using test_type = const json::binary_t; - const json value = json::binary_array({1, 2, 3}); + const json value = json::binary({1, 2, 3}); // check if pointers are returned correctly test_type* p1 = value.get_ptr(); @@ -472,7 +472,7 @@ TEST_CASE("pointer access") SECTION("pointer access to const binary_t") { using test_type = const json::binary_t; - const json value = json::binary_array({}); + const json value = json::binary({}); // check if pointers are returned correctly test_type* p1 = value.get_ptr(); diff --git a/test/src/unit-serialization.cpp b/test/src/unit-serialization.cpp index d0ddc58f05..067d44c67c 100644 --- a/test/src/unit-serialization.cpp +++ b/test/src/unit-serialization.cpp @@ -209,10 +209,10 @@ TEST_CASE_TEMPLATE("serialization for extreme integer values", T, int32_t, uint3 TEST_CASE("dump with binary values") { - auto binary = json::binary_array({1, 2, 3, 4}); - auto binary_empty = json::binary_array({}); - auto binary_with_subtype = json::binary_array({1, 2, 3, 4}, 128); - auto binary_empty_with_subtype = json::binary_array({}, 128); + auto binary = json::binary({1, 2, 3, 4}); + auto binary_empty = json::binary({}); + auto binary_with_subtype = json::binary({1, 2, 3, 4}, 128); + auto binary_empty_with_subtype = json::binary({}, 128); json object = {{"key", binary}}; json object_empty = {{"key", binary_empty}}; diff --git a/test/src/unit-ubjson.cpp b/test/src/unit-ubjson.cpp index e3395bf226..d6dde7ad7b 100644 --- a/test/src/unit-ubjson.cpp +++ b/test/src/unit-ubjson.cpp @@ -921,7 +921,7 @@ TEST_CASE("UBJSON") // create JSON value with byte array containing of N * 'x' const auto s = std::vector(N, 'x'); - json j = json::binary_array(s); + json j = json::binary(s); // create expected byte vector std::vector expected; @@ -972,7 +972,7 @@ TEST_CASE("UBJSON") // create JSON value with byte array containing of N * 'x' const auto s = std::vector(N, 'x'); - json j = json::binary_array(s); + json j = json::binary(s); // create expected byte vector std::vector expected; @@ -1012,7 +1012,7 @@ TEST_CASE("UBJSON") // create JSON value with byte array containing of N * 'x' const auto s = std::vector(N, 'x'); - json j = json::binary_array(s); + json j = json::binary(s); // create expected byte vector std::vector expected(N + 7, 'x'); @@ -1049,7 +1049,7 @@ TEST_CASE("UBJSON") // create JSON value with byte array containing of N * 'x' const auto s = std::vector(N, 'x'); - json j = json::binary_array(s); + json j = json::binary(s); // create expected byte vector std::vector expected(N + 9, 'x'); @@ -1081,7 +1081,7 @@ TEST_CASE("UBJSON") { const std::size_t N = 10; const auto s = std::vector(N, 'x'); - json j = json::binary_array(s); + json j = json::binary(s); SECTION("No Count No Type") { diff --git a/test/src/unit-udt.cpp b/test/src/unit-udt.cpp index 42b1375ef7..bb1c1f1b6c 100644 --- a/test/src/unit-udt.cpp +++ b/test/src/unit-udt.cpp @@ -765,7 +765,7 @@ TEST_CASE("different basic_json types conversions") SECTION("binary") { - json j = json::binary_array({1, 2, 3}); + json j = json::binary({1, 2, 3}); custom_json cj = j; CHECK(cj.get_binary() == j.get_binary()); } From 4d39644bd048d16e0674a7285445af06d2b79fa4 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Tue, 19 May 2020 13:45:52 +0200 Subject: [PATCH 35/36] :green_heart: fix build --- .github/workflows/macos.yml | 2 +- .github/workflows/ubuntu.yml | 2 +- .github/workflows/windows.yml | 2 +- test/src/unit-bson.cpp | 2 +- test/src/unit-udt.cpp | 7 +++++-- 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 96435a636f..4444f72bab 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -14,4 +14,4 @@ jobs: - name: build run: cmake --build build --parallel 10 - name: test - run: cd build ; ctest -j 10 + run: cd build ; ctest -j 10 --output-on-failure diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 5aa0dacbb7..6ee33cfae1 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -14,4 +14,4 @@ jobs: - name: build run: cmake --build build --parallel 10 - name: test - run: cd build ; ctest -j 10 + run: cd build ; ctest -j 10 --output-on-failure diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 2758c185de..f4b07c89b0 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -14,4 +14,4 @@ jobs: - name: build run: cmake --build build --parallel 10 - name: test - run: cd build ; ctest -j 10 -C Debug --exclude-regex "test-unicode" + run: cd build ; ctest -j 10 -C Debug --exclude-regex "test-unicode" --output-on-failure diff --git a/test/src/unit-bson.cpp b/test/src/unit-bson.cpp index 2a17f180e5..3f3dbd10e1 100644 --- a/test/src/unit-bson.cpp +++ b/test/src/unit-bson.cpp @@ -499,7 +499,7 @@ TEST_CASE("BSON") const auto s = std::vector(N, 'x'); json j = { - { "entry", json::binary(s) } + { "entry", json::binary(s, 0) } }; std::vector expected = diff --git a/test/src/unit-udt.cpp b/test/src/unit-udt.cpp index bb1c1f1b6c..2040899edb 100644 --- a/test/src/unit-udt.cpp +++ b/test/src/unit-udt.cpp @@ -765,9 +765,12 @@ TEST_CASE("different basic_json types conversions") SECTION("binary") { - json j = json::binary({1, 2, 3}); + json j = json::binary({1, 2, 3}, 42); custom_json cj = j; - CHECK(cj.get_binary() == j.get_binary()); + CHECK(cj.get_binary().subtype() == 42); + std::vector cv = cj.get_binary(); + std::vector v = j.get_binary(); + CHECK(cv == v); } SECTION("object") From ae29456b3f2995166e2210d47d8917cb2e1cb744 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Wed, 20 May 2020 18:57:21 +0200 Subject: [PATCH 36/36] :children_crossing: overwork report templates --- .github/ISSUE_TEMPLATE/Bug_report.md | 49 +++++++++++++++++++---- .github/ISSUE_TEMPLATE/Feature_request.md | 9 ++++- .github/ISSUE_TEMPLATE/question.md | 26 ++++++++++-- 3 files changed, 71 insertions(+), 13 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/Bug_report.md b/.github/ISSUE_TEMPLATE/Bug_report.md index 748357a95e..3485a6895b 100644 --- a/.github/ISSUE_TEMPLATE/Bug_report.md +++ b/.github/ISSUE_TEMPLATE/Bug_report.md @@ -7,16 +7,51 @@ assignees: '' --- -- What is the issue you have? + -- Please describe the steps to reproduce the issue. Can you provide a small but working code example? +#### What is the issue you have? -- What is the expected behavior? + + -- And what is the actual behavior instead? +#### Please describe the steps to reproduce the issue. -- Which compiler and operating system are you using? Is it a [supported compiler](https://github.com/nlohmann/json#supported-compilers)? + + -- Did you use a released version of the library or the version from the `develop` branch? +1. +2. +3. -- If you experience a compilation error: can you [compile and run the unit tests](https://github.com/nlohmann/json#execute-unit-tests)? +#### Can you provide a small but working code example? + + + +#### What is the expected behavior? + + + +#### And what is the actual behavior instead? + + + +#### Which compiler and operating system are you using? + + + + +- Compiler: ___ +- Operating system: ___ + +#### Which version of the library did you use? + + + +- [ ] latest release version 3.7.3 +- [ ] other release - please state the version: ___ +- [ ] the `develop` branch + +#### If you experience a compilation error: can you [compile and run the unit tests](https://github.com/nlohmann/json#execute-unit-tests)? + +- [ ] yes +- [ ] no - please copy/paste the error message below diff --git a/.github/ISSUE_TEMPLATE/Feature_request.md b/.github/ISSUE_TEMPLATE/Feature_request.md index 05a2c946e7..3652a1ee4a 100644 --- a/.github/ISSUE_TEMPLATE/Feature_request.md +++ b/.github/ISSUE_TEMPLATE/Feature_request.md @@ -7,6 +7,11 @@ assignees: '' --- -- Describe the feature in as much detail as possible. +#### Which feature do you want to see in the library? + + + +#### How would the feature be usable for other users? + + -- Include sample usage where appropriate. diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md index 0870cd17b1..ec3ad69e02 100644 --- a/.github/ISSUE_TEMPLATE/question.md +++ b/.github/ISSUE_TEMPLATE/question.md @@ -7,10 +7,28 @@ assignees: '' --- -- Describe what you want to achieve. +#### What do you want to achieve? -- Describe what you tried. + -- Describe which system (OS, compiler) you are using. +#### What have you tried? -- Describe which version of the library you are using (release version, develop branch). + + + + +#### Which compiler and operating system are you using? + + + + +- Compiler: ___ +- Operating system: ___ + +#### Which version of the library did you use? + + + +- [ ] latest release version 3.7.3 +- [ ] other release - please state the version: ___ +- [ ] the `develop` branch