diff --git a/include/nlohmann/detail/output/binary_writer.hpp b/include/nlohmann/detail/output/binary_writer.hpp
index 363bb9b2..bce5116d 100644
--- a/include/nlohmann/detail/output/binary_writer.hpp
+++ b/include/nlohmann/detail/output/binary_writer.hpp
@@ -9,6 +9,7 @@
 #include <nlohmann/detail/input/binary_reader.hpp>
 #include <nlohmann/detail/output/output_adapters.hpp>
 
+
 namespace nlohmann
 {
 namespace detail
@@ -676,187 +677,278 @@ class binary_writer
         }
     }
 
-    std::size_t write_bson_boolean(const typename BasicJsonType::string_t& name, const BasicJsonType& j)
+    /*!
+    @return The size of a BSON document entry header, including the id marker and the entry name size (and its null-terminator).
+    */
+    static std::size_t calc_bson_entry_header_size(const typename BasicJsonType::string_t& name)
     {
-        oa->write_character(static_cast<CharType>(0x08)); // boolean
+        return /*id*/ 1ul + name.size() + /*zero-terminator*/1u;
+    }
+
+    /*!
+    @brief Writes the given @a element_type and @a name to the output adapter
+    */
+    void write_bson_entry_header(const typename BasicJsonType::string_t& name, std::uint8_t element_type)
+    {
+        oa->write_character(static_cast<CharType>(element_type)); // boolean
         oa->write_characters(
             reinterpret_cast<const CharType*>(name.c_str()),
             name.size() + 1u);
-        oa->write_character(j.m_value.boolean ? static_cast<CharType>(0x01) : static_cast<CharType>(0x00));
-        return /*id*/ 1ul + name.size() + 1u + /*boolean value*/ 1u;
     }
 
-    std::size_t write_bson_double(const typename BasicJsonType::string_t& name, const BasicJsonType& j)
+    /*!
+    @brief Writes a BSON element with key @a name and boolean value @a value
+    */
+    void write_bson_boolean(const typename BasicJsonType::string_t& name, const bool value)
     {
-        oa->write_character(static_cast<CharType>(0x01)); // double
-        oa->write_characters(
-            reinterpret_cast<const CharType*>(name.c_str()),
-            name.size() + 1u);
-        write_number<decltype(j.m_value.number_float), true>(j.m_value.number_float);
-        return /*id*/ 1ul + name.size() + 1u + /*double value*/ 8u;
+        write_bson_entry_header(name, 0x08);
+        oa->write_character(value ? static_cast<CharType>(0x01) : static_cast<CharType>(0x00));
     }
 
-    std::size_t write_bson_string(const typename BasicJsonType::string_t& name, const BasicJsonType& j)
+    /*!
+    @brief Writes a BSON element with key @a name and double value @a value
+    */
+    void write_bson_double(const typename BasicJsonType::string_t& name, const double value)
     {
-        oa->write_character(static_cast<CharType>(0x02)); // string (UTF-8)
-        oa->write_characters(
-            reinterpret_cast<const CharType*>(name.c_str()),
-            name.size() + 1u);
-
-        write_number<std::int32_t, true>(static_cast<std::int32_t>(j.m_value.string->size() + 1ul));
-        oa->write_characters(
-            reinterpret_cast<const CharType*>(j.m_value.string->c_str()),
-            j.m_value.string->size() + 1);
-
-        return /*id*/ 1ul + name.size() + 1ul + sizeof(std::int32_t) + j.m_value.string->size() + 1ul;
+        write_bson_entry_header(name, 0x01);
+        write_number<double, true>(value);
     }
 
-    std::size_t write_bson_null(const typename BasicJsonType::string_t& name, const BasicJsonType&)
+    /*!
+    @return The size of the BSON-encoded string in @a value
+    */
+    static std::size_t calc_bson_string_size(const typename BasicJsonType::string_t& value)
     {
-        oa->write_character(static_cast<CharType>(0x0A)); // null
-        oa->write_characters(
-            reinterpret_cast<const CharType*>(name.c_str()),
-            name.size() + 1u);
-
-        return /*id*/ 1ul + name.size() + 1ul;
+        return sizeof(std::int32_t) + value.size() + 1ul;
     }
 
-    std::size_t write_bson_integer(const typename BasicJsonType::string_t& name, const BasicJsonType& j)
+    /*!
+    @brief Writes a BSON element with key @a name and string value @a value
+    */
+    void write_bson_string(const typename BasicJsonType::string_t& name, const typename BasicJsonType::string_t& value)
     {
-        auto n = j.m_value.number_integer;
-        if ((std::numeric_limits<int32_t>::min)() <= n and n <= (std::numeric_limits<int32_t>::max)())
+        write_bson_entry_header(name, 0x02);
+
+        write_number<std::int32_t, true>(static_cast<std::int32_t>(value.size() + 1ul));
+        oa->write_characters(
+            reinterpret_cast<const CharType*>(value.c_str()),
+            value.size() + 1);
+    }
+
+    /*!
+    @brief Writes a BSON element with key @a name and null value
+    */
+    void write_bson_null(const typename BasicJsonType::string_t& name)
+    {
+        write_bson_entry_header(name, 0x0A);
+    }
+
+    /*!
+    @return The size of the BSON-encoded integer @a value
+    */
+    static std::size_t calc_bson_integer_size(const std::int64_t value)
+    {
+        if ((std::numeric_limits<std::int32_t>::min)() <= value and value <= (std::numeric_limits<std::int32_t>::max)())
         {
-            oa->write_character(static_cast<CharType>(0x10)); // int32
-            oa->write_characters(
-                reinterpret_cast<const CharType*>(name.c_str()),
-                name.size() + 1u);
-
-            write_number<std::int32_t, true>(static_cast<std::int32_t>(n));
-
-            return /*id*/ 1ul + name.size() + 1ul + sizeof(std::int32_t);
+            return sizeof(std::int32_t);
         }
         else
         {
-            oa->write_character(static_cast<CharType>(0x12)); // int64
-            oa->write_characters(
-                reinterpret_cast<const CharType*>(name.c_str()),
-                name.size() + 1u);
-
-            write_number<std::int64_t, true>(static_cast<std::int64_t>(j.m_value.number_integer));
-
-            return /*id*/ 1ul + name.size() + 1ul + sizeof(std::int64_t);
+            return sizeof(std::int64_t);
         }
     }
 
