//     __ _____ _____ _____
//  __|  |   __|     |   | |  JSON for Modern C++ (supporting code)
// |  |  |__   |  |  | | | |  version 3.12.0
// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT

#include "doctest_compatibility.h"

#define JSON_TESTS_PRIVATE
#include <nlohmann/json.hpp>
using nlohmann::json;

#include <deque>
#include <forward_list>
#include <fstream>
#include <list>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <valarray>

TEST_CASE("constructors")
{
    SECTION("create an empty value with a given type")
    {
        SECTION("null")
        {
            auto const t = json::value_t::null;
            json const j(t);
            CHECK(j.type() == t);
        }

        SECTION("discarded")
        {
            auto const t = json::value_t::discarded;
            json const j(t);
            CHECK(j.type() == t);
        }

        SECTION("object")
        {
            auto const t = json::value_t::object;
            json const j(t);
            CHECK(j.type() == t);
        }

        SECTION("array")
        {
            auto const t = json::value_t::array;
            json const j(t);
            CHECK(j.type() == t);
        }

        SECTION("boolean")
        {
            auto const t = json::value_t::boolean;
            json const j(t);
            CHECK(j.type() == t);
            CHECK(j == false);
        }

        SECTION("string")
        {
            auto const t = json::value_t::string;
            json const j(t);
            CHECK(j.type() == t);
            CHECK(j == "");
        }

        SECTION("number_integer")
        {
            auto const t = json::value_t::number_integer;
            json const j(t);
            CHECK(j.type() == t);
            CHECK(j == 0);
        }

        SECTION("number_unsigned")
        {
            auto const t = json::value_t::number_unsigned;
            json const j(t);
            CHECK(j.type() == t);
            CHECK(j == 0);
        }

        SECTION("number_float")
        {
            auto const t = json::value_t::number_float;
            json const j(t);
            CHECK(j.type() == t);
            CHECK(j == 0.0);
        }

        SECTION("binary")
        {
            auto const t = json::value_t::binary;
            json const j(t);
            CHECK(j.type() == t);
            CHECK(j == json::binary({}));
        }
    }

    SECTION("create a null object (implicitly)")
    {
        SECTION("no parameter")
        {
            json const j{};
            CHECK(j.type() == json::value_t::null);
        }
    }

    SECTION("create a null object (explicitly)")
    {
        SECTION("parameter")
        {
            json const j(nullptr);
            CHECK(j.type() == json::value_t::null);
        }
    }

    SECTION("create an object (explicit)")
    {
        SECTION("empty object")
        {
            json::object_t const o{};
            json const j(o);
            CHECK(j.type() == json::value_t::object);
        }

        SECTION("filled object")
        {
            json::object_t const o {{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}};
            json const j(o);
            CHECK(j.type() == json::value_t::object);
        }
    }

    SECTION("create an object (implicit)")
    {
        // reference object
        json::object_t const o_reference {{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}};
        json const j_reference(o_reference);

        SECTION("std::map<json::string_t, json>")
        {
            std::map<json::string_t, json> const o {{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}};
            json const j(o);
            CHECK(j.type() == json::value_t::object);
            CHECK(j == j_reference);
        }

        SECTION("std::map<std::string, std::string> #600")
        {
            const std::map<std::string, std::string> m
            {
                {"a", "b"},
                {"c", "d"},
                {"e", "f"},
            };

            json const j(m);
            CHECK((j.get<decltype(m)>() == m));
        }

        SECTION("std::map<const char*, json>")
        {
            std::map<const char*, json> const o {{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}};
            json const j(o);
            CHECK(j.type() == json::value_t::object);
            CHECK(j == j_reference);
        }

        SECTION("std::multimap<json::string_t, json>")
        {
            std::multimap<json::string_t, json> const o {{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}};
            json const j(o);
            CHECK(j.type() == json::value_t::object);
            CHECK(j == j_reference);
        }

        SECTION("std::unordered_map<json::string_t, json>")
        {
            std::unordered_map<json::string_t, json> const o {{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}};
            json const j(o);
            CHECK(j.type() == json::value_t::object);
            CHECK(j == j_reference);
        }

        SECTION("std::unordered_multimap<json::string_t, json>")
        {
            std::unordered_multimap<json::string_t, json> const o {{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}};
            json const j(o);
            CHECK(j.type() == json::value_t::object);
            CHECK(j == j_reference);
        }

        SECTION("associative container literal")
        {
            json const j({{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}});
            CHECK(j.type() == json::value_t::object);
            CHECK(j == j_reference);
        }
    }

    SECTION("create an array (explicit)")
    {
        SECTION("empty array")
        {
            json::array_t const a{};
            json const j(a);
            CHECK(j.type() == json::value_t::array);
        }

        SECTION("filled array")
        {
            json::array_t const a {json(1), json(1u), json(2.2), json(false), json("string"), json()};
            json const j(a);
            CHECK(j.type() == json::value_t::array);
        }
    }

    SECTION("create an array (implicit)")
    {
        // reference array
        json::array_t const a_reference {json(1), json(1u), json(2.2), json(false), json("string"), json()};
        json const j_reference(a_reference);

        SECTION("std::list<json>")
        {
            std::list<json> const a {json(1), json(1u), json(2.2), json(false), json("string"), json()};
            json const j(a);
            CHECK(j.type() == json::value_t::array);
            CHECK(j == j_reference);
        }

        SECTION("std::pair")
        {
            std::pair<float, std::string> const p{1.0f, "string"};
            json const j(p);

            CHECK(j.type() == json::value_t::array);
            CHECK(j.get<decltype(p)>() == p);
            REQUIRE(j.size() == 2);
            CHECK(j[0] == std::get<0>(p));
            CHECK(j[1] == std::get<1>(p));
        }

        SECTION("std::pair with discarded values")
        {
            json const j{1, 2.0, "string"};

            const auto p = j.get<std::pair<int, float>>();
            CHECK(p.first == j[0]);
            CHECK(p.second == j[1]);
        }

        SECTION("std::tuple")
        {
            const auto t = std::make_tuple(1.0, std::string{"string"}, 42, std::vector<int> {0, 1});
            json const j(t);

            CHECK(j.type() == json::value_t::array);
            REQUIRE(j.size() == 4);
            CHECK(j.get<decltype(t)>() == t);
            CHECK(j[0] == std::get<0>(t));
            CHECK(j[1] == std::get<1>(t));
            CHECK(j[2] == std::get<2>(t));
            CHECK(j[3][0] == 0);
            CHECK(j[3][1] == 1);
        }

        SECTION("std::tuple with discarded values")
        {
            json const j{1, 2.0, "string", 42};

            const auto t = j.get<std::tuple<int, float, std::string>>();
            CHECK(std::get<0>(t) == j[0]);
            CHECK(std::get<1>(t) == j[1]);
            CHECK(std::get<2>(t) == j[2]);
        }

        SECTION("std::tuple tie")
        {
            const auto a = 1.0;
            const auto* const b = "string";
            const auto c = 42;
            const auto d = std::vector<int> {0, 2};
            const size_t e = 1234;
            auto t = std::tie(a, b, c, d, e);
            json const j(t);

            double a_out = 0;
            std::string b_out;
            int c_out = 0;
            std::vector<int> d_out;
            int64_t e_out = 0;
            auto t_out = std::tie(a_out, b_out, c_out, d_out, e_out);
            j.get_to(t_out);
            CHECK(a_out == a);
            CHECK(b_out == b);
            CHECK(c_out == c);
            CHECK(d_out == d);
            CHECK(e_out == e);
        }

        SECTION("std::tuple of references to elements")
        {
            const auto a = 1.0;
            const auto* const b = "string";
            const auto c = 42;
            const size_t d = 1234;
            const auto t = std::tie(a, b, c, d);
            json const j(t);

            auto t_out = j.get<std::tuple<const json::number_float_t&,
                 const json::string_t&,
                 const json::number_integer_t&,
                 const json::number_unsigned_t&>>();
            CHECK(&std::get<0>(t_out) == j[0].get_ptr<const json::number_float_t*>());
            CHECK(&std::get<1>(t_out) == j[1].get_ptr<const json::string_t*>());
            CHECK(&std::get<2>(t_out) == j[2].get_ptr<const json::number_integer_t*>());
            CHECK(&std::get<3>(t_out) == j[3].get_ptr<const json::number_unsigned_t*>());
            CHECK(std::get<0>(t_out) == a);
            CHECK(std::get<1>(t_out) == b);
            CHECK(std::get<2>(t_out) == c);
            CHECK(std::get<3>(t_out) == d);
        }

        SECTION("std::tuple mixed arithmetic types")
        {
            using j_float_t = json::number_float_t;
            using j_int_t = json::number_integer_t;
            using j_uint_t = json::number_unsigned_t;
            const j_float_t a = 1.0;
            const j_int_t b = 1234;
            const j_uint_t c = 42;
            json const j(std::tie(a, b, c, c));

            auto t1 = j.get<std::tuple<j_int_t, j_uint_t, j_float_t, const j_uint_t&>>();
            j_uint_t a2 = 0;
            j_float_t b2 = 0;
            j_int_t c2 = 0;
            auto t2 = std::tie(a2, b2, c2);
            j.get_to(t2);

            CHECK(std::get<0>(t1) == static_cast<j_int_t>(a));
            CHECK(std::get<1>(t1) == static_cast<j_uint_t>(b));
            CHECK(std::get<2>(t1) == static_cast<j_float_t>(c));
            // t1[3] exists only to force usage of the no-default-constructor version
            CHECK(a2 == static_cast<j_uint_t>(a));
            CHECK(b2 == static_cast<j_float_t>(b));
            CHECK(c2 == static_cast<j_int_t>(c));
        }

        SECTION("std::pair/tuple/array failures")
        {
            json const j{1};

            CHECK_THROWS_WITH_AS((j.get<std::pair<int, int>>()), "[json.exception.out_of_range.401] array index 1 is out of range", json::out_of_range&);
            CHECK_THROWS_WITH_AS((j.get<std::tuple<int, int>>()), "[json.exception.out_of_range.401] array index 1 is out of range", json::out_of_range&);
            CHECK_THROWS_WITH_AS((j.get<std::array<int, 3>>()), "[json.exception.out_of_range.401] array index 1 is out of range", json::out_of_range&);
        }

        SECTION("std::forward_list<json>")
        {
            std::forward_list<json> const a {json(1), json(1u), json(2.2), json(false), json("string"), json()};
            json const j(a);
            CHECK(j.type() == json::value_t::array);
            CHECK(j == j_reference);
        }

        SECTION("std::array<json, 6>")
        {
            std::array<json, 6> const a {{json(1), json(1u), json(2.2), json(false), json("string"), json()}};
            json const j(a);
            CHECK(j.type() == json::value_t::array);
            CHECK(j == j_reference);

            const auto a2 = j.get<std::array<json, 6>>();
            CHECK(a2 == a);
        }

        SECTION("std::valarray<int>")
        {
            std::valarray<int> const va = {1, 2, 3, 4, 5};
            json const j(va);
            CHECK(j.type() == json::value_t::array);
            CHECK(j == json({1, 2, 3, 4, 5}));

            auto jva = j.get<std::valarray<int>>();
            CHECK(jva.size() == va.size());
            for (size_t i = 0; i < jva.size(); ++i)
            {
                CHECK(va[i] == jva[i]);
            }
        }

        SECTION("std::valarray<double>")
        {
            std::valarray<double> const va = {1.2, 2.3, 3.4, 4.5, 5.6};
            json const j(va);
            CHECK(j.type() == json::value_t::array);
            CHECK(j == json({1.2, 2.3, 3.4, 4.5, 5.6}));

            auto jva = j.get<std::valarray<double>>();
            CHECK(jva.size() == va.size());
            for (size_t i = 0; i < jva.size(); ++i)
            {
                CHECK(va[i] == jva[i]);
            }
        }

        SECTION("std::vector<json>")
        {
            std::vector<json> const a {json(1), json(1u), json(2.2), json(false), json("string"), json()};
            json const j(a);
            CHECK(j.type() == json::value_t::array);
            CHECK(j == j_reference);
        }

        SECTION("std::deque<json>")
        {
            std::deque<json> const a {json(1), json(1u), json(2.2), json(false), json("string"), json()};
            json const j(a);
            CHECK(j.type() == json::value_t::array);
            CHECK(j == j_reference);
        }

        SECTION("std::set<json>")
        {
            std::set<json> const a {json(1), json(1u), json(2.2), json(false), json("string"), json()};
            json const j(a);
            CHECK(j.type() == json::value_t::array);
            // we cannot really check for equality here
        }

        SECTION("std::unordered_set<json>")
        {
            std::unordered_set<json> const a {json(1), json(1u), json(2.2), json(false), json("string"), json()};
            json const j(a);
            CHECK(j.type() == json::value_t::array);
            // we cannot really check for equality here
        }

        SECTION("sequence container literal")
        {
            json const j({json(1), json(1u), json(2.2), json(false), json("string"), json()});
            CHECK(j.type() == json::value_t::array);
            CHECK(j == j_reference);
        }
    }

    SECTION("create a string (explicit)")
    {
        SECTION("empty string")
        {
            json::string_t const s{};
            json const j(s);
            CHECK(j.type() == json::value_t::string);
        }

        SECTION("filled string")
        {
            json::string_t const s {"Hello world"};
            json const j(s);
            CHECK(j.type() == json::value_t::string);
        }
    }

    SECTION("create a string (implicit)")
    {
        // reference string
        json::string_t const s_reference {"Hello world"};
        json const j_reference(s_reference);

        SECTION("std::string")
        {
            std::string const s {"Hello world"};
            json const j(s);
            CHECK(j.type() == json::value_t::string);
            CHECK(j == j_reference);
        }

        SECTION("char[]")
        {
            const char s[] {"Hello world"}; // NOLINT(misc-const-correctness,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
            json const j(s);
            CHECK(j.type() == json::value_t::string);
            CHECK(j == j_reference);
        }

        SECTION("const char*")
        {
            const char* s {"Hello world"};
            json const j(s);
            CHECK(j.type() == json::value_t::string);
            CHECK(j == j_reference);
        }

        SECTION("string literal")
        {
            json const j("Hello world");
            CHECK(j.type() == json::value_t::string);
            CHECK(j == j_reference);
        }
    }

    SECTION("create a boolean (explicit)")
    {
        SECTION("empty boolean")
        {
            json::boolean_t const b{};
            json const j(b);
            CHECK(j.type() == json::value_t::boolean);
        }

        SECTION("filled boolean (true)")
        {
            json const j(true);
            CHECK(j.type() == json::value_t::boolean);
        }

        SECTION("filled boolean (false)")
        {
            json const j(false);
            CHECK(j.type() == json::value_t::boolean);
        }

        SECTION("from std::vector<bool>::reference")
        {
            std::vector<bool> v{true};
            json const j(v[0]);
            CHECK(std::is_same<decltype(v[0]), std::vector<bool>::reference>::value);
            CHECK(j.type() == json::value_t::boolean);
        }

        SECTION("from std::vector<bool>::const_reference")
        {
            const std::vector<bool> v{true};
            json const j(v[0]);
            CHECK(std::is_same<decltype(v[0]), std::vector<bool>::const_reference>::value);
            CHECK(j.type() == json::value_t::boolean);
        }
    }

    SECTION("create a binary (explicit)")
    {
        SECTION("empty binary")
        {
            json::binary_t const b{};
            json const j(b);
            CHECK(j.type() == json::value_t::binary);
        }

        SECTION("filled binary")
        {
            json::binary_t const b({1, 2, 3});
            json const j(b);
            CHECK(j.type() == json::value_t::binary);
        }
    }

    SECTION("create an integer number (explicit)")
    {
        SECTION("uninitialized value")
        {
            json::number_integer_t const n{};
            json const j(n);
            CHECK(j.type() == json::value_t::number_integer);
        }

        SECTION("initialized value")
        {
            json::number_integer_t const n(42);
            json const j(n);
            CHECK(j.type() == json::value_t::number_integer);
        }
    }

    SECTION("create an integer number (implicit)")
    {
        // reference objects
        json::number_integer_t const n_reference = 42;
        json const j_reference(n_reference);
        json::number_unsigned_t const n_unsigned_reference = 42;
        json const j_unsigned_reference(n_unsigned_reference);

        SECTION("short")
        {
            short const n = 42;
            json const j(n);
            CHECK(j.type() == json::value_t::number_integer);
            CHECK(j == j_reference);
        }

        SECTION("unsigned short")
        {
            unsigned short const n = 42;
            json const j(n);
            CHECK(j.type() == json::value_t::number_unsigned);
            CHECK(j == j_unsigned_reference);
        }

        SECTION("int")
        {
            int const n = 42;
            json const j(n);
            CHECK(j.type() == json::value_t::number_integer);
            CHECK(j == j_reference);
        }

        SECTION("unsigned int")
        {
            unsigned int const n = 42;
            json const j(n);
            CHECK(j.type() == json::value_t::number_unsigned);
            CHECK(j == j_unsigned_reference);
        }

        SECTION("long")
        {
            long const n = 42;
            json const j(n);
            CHECK(j.type() == json::value_t::number_integer);
            CHECK(j == j_reference);
        }

        SECTION("unsigned long")
        {
            unsigned long const n = 42;
            json const j(n);
            CHECK(j.type() == json::value_t::number_unsigned);
            CHECK(j == j_unsigned_reference);
        }

        SECTION("long long")
        {
            long long const n = 42;
            json const j(n);
            CHECK(j.type() == json::value_t::number_integer);
            CHECK(j == j_reference);
        }

        SECTION("unsigned long long")
        {
            unsigned long long const n = 42;
            json const j(n);
            CHECK(j.type() == json::value_t::number_unsigned);
            CHECK(j == j_unsigned_reference);
        }

        SECTION("int8_t")
        {
            int8_t const n = 42;
            json const j(n);
            CHECK(j.type() == json::value_t::number_integer);
            CHECK(j == j_reference);
        }

        SECTION("int16_t")
        {
            int16_t const n = 42;
            json const j(n);
            CHECK(j.type() == json::value_t::number_integer);
            CHECK(j == j_reference);
        }

        SECTION("int32_t")
        {
            int32_t const n = 42;
            json const j(n);
            CHECK(j.type() == json::value_t::number_integer);
            CHECK(j == j_reference);
        }

        SECTION("int64_t")
        {
            int64_t const n = 42;
            json const j(n);
            CHECK(j.type() == json::value_t::number_integer);
            CHECK(j == j_reference);
        }

        SECTION("int_fast8_t")
        {
            int_fast8_t const n = 42;
            json const j(n);
            CHECK(j.type() == json::value_t::number_integer);
            CHECK(j == j_reference);
        }

        SECTION("int_fast16_t")
        {
            int_fast16_t const n = 42;
            json const j(n);
            CHECK(j.type() == json::value_t::number_integer);
            CHECK(j == j_reference);
        }

        SECTION("int_fast32_t")
        {
            int_fast32_t const n = 42;
            json const j(n);
            CHECK(j.type() == json::value_t::number_integer);
            CHECK(j == j_reference);
        }

        SECTION("int_fast64_t")
        {
            int_fast64_t const n = 42;
            json const j(n);
            CHECK(j.type() == json::value_t::number_integer);
            CHECK(j == j_reference);
        }

        SECTION("int_least8_t")
        {
            int_least8_t const n = 42;
            json const j(n);
            CHECK(j.type() == json::value_t::number_integer);
            CHECK(j == j_reference);
        }

        SECTION("int_least16_t")
        {
            int_least16_t const n = 42;
            json const j(n);
            CHECK(j.type() == json::value_t::number_integer);
            CHECK(j == j_reference);
        }

        SECTION("int_least32_t")
        {
            int_least32_t const n = 42;
            json const j(n);
            CHECK(j.type() == json::value_t::number_integer);
            CHECK(j == j_reference);
        }

        SECTION("int_least64_t")
        {
            int_least64_t const n = 42;
            json const j(n);
            CHECK(j.type() == json::value_t::number_integer);
            CHECK(j == j_reference);
        }

        SECTION("uint8_t")
        {
            uint8_t const n = 42;
            json const j(n);
            CHECK(j.type() == json::value_t::number_unsigned);
            CHECK(j == j_unsigned_reference);
        }

        SECTION("uint16_t")
        {
            uint16_t const n = 42;
            json const j(n);
            CHECK(j.type() == json::value_t::number_unsigned);
            CHECK(j == j_unsigned_reference);
        }

        SECTION("uint32_t")
        {
            uint32_t const n = 42;
            json const j(n);
            CHECK(j.type() == json::value_t::number_unsigned);
            CHECK(j == j_unsigned_reference);
        }

        SECTION("uint64_t")
        {
            uint64_t const n = 42;
            json const j(n);
            CHECK(j.type() == json::value_t::number_unsigned);
            CHECK(j == j_unsigned_reference);
        }

        SECTION("uint_fast8_t")
        {
            uint_fast8_t const n = 42;
            json const j(n);
            CHECK(j.type() == json::value_t::number_unsigned);
            CHECK(j == j_unsigned_reference);
        }

        SECTION("uint_fast16_t")
        {
            uint_fast16_t const n = 42;
            json const j(n);
            CHECK(j.type() == json::value_t::number_unsigned);
            CHECK(j == j_unsigned_reference);
        }

        SECTION("uint_fast32_t")
        {
            uint_fast32_t const n = 42;
            json const j(n);
            CHECK(j.type() == json::value_t::number_unsigned);
            CHECK(j == j_unsigned_reference);
        }

        SECTION("uint_fast64_t")
        {
            uint_fast64_t const n = 42;
            json const j(n);
            CHECK(j.type() == json::value_t::number_unsigned);
            CHECK(j == j_unsigned_reference);
        }

        SECTION("uint_least8_t")
        {
            uint_least8_t const n = 42;
            json const j(n);
            CHECK(j.type() == json::value_t::number_unsigned);
            CHECK(j == j_unsigned_reference);
        }

        SECTION("uint_least16_t")
        {
            uint_least16_t const n = 42;
            json const j(n);
            CHECK(j.type() == json::value_t::number_unsigned);
            CHECK(j == j_unsigned_reference);
        }

        SECTION("uint_least32_t")
        {
            uint_least32_t const n = 42;
            json const j(n);
            CHECK(j.type() == json::value_t::number_unsigned);
            CHECK(j == j_unsigned_reference);
        }

        SECTION("uint_least64_t")
        {
            uint_least64_t const n = 42;
            json const j(n);
            CHECK(j.type() == json::value_t::number_unsigned);
            CHECK(j == j_unsigned_reference);
        }

        SECTION("integer literal without suffix")
        {
            json const j(42);
            CHECK(j.type() == json::value_t::number_integer);
            CHECK(j == j_reference);
        }

        SECTION("integer literal with u suffix")
        {
            const json j(42u);
            CHECK(j.type() == json::value_t::number_unsigned);
            CHECK(j == j_unsigned_reference);
        }

        SECTION("integer literal with l suffix")
        {
            json const j(42L);
            CHECK(j.type() == json::value_t::number_integer);
            CHECK(j == j_reference);
        }

        SECTION("integer literal with ul suffix")
        {
            const json j(42ul);
            CHECK(j.type() == json::value_t::number_unsigned);
            CHECK(j == j_unsigned_reference);
        }

        SECTION("integer literal with ll suffix")
        {
            json const j(42LL);
            CHECK(j.type() == json::value_t::number_integer);
            CHECK(j == j_reference);
        }

        SECTION("integer literal with ull suffix")
        {
            const json j(42ull);
            CHECK(j.type() == json::value_t::number_unsigned);
            CHECK(j == j_unsigned_reference);
        }
    }

    SECTION("create a floating-point number (explicit)")
    {
        SECTION("uninitialized value")
        {
            json::number_float_t const n{};
            json const j(n);
            CHECK(j.type() == json::value_t::number_float);
        }

        SECTION("initialized value")
        {
            json::number_float_t const n(42.23);
            json const j(n);
            CHECK(j.type() == json::value_t::number_float);
        }

        SECTION("NaN")
        {
            // NaN is stored properly, but serialized to null
            json::number_float_t const n(std::numeric_limits<json::number_float_t>::quiet_NaN());
            json const j(n);
            CHECK(j.type() == json::value_t::number_float);

            // check round trip of NaN
            json::number_float_t const d{j};
            CHECK((std::isnan(d) && std::isnan(n)) == true);

            // check that NaN is serialized to null
            CHECK(j.dump() == "null");
        }

        SECTION("infinity")
        {
            // infinity is stored properly, but serialized to null
            json::number_float_t const n(std::numeric_limits<json::number_float_t>::infinity());
            json const j(n);
            CHECK(j.type() == json::value_t::number_float);

            // check round trip of infinity
            json::number_float_t const d{j};
            CHECK(d == n);

            // check that inf is serialized to null
            CHECK(j.dump() == "null");
        }
    }

    SECTION("create a floating-point number (implicit)")
    {
        // reference object
        json::number_float_t const n_reference = 42.23;
        json const j_reference(n_reference);

        SECTION("float")
        {
            float const n = 42.23f;
            json const j(n);
            CHECK(j.type() == json::value_t::number_float);
            CHECK(j.m_data.m_value.number_float == Approx(j_reference.m_data.m_value.number_float));
        }

        SECTION("double")
        {
            double const n = 42.23;
            json const j(n);
            CHECK(j.type() == json::value_t::number_float);
            CHECK(j.m_data.m_value.number_float == Approx(j_reference.m_data.m_value.number_float));
        }

        SECTION("long double")
        {
            long double const n = 42.23L;
            json const j(n);
            CHECK(j.type() == json::value_t::number_float);
            CHECK(j.m_data.m_value.number_float == Approx(j_reference.m_data.m_value.number_float));
        }

        SECTION("floating-point literal without suffix")
        {
            json const j(42.23);
            CHECK(j.type() == json::value_t::number_float);
            CHECK(j.m_data.m_value.number_float == Approx(j_reference.m_data.m_value.number_float));
        }

        SECTION("integer literal with f suffix")
        {
            json const j(42.23f);
            CHECK(j.type() == json::value_t::number_float);
            CHECK(j.m_data.m_value.number_float == Approx(j_reference.m_data.m_value.number_float));
        }

        SECTION("integer literal with l suffix")
        {
            json const j(42.23L);
            CHECK(j.type() == json::value_t::number_float);
            CHECK(j.m_data.m_value.number_float == Approx(j_reference.m_data.m_value.number_float));
        }
    }

    SECTION("create a container (array or object) from an initializer list")
    {
        SECTION("empty initializer list")
        {
            SECTION("explicit")
            {
                json const j(json::initializer_list_t {});
                CHECK(j.type() == json::value_t::object);
            }

            SECTION("implicit")
            {
                json const j {};
                CHECK(j.type() == json::value_t::null);
            }
        }

        SECTION("one element")
        {
            SECTION("array")
            {
                SECTION("explicit")
                {
                    json const j(json::initializer_list_t {json(json::array_t())});
                    CHECK(j.type() == json::value_t::array);
                }

                SECTION("implicit")
                {
                    json const j {json::array_t()};
                    CHECK(j.type() == json::value_t::array);
                }
            }

            SECTION("object")
            {
                SECTION("explicit")
                {
                    json const j(json::initializer_list_t {json(json::object_t())});
                    CHECK(j.type() == json::value_t::array);
                }

                SECTION("implicit")
                {
                    json const j {json::object_t()};
                    CHECK(j.type() == json::value_t::array);
                }
            }

            SECTION("string")
            {
                SECTION("explicit")
                {
                    json const j(json::initializer_list_t {json("Hello world")});
                    CHECK(j.type() == json::value_t::array);
                }

                SECTION("implicit")
                {
                    json const j {"Hello world"};
                    CHECK(j.type() == json::value_t::array);
                }
            }

            SECTION("boolean")
            {
                SECTION("explicit")
                {
                    json const j(json::initializer_list_t {json(true)});
                    CHECK(j.type() == json::value_t::array);
                }

                SECTION("implicit")
                {
                    json const j {true};
                    CHECK(j.type() == json::value_t::array);
                }
            }

            SECTION("number (integer)")
            {
                SECTION("explicit")
                {
                    json const j(json::initializer_list_t {json(1)});
                    CHECK(j.type() == json::value_t::array);
                }

                SECTION("implicit")
                {
                    json const j {1};
                    CHECK(j.type() == json::value_t::array);
                }
            }

            SECTION("number (unsigned)")
            {
                SECTION("explicit")
                {
                    json const j(json::initializer_list_t {json(1u)});
                    CHECK(j.type() == json::value_t::array);
                }

                SECTION("implicit")
                {
                    json const j {1u};
                    CHECK(j.type() == json::value_t::array);
                }
            }

            SECTION("number (floating-point)")
            {
                SECTION("explicit")
                {
                    json const j(json::initializer_list_t {json(42.23)});
                    CHECK(j.type() == json::value_t::array);
                }

                SECTION("implicit")
                {
                    json const j {42.23};
                    CHECK(j.type() == json::value_t::array);
                }
            }
        }

        SECTION("more elements")
        {
            SECTION("explicit")
            {
                json const j(json::initializer_list_t {1, 1u, 42.23, true, nullptr, json::object_t(), json::array_t()});
                CHECK(j.type() == json::value_t::array);
            }

            SECTION("implicit")
            {
                json const j {1, 1u, 42.23, true, nullptr, json::object_t(), json::array_t()};
                CHECK(j.type() == json::value_t::array);
            }
        }

        SECTION("implicit type deduction")
        {
            SECTION("object")
            {
                json const j { {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false} };
                CHECK(j.type() == json::value_t::object);
            }

            SECTION("array")
            {
                json const j { {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false}, 13 };
                CHECK(j.type() == json::value_t::array);
            }
        }

        SECTION("explicit type deduction")
        {
            SECTION("empty object")
            {
                json const j = json::object();
                CHECK(j.type() == json::value_t::object);
            }

            SECTION("object")
            {
                json const j = json::object({ {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false} });
                CHECK(j.type() == json::value_t::object);
            }

            SECTION("object with error")
            {
                json _;
                CHECK_THROWS_WITH_AS(_ = json::object({ {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false}, 13 }), "[json.exception.type_error.301] cannot create object from initializer list", json::type_error&);
            }

            SECTION("empty array")
            {
                json const j = json::array();
                CHECK(j.type() == json::value_t::array);
            }

            SECTION("array")
            {
                json const j = json::array({ {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false} });
                CHECK(j.type() == json::value_t::array);
            }
        }

        SECTION("move from initializer_list")
        {
            SECTION("string")
            {
                SECTION("constructor with implicit types (array)")
                {
                    // This should break through any short string optimization in std::string
                    std::string source(1024, '!');
                    const auto* source_addr = source.data();
                    json j = {std::move(source)};
                    const auto* target_addr = j[0].get_ref<std::string const&>().data();
                    const bool success = (target_addr == source_addr);
                    CHECK(success);
                }

                SECTION("constructor with implicit types (object)")
                {
                    // This should break through any short string optimization in std::string
                    std::string source(1024, '!');
                    const auto* source_addr = source.data();
                    json j = {{"key", std::move(source)}};
                    const auto* target_addr = j["key"].get_ref<std::string const&>().data();
                    const bool success = (target_addr == source_addr);
                    CHECK(success);
                }

                SECTION("constructor with implicit types (object key)")
                {
                    // This should break through any short string optimization in std::string
                    std::string source(1024, '!');
                    const auto* source_addr = source.data();
                    json j = {{std::move(source), 42}};
                    const auto* target_addr = j.get_ref<json::object_t&>().begin()->first.data();
                    const bool success = (target_addr == source_addr);
                    CHECK(success);
                }
            }

            SECTION("array")
            {
                SECTION("constructor with implicit types (array)")
                {
                    json::array_t source = {1, 2, 3};
                    const auto* source_addr = source.data();
                    json j {std::move(source)};
                    const auto* target_addr = j[0].get_ref<json::array_t const&>().data();
                    const bool success = (target_addr == source_addr);
                    CHECK(success);
                }

                SECTION("constructor with implicit types (object)")
                {
                    json::array_t source = {1, 2, 3};
                    const auto* source_addr = source.data();
                    json const j {{"key", std::move(source)}};
                    const auto* target_addr = j["key"].get_ref<json::array_t const&>().data();
                    const bool success = (target_addr == source_addr);
                    CHECK(success);
                }

                SECTION("assignment with implicit types (array)")
                {
                    json::array_t source = {1, 2, 3};
                    const auto* source_addr = source.data();
                    json j = {std::move(source)};
                    const auto* target_addr = j[0].get_ref<json::array_t const&>().data();
                    const bool success = (target_addr == source_addr);
                    CHECK(success);
                }

                SECTION("assignment with implicit types (object)")
                {
                    json::array_t source = {1, 2, 3};
                    const auto* source_addr = source.data();
                    json j = {{"key", std::move(source)}};
                    const auto* target_addr = j["key"].get_ref<json::array_t const&>().data();
                    const bool success = (target_addr == source_addr);
                    CHECK(success);
                }
            }

            SECTION("object")
            {
                SECTION("constructor with implicit types (array)")
                {
                    json::object_t source = {{"hello", "world"}};
                    const json* source_addr = &source.at("hello");
                    json j {std::move(source)};
                    CHECK(&(j[0].get_ref<json::object_t const&>().at("hello")) == source_addr);
                }

                SECTION("constructor with implicit types (object)")
                {
                    json::object_t source = {{"hello", "world"}};
                    const json* source_addr = &source.at("hello");
                    json j {{"key", std::move(source)}};
                    CHECK(&(j["key"].get_ref<json::object_t const&>().at("hello")) == source_addr);
                }

                SECTION("assignment with implicit types (array)")
                {
                    json::object_t source = {{"hello", "world"}};
                    const json* source_addr = &source.at("hello");
                    json j = {std::move(source)};
                    CHECK(&(j[0].get_ref<json::object_t const&>().at("hello")) == source_addr);
                }

                SECTION("assignment with implicit types (object)")
                {
                    json::object_t source = {{"hello", "world"}};
                    const json* source_addr = &source.at("hello");
                    json j = {{"key", std::move(source)}};
                    CHECK(&(j["key"].get_ref<json::object_t const&>().at("hello")) == source_addr);
                }
            }

            SECTION("json")
            {
                SECTION("constructor with implicit types (array)")
                {
                    json source {1, 2, 3};
                    const json* source_addr = &source[0];
                    json j {std::move(source), {}};
                    CHECK(&j[0][0] == source_addr);
                }

                SECTION("constructor with implicit types (object)")
                {
                    json source {1, 2, 3};
                    const json* source_addr = &source[0];
                    json j {{"key", std::move(source)}};
                    CHECK(&j["key"][0] == source_addr);
                }

                SECTION("assignment with implicit types (array)")
                {
                    json source {1, 2, 3};
                    const json* source_addr = &source[0];
                    json j = {std::move(source), {}};
                    CHECK(&j[0][0] == source_addr);
                }

                SECTION("assignment with implicit types (object)")
                {
                    json source {1, 2, 3};
                    const json* source_addr = &source[0];
                    json j = {{"key", std::move(source)}};
                    CHECK(&j["key"][0] == source_addr);
                }
            }

        }
    }

    SECTION("create an array of n copies of a given value")
    {
        SECTION("cnt = 0")
        {
            json const v = {1, "foo", 34.23, {1, 2, 3}, {{"A", 1}, {"B", 2u}}};
            json const arr(0, v);
            CHECK(arr.size() == 0);
        }

        SECTION("cnt = 1")
        {
            json const v = {1, "foo", 34.23, {1, 2, 3}, {{"A", 1}, {"B", 2u}}};
            json const arr(1, v);
            CHECK(arr.size() == 1);
            for (const auto& x : arr)
            {
                CHECK(x == v);
            }
        }

        SECTION("cnt = 3")
        {
            json const v = {1, "foo", 34.23, {1, 2, 3}, {{"A", 1}, {"B", 2u}}};
            json const arr(3, v);
            CHECK(arr.size() == 3);
            for (const auto& x : arr)
            {
                CHECK(x == v);
            }
        }
    }

    SECTION("create a JSON container from an iterator range")
    {
        SECTION("object")
        {
            SECTION("json(begin(), end())")
            {
                {
                    json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}};
                    json const j_new(jobject.begin(), jobject.end());
                    CHECK(j_new == jobject);
                }
                {
                    json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}};
                    json const j_new(jobject.cbegin(), jobject.cend());
                    CHECK(j_new == jobject);
                }
            }

            SECTION("json(begin(), begin())")
            {
                {
                    json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}};
                    json const j_new(jobject.begin(), jobject.begin());
                    CHECK(j_new == json::object());
                }
                {
                    json const jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}};
                    json const j_new(jobject.cbegin(), jobject.cbegin());
                    CHECK(j_new == json::object());
                }
            }

            SECTION("construct from subrange")
            {
                json const jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}};
                json const j_new(jobject.find("b"), jobject.find("e"));
                CHECK(j_new == json({{"b", 1}, {"c", 17u}, {"d", false}}));
            }

            SECTION("incompatible iterators")
            {
                {
                    json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}};
                    json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17u}};
                    CHECK_THROWS_WITH_AS(json(jobject.begin(), jobject2.end()), "[json.exception.invalid_iterator.201] iterators are not compatible", json::invalid_iterator&);
                    CHECK_THROWS_WITH_AS(json(jobject2.begin(), jobject.end()), "[json.exception.invalid_iterator.201] iterators are not compatible", json::invalid_iterator&);
                }
                {
                    json const jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}};
                    json const jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17u}};
                    CHECK_THROWS_WITH_AS(json(jobject.cbegin(), jobject2.cend()), "[json.exception.invalid_iterator.201] iterators are not compatible", json::invalid_iterator&);
                    CHECK_THROWS_WITH_AS(json(jobject2.cbegin(), jobject.cend()), "[json.exception.invalid_iterator.201] iterators are not compatible", json::invalid_iterator&);
                }
            }
        }

        SECTION("array")
        {
            SECTION("json(begin(), end())")
            {
                {
                    json jarray = {1, 2, 3, 4, 5};
                    json const j_new(jarray.begin(), jarray.end());
                    CHECK(j_new == jarray);
                }
                {
                    json const jarray = {1, 2, 3, 4, 5};
                    json const j_new(jarray.cbegin(), jarray.cend());
                    CHECK(j_new == jarray);
                }
            }

            SECTION("json(begin(), begin())")
            {
                {
                    json jarray = {1, 2, 3, 4, 5};
                    const json j_new(jarray.begin(), jarray.begin());
                    CHECK(j_new == json::array());
                }
                {
                    json const jarray = {1, 2, 3, 4, 5};
                    json const j_new(jarray.cbegin(), jarray.cbegin());
                    CHECK(j_new == json::array());
                }
            }

            SECTION("construct from subrange")
            {
                {
                    json jarray = {1, 2, 3, 4, 5};
                    json const j_new(jarray.begin() + 1, jarray.begin() + 3);
                    CHECK(j_new == json({2, 3}));
                }
                {
                    json const jarray = {1, 2, 3, 4, 5};
                    json const j_new(jarray.cbegin() + 1, jarray.cbegin() + 3);
                    CHECK(j_new == json({2, 3}));
                }
            }

            SECTION("incompatible iterators")
            {
                {
                    json jarray = {1, 2, 3, 4};
                    json jarray2 = {2, 3, 4, 5};
                    CHECK_THROWS_WITH_AS(json(jarray.begin(), jarray2.end()), "[json.exception.invalid_iterator.201] iterators are not compatible", json::invalid_iterator&);
                    CHECK_THROWS_WITH_AS(json(jarray2.begin(), jarray.end()), "[json.exception.invalid_iterator.201] iterators are not compatible", json::invalid_iterator&);
                }
                {
                    json const jarray = {1, 2, 3, 4};
                    json const jarray2 = {2, 3, 4, 5};
                    CHECK_THROWS_WITH_AS(json(jarray.cbegin(), jarray2.cend()), "[json.exception.invalid_iterator.201] iterators are not compatible", json::invalid_iterator&);
                    CHECK_THROWS_WITH_AS(json(jarray2.cbegin(), jarray.cend()), "[json.exception.invalid_iterator.201] iterators are not compatible", json::invalid_iterator&);
                }
            }
        }

        SECTION("other values")
        {
            SECTION("construct with two valid iterators")
            {
                SECTION("null")
                {
                    {
                        json j;
                        CHECK_THROWS_WITH_AS(json(j.begin(), j.end()), "[json.exception.invalid_iterator.206] cannot construct with iterators from null", json::invalid_iterator&);
                    }
                    {
                        json const j;
                        CHECK_THROWS_WITH_AS(json(j.cbegin(), j.cend()), "[json.exception.invalid_iterator.206] cannot construct with iterators from null", json::invalid_iterator&);
                    }
                }

                SECTION("string")
                {
                    {
                        json j = "foo";
                        json const j_new(j.begin(), j.end());
                        CHECK(j == j_new);
                    }
                    {
                        json const j = "bar";
                        json const j_new(j.cbegin(), j.cend());
                        CHECK(j == j_new);
                    }
                }

                SECTION("number (boolean)")
                {
                    {
                        json j = false;
                        json const j_new(j.begin(), j.end());
                        CHECK(j == j_new);
                    }
                    {
                        json const j = true;
                        json const j_new(j.cbegin(), j.cend());
                        CHECK(j == j_new);
                    }
                }

                SECTION("number (integer)")
                {
                    {
                        json j = 17;
                        json const j_new(j.begin(), j.end());
                        CHECK(j == j_new);
                    }
                    {
                        json const j = 17;
                        json const j_new(j.cbegin(), j.cend());
                        CHECK(j == j_new);
                    }
                }

                SECTION("number (unsigned)")
                {
                    {
                        json j = 17u;
                        json const j_new(j.begin(), j.end());
                        CHECK(j == j_new);
                    }
                    {
                        json const j = 17u;
                        json const j_new(j.cbegin(), j.cend());
                        CHECK(j == j_new);
                    }
                }

                SECTION("number (floating point)")
                {
                    {
                        json j = 23.42;
                        json const j_new(j.begin(), j.end());
                        CHECK(j == j_new);
                    }
                    {
                        json const j = 23.42;
                        json const j_new(j.cbegin(), j.cend());
                        CHECK(j == j_new);
                    }
                }

                SECTION("binary")
                {
                    {
                        json j = json::binary({1, 2, 3});
                        json const j_new(j.begin(), j.end());
                        CHECK((j == j_new));
                    }
                    {
                        json const j = json::binary({1, 2, 3});
                        json const j_new(j.cbegin(), j.cend());
                        CHECK((j == j_new));
                    }
                }
            }

            SECTION("construct with two invalid iterators")
            {
                SECTION("string")
                {
                    {
                        json j = "foo";
                        CHECK_THROWS_WITH_AS(json(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
                        CHECK_THROWS_WITH_AS(json(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
                    }
                    {
                        json const j = "bar";
                        CHECK_THROWS_WITH_AS(json(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
                        CHECK_THROWS_WITH_AS(json(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
                    }
                }

                SECTION("number (boolean)")
                {
                    {
                        json j = false;
                        CHECK_THROWS_WITH_AS(json(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
                        CHECK_THROWS_WITH_AS(json(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
                    }
                    {
                        json const j = true;
                        CHECK_THROWS_WITH_AS(json(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
                        CHECK_THROWS_WITH_AS(json(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
                    }
                }

                SECTION("number (integer)")
                {
                    {
                        json j = 17;
                        CHECK_THROWS_WITH_AS(json(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
                        CHECK_THROWS_WITH_AS(json(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
                    }
                    {
                        json const j = 17;
                        CHECK_THROWS_WITH_AS(json(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
                        CHECK_THROWS_WITH_AS(json(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
                    }
                }

                SECTION("number (integer)")
                {
                    {
                        json j = 17u;
                        CHECK_THROWS_WITH_AS(json(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
                        CHECK_THROWS_WITH_AS(json(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
                    }
                    {
                        json const j = 17u;
                        CHECK_THROWS_WITH_AS(json(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
                        CHECK_THROWS_WITH_AS(json(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
                    }
                }

                SECTION("number (floating point)")
                {
                    {
                        json j = 23.42;
                        CHECK_THROWS_WITH_AS(json(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
                        CHECK_THROWS_WITH_AS(json(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
                    }
                    {
                        json const j = 23.42;
                        CHECK_THROWS_WITH_AS(json(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
                        CHECK_THROWS_WITH_AS(json(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
                    }
                }
            }
        }
    }
}


# <small>nlohmann::basic_json::</small>binary

```cpp
// (1)
static basic_json binary(const typename binary_t::container_type& init);
static basic_json binary(typename binary_t::container_type&& init);

// (2)
static basic_json binary(const typename binary_t::container_type& init,
                         std::uint8_t subtype);
static basic_json binary(typename binary_t::container_type&& init,
                         std::uint8_t subtype);
```

1. Creates a JSON binary array value from a given binary container.
2. Creates a JSON binary array value from a given binary container with subtype.

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.

## Parameters

`init` (in)
:   container containing bytes to use as a binary type

`subtype` (in)
:   subtype to use in CBOR, MessagePack, and BSON

## Return value

JSON binary array value

## Exception safety

Strong guarantee: if an exception is thrown, there are no changes in the JSON value.

## Complexity

Linear in the size of `init`; constant for `typename binary_t::container_type&& init` versions.

## Notes

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 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.

## Examples

??? example

    The following code shows how to create a binary value.

    ```cpp
    --8<-- "examples/binary.cpp"
    ```

    Output:

    ```json
    --8<-- "examples/binary.output"
    ```

## Version history

- Added in version 3.8.0.


#include <iostream>

#define JSON_DIAGNOSTIC_POSITIONS 1
#include <nlohmann/json.hpp>

using json = nlohmann::json;

int main()
{
    std::string json_string = R"(
    {
        "address": {
            "street": "Fake Street",
            "housenumber": 1
        }
    }
    )";
    json j = json::parse(json_string);

    std::cout << "Root diagnostic positions: \n";
    std::cout << "\tstart_pos: " << j.start_pos() << '\n';
    std::cout << "\tend_pos:" << j.end_pos() << "\n";
    std::cout << "Original string: \n";
    std::cout << "{\n        \"address\": {\n            \"street\": \"Fake Street\",\n            \"housenumber\": 1\n        }\n    }" << "\n";
    std::cout << "Parsed string: \n";
    std::cout << json_string.substr(j.start_pos(), j.end_pos() - j.start_pos()) << "\n\n";

    std::cout << "address diagnostic positions: \n";
    std::cout << "\tstart_pos:" << j["address"].start_pos() << '\n';
    std::cout << "\tend_pos:" << j["address"].end_pos() << "\n\n";
    std::cout << "Original string: \n";
    std::cout << "{            \"street\": \"Fake Street\",\n            \"housenumber\": 1\n        }" << "\n";
    std::cout << "Parsed string: \n";
    std::cout << json_string.substr(j["address"].start_pos(), j["address"].end_pos() - j["address"].start_pos()) << "\n\n";

    std::cout << "street diagnostic positions: \n";
    std::cout << "\tstart_pos:" << j["address"]["street"].start_pos() << '\n';
    std::cout << "\tend_pos:" << j["address"]["street"].end_pos() << "\n\n";
    std::cout << "Original string: \n";
    std::cout << "\"Fake Street\"" << "\n";
    std::cout << "Parsed string: \n";
    std::cout << json_string.substr(j["address"]["street"].start_pos(), j["address"]["street"].end_pos() - j["address"]["street"].start_pos()) << "\n\n";

    std::cout << "housenumber diagnostic positions: \n";
    std::cout << "\tstart_pos:" << j["address"]["housenumber"].start_pos() << '\n';
    std::cout << "\tend_pos:" << j["address"]["housenumber"].end_pos() << "\n\n";
    std::cout << "Original string: \n";
    std::cout << "1" << "\n";
    std::cout << "Parsed string: \n";
    std::cout << json_string.substr(j["address"]["housenumber"].start_pos(), j["address"]["housenumber"].end_pos() - j["address"]["housenumber"].start_pos()) << "\n\n";
}