-    std::size_t write_bson_unsigned(const typename BasicJsonType::string_t& name, const BasicJsonType& j)
+    /*!
+    @brief Writes a BSON element with key @a name and integer @a value
+    */
+    void write_bson_integer(const typename BasicJsonType::string_t& name, const std::int64_t value)
     {
-        auto n = j.m_value.number_integer;
-        if (n <= static_cast<uint64_t>((std::numeric_limits<uint32_t>::max)()))
+        if ((std::numeric_limits<std::int32_t>::min)() <= value and value <= (std::numeric_limits<std::int32_t>::max)())
         {
-            oa->write_character(static_cast<CharType>(0x10)); // int32
-            oa->write_characters(
-                reinterpret_cast<const CharType*>(name.c_str()),
-                name.size() + 1u);
-
-            write_number<std::int32_t, true>(static_cast<std::int32_t>(n));
-
-            return /*id*/ 1ul + name.size() + 1ul + sizeof(std::int32_t);
+            write_bson_entry_header(name, 0x10); // int32
+            write_number<std::int32_t, true>(static_cast<std::int32_t>(value));
         }
         else
         {
-            oa->write_character(static_cast<CharType>(0x12)); // int64
-            oa->write_characters(
-                reinterpret_cast<const CharType*>(name.c_str()),
-                name.size() + 1u);
-
-            write_number<std::int64_t, true>(static_cast<std::int64_t>(j.m_value.number_integer));
-
-            return /*id*/ 1ul + name.size() + 1ul + sizeof(std::int64_t);
+            write_bson_entry_header(name, 0x12); // int64
+            write_number<std::int64_t, true>(static_cast<std::int64_t>(value));
         }
     }
 
-    std::size_t write_bson_object_internal(const typename BasicJsonType::string_t& name, const BasicJsonType& j)
+
+    /*!
+    @return The size of the BSON-encoded unsigned integer in @a j
+    */
+    static std::size_t calc_bson_unsigned_size(const std::uint64_t value)
     {
-        oa->write_character(static_cast<CharType>(0x03)); // object
-        oa->write_characters(
-            reinterpret_cast<const CharType*>(name.c_str()),
-            name.size() + 1u);
-
-        auto const embedded_document_size = write_bson_object(j);
-
-        return /*id*/ 1ul + name.size() + 1ul + embedded_document_size;
+        if (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
+        {
+            return sizeof(std::int32_t);
+        }
+        else
+        {
+            return sizeof(std::int64_t);
+        }
     }
 
-    std::size_t write_bson_array(const typename BasicJsonType::string_t& name, const BasicJsonType& j)
+    /*!
+    @brief Writes a BSON element with key @a name and unsigned @a value
+    */
+    void write_bson_unsigned(const typename BasicJsonType::string_t& name, const std::uint64_t value)
     {
-        oa->write_character(static_cast<CharType>(0x04)); // object
-        oa->write_characters(
-            reinterpret_cast<const CharType*>(name.c_str()),
-            name.size() + 1u);
-
-
-        auto document_size_offset = oa->reserve_characters(4ul);
-        std::int32_t embedded_document_size = 5ul;
-
-        for (const auto& el : *j.m_value.array)
+        if (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
         {
-            embedded_document_size += write_bson_object_entry("", el);
+            write_bson_entry_header(name, 0x10); // int32
+            write_number<std::int32_t, true>(static_cast<std::int32_t>(value));
+        }
+        else
+        {
+            write_bson_entry_header(name, 0x12); // int64
+            write_number<std::int64_t, true>(static_cast<std::int64_t>(value));
+        }
+    }
+
+    /*!
+    @brief Writes a BSON element with key @a name and object @a value
+    */
+    void write_bson_object_entry(const typename BasicJsonType::string_t& name, const typename BasicJsonType::object_t& value)
+    {
+        write_bson_entry_header(name, 0x03); // object
+        write_bson_object(value);
+    }
+
+
+    /*!
+    @return The size of the BSON-encoded array @a value
+    */
+    static std::size_t calc_bson_array_size(const typename BasicJsonType::array_t& value)
+    {
+        std::size_t embedded_document_size = 0ul;
+
+        for (const auto& el : value)
+        {
+            embedded_document_size += calc_bson_element_size("", el);
+        }
+
+        return sizeof(std::int32_t) + embedded_document_size + 1ul;
+    }
+
+    /*!
+    @brief Writes a BSON element with key @a name and array @a value
+    */
+    void write_bson_array(const typename BasicJsonType::string_t& name, const typename BasicJsonType::array_t& value)
+    {
+        write_bson_entry_header(name, 0x04); // array
+        write_number<std::int32_t, true>(calc_bson_array_size(value));
+
+        for (const auto& el : value)
+        {
+            write_bson_element("", el);
         }
 
         oa->write_character(static_cast<CharType>(0x00));
-        write_number_at<std::int32_t, true>(document_size_offset, embedded_document_size);
-
-        return /*id*/ 1ul + name.size() + 1ul + embedded_document_size;
     }
 
-    std::size_t write_bson_object_entry(const typename BasicJsonType::string_t& name, const BasicJsonType& j)
+
+    /*!
+    @brief Calculates the size necessary to serialize the JSON value @a j with its @a name
+    @return The calculated size for the BSON document entry for @a j with the given @a name.
+    */
+    static std::size_t calc_bson_element_size(const typename BasicJsonType::string_t& name, const BasicJsonType& j)
+    {
+        const auto header_size = calc_bson_entry_header_size(name);
+        switch (j.type())
+        {
+            // LCOV_EXCL_START
+            default:
+                assert(false);
+                return 0ul;
+            // LCOV_EXCL_STOP
+            case value_t::object:
+                return header_size + calc_bson_object_size(*j.m_value.object);
+            case value_t::array:
+                return header_size + calc_bson_array_size(*j.m_value.array);
+            case value_t::boolean:
+                return header_size + 1ul;
+            case value_t::number_float:
+                return header_size + 8ul;
+            case value_t::number_integer:
+                return header_size + calc_bson_integer_size(j.m_value.number_integer);
+            case value_t::number_unsigned:
+                return header_size + calc_bson_unsigned_size(j.m_value.number_unsigned);
+            case value_t::string:
+                return header_size + calc_bson_string_size(*j.m_value.string);
+            case value_t::null:
+                return header_size + 0ul;
+        };
+    }
+
+
+    /*!
+    @brief Serializes the JSON value @a j to BSON and associates it with the key @a name.
+    @param name The name to associate with the JSON entity @a j within the current BSON document
+    @return The size of the bson entry
+    */
+    void write_bson_element(const typename BasicJsonType::string_t& name, const BasicJsonType& j)
     {
         switch (j.type())
         {
             // LCOV_EXCL_START
             default:
                 assert(false);
-                break;
+                return;
             // LCOV_EXCL_STOP
             case value_t::object:
-                return write_bson_object_internal(name, j);
+                return write_bson_object_entry(name, *j.m_value.object);
             case value_t::array:
-                return write_bson_array(name, j);
+                return write_bson_array(name, *j.m_value.array);
             case value_t::boolean:
-                return write_bson_boolean(name, j);
+                return write_bson_boolean(name, j.m_value.boolean);
             case value_t::number_float:
-                return write_bson_double(name, j);
+                return write_bson_double(name, j.m_value.number_float);
             case value_t::number_integer:
-                return write_bson_integer(name, j);
+                return write_bson_integer(name, j.m_value.number_integer);
             case value_t::number_unsigned:
-                return write_bson_unsigned(name, j);
+                return write_bson_unsigned(name, j.m_value.number_unsigned);
             case value_t::string:
-                return write_bson_string(name, j);
+                return write_bson_string(name, *j.m_value.string);
             case value_t::null:
-                return write_bson_null(name, j);
+                return write_bson_null(name);
         };
+    }
 
-        return 0ul;
+    /*!
+    @brief Calculates the size of the BSON serialization of the given
+           JSON-object @a j.
+    @param[in] j  JSON value to serialize
+    @pre       j.type() == value_t::object
+    */
+    static std::size_t calc_bson_object_size(const typename BasicJsonType::object_t& value)
+    {
+        std::size_t document_size = 0;
+
+        for (const auto& el : value)
+        {
+            document_size += calc_bson_element_size(el.first, el.second);
+        }
+
+        return sizeof(std::int32_t) + document_size + 1ul;
     }
 
     /*!
     @param[in] j  JSON value to serialize
     @pre       j.type() == value_t::object
     */
-    std::size_t write_bson_object(const BasicJsonType& j)
+    void write_bson_object(const typename BasicJsonType::object_t& value)
     {
-        assert(j.type() == value_t::object);
-        auto document_size_offset = oa->reserve_characters(4ul);
-        std::int32_t document_size = 5ul;
+        write_number<std::int32_t, true>(calc_bson_object_size(value));
 
-        for (const auto& el : *j.m_value.object)
+        for (const auto& el : value)
         {
-            document_size += write_bson_object_entry(el.first, el.second);
+            write_bson_element(el.first, el.second);
         }
 
         oa->write_character(static_cast<CharType>(0x00));
-        write_number_at<std::int32_t, true>(document_size_offset, document_size);
-        return document_size;
     }
 
     /*!
@@ -873,7 +965,7 @@ class binary_writer
             case value_t::discarded:
                 break;
             case value_t::object:
-                write_bson_object(j);
+                write_bson_object(*j.m_value.object);
                 break;
         }
     }
@@ -909,35 +1001,6 @@ class binary_writer
         oa->write_characters(vec.data(), sizeof(NumberType));
     }
 
-    /*
-    @brief write a number to output in little endian format
-
-    @param[in] offset The offset where to start writing
-    @param[in] n number of type @a NumberType
-    @tparam NumberType the type of the number
-    @tparam OutputIsLittleEndian Set to true if output data is
-                                 required to be little endian
-    */
-    template<typename NumberType, bool OutputIsLittleEndian = false>
-    void write_number_at(std::size_t offset, const NumberType n)
-    {
-        // step 1: write number to array of length NumberType
-        std::array<CharType, sizeof(NumberType)> vec;
-        std::memcpy(vec.data(), &n, sizeof(NumberType));
-
-        // step 2: write array to output (with possible reordering)
-        // LCOV_EXCL_START
-        if (is_little_endian && !OutputIsLittleEndian)
-        {
-            // reverse byte order prior to conversion if necessary
-            std::reverse(vec.begin(), vec.end());
-        }
-        // LCOV_EXCL_STOP
-
-        oa->write_characters_at(offset, vec.data(), sizeof(NumberType));
-    }
-
-
     // UBJSON: write number (floating point)
     template<typename NumberType, typename std::enable_if<
                  std::is_floating_point<NumberType>::value, int>::type = 0>
diff --git a/include/nlohmann/detail/output/output_adapters.hpp b/include/nlohmann/detail/output/output_adapters.hpp
index 64960011..ff86a6e1 100644
--- a/include/nlohmann/detail/output/output_adapters.hpp
+++ b/include/nlohmann/detail/output/output_adapters.hpp
@@ -18,8 +18,6 @@ template<typename CharType> struct output_adapter_protocol
 {
     virtual void write_character(CharType c) = 0;
     virtual void write_characters(const CharType* s, std::size_t length) = 0;
-    virtual void write_characters_at(std::size_t position, const CharType* s, std::size_t length) = 0;
-    virtual std::size_t reserve_characters(std::size_t length) = 0;
     virtual ~output_adapter_protocol() = default;
 };
 
@@ -44,18 +42,6 @@ class output_vector_adapter : public output_adapter_protocol<CharType>
         std::copy(s, s + length, std::back_inserter(v));
     }
 
-    void write_characters_at(std::size_t position, const CharType* s, std::size_t length) override
-    {
-        std::copy(s, s + length, std::begin(v) + position);
-    }
-
-    std::size_t reserve_characters(std::size_t length) override
-    {
-        const auto position = v.size();
-        std::fill_n(std::back_inserter(v), length, static_cast<CharType>(0x00));
-        return position;
-    }
-
   private:
     std::vector<CharType>& v;
 };
@@ -77,22 +63,6 @@ class output_stream_adapter : public output_adapter_protocol<CharType>
         stream.write(s, static_cast<std::streamsize>(length));
     }
 
-    void write_characters_at(std::size_t position, const CharType* s, std::size_t length) override
-    {
-        const auto orig_offset = stream.tellp();
-        stream.seekp(static_cast<typename std::basic_ostream<CharType>::pos_type>(position));
-        stream.write(s, static_cast<std::streamsize>(length));
-        stream.seekp(orig_offset);
-    }
-
-    std::size_t reserve_characters(std::size_t length) override
-    {
-        const auto position = stream.tellp();
-        std::vector<CharType> empty(length, static_cast<CharType>(0));
-        stream.write(empty.data(), length);
-        return static_cast<std::size_t>(position);
-    }
-
   private:
     std::basic_ostream<CharType>& stream;
 };
@@ -114,19 +84,6 @@ class output_string_adapter : public output_adapter_protocol<CharType>
         str.append(s, length);
     }
 
-    void write_characters_at(std::size_t position, const CharType* s, std::size_t length) override
-    {
-        std::copy(s, s + length, std::begin(str) + position);
-    }
-
-    std::size_t reserve_characters(std::size_t length) override
-    {
-        const auto position = str.size();
-        std::fill_n(std::back_inserter(str), length, static_cast<CharType>(0x00));
-        return position;
-    }
-
-
   private:
     StringType& str;
 };
diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp
index c5d2e0db..1b61e995 100644
--- a/include/nlohmann/json.hpp
+++ b/include/nlohmann/json.hpp
@@ -6594,9 +6594,45 @@ class basic_json
     /*!
     @brief Serializes the given JSON object `j` to BSON and returns a vector
            containing the corresponding BSON-representation.
-    @param j The JSON object to convert to BSON.
-    @return The BSON representation of the JSON input `j`.
-    @pre The input `j` shall be an object: `j.is_object() == true`
+
+    BSON (Binary JSON) is a binary format in which zero or more ordered key/value pairs are
+    stored as a single entity (a so-called document).
+
+    The library uses the following mapping from JSON values types to BSON types:
+
+    JSON value type | value/range                       | BSON type   | marker
+    --------------- | --------------------------------- | ----------- | ------
+    null            | `null`                            | null        | 0x0A
+    boolean         | `true`, `false`                   | boolean     | 0x08
+    number_integer  | -9223372036854775808..-2147483649 | int64       | 0x12
+    number_integer  | -2147483648..2147483647           | int32       | 0x10
+    number_integer  | 2147483648..9223372036854775807   | int64       | 0x12
+    number_unsigned | 0..2147483647                     | int32       | 0x10
+    number_unsigned | 2147483648..9223372036854775807   | int64       | 0x12
+    number_float    | *any value*                       | double      | 0x01
+    string          | *any value*                       | string      | 0x02
+    array           | *any value*                       | document    | 0x04
+    object          | *any value*                       | document    | 0x03
+
+    @warning The mapping is **incomplete**, since only JSON-objects (and things
+    contained therein) can be serialized to BSON.
+
+    @pre The input `j` is required to be an object: `j.is_object() == true`
+
+    @note Any BSON output created via @ref to_bson can be successfully parsed
+          by @ref from_bson.
+
+    @param[in] j  JSON value to serialize
+    @return BSON serialization as byte vector
+
+    @complexity Linear in the size of the JSON value @a j.
+
+    @sa http://bsonspec.org/spec.html
+    @sa @ref from_bson(detail::input_adapter, const bool strict) for the
+        analogous deserialization
+    @sa @ref to_ubjson(const basic_json&) for the related UBJSON format
+    @sa @ref to_cbor(const basic_json&) for the related CBOR format
+    @sa @ref to_msgpack(const basic_json&) for the related MessagePack format
     */
     static std::vector<uint8_t> to_bson(const basic_json& j)
     {
@@ -6611,6 +6647,7 @@ class basic_json
     @param j The JSON object to convert to BSON.
     @param o The output adapter that receives the binary BSON representation.
     @pre The input `j` shall be an object: `j.is_object() == true`
+    @sa @ref to_bson(const basic_json&)
     */
     static void to_bson(const basic_json& j, detail::output_adapter<uint8_t> o)
     {
diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp
index 52fd79ca..48b17d17 100644
--- a/single_include/nlohmann/json.hpp
+++ b/single_include/nlohmann/json.hpp
@@ -5839,8 +5839,6 @@ template<typename CharType> struct output_adapter_protocol
 {
     virtual void write_character(CharType c) = 0;
     virtual void write_characters(const CharType* s, std::size_t length) = 0;
-    virtual void write_characters_at(std::size_t position, const CharType* s, std::size_t length) = 0;
-    virtual std::size_t reserve_characters(std::size_t length) = 0;
     virtual ~output_adapter_protocol() = default;
 };
 
@@ -5865,18 +5863,6 @@ class output_vector_adapter : public output_adapter_protocol<CharType>
         std::copy(s, s + length, std::back_inserter(v));
     }
 
-    void write_characters_at(std::size_t position, const CharType* s, std::size_t length) override
-    {
-        std::copy(s, s + length, std::begin(v) + position);
-    }
-
-    std::size_t reserve_characters(std::size_t length) override
-    {
-        const auto position = v.size();
-        std::fill_n(std::back_inserter(v), length, static_cast<CharType>(0x00));
-        return position;
-    }
-
   private:
     std::vector<CharType>& v;
 };
@@ -5898,22 +5884,6 @@ class output_stream_adapter : public output_adapter_protocol<CharType>
         stream.write(s, static_cast<std::streamsize>(length));
     }
 
-    void write_characters_at(std::size_t position, const CharType* s, std::size_t length) override
-    {
-        const auto orig_offset = stream.tellp();
-        stream.seekp(static_cast<typename std::basic_ostream<CharType>::pos_type>(position));
-        stream.write(s, static_cast<std::streamsize>(length));
-        stream.seekp(orig_offset);
-    }
-
-    std::size_t reserve_characters(std::size_t length) override
-    {
-        const auto position = stream.tellp();
-        std::vector<CharType> empty(length, static_cast<CharType>(0));
-        stream.write(empty.data(), length);
-        return static_cast<std::size_t>(position);
-    }
-
   private:
     std::basic_ostream<CharType>& stream;
 };
@@ -5935,19 +5905,6 @@ class output_string_adapter : public output_adapter_protocol<CharType>
         str.append(s, length);
     }
 
-    void write_characters_at(std::size_t position, const CharType* s, std::size_t length) override
-    {
-        std::copy(s, s + length, std::begin(str) + position);
-    }
-
-    std::size_t reserve_characters(std::size_t length) override
-    {
-        const auto position = str.size();
-        std::fill_n(std::back_inserter(str), length, static_cast<CharType>(0x00));
-        return position;
-    }
-
-
   private:
     StringType& str;
 };
@@ -7896,6 +7853,7 @@ class binary_reader
 // #include <nlohmann/detail/output/output_adapters.hpp>
 
 
+
 namespace nlohmann
 {
 namespace detail
@@ -8563,187 +8521,278 @@ class binary_writer
         }
     }
 
-    std::size_t write_bson_boolean(const typename BasicJsonType::string_t& name, const BasicJsonType& j)
+    /*!
+    @return The size of a BSON document entry header, including the id marker and the entry name size (and its null-terminator).
+    */
+    static std::size_t calc_bson_entry_header_size(const typename BasicJsonType::string_t& name)
     {
-        oa->write_character(static_cast<CharType>(0x08)); // boolean
+        return /*id*/ 1ul + name.size() + /*zero-terminator*/1u;
+    }
+
+    /*!
+    @brief Writes the given @a element_type and @a name to the output adapter
+    */
+    void write_bson_entry_header(const typename BasicJsonType::string_t& name, std::uint8_t element_type)
+    {
+        oa->write_character(static_cast<CharType>(element_type)); // boolean
         oa->write_characters(
             reinterpret_cast<const CharType*>(name.c_str()),
             name.size() + 1u);
-        oa->write_character(j.m_value.boolean ? static_cast<CharType>(0x01) : static_cast<CharType>(0x00));
-        return /*id*/ 1ul + name.size() + 1u + /*boolean value*/ 1u;
     }
 
-    std::size_t write_bson_double(const typename BasicJsonType::string_t& name, const BasicJsonType& j)
+    /*!
+    @brief Writes a BSON element with key @a name and boolean value @a value
+    */
+    void write_bson_boolean(const typename BasicJsonType::string_t& name, const bool value)
     {
-        oa->write_character(static_cast<CharType>(0x01)); // double
-        oa->write_characters(
-            reinterpret_cast<const CharType*>(name.c_str()),
-            name.size() + 1u);
-        write_number<decltype(j.m_value.number_float), true>(j.m_value.number_float);
-        return /*id*/ 1ul + name.size() + 1u + /*double value*/ 8u;
+        write_bson_entry_header(name, 0x08);
+        oa->write_character(value ? static_cast<CharType>(0x01) : static_cast<CharType>(0x00));
     }
 
-    std::size_t write_bson_string(const typename BasicJsonType::string_t& name, const BasicJsonType& j)
+    /*!
+    @brief Writes a BSON element with key @a name and double value @a value
+    */
+    void write_bson_double(const typename BasicJsonType::string_t& name, const double value)
     {
-        oa->write_character(static_cast<CharType>(0x02)); // string (UTF-8)
-        oa->write_characters(
-            reinterpret_cast<const CharType*>(name.c_str()),
-            name.size() + 1u);
-
-        write_number<std::int32_t, true>(static_cast<std::int32_t>(j.m_value.string->size() + 1ul));
-        oa->write_characters(
-            reinterpret_cast<const CharType*>(j.m_value.string->c_str()),
-            j.m_value.string->size() + 1);
-
-        return /*id*/ 1ul + name.size() + 1ul + sizeof(std::int32_t) + j.m_value.string->size() + 1ul;
+        write_bson_entry_header(name, 0x01);
+        write_number<double, true>(value);
     }
 
-    std::size_t write_bson_null(const typename BasicJsonType::string_t& name, const BasicJsonType&)
+    /*!
+    @return The size of the BSON-encoded string in @a value
+    */
+    static std::size_t calc_bson_string_size(const typename BasicJsonType::string_t& value)
     {
-        oa->write_character(static_cast<CharType>(0x0A)); // null
-        oa->write_characters(
-            reinterpret_cast<const CharType*>(name.c_str()),
-            name.size() + 1u);
-
-        return /*id*/ 1ul + name.size() + 1ul;
+        return sizeof(std::int32_t) + value.size() + 1ul;
     }
 
-    std::size_t write_bson_integer(const typename BasicJsonType::string_t& name, const BasicJsonType& j)
+    /*!
+    @brief Writes a BSON element with key @a name and string value @a value
+    */
+    void write_bson_string(const typename BasicJsonType::string_t& name, const typename BasicJsonType::string_t& value)
     {
-        auto n = j.m_value.number_integer;
-        if ((std::numeric_limits<int32_t>::min)() <= n and n <= (std::numeric_limits<int32_t>::max)())
+        write_bson_entry_header(name, 0x02);
+
+        write_number<std::int32_t, true>(static_cast<std::int32_t>(value.size() + 1ul));
+        oa->write_characters(
+            reinterpret_cast<const CharType*>(value.c_str()),
+            value.size() + 1);
+    }
+
+    /*!
+    @brief Writes a BSON element with key @a name and null value
+    */
+    void write_bson_null(const typename BasicJsonType::string_t& name)
+    {
+        write_bson_entry_header(name, 0x0A);
+    }
+
+    /*!
+    @return The size of the BSON-encoded integer @a value
+    */
+    static std::size_t calc_bson_integer_size(const std::int64_t value)
+    {
+        if ((std::numeric_limits<std::int32_t>::min)() <= value and value <= (std::numeric_limits<std::int32_t>::max)())
         {
-            oa->write_character(static_cast<CharType>(0x10)); // int32
-            oa->write_characters(
-                reinterpret_cast<const CharType*>(name.c_str()),
-                name.size() + 1u);
-
-            write_number<std::int32_t, true>(static_cast<std::int32_t>(n));
-
-            return /*id*/ 1ul + name.size() + 1ul + sizeof(std::int32_t);
+            return sizeof(std::int32_t);
         }
         else
         {
-            oa->write_character(static_cast<CharType>(0x12)); // int64
-            oa->write_characters(
-                reinterpret_cast<const CharType*>(name.c_str()),
-                name.size() + 1u);
-
-            write_number<std::int64_t, true>(static_cast<std::int64_t>(j.m_value.number_integer));
-
-            return /*id*/ 1ul + name.size() + 1ul + sizeof(std::int64_t);
+            return sizeof(std::int64_t);
         }
     }
 
-    std::size_t write_bson_unsigned(const typename BasicJsonType::string_t& name, const BasicJsonType& j)
+    /*!
+    @brief Writes a BSON element with key @a name and integer @a value
+    */
+    void write_bson_integer(const typename BasicJsonType::string_t& name, const std::int64_t value)
     {
-        auto n = j.m_value.number_integer;
-        if (n <= static_cast<uint64_t>((std::numeric_limits<uint32_t>::max)()))
+        if ((std::numeric_limits<std::int32_t>::min)() <= value and value <= (std::numeric_limits<std::int32_t>::max)())
         {
-            oa->write_character(static_cast<CharType>(0x10)); // int32
-            oa->write_characters(
-                reinterpret_cast<const CharType*>(name.c_str()),
-                name.size() + 1u);
-
-            write_number<std::int32_t, true>(static_cast<std::int32_t>(n));
-
-            return /*id*/ 1ul + name.size() + 1ul + sizeof(std::int32_t);
+            write_bson_entry_header(name, 0x10); // int32
+            write_number<std::int32_t, true>(static_cast<std::int32_t>(value));
         }
         else
         {
-            oa->write_character(static_cast<CharType>(0x12)); // int64
-            oa->write_characters(
-                reinterpret_cast<const CharType*>(name.c_str()),
-                name.size() + 1u);
-
-            write_number<std::int64_t, true>(static_cast<std::int64_t>(j.m_value.number_integer));
-
-            return /*id*/ 1ul + name.size() + 1ul + sizeof(std::int64_t);
+            write_bson_entry_header(name, 0x12); // int64
+            write_number<std::int64_t, true>(static_cast<std::int64_t>(value));
         }
     }
 
-    std::size_t write_bson_object_internal(const typename BasicJsonType::string_t& name, const BasicJsonType& j)
+
+    /*!
+    @return The size of the BSON-encoded unsigned integer in @a j
+    */
+    static std::size_t calc_bson_unsigned_size(const std::uint64_t value)
     {
-        oa->write_character(static_cast<CharType>(0x03)); // object
-        oa->write_characters(
-            reinterpret_cast<const CharType*>(name.c_str()),
-            name.size() + 1u);
-
-        auto const embedded_document_size = write_bson_object(j);
-
-        return /*id*/ 1ul + name.size() + 1ul + embedded_document_size;
+        if (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
+        {
+            return sizeof(std::int32_t);
+        }
+        else
+        {
+            return sizeof(std::int64_t);
+        }
     }
 
-    std::size_t write_bson_array(const typename BasicJsonType::string_t& name, const BasicJsonType& j)
+    /*!
+    @brief Writes a BSON element with key @a name and unsigned @a value
+    */
+    void write_bson_unsigned(const typename BasicJsonType::string_t& name, const std::uint64_t value)
     {
-        oa->write_character(static_cast<CharType>(0x04)); // object
-        oa->write_characters(
-            reinterpret_cast<const CharType*>(name.c_str()),
-            name.size() + 1u);
-
-
-        auto document_size_offset = oa->reserve_characters(4ul);
-        std::int32_t embedded_document_size = 5ul;
-
-        for (const auto& el : *j.m_value.array)
+        if (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
         {
-            embedded_document_size += write_bson_object_entry("", el);
+            write_bson_entry_header(name, 0x10); // int32
+            write_number<std::int32_t, true>(static_cast<std::int32_t>(value));
+        }
+        else
+        {
+            write_bson_entry_header(name, 0x12); // int64
+            write_number<std::int64_t, true>(static_cast<std::int64_t>(value));
+        }
+    }
+
+    /*!
+    @brief Writes a BSON element with key @a name and object @a value
+    */
+    void write_bson_object_entry(const typename BasicJsonType::string_t& name, const typename BasicJsonType::object_t& value)
+    {
+        write_bson_entry_header(name, 0x03); // object
+        write_bson_object(value);
+    }
+
+
+    /*!
+    @return The size of the BSON-encoded array @a value
+    */
+    static std::size_t calc_bson_array_size(const typename BasicJsonType::array_t& value)
+    {
+        std::size_t embedded_document_size = 0ul;
+
+        for (const auto& el : value)
+        {
+            embedded_document_size += calc_bson_element_size("", el);
+        }
+
+        return sizeof(std::int32_t) + embedded_document_size + 1ul;
+    }
+
+    /*!
+    @brief Writes a BSON element with key @a name and array @a value
+    */
+    void write_bson_array(const typename BasicJsonType::string_t& name, const typename BasicJsonType::array_t& value)
+    {
+        write_bson_entry_header(name, 0x04); // array
+        write_number<std::int32_t, true>(calc_bson_array_size(value));
+
+        for (const auto& el : value)
+        {
+            write_bson_element("", el);
         }
 
         oa->write_character(static_cast<CharType>(0x00));
-        write_number_at<std::int32_t, true>(document_size_offset, embedded_document_size);
-
-        return /*id*/ 1ul + name.size() + 1ul + embedded_document_size;
     }
 
-    std::size_t write_bson_object_entry(const typename BasicJsonType::string_t& name, const BasicJsonType& j)
+
+    /*!
+    @brief Calculates the size necessary to serialize the JSON value @a j with its @a name
+    @return The calculated size for the BSON document entry for @a j with the given @a name.
+    */
+    static std::size_t calc_bson_element_size(const typename BasicJsonType::string_t& name, const BasicJsonType& j)
+    {
+        const auto header_size = calc_bson_entry_header_size(name);
+        switch (j.type())
+        {
+            // LCOV_EXCL_START
+            default:
+                assert(false);
+                return 0ul;
+            // LCOV_EXCL_STOP
+            case value_t::object:
+                return header_size + calc_bson_object_size(*j.m_value.object);
+            case value_t::array:
+                return header_size + calc_bson_array_size(*j.m_value.array);
+            case value_t::boolean:
+                return header_size + 1ul;
+            case value_t::number_float:
+                return header_size + 8ul;
+            case value_t::number_integer:
+                return header_size + calc_bson_integer_size(j.m_value.number_integer);
+            case value_t::number_unsigned:
+                return header_size + calc_bson_unsigned_size(j.m_value.number_unsigned);
+            case value_t::string:
+                return header_size + calc_bson_string_size(*j.m_value.string);
+            case value_t::null:
+                return header_size + 0ul;
+        };
+    }
+
+
+    /*!
+    @brief Serializes the JSON value @a j to BSON and associates it with the key @a name.
+    @param name The name to associate with the JSON entity @a j within the current BSON document
+    @return The size of the bson entry
+    */
+    void write_bson_element(const typename BasicJsonType::string_t& name, const BasicJsonType& j)
     {
         switch (j.type())
         {
             // LCOV_EXCL_START
             default:
                 assert(false);
-                break;
+                return;
             // LCOV_EXCL_STOP
             case value_t::object:
-                return write_bson_object_internal(name, j);
+                return write_bson_object_entry(name, *j.m_value.object);
             case value_t::array:
-                return write_bson_array(name, j);
+                return write_bson_array(name, *j.m_value.array);
             case value_t::boolean:
-                return write_bson_boolean(name, j);
+                return write_bson_boolean(name, j.m_value.boolean);
             case value_t::number_float:
-                return write_bson_double(name, j);
+                return write_bson_double(name, j.m_value.number_float);
             case value_t::number_integer:
-                return write_bson_integer(name, j);
+                return write_bson_integer(name, j.m_value.number_integer);
             case value_t::number_unsigned:
-                return write_bson_unsigned(name, j);
+                return write_bson_unsigned(name, j.m_value.number_unsigned);
             case value_t::string:
-                return write_bson_string(name, j);
+                return write_bson_string(name, *j.m_value.string);
             case value_t::null:
-                return write_bson_null(name, j);
+                return write_bson_null(name);
         };
+    }
 
-        return 0ul;
+    /*!
+    @brief Calculates the size of the BSON serialization of the given
+           JSON-object @a j.
+    @param[in] j  JSON value to serialize
+    @pre       j.type() == value_t::object
+    */
+    static std::size_t calc_bson_object_size(const typename BasicJsonType::object_t& value)
+    {
+        std::size_t document_size = 0;
+
+        for (const auto& el : value)
+        {
+            document_size += calc_bson_element_size(el.first, el.second);
+        }
+
+        return sizeof(std::int32_t) + document_size + 1ul;
     }
 
     /*!
     @param[in] j  JSON value to serialize
     @pre       j.type() == value_t::object
     */
-    std::size_t write_bson_object(const BasicJsonType& j)
+    void write_bson_object(const typename BasicJsonType::object_t& value)
     {
-        assert(j.type() == value_t::object);
-        auto document_size_offset = oa->reserve_characters(4ul);
-        std::int32_t document_size = 5ul;
+        write_number<std::int32_t, true>(calc_bson_object_size(value));
 
-        for (const auto& el : *j.m_value.object)
+        for (const auto& el : value)
         {
-            document_size += write_bson_object_entry(el.first, el.second);
+            write_bson_element(el.first, el.second);
         }
 
         oa->write_character(static_cast<CharType>(0x00));
-        write_number_at<std::int32_t, true>(document_size_offset, document_size);
-        return document_size;
     }
 
     /*!
@@ -8760,7 +8809,7 @@ class binary_writer
             case value_t::discarded:
                 break;
             case value_t::object:
-                write_bson_object(j);
+                write_bson_object(*j.m_value.object);
                 break;
         }
     }
@@ -8796,35 +8845,6 @@ class binary_writer
         oa->write_characters(vec.data(), sizeof(NumberType));
     }
 
-    /*
-    @brief write a number to output in little endian format
-
-    @param[in] offset The offset where to start writing
-    @param[in] n number of type @a NumberType
-    @tparam NumberType the type of the number
-    @tparam OutputIsLittleEndian Set to true if output data is
-                                 required to be little endian
-    */
-    template<typename NumberType, bool OutputIsLittleEndian = false>
-    void write_number_at(std::size_t offset, const NumberType n)
-    {
-        // step 1: write number to array of length NumberType
-        std::array<CharType, sizeof(NumberType)> vec;
-        std::memcpy(vec.data(), &n, sizeof(NumberType));
-
-        // step 2: write array to output (with possible reordering)
-        // LCOV_EXCL_START
-        if (is_little_endian && !OutputIsLittleEndian)
-        {
-            // reverse byte order prior to conversion if necessary
-            std::reverse(vec.begin(), vec.end());
-        }
-        // LCOV_EXCL_STOP
-
-        oa->write_characters_at(offset, vec.data(), sizeof(NumberType));
-    }
-
-
     // UBJSON: write number (floating point)
     template<typename NumberType, typename std::enable_if<
                  std::is_floating_point<NumberType>::value, int>::type = 0>
@@ -18147,9 +18167,45 @@ class basic_json
     /*!
     @brief Serializes the given JSON object `j` to BSON and returns a vector
            containing the corresponding BSON-representation.
-    @param j The JSON object to convert to BSON.
-    @return The BSON representation of the JSON input `j`.
-    @pre The input `j` shall be an object: `j.is_object() == true`
+
+    BSON (Binary JSON) is a binary format in which zero or more ordered key/value pairs are
+    stored as a single entity (a so-called document).
+
+    The library uses the following mapping from JSON values types to BSON types:
+
+    JSON value type | value/range                       | BSON type   | marker
+    --------------- | --------------------------------- | ----------- | ------
+    null            | `null`                            | null        | 0x0A
+    boolean         | `true`, `false`                   | boolean     | 0x08
+    number_integer  | -9223372036854775808..-2147483649 | int64       | 0x12
+    number_integer  | -2147483648..2147483647           | int32       | 0x10
+    number_integer  | 2147483648..9223372036854775807   | int64       | 0x12
+    number_unsigned | 0..2147483647                     | int32       | 0x10
+    number_unsigned | 2147483648..9223372036854775807   | int64       | 0x12
+    number_float    | *any value*                       | double      | 0x01
+    string          | *any value*                       | string      | 0x02
+    array           | *any value*                       | document    | 0x04
+    object          | *any value*                       | document    | 0x03
+
+    @warning The mapping is **incomplete**, since only JSON-objects (and things
+    contained therein) can be serialized to BSON.
+
+    @pre The input `j` is required to be an object: `j.is_object() == true`
+
+    @note Any BSON output created via @ref to_bson can be successfully parsed
+          by @ref from_bson.
+
+    @param[in] j  JSON value to serialize
+    @return BSON serialization as byte vector
+
+    @complexity Linear in the size of the JSON value @a j.
+
+    @sa http://bsonspec.org/spec.html
+    @sa @ref from_bson(detail::input_adapter, const bool strict) for the
+        analogous deserialization
+    @sa @ref to_ubjson(const basic_json&) for the related UBJSON format
+    @sa @ref to_cbor(const basic_json&) for the related CBOR format
+    @sa @ref to_msgpack(const basic_json&) for the related MessagePack format
     */
     static std::vector<uint8_t> to_bson(const basic_json& j)
     {
@@ -18164,6 +18220,7 @@ class basic_json
     @param j The JSON object to convert to BSON.
     @param o The output adapter that receives the binary BSON representation.
     @pre The input `j` shall be an object: `j.is_object() == true`
+    @sa @ref to_bson(const basic_json&)
     */
     static void to_bson(const basic_json& j, detail::output_adapter<uint8_t> o)
     {
diff --git a/test/src/unit-alt-string.cpp b/test/src/unit-alt-string.cpp
index d866ed70..356835c0 100644
--- a/test/src/unit-alt-string.cpp
+++ b/test/src/unit-alt-string.cpp
@@ -102,16 +102,6 @@ class alt_string
         str_impl.resize(n, c);
     }
 
-    auto begin() -> std::string::iterator
-    {
-        return str_impl.begin();
-    }
-
-    auto end() -> std::string::iterator
-    {
-        return str_impl.end();
-    }
-
     template <typename op_type>
     bool operator<(const op_type& op) const
     